blob: d1cec3976063b8fedaa7748f9b817fd7196c7504 [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>
Luc Saillard2b455db2006-04-24 10:29:46 -030067#include <linux/moduleparam.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69#include "pwc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#include "pwc-kiara.h"
71#include "pwc-timon.h"
Luc Saillard2b455db2006-04-24 10:29:46 -030072#include "pwc-dec23.h"
73#include "pwc-dec1.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#include "pwc-uncompress.h"
75
76/* Function prototypes and driver templates */
77
78/* hotplug device table support */
Luc Saillard2b455db2006-04-24 10:29:46 -030079static const struct usb_device_id pwc_device_table [] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
81 { USB_DEVICE(0x0471, 0x0303) },
82 { USB_DEVICE(0x0471, 0x0304) },
83 { USB_DEVICE(0x0471, 0x0307) },
84 { USB_DEVICE(0x0471, 0x0308) },
85 { USB_DEVICE(0x0471, 0x030C) },
86 { USB_DEVICE(0x0471, 0x0310) },
Luc Saillard2b455db2006-04-24 10:29:46 -030087 { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 { USB_DEVICE(0x0471, 0x0312) },
89 { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
Luc Saillard2b455db2006-04-24 10:29:46 -030090 { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
92 { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
93 { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
94 { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
95 { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
96 { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
97 { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
98 { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
99 { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
100 { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
Luc Saillard2b455db2006-04-24 10:29:46 -0300101 { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
102 { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
103 { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
105 { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
106 { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
107 { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
108 { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
109 { USB_DEVICE(0x0d81, 0x1900) },
110 { }
111};
112MODULE_DEVICE_TABLE(usb, pwc_device_table);
113
114static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
115static void usb_pwc_disconnect(struct usb_interface *intf);
116
117static struct usb_driver pwc_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 .name = "Philips webcam", /* name */
119 .id_table = pwc_device_table,
120 .probe = usb_pwc_probe, /* probe() */
121 .disconnect = usb_pwc_disconnect, /* disconnect() */
122};
123
124#define MAX_DEV_HINTS 20
125#define MAX_ISOC_ERRORS 20
126
127static int default_size = PSZ_QCIF;
128static int default_fps = 10;
129static int default_fbufs = 3; /* Default number of frame buffers */
Luc Saillard2b455db2006-04-24 10:29:46 -0300130 int pwc_mbufs = 2; /* Default number of mmap() buffers */
131#if CONFIG_PWC_DEBUG
132 int pwc_trace = PWC_DEBUG_LEVEL;
133#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134static int power_save = 0;
135static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
Luc Saillard2b455db2006-04-24 10:29:46 -0300136 int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137static struct {
138 int type;
139 char serial_number[30];
140 int device_node;
141 struct pwc_device *pdev;
142} device_hint[MAX_DEV_HINTS];
143
144/***/
145
146static int pwc_video_open(struct inode *inode, struct file *file);
147static int pwc_video_close(struct inode *inode, struct file *file);
Luc Saillard2b455db2006-04-24 10:29:46 -0300148static ssize_t pwc_video_read(struct file *file, char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 size_t count, loff_t *ppos);
150static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
151static int pwc_video_ioctl(struct inode *inode, struct file *file,
152 unsigned int ioctlnr, unsigned long arg);
153static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
154
155static struct file_operations pwc_fops = {
156 .owner = THIS_MODULE,
157 .open = pwc_video_open,
158 .release = pwc_video_close,
159 .read = pwc_video_read,
160 .poll = pwc_video_poll,
161 .mmap = pwc_video_mmap,
162 .ioctl = pwc_video_ioctl,
163 .llseek = no_llseek,
164};
165static struct video_device pwc_template = {
166 .owner = THIS_MODULE,
167 .name = "Philips Webcam", /* Filled in later */
168 .type = VID_TYPE_CAPTURE,
169 .hardware = VID_HARDWARE_PWC,
170 .release = video_device_release,
171 .fops = &pwc_fops,
172 .minor = -1,
173};
174
175/***************************************************************************/
176
177/* Okay, this is some magic that I worked out and the reasoning behind it...
178
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300179 The biggest problem with any USB device is of course: "what to do
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 when the user unplugs the device while it is in use by an application?"
181 We have several options:
182 1) Curse them with the 7 plagues when they do (requires divine intervention)
183 2) Tell them not to (won't work: they'll do it anyway)
184 3) Oops the kernel (this will have a negative effect on a user's uptime)
185 4) Do something sensible.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 Of course, we go for option 4.
188
189 It happens that this device will be linked to two times, once from
190 usb_device and once from the video_device in their respective 'private'
191 pointers. This is done when the device is probed() and all initialization
192 succeeded. The pwc_device struct links back to both structures.
193
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300194 When a device is unplugged while in use it will be removed from the
195 list of known USB devices; I also de-register it as a V4L device, but
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 unfortunately I can't free the memory since the struct is still in use
197 by the file descriptor. This free-ing is then deferend until the first
198 opportunity. Crude, but it works.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 A small 'advantage' is that if a user unplugs the cam and plugs it back
201 in, it should get assigned the same video device minor, but unfortunately
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300202 it's non-trivial to re-link the cam back to the video device... (that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 would surely be magic! :))
204*/
205
206/***************************************************************************/
207/* Private functions */
208
209/* Here we want the physical address of the memory.
210 * This is used when initializing the contents of the area.
211 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Luc Saillard2b455db2006-04-24 10:29:46 -0300214
215static void *pwc_rvmalloc(unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
217 void * mem;
218 unsigned long adr;
219
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300220 mem=vmalloc_32(size);
Luc Saillard2b455db2006-04-24 10:29:46 -0300221 if (!mem)
222 return NULL;
223
224 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
225 adr=(unsigned long) mem;
226 while (size > 0)
227 {
228 SetPageReserved(vmalloc_to_page((void *)adr));
229 adr += PAGE_SIZE;
230 size -= PAGE_SIZE;
231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 return mem;
233}
234
Luc Saillard2b455db2006-04-24 10:29:46 -0300235static void pwc_rvfree(void * mem, unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300237 unsigned long adr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Luc Saillard2b455db2006-04-24 10:29:46 -0300239 if (!mem)
240 return;
241
242 adr=(unsigned long) mem;
243 while ((long) size > 0)
244 {
245 ClearPageReserved(vmalloc_to_page((void *)adr));
246 adr += PAGE_SIZE;
247 size -= PAGE_SIZE;
248 }
249 vfree(mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250}
251
252
253
254
255static int pwc_allocate_buffers(struct pwc_device *pdev)
256{
Luc Saillard2b455db2006-04-24 10:29:46 -0300257 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 void *kbuf;
259
Luc Saillard2b455db2006-04-24 10:29:46 -0300260 PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 if (pdev == NULL)
263 return -ENXIO;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300264
Luc Saillard2b455db2006-04-24 10:29:46 -0300265 /* Allocate Isochronuous pipe buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 for (i = 0; i < MAX_ISO_BUFS; i++) {
267 if (pdev->sbuf[i].data == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300268 kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300270 PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 return -ENOMEM;
272 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300273 PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 pdev->sbuf[i].data = kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 }
276 }
277
278 /* Allocate frame buffer structure */
279 if (pdev->fbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300280 kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300282 PWC_ERROR("Failed to allocate frame buffer structure.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 return -ENOMEM;
284 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300285 PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 pdev->fbuf = kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300288
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 /* create frame buffers, and make circular ring */
290 for (i = 0; i < default_fbufs; i++) {
291 if (pdev->fbuf[i].data == NULL) {
292 kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
293 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300294 PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 return -ENOMEM;
296 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300297 PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 pdev->fbuf[i].data = kbuf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300299 memset(kbuf, 0, PWC_FRAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300302
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 /* Allocate decompressor table space */
Luc Saillard2b455db2006-04-24 10:29:46 -0300304 if (DEVICE_USE_CODEC1(pdev->type))
305 err = pwc_dec1_alloc(pdev);
306 else
307 err = pwc_dec23_alloc(pdev);
308
309 if (err) {
310 PWC_ERROR("Failed to allocate decompress table.\n");
311 return err;
312 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 /* Allocate image buffer; double buffer for mmap() */
Luc Saillard2b455db2006-04-24 10:29:46 -0300315 kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300317 PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
318 pwc_mbufs * pdev->len_per_image);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 return -ENOMEM;
320 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300321 PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 pdev->image_data = kbuf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300323 for (i = 0; i < pwc_mbufs; i++) {
324 pdev->images[i].offset = i * pdev->len_per_image;
325 pdev->images[i].vma_use_count = 0;
326 }
327 for (; i < MAX_IMAGES; i++) {
328 pdev->images[i].offset = 0;
329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 kbuf = NULL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300332
Luc Saillard2b455db2006-04-24 10:29:46 -0300333 PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 return 0;
335}
336
337static void pwc_free_buffers(struct pwc_device *pdev)
338{
339 int i;
340
Luc Saillard2b455db2006-04-24 10:29:46 -0300341 PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 if (pdev == NULL)
344 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 /* Release Iso-pipe buffers */
346 for (i = 0; i < MAX_ISO_BUFS; i++)
347 if (pdev->sbuf[i].data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300348 PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 kfree(pdev->sbuf[i].data);
350 pdev->sbuf[i].data = NULL;
351 }
352
353 /* The same for frame buffers */
354 if (pdev->fbuf != NULL) {
355 for (i = 0; i < default_fbufs; i++) {
356 if (pdev->fbuf[i].data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300357 PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 vfree(pdev->fbuf[i].data);
359 pdev->fbuf[i].data = NULL;
360 }
361 }
362 kfree(pdev->fbuf);
363 pdev->fbuf = NULL;
364 }
365
366 /* Intermediate decompression buffer & tables */
367 if (pdev->decompress_data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300368 PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 kfree(pdev->decompress_data);
370 pdev->decompress_data = NULL;
371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 /* Release image buffers */
374 if (pdev->image_data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300375 PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
376 pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 }
378 pdev->image_data = NULL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300379
Luc Saillard2b455db2006-04-24 10:29:46 -0300380 PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381}
382
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300383/* The frame & image buffer mess.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 Yes, this is a mess. Well, it used to be simple, but alas... In this
386 module, 3 buffers schemes are used to get the data from the USB bus to
387 the user program. The first scheme involves the ISO buffers (called thus
388 since they transport ISO data from the USB controller), and not really
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300389 interesting. Suffices to say the data from this buffer is quickly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 gathered in an interrupt handler (pwc_isoc_handler) and placed into the
391 frame buffer.
392
393 The frame buffer is the second scheme, and is the central element here.
394 It collects the data from a single frame from the camera (hence, the
395 name). Frames are delimited by the USB camera with a short USB packet,
396 so that's easy to detect. The frame buffers form a list that is filled
397 by the camera+USB controller and drained by the user process through
398 either read() or mmap().
399
400 The image buffer is the third scheme, in which frames are decompressed
401 and converted into planar format. For mmap() there is more than
402 one image buffer available.
403
404 The frame buffers provide the image buffering. In case the user process
405 is a bit slow, this introduces lag and some undesired side-effects.
406 The problem arises when the frame buffer is full. I used to drop the last
407 frame, which makes the data in the queue stale very quickly. But dropping
408 the frame at the head of the queue proved to be a litte bit more difficult.
409 I tried a circular linked scheme, but this introduced more problems than
410 it solved.
411
412 Because filling and draining are completely asynchronous processes, this
413 requires some fiddling with pointers and mutexes.
414
415 Eventually, I came up with a system with 2 lists: an 'empty' frame list
416 and a 'full' frame list:
417 * Initially, all frame buffers but one are on the 'empty' list; the one
418 remaining buffer is our initial fill frame.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300419 * If a frame is needed for filling, we try to take it from the 'empty'
420 list, unless that list is empty, in which case we take the buffer at
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 the head of the 'full' list.
422 * When our fill buffer has been filled, it is appended to the 'full'
423 list.
424 * If a frame is needed by read() or mmap(), it is taken from the head of
425 the 'full' list, handled, and then appended to the 'empty' list. If no
426 buffer is present on the 'full' list, we wait.
427 The advantage is that the buffer that is currently being decompressed/
428 converted, is on neither list, and thus not in our way (any other scheme
429 I tried had the problem of old data lingering in the queue).
430
431 Whatever strategy you choose, it always remains a tradeoff: with more
432 frame buffers the chances of a missed frame are reduced. On the other
433 hand, on slower machines it introduces lag because the queue will
434 always be full.
435 */
436
437/**
438 \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
439 */
Luc Saillard2b455db2006-04-24 10:29:46 -0300440static int pwc_next_fill_frame(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
442 int ret;
443 unsigned long flags;
444
445 ret = 0;
446 spin_lock_irqsave(&pdev->ptrlock, flags);
447 if (pdev->fill_frame != NULL) {
448 /* append to 'full' list */
449 if (pdev->full_frames == NULL) {
450 pdev->full_frames = pdev->fill_frame;
451 pdev->full_frames_tail = pdev->full_frames;
452 }
453 else {
454 pdev->full_frames_tail->next = pdev->fill_frame;
455 pdev->full_frames_tail = pdev->fill_frame;
456 }
457 }
458 if (pdev->empty_frames != NULL) {
459 /* We have empty frames available. That's easy */
460 pdev->fill_frame = pdev->empty_frames;
461 pdev->empty_frames = pdev->empty_frames->next;
462 }
463 else {
464 /* Hmm. Take it from the full list */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 /* sanity check */
466 if (pdev->full_frames == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300467 PWC_ERROR("Neither empty or full frames available!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 spin_unlock_irqrestore(&pdev->ptrlock, flags);
469 return -EINVAL;
470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 pdev->fill_frame = pdev->full_frames;
472 pdev->full_frames = pdev->full_frames->next;
473 ret = 1;
474 }
475 pdev->fill_frame->next = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 spin_unlock_irqrestore(&pdev->ptrlock, flags);
477 return ret;
478}
479
480
481/**
482 \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
483
484 If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
485 */
486static void pwc_reset_buffers(struct pwc_device *pdev)
487{
488 int i;
489 unsigned long flags;
490
Luc Saillard2b455db2006-04-24 10:29:46 -0300491 PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 spin_lock_irqsave(&pdev->ptrlock, flags);
494 pdev->full_frames = NULL;
495 pdev->full_frames_tail = NULL;
496 for (i = 0; i < default_fbufs; i++) {
497 pdev->fbuf[i].filled = 0;
498 if (i > 0)
499 pdev->fbuf[i].next = &pdev->fbuf[i - 1];
500 else
501 pdev->fbuf->next = NULL;
502 }
503 pdev->empty_frames = &pdev->fbuf[default_fbufs - 1];
504 pdev->empty_frames_tail = pdev->fbuf;
505 pdev->read_frame = NULL;
506 pdev->fill_frame = pdev->empty_frames;
507 pdev->empty_frames = pdev->empty_frames->next;
508
509 pdev->image_read_pos = 0;
510 pdev->fill_image = 0;
511 spin_unlock_irqrestore(&pdev->ptrlock, flags);
Luc Saillard2b455db2006-04-24 10:29:46 -0300512
513 PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514}
515
516
517/**
518 \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
519 */
Luc Saillard2b455db2006-04-24 10:29:46 -0300520int pwc_handle_frame(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
522 int ret = 0;
523 unsigned long flags;
524
525 spin_lock_irqsave(&pdev->ptrlock, flags);
526 /* First grab our read_frame; this is removed from all lists, so
527 we can release the lock after this without problems */
528 if (pdev->read_frame != NULL) {
529 /* This can't theoretically happen */
Luc Saillard2b455db2006-04-24 10:29:46 -0300530 PWC_ERROR("Huh? Read frame still in use?\n");
531 spin_unlock_irqrestore(&pdev->ptrlock, flags);
532 return ret;
533 }
534
535
536 if (pdev->full_frames == NULL) {
537 PWC_ERROR("Woops. No frames ready.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 }
539 else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300540 pdev->read_frame = pdev->full_frames;
541 pdev->full_frames = pdev->full_frames->next;
542 pdev->read_frame->next = NULL;
543 }
544
545 if (pdev->read_frame != NULL) {
546 /* Decompression is a lenghty process, so it's outside of the lock.
547 This gives the isoc_handler the opportunity to fill more frames
548 in the mean time.
549 */
550 spin_unlock_irqrestore(&pdev->ptrlock, flags);
551 ret = pwc_decompress(pdev);
552 spin_lock_irqsave(&pdev->ptrlock, flags);
553
554 /* We're done with read_buffer, tack it to the end of the empty buffer list */
555 if (pdev->empty_frames == NULL) {
556 pdev->empty_frames = pdev->read_frame;
557 pdev->empty_frames_tail = pdev->empty_frames;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 }
559 else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300560 pdev->empty_frames_tail->next = pdev->read_frame;
561 pdev->empty_frames_tail = pdev->read_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300563 pdev->read_frame = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 }
565 spin_unlock_irqrestore(&pdev->ptrlock, flags);
566 return ret;
567}
568
569/**
570 \brief Advance pointers of image buffer (after each user request)
571*/
Luc Saillard2b455db2006-04-24 10:29:46 -0300572void pwc_next_image(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
574 pdev->image_used[pdev->fill_image] = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300575 pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576}
577
Luc Saillard2b455db2006-04-24 10:29:46 -0300578/**
579 * Print debug information when a frame is discarded because all of our buffer
580 * is full
581 */
582static void pwc_frame_dumped(struct pwc_device *pdev)
583{
584 pdev->vframes_dumped++;
585 if (pdev->vframe_count < FRAME_LOWMARK)
586 return;
587
588 if (pdev->vframes_dumped < 20)
589 PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
590 else if (pdev->vframes_dumped == 20)
591 PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
592 pdev->vframe_count);
593}
594
595static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
596{
597 int awake = 0;
598
599 /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
600 frames on the USB wire after an exposure change. This conditition is
601 however detected in the cam and a bit is set in the header.
602 */
603 if (pdev->type == 730) {
604 unsigned char *ptr = (unsigned char *)fbuf->data;
605
606 if (ptr[1] == 1 && ptr[0] & 0x10) {
607 PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
608 pdev->drop_frames += 2;
609 pdev->vframes_error++;
610 }
611 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
612 if (ptr[0] & 0x01) {
613 pdev->snapshot_button_status = 1;
614 PWC_TRACE("Snapshot button pressed.\n");
615 }
616 else {
617 PWC_TRACE("Snapshot button released.\n");
618 }
619 }
620 if ((ptr[0] ^ pdev->vmirror) & 0x02) {
621 if (ptr[0] & 0x02)
622 PWC_TRACE("Image is mirrored.\n");
623 else
624 PWC_TRACE("Image is normal.\n");
625 }
626 pdev->vmirror = ptr[0] & 0x03;
627 /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
628 after a short frame; this condition is filtered out specifically. A 4 byte
629 frame doesn't make sense anyway.
630 So we get either this sequence:
631 drop_bit set -> 4 byte frame -> short frame -> good frame
632 Or this one:
633 drop_bit set -> short frame -> good frame
634 So we drop either 3 or 2 frames in all!
635 */
636 if (fbuf->filled == 4)
637 pdev->drop_frames++;
638 }
639 else if (pdev->type == 740 || pdev->type == 720) {
640 unsigned char *ptr = (unsigned char *)fbuf->data;
641 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
642 if (ptr[0] & 0x01) {
643 pdev->snapshot_button_status = 1;
644 PWC_TRACE("Snapshot button pressed.\n");
645 }
646 else
647 PWC_TRACE("Snapshot button released.\n");
648 }
649 pdev->vmirror = ptr[0] & 0x03;
650 }
651
652 /* In case we were instructed to drop the frame, do so silently.
653 The buffer pointers are not updated either (but the counters are reset below).
654 */
655 if (pdev->drop_frames > 0)
656 pdev->drop_frames--;
657 else {
658 /* Check for underflow first */
659 if (fbuf->filled < pdev->frame_total_size) {
660 PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
661 " discarded.\n", fbuf->filled);
662 pdev->vframes_error++;
663 }
664 else {
665 /* Send only once per EOF */
666 awake = 1; /* delay wake_ups */
667
668 /* Find our next frame to fill. This will always succeed, since we
669 * nick a frame from either empty or full list, but if we had to
670 * take it from the full list, it means a frame got dropped.
671 */
672 if (pwc_next_fill_frame(pdev))
673 pwc_frame_dumped(pdev);
674
675 }
676 } /* !drop_frames */
677 pdev->vframe_count++;
678 return awake;
679}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681/* This gets called for the Isochronous pipe (video). This is done in
682 * interrupt time, so it has to be fast, not crash, and not stall. Neat.
683 */
684static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
685{
686 struct pwc_device *pdev;
687 int i, fst, flen;
688 int awake;
689 struct pwc_frame_buf *fbuf;
690 unsigned char *fillptr = NULL, *iso_buf = NULL;
691
692 awake = 0;
693 pdev = (struct pwc_device *)urb->context;
694 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300695 PWC_ERROR("isoc_handler() called with NULL device?!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return;
697 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300700 PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 return;
702 }
703 if (urb->status != -EINPROGRESS && urb->status != 0) {
704 const char *errmsg;
705
706 errmsg = "Unknown";
707 switch(urb->status) {
708 case -ENOSR: errmsg = "Buffer error (overrun)"; break;
709 case -EPIPE: errmsg = "Stalled (device not responding)"; break;
710 case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break;
711 case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break;
712 case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
713 case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break;
714 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300715 PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300716 /* Give up after a number of contiguous errors on the USB bus.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 Appearantly something is wrong so we simulate an unplug event.
718 */
719 if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
720 {
Luc Saillard2b455db2006-04-24 10:29:46 -0300721 PWC_INFO("Too many ISOC errors, bailing out.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 pdev->error_status = EIO;
723 awake = 1;
724 wake_up_interruptible(&pdev->frameq);
725 }
726 goto handler_end; // ugly, but practical
727 }
728
729 fbuf = pdev->fill_frame;
730 if (fbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300731 PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 awake = 1;
733 goto handler_end;
734 }
735 else {
736 fillptr = fbuf->data + fbuf->filled;
737 }
738
739 /* Reset ISOC error counter. We did get here, after all. */
740 pdev->visoc_errors = 0;
741
742 /* vsync: 0 = don't copy data
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300743 1 = sync-hunt
744 2 = synched
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 */
746 /* Compact data */
747 for (i = 0; i < urb->number_of_packets; i++) {
748 fst = urb->iso_frame_desc[i].status;
749 flen = urb->iso_frame_desc[i].actual_length;
750 iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
751 if (fst == 0) {
752 if (flen > 0) { /* if valid data... */
753 if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */
754 pdev->vsync = 2;
755
756 /* ...copy data to frame buffer, if possible */
757 if (flen + fbuf->filled > pdev->frame_total_size) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300758 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 -0700759 pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
760 pdev->vframes_error++;
761 }
762 else {
763 memmove(fillptr, iso_buf, flen);
764 fillptr += flen;
765 }
766 }
767 fbuf->filled += flen;
768 } /* ..flen > 0 */
769
770 if (flen < pdev->vlast_packet_size) {
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300771 /* Shorter packet... We probably have the end of an image-frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 wake up read() process and let select()/poll() do something.
773 Decompression is done in user time over there.
Luc Saillard2b455db2006-04-24 10:29:46 -0300774 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if (pdev->vsync == 2) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300776 if (pwc_rcv_short_packet(pdev, fbuf)) {
777 awake = 1;
778 fbuf = pdev->fill_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 }
781 fbuf->filled = 0;
782 fillptr = fbuf->data;
783 pdev->vsync = 1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300784 }
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 pdev->vlast_packet_size = flen;
787 } /* ..status == 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300789 /* This is normally not interesting to the user, unless
790 * you are really debugging something */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 static int iso_error = 0;
792 iso_error++;
793 if (iso_error < 20)
Luc Saillard2b455db2006-04-24 10:29:46 -0300794 PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 }
797
798handler_end:
799 if (awake)
800 wake_up_interruptible(&pdev->frameq);
801
802 urb->dev = pdev->udev;
803 i = usb_submit_urb(urb, GFP_ATOMIC);
804 if (i != 0)
Luc Saillard2b455db2006-04-24 10:29:46 -0300805 PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806}
807
808
Luc Saillard2b455db2006-04-24 10:29:46 -0300809int pwc_isoc_init(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810{
811 struct usb_device *udev;
812 struct urb *urb;
813 int i, j, ret;
814
815 struct usb_interface *intf;
816 struct usb_host_interface *idesc = NULL;
817
818 if (pdev == NULL)
819 return -EFAULT;
820 if (pdev->iso_init)
821 return 0;
822 pdev->vsync = 0;
823 udev = pdev->udev;
824
825 /* Get the current alternate interface, adjust packet size */
826 if (!udev->actconfig)
827 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 intf = usb_ifnum_to_if(udev, 0);
829 if (intf)
830 idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 if (!idesc)
833 return -EFAULT;
834
835 /* Search video endpoint */
836 pdev->vmax_packet_size = -1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300837 for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
839 pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
840 break;
841 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300842 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300843
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300845 PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
Steven Cole093cf722005-05-03 19:07:24 -0600846 return -ENFILE; /* Odd error, that should be noticeable */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848
849 /* Set alternate interface */
850 ret = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300851 PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
853 if (ret < 0)
854 return ret;
855
856 for (i = 0; i < MAX_ISO_BUFS; i++) {
857 urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
858 if (urb == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300859 PWC_ERROR("Failed to allocate urb %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 ret = -ENOMEM;
861 break;
862 }
863 pdev->sbuf[i].urb = urb;
Luc Saillard2b455db2006-04-24 10:29:46 -0300864 PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 }
866 if (ret) {
867 /* De-allocate in reverse order */
868 while (i >= 0) {
869 if (pdev->sbuf[i].urb != NULL)
870 usb_free_urb(pdev->sbuf[i].urb);
871 pdev->sbuf[i].urb = NULL;
872 i--;
873 }
874 return ret;
875 }
876
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300877 /* init URB structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 for (i = 0; i < MAX_ISO_BUFS; i++) {
879 urb = pdev->sbuf[i].urb;
880
881 urb->interval = 1; // devik
882 urb->dev = udev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300883 urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 urb->transfer_flags = URB_ISO_ASAP;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300885 urb->transfer_buffer = pdev->sbuf[i].data;
886 urb->transfer_buffer_length = ISO_BUFFER_SIZE;
887 urb->complete = pwc_isoc_handler;
888 urb->context = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 urb->start_frame = 0;
890 urb->number_of_packets = ISO_FRAMES_PER_DESC;
891 for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
892 urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
893 urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
894 }
895 }
896
897 /* link */
898 for (i = 0; i < MAX_ISO_BUFS; i++) {
899 ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
900 if (ret)
Luc Saillard2b455db2006-04-24 10:29:46 -0300901 PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 else
Luc Saillard2b455db2006-04-24 10:29:46 -0300903 PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 }
905
906 /* All is done... */
907 pdev->iso_init = 1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300908 PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 return 0;
910}
911
Luc Saillard2b455db2006-04-24 10:29:46 -0300912void pwc_isoc_cleanup(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913{
914 int i;
915
Luc Saillard2b455db2006-04-24 10:29:46 -0300916 PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 if (pdev == NULL)
918 return;
Luc Saillard2b455db2006-04-24 10:29:46 -0300919 if (pdev->iso_init == 0)
920 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
922 /* Unlinking ISOC buffers one by one */
923 for (i = 0; i < MAX_ISO_BUFS; i++) {
924 struct urb *urb;
925
926 urb = pdev->sbuf[i].urb;
927 if (urb != 0) {
928 if (pdev->iso_init) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300929 PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 usb_kill_urb(urb);
931 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300932 PWC_DEBUG_MEMORY("Freeing URB\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 usb_free_urb(urb);
934 pdev->sbuf[i].urb = NULL;
935 }
936 }
937
938 /* Stop camera, but only if we are sure the camera is still there (unplug
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300939 is signalled by EPIPE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 */
941 if (pdev->error_status && pdev->error_status != EPIPE) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300942 PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 usb_set_interface(pdev->udev, 0, 0);
944 }
945
946 pdev->iso_init = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300947 PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948}
949
950int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
951{
952 int ret, start;
953
954 /* Stop isoc stuff */
955 pwc_isoc_cleanup(pdev);
956 /* Reset parameters */
957 pwc_reset_buffers(pdev);
958 /* Try to set video mode... */
959 start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300960 if (ret) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300961 PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 /* That failed... restore old mode (we know that worked) */
963 start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
964 if (start) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300965 PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 }
967 }
968 if (start == 0)
969 {
970 if (pwc_isoc_init(pdev) < 0)
971 {
Luc Saillard2b455db2006-04-24 10:29:46 -0300972 PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 ret = -EAGAIN; /* let's try again, who knows if it works a second time */
974 }
975 }
976 pdev->drop_frames++; /* try to avoid garbage during switch */
977 return ret; /* Return original error code */
978}
979
Luc Saillard2b455db2006-04-24 10:29:46 -0300980/*********
981 * sysfs
982 *********/
983static struct pwc_device *cd_to_pwc(struct class_device *cd)
984{
985 struct video_device *vdev = to_video_device(cd);
986 return video_get_drvdata(vdev);
987}
988
989static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
990{
991 struct pwc_device *pdev = cd_to_pwc(class_dev);
992 return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
993}
994
995static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
996 size_t count)
997{
998 struct pwc_device *pdev = cd_to_pwc(class_dev);
999 int pan, tilt;
1000 int ret = -EINVAL;
1001
1002 if (strncmp(buf, "reset", 5) == 0)
1003 ret = pwc_mpt_reset(pdev, 0x3);
1004
1005 else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
1006 ret = pwc_mpt_set_angle(pdev, pan, tilt);
1007
1008 if (ret < 0)
1009 return ret;
1010 return strlen(buf);
1011}
1012static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
1013 store_pan_tilt);
1014
1015static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
1016{
1017 struct pwc_device *pdev = cd_to_pwc(class_dev);
1018 int status = pdev->snapshot_button_status;
1019 pdev->snapshot_button_status = 0;
1020 return sprintf(buf, "%d\n", status);
1021}
1022
1023static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
1024 NULL);
1025
1026static void pwc_create_sysfs_files(struct video_device *vdev)
1027{
1028 struct pwc_device *pdev = video_get_drvdata(vdev);
1029 if (pdev->features & FEATURE_MOTOR_PANTILT)
1030 video_device_create_file(vdev, &class_device_attr_pan_tilt);
1031 video_device_create_file(vdev, &class_device_attr_button);
1032}
1033
1034static void pwc_remove_sysfs_files(struct video_device *vdev)
1035{
1036 struct pwc_device *pdev = video_get_drvdata(vdev);
1037 if (pdev->features & FEATURE_MOTOR_PANTILT)
1038 video_device_remove_file(vdev, &class_device_attr_pan_tilt);
1039 video_device_remove_file(vdev, &class_device_attr_button);
1040}
1041
1042#if CONFIG_PWC_DEBUG
1043static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
1044{
1045 switch(sensor_type) {
1046 case 0x00:
1047 return "Hyundai CMOS sensor";
1048 case 0x20:
1049 return "Sony CCD sensor + TDA8787";
1050 case 0x2E:
1051 return "Sony CCD sensor + Exas 98L59";
1052 case 0x2F:
1053 return "Sony CCD sensor + ADI 9804";
1054 case 0x30:
1055 return "Sharp CCD sensor + TDA8787";
1056 case 0x3E:
1057 return "Sharp CCD sensor + Exas 98L59";
1058 case 0x3F:
1059 return "Sharp CCD sensor + ADI 9804";
1060 case 0x40:
1061 return "UPA 1021 sensor";
1062 case 0x100:
1063 return "VGA sensor";
1064 case 0x101:
1065 return "PAL MR sensor";
1066 default:
Trent Piepho657de3c2006-06-20 00:30:57 -03001067 return "unknown type of sensor";
Luc Saillard2b455db2006-04-24 10:29:46 -03001068 }
1069}
1070#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072/***************************************************************************/
1073/* Video4Linux functions */
1074
1075static int pwc_video_open(struct inode *inode, struct file *file)
1076{
Luc Saillard2b455db2006-04-24 10:29:46 -03001077 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 struct video_device *vdev = video_devdata(file);
1079 struct pwc_device *pdev;
1080
Luc Saillard2b455db2006-04-24 10:29:46 -03001081 PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001082
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 pdev = (struct pwc_device *)vdev->priv;
1084 if (pdev == NULL)
1085 BUG();
Luc Saillard2b455db2006-04-24 10:29:46 -03001086 if (pdev->vopen) {
1087 PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 return -EBUSY;
Luc Saillard2b455db2006-04-24 10:29:46 -03001089 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 down(&pdev->modlock);
1092 if (!pdev->usb_init) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001093 PWC_DEBUG_OPEN("Doing first time initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 pdev->usb_init = 1;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001095
Luc Saillard2b455db2006-04-24 10:29:46 -03001096 /* Query sensor type */
1097 ret = pwc_get_cmos_sensor(pdev, &i);
1098 if (ret >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 {
Luc Saillard2b455db2006-04-24 10:29:46 -03001100 PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
1101 pdev->vdev->name,
1102 pwc_sensor_type_to_string(i), i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 }
1104 }
1105
1106 /* Turn on camera */
1107 if (power_save) {
1108 i = pwc_camera_power(pdev, 1);
1109 if (i < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001110 PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 }
1112 /* Set LED on/off time */
1113 if (pwc_set_leds(pdev, led_on, led_off) < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001114 PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001115
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 pwc_construct(pdev); /* set min/max sizes correct */
1117
1118 /* So far, so good. Allocate memory. */
1119 i = pwc_allocate_buffers(pdev);
1120 if (i < 0) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001121 PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
1122 pwc_free_buffers(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 up(&pdev->modlock);
1124 return i;
1125 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 /* Reset buffers & parameters */
1128 pwc_reset_buffers(pdev);
Luc Saillard2b455db2006-04-24 10:29:46 -03001129 for (i = 0; i < pwc_mbufs; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 pdev->image_used[i] = 0;
1131 pdev->vframe_count = 0;
1132 pdev->vframes_dumped = 0;
1133 pdev->vframes_error = 0;
1134 pdev->visoc_errors = 0;
1135 pdev->error_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 pwc_construct(pdev); /* set min/max sizes correct */
1137
1138 /* Set some defaults */
1139 pdev->vsnapshot = 0;
1140
1141 /* Start iso pipe for video; first try the last used video size
1142 (or the default one); if that fails try QCIF/10 or QSIF/10;
1143 it that fails too, give up.
1144 */
1145 i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
1146 if (i) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001147 unsigned int default_resolution;
1148 PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
1149 if (pdev->type>= 730)
1150 default_resolution = PSZ_QSIF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 else
Luc Saillard2b455db2006-04-24 10:29:46 -03001152 default_resolution = PSZ_QCIF;
1153
1154 i = pwc_set_video_mode(pdev,
1155 pwc_image_sizes[default_resolution].x,
1156 pwc_image_sizes[default_resolution].y,
1157 10,
1158 pdev->vcompression,
1159 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
1161 if (i) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001162 PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
1163 pwc_free_buffers(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 up(&pdev->modlock);
1165 return i;
1166 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 i = pwc_isoc_init(pdev);
1169 if (i) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001170 PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
1171 pwc_isoc_cleanup(pdev);
1172 pwc_free_buffers(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 up(&pdev->modlock);
1174 return i;
1175 }
1176
Luc Saillard2b455db2006-04-24 10:29:46 -03001177 /* Initialize the webcam to sane value */
1178 pwc_set_brightness(pdev, 0x7fff);
1179 pwc_set_agc(pdev, 1, 0);
1180
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 pdev->vopen++;
1182 file->private_data = vdev;
1183 up(&pdev->modlock);
Luc Saillard2b455db2006-04-24 10:29:46 -03001184 PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 return 0;
1186}
1187
1188/* Note that all cleanup is done in the reverse order as in _open */
1189static int pwc_video_close(struct inode *inode, struct file *file)
1190{
1191 struct video_device *vdev = file->private_data;
1192 struct pwc_device *pdev;
1193 int i;
1194
Luc Saillard2b455db2006-04-24 10:29:46 -03001195 PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
1197 pdev = (struct pwc_device *)vdev->priv;
1198 if (pdev->vopen == 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001199 PWC_DEBUG_MODULE("video_close() called on closed device?\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 /* Dump statistics, but only if a reasonable amount of frames were
1202 processed (to prevent endless log-entries in case of snap-shot
1203 programs)
1204 */
1205 if (pdev->vframe_count > 20)
Luc Saillard2b455db2006-04-24 10:29:46 -03001206 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 -07001207
Luc Saillard2b455db2006-04-24 10:29:46 -03001208 if (DEVICE_USE_CODEC1(pdev->type))
1209 pwc_dec1_exit();
1210 else
1211 pwc_dec23_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 pwc_isoc_cleanup(pdev);
1214 pwc_free_buffers(pdev);
1215
1216 /* Turn off LEDS and power down camera, but only when not unplugged */
1217 if (pdev->error_status != EPIPE) {
1218 /* Turn LEDs off */
1219 if (pwc_set_leds(pdev, 0, 0) < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001220 PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 if (power_save) {
1222 i = pwc_camera_power(pdev, 0);
1223 if (i < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001224 PWC_ERROR("Failed to power down camera (%d)\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 }
1226 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001227 pdev->vopen--;
1228 PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 return 0;
1230}
1231
1232/*
1233 * FIXME: what about two parallel reads ????
1234 * ANSWER: Not supported. You can't open the device more than once,
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001235 despite what the V4L1 interface says. First, I don't see
1236 the need, second there's no mechanism of alerting the
1237 2nd/3rd/... process of events like changing image size.
1238 And I don't see the point of blocking that for the
1239 2nd/3rd/... process.
1240 In multi-threaded environments reading parallel from any
1241 device is tricky anyhow.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 */
1243
Luc Saillard2b455db2006-04-24 10:29:46 -03001244static ssize_t pwc_video_read(struct file *file, char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 size_t count, loff_t *ppos)
1246{
1247 struct video_device *vdev = file->private_data;
1248 struct pwc_device *pdev;
1249 int noblock = file->f_flags & O_NONBLOCK;
1250 DECLARE_WAITQUEUE(wait, current);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001251 int bytes_to_read;
Luc Saillard2b455db2006-04-24 10:29:46 -03001252 void *image_buffer_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
Luc Saillard2b455db2006-04-24 10:29:46 -03001254 PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
1255 vdev, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 if (vdev == NULL)
1257 return -EFAULT;
1258 pdev = vdev->priv;
1259 if (pdev == NULL)
1260 return -EFAULT;
1261 if (pdev->error_status)
1262 return -pdev->error_status; /* Something happened, report what. */
1263
1264 /* In case we're doing partial reads, we don't have to wait for a frame */
1265 if (pdev->image_read_pos == 0) {
1266 /* Do wait queueing according to the (doc)book */
1267 add_wait_queue(&pdev->frameq, &wait);
1268 while (pdev->full_frames == NULL) {
1269 /* Check for unplugged/etc. here */
1270 if (pdev->error_status) {
1271 remove_wait_queue(&pdev->frameq, &wait);
1272 set_current_state(TASK_RUNNING);
1273 return -pdev->error_status ;
1274 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001275 if (noblock) {
1276 remove_wait_queue(&pdev->frameq, &wait);
1277 set_current_state(TASK_RUNNING);
1278 return -EWOULDBLOCK;
1279 }
1280 if (signal_pending(current)) {
1281 remove_wait_queue(&pdev->frameq, &wait);
1282 set_current_state(TASK_RUNNING);
1283 return -ERESTARTSYS;
1284 }
1285 schedule();
1286 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 }
1288 remove_wait_queue(&pdev->frameq, &wait);
1289 set_current_state(TASK_RUNNING);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001290
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 /* Decompress and release frame */
1292 if (pwc_handle_frame(pdev))
1293 return -EFAULT;
1294 }
1295
Luc Saillard2b455db2006-04-24 10:29:46 -03001296 PWC_DEBUG_READ("Copying data to user space.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (pdev->vpalette == VIDEO_PALETTE_RAW)
Luc Saillard2b455db2006-04-24 10:29:46 -03001298 bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 else
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001300 bytes_to_read = pdev->view.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302 /* copy bytes to user space; we allow for partial reads */
1303 if (count + pdev->image_read_pos > bytes_to_read)
1304 count = bytes_to_read - pdev->image_read_pos;
Luc Saillard2b455db2006-04-24 10:29:46 -03001305 image_buffer_addr = pdev->image_data;
1306 image_buffer_addr += pdev->images[pdev->fill_image].offset;
1307 image_buffer_addr += pdev->image_read_pos;
1308 if (copy_to_user(buf, image_buffer_addr, count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 return -EFAULT;
1310 pdev->image_read_pos += count;
1311 if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
1312 pdev->image_read_pos = 0;
1313 pwc_next_image(pdev);
1314 }
1315 return count;
1316}
1317
1318static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
1319{
1320 struct video_device *vdev = file->private_data;
1321 struct pwc_device *pdev;
1322
1323 if (vdev == NULL)
1324 return -EFAULT;
1325 pdev = vdev->priv;
1326 if (pdev == NULL)
1327 return -EFAULT;
1328
1329 poll_wait(file, &pdev->frameq, wait);
1330 if (pdev->error_status)
1331 return POLLERR;
1332 if (pdev->full_frames != NULL) /* we have frames waiting */
1333 return (POLLIN | POLLRDNORM);
1334
1335 return 0;
1336}
1337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338static int pwc_video_ioctl(struct inode *inode, struct file *file,
1339 unsigned int cmd, unsigned long arg)
1340{
1341 return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
1342}
1343
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
1345{
1346 struct video_device *vdev = file->private_data;
1347 struct pwc_device *pdev;
Luc Saillard2b455db2006-04-24 10:29:46 -03001348 unsigned long start;
1349 unsigned long size;
1350 unsigned long page, pos = 0;
1351 int index;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001352
Luc Saillard2b455db2006-04-24 10:29:46 -03001353 PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 pdev = vdev->priv;
Luc Saillard2b455db2006-04-24 10:29:46 -03001355 size = vma->vm_end - vma->vm_start;
1356 start = vma->vm_start;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001357
Luc Saillard2b455db2006-04-24 10:29:46 -03001358 /* Find the idx buffer for this mapping */
1359 for (index = 0; index < pwc_mbufs; index++) {
1360 pos = pdev->images[index].offset;
1361 if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
1362 break;
1363 }
1364 if (index == MAX_IMAGES)
1365 return -EINVAL;
1366 if (index == 0) {
1367 /*
1368 * Special case for v4l1. In v4l1, we map only one big buffer,
1369 * but in v4l2 each buffer is mapped
1370 */
1371 unsigned long total_size;
1372 total_size = pwc_mbufs * pdev->len_per_image;
1373 if (size != pdev->len_per_image && size != total_size) {
1374 PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
1375 size, pdev->len_per_image, total_size);
1376 return -EINVAL;
1377 }
1378 } else if (size > pdev->len_per_image)
1379 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Luc Saillard2b455db2006-04-24 10:29:46 -03001381 vma->vm_flags |= VM_IO; /* from 2.6.9-acX */
1382
1383 pos += (unsigned long)pdev->image_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 while (size > 0) {
1385 page = vmalloc_to_pfn((void *)pos);
1386 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1387 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 start += PAGE_SIZE;
1389 pos += PAGE_SIZE;
1390 if (size > PAGE_SIZE)
1391 size -= PAGE_SIZE;
1392 else
1393 size = 0;
1394 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 return 0;
1396}
1397
1398/***************************************************************************/
1399/* USB functions */
1400
1401/* This function gets called when a new device is plugged in or the usb core
1402 * is loaded.
1403 */
1404
1405static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
1406{
1407 struct usb_device *udev = interface_to_usbdev(intf);
1408 struct pwc_device *pdev = NULL;
1409 int vendor_id, product_id, type_id;
1410 int i, hint;
1411 int features = 0;
1412 int video_nr = -1; /* default: use next available device */
1413 char serial_number[30], *name;
1414
Luc Saillard2b455db2006-04-24 10:29:46 -03001415 vendor_id = le16_to_cpu(udev->descriptor.idVendor);
1416 product_id = le16_to_cpu(udev->descriptor.idProduct);
1417
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 /* Check if we can handle this device */
Luc Saillard2b455db2006-04-24 10:29:46 -03001419 PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
1420 vendor_id, product_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 intf->altsetting->desc.bInterfaceNumber);
1422
1423 /* the interfaces are probed one by one. We are only interested in the
1424 video interface (0) now.
1425 Interface 1 is the Audio Control, and interface 2 Audio itself.
1426 */
1427 if (intf->altsetting->desc.bInterfaceNumber > 0)
1428 return -ENODEV;
1429
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 if (vendor_id == 0x0471) {
1431 switch (product_id) {
1432 case 0x0302:
Luc Saillard2b455db2006-04-24 10:29:46 -03001433 PWC_INFO("Philips PCA645VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 name = "Philips 645 webcam";
1435 type_id = 645;
1436 break;
1437 case 0x0303:
Luc Saillard2b455db2006-04-24 10:29:46 -03001438 PWC_INFO("Philips PCA646VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 name = "Philips 646 webcam";
1440 type_id = 646;
1441 break;
1442 case 0x0304:
Luc Saillard2b455db2006-04-24 10:29:46 -03001443 PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 name = "Askey VC010 webcam";
1445 type_id = 646;
1446 break;
1447 case 0x0307:
Luc Saillard2b455db2006-04-24 10:29:46 -03001448 PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 name = "Philips 675 webcam";
1450 type_id = 675;
1451 break;
1452 case 0x0308:
Luc Saillard2b455db2006-04-24 10:29:46 -03001453 PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 name = "Philips 680 webcam";
1455 type_id = 680;
1456 break;
1457 case 0x030C:
Luc Saillard2b455db2006-04-24 10:29:46 -03001458 PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 name = "Philips 690 webcam";
1460 type_id = 690;
1461 break;
1462 case 0x0310:
Luc Saillard2b455db2006-04-24 10:29:46 -03001463 PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 name = "Philips 730 webcam";
1465 type_id = 730;
1466 break;
1467 case 0x0311:
Luc Saillard2b455db2006-04-24 10:29:46 -03001468 PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 name = "Philips 740 webcam";
1470 type_id = 740;
1471 break;
1472 case 0x0312:
Luc Saillard2b455db2006-04-24 10:29:46 -03001473 PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 name = "Philips 750 webcam";
1475 type_id = 750;
1476 break;
1477 case 0x0313:
Luc Saillard2b455db2006-04-24 10:29:46 -03001478 PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 name = "Philips 720K/40 webcam";
1480 type_id = 720;
1481 break;
Luc Saillard2b455db2006-04-24 10:29:46 -03001482 case 0x0329:
1483 PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
1484 name = "Philips SPC 900NC webcam";
1485 type_id = 720;
1486 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 default:
1488 return -ENODEV;
1489 break;
1490 }
1491 }
1492 else if (vendor_id == 0x069A) {
1493 switch(product_id) {
1494 case 0x0001:
Luc Saillard2b455db2006-04-24 10:29:46 -03001495 PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 name = "Askey VC010 webcam";
1497 type_id = 645;
1498 break;
1499 default:
1500 return -ENODEV;
1501 break;
1502 }
1503 }
1504 else if (vendor_id == 0x046d) {
1505 switch(product_id) {
1506 case 0x08b0:
Luc Saillard2b455db2006-04-24 10:29:46 -03001507 PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 name = "Logitech QuickCam Pro 3000";
1509 type_id = 740; /* CCD sensor */
1510 break;
1511 case 0x08b1:
Luc Saillard2b455db2006-04-24 10:29:46 -03001512 PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 name = "Logitech QuickCam Notebook Pro";
1514 type_id = 740; /* CCD sensor */
1515 break;
1516 case 0x08b2:
Luc Saillard2b455db2006-04-24 10:29:46 -03001517 PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 name = "Logitech QuickCam Pro 4000";
1519 type_id = 740; /* CCD sensor */
1520 break;
1521 case 0x08b3:
Luc Saillard2b455db2006-04-24 10:29:46 -03001522 PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 name = "Logitech QuickCam Zoom";
1524 type_id = 740; /* CCD sensor */
1525 break;
1526 case 0x08B4:
Luc Saillard2b455db2006-04-24 10:29:46 -03001527 PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 name = "Logitech QuickCam Zoom";
1529 type_id = 740; /* CCD sensor */
Luc Saillard2b455db2006-04-24 10:29:46 -03001530 power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 break;
1532 case 0x08b5:
Luc Saillard2b455db2006-04-24 10:29:46 -03001533 PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 name = "Logitech QuickCam Orbit";
1535 type_id = 740; /* CCD sensor */
1536 features |= FEATURE_MOTOR_PANTILT;
1537 break;
1538 case 0x08b6:
1539 case 0x08b7:
1540 case 0x08b8:
Luc Saillard2b455db2006-04-24 10:29:46 -03001541 PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 name = "Logitech QuickCam (res.)";
1543 type_id = 730; /* Assuming CMOS */
1544 break;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001545 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001547 break;
1548 }
1549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 else if (vendor_id == 0x055d) {
1551 /* I don't know the difference between the C10 and the C30;
1552 I suppose the difference is the sensor, but both cameras
1553 work equally well with a type_id of 675
1554 */
1555 switch(product_id) {
1556 case 0x9000:
Luc Saillard2b455db2006-04-24 10:29:46 -03001557 PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 name = "Samsung MPC-C10";
1559 type_id = 675;
1560 break;
1561 case 0x9001:
Luc Saillard2b455db2006-04-24 10:29:46 -03001562 PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 name = "Samsung MPC-C30";
1564 type_id = 675;
1565 break;
Luc Saillard2b455db2006-04-24 10:29:46 -03001566 case 0x9002:
1567 PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
1568 name = "Samsung MPC-C30";
1569 type_id = 740;
1570 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 default:
1572 return -ENODEV;
1573 break;
1574 }
1575 }
1576 else if (vendor_id == 0x041e) {
1577 switch(product_id) {
1578 case 0x400c:
Luc Saillard2b455db2006-04-24 10:29:46 -03001579 PWC_INFO("Creative Labs Webcam 5 detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 name = "Creative Labs Webcam 5";
1581 type_id = 730;
1582 break;
1583 case 0x4011:
Luc Saillard2b455db2006-04-24 10:29:46 -03001584 PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 name = "Creative Labs Webcam Pro Ex";
1586 type_id = 740;
1587 break;
1588 default:
1589 return -ENODEV;
1590 break;
1591 }
1592 }
1593 else if (vendor_id == 0x04cc) {
1594 switch(product_id) {
1595 case 0x8116:
Luc Saillard2b455db2006-04-24 10:29:46 -03001596 PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 name = "Sotec Afina Eye";
1598 type_id = 730;
1599 break;
1600 default:
1601 return -ENODEV;
1602 break;
1603 }
1604 }
1605 else if (vendor_id == 0x06be) {
1606 switch(product_id) {
1607 case 0x8116:
1608 /* This is essentially the same cam as the Sotec Afina Eye */
Luc Saillard2b455db2006-04-24 10:29:46 -03001609 PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 name = "AME Co. Afina Eye";
1611 type_id = 750;
1612 break;
1613 default:
1614 return -ENODEV;
1615 break;
1616 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001617
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 }
1619 else if (vendor_id == 0x0d81) {
1620 switch(product_id) {
1621 case 0x1900:
Luc Saillard2b455db2006-04-24 10:29:46 -03001622 PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 name = "Visionite VCS-UC300";
1624 type_id = 740; /* CCD sensor */
1625 break;
1626 case 0x1910:
Luc Saillard2b455db2006-04-24 10:29:46 -03001627 PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 name = "Visionite VCS-UM100";
1629 type_id = 730; /* CMOS sensor */
1630 break;
1631 default:
1632 return -ENODEV;
1633 break;
1634 }
1635 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001636 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 return -ENODEV; /* Not any of the know types; but the list keeps growing. */
1638
1639 memset(serial_number, 0, 30);
1640 usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
Luc Saillard2b455db2006-04-24 10:29:46 -03001641 PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
1643 if (udev->descriptor.bNumConfigurations > 1)
Luc Saillard2b455db2006-04-24 10:29:46 -03001644 PWC_WARNING("Warning: more than 1 configuration available.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01001647 pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001649 PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 return -ENOMEM;
1651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 pdev->type = type_id;
1653 pdev->vsize = default_size;
1654 pdev->vframes = default_fps;
1655 strcpy(pdev->serial, serial_number);
1656 pdev->features = features;
1657 if (vendor_id == 0x046D && product_id == 0x08B5)
1658 {
1659 /* Logitech QuickCam Orbit
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001660 The ranges have been determined experimentally; they may differ from cam to cam.
1661 Also, the exact ranges left-right and up-down are different for my cam
1662 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 pdev->angle_range.pan_min = -7000;
1664 pdev->angle_range.pan_max = 7000;
1665 pdev->angle_range.tilt_min = -3000;
1666 pdev->angle_range.tilt_max = 2500;
1667 }
1668
1669 init_MUTEX(&pdev->modlock);
1670 spin_lock_init(&pdev->ptrlock);
1671
1672 pdev->udev = udev;
1673 init_waitqueue_head(&pdev->frameq);
1674 pdev->vcompression = pwc_preferred_compression;
1675
1676 /* Allocate video_device structure */
1677 pdev->vdev = video_device_alloc();
1678 if (pdev->vdev == 0)
1679 {
Luc Saillard2b455db2006-04-24 10:29:46 -03001680 PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 kfree(pdev);
1682 return -ENOMEM;
1683 }
1684 memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
Luc Saillard2b455db2006-04-24 10:29:46 -03001685 pdev->vdev->dev = &(udev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 strcpy(pdev->vdev->name, name);
1687 pdev->vdev->owner = THIS_MODULE;
1688 video_set_drvdata(pdev->vdev, pdev);
1689
1690 pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
Luc Saillard2b455db2006-04-24 10:29:46 -03001691 PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 /* Now search device_hint[] table for a match, so we can hint a node number. */
1694 for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
1695 if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
1696 (device_hint[hint].pdev == NULL)) {
1697 /* so far, so good... try serial number */
1698 if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
Trent Piepho657de3c2006-06-20 00:30:57 -03001699 /* match! */
1700 video_nr = device_hint[hint].device_node;
1701 PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
1702 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 }
1704 }
1705 }
1706
1707 pdev->vdev->release = video_device_release;
1708 i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
1709 if (i < 0) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001710 PWC_ERROR("Failed to register as video device (%d).\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 video_device_release(pdev->vdev); /* Drip... drip... drip... */
1712 kfree(pdev); /* Oops, no memory leaks please */
1713 return -EIO;
1714 }
1715 else {
Luc Saillard2b455db2006-04-24 10:29:46 -03001716 PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 }
1718
1719 /* occupy slot */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001720 if (hint < MAX_DEV_HINTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 device_hint[hint].pdev = pdev;
1722
Luc Saillard2b455db2006-04-24 10:29:46 -03001723 PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 usb_set_intfdata (intf, pdev);
Luc Saillard2b455db2006-04-24 10:29:46 -03001725 pwc_create_sysfs_files(pdev->vdev);
1726
1727 /* Set the leds off */
1728 pwc_set_leds(pdev, 0, 0);
1729 pwc_camera_power(pdev, 0);
1730
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 return 0;
1732}
1733
1734/* The user janked out the cable... */
1735static void usb_pwc_disconnect(struct usb_interface *intf)
1736{
1737 struct pwc_device *pdev;
1738 int hint;
1739
1740 lock_kernel();
1741 pdev = usb_get_intfdata (intf);
1742 usb_set_intfdata (intf, NULL);
1743 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001744 PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 goto disconnect_out;
1746 }
1747 if (pdev->udev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001748 PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 goto disconnect_out;
1750 }
1751 if (pdev->udev != interface_to_usbdev(intf)) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001752 PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 goto disconnect_out;
1754 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 /* We got unplugged; this is signalled by an EPIPE error code */
1757 if (pdev->vopen) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001758 PWC_INFO("Disconnected while webcam is in use!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 pdev->error_status = EPIPE;
1760 }
1761
1762 /* Alert waiting processes */
1763 wake_up_interruptible(&pdev->frameq);
1764 /* Wait until device is closed */
1765 while (pdev->vopen)
1766 schedule();
1767 /* Device is now closed, so we can safely unregister it */
Luc Saillard2b455db2006-04-24 10:29:46 -03001768 PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
1769 pwc_remove_sysfs_files(pdev->vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 video_unregister_device(pdev->vdev);
1771
1772 /* Free memory (don't set pdev to 0 just yet) */
1773 kfree(pdev);
1774
1775disconnect_out:
1776 /* search device_hint[] table if we occupy a slot, by any chance */
1777 for (hint = 0; hint < MAX_DEV_HINTS; hint++)
1778 if (device_hint[hint].pdev == pdev)
1779 device_hint[hint].pdev = NULL;
1780
1781 unlock_kernel();
1782}
1783
1784
1785/* *grunt* We have to do atoi ourselves :-( */
1786static int pwc_atoi(const char *s)
1787{
1788 int k = 0;
1789
1790 k = 0;
1791 while (*s != '\0' && *s >= '0' && *s <= '9') {
1792 k = 10 * k + (*s - '0');
1793 s++;
1794 }
1795 return k;
1796}
1797
1798
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001799/*
1800 * Initialization code & module stuff
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 */
1802
Luc Saillard2b455db2006-04-24 10:29:46 -03001803static char *size;
1804static int fps;
1805static int fbufs;
1806static int mbufs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807static int compression = -1;
1808static int leds[2] = { -1, -1 };
Luc Saillard2b455db2006-04-24 10:29:46 -03001809static int leds_nargs;
1810static char *dev_hint[MAX_DEV_HINTS];
1811static int dev_hint_nargs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
Luc Saillard2b455db2006-04-24 10:29:46 -03001813module_param(size, charp, 0444);
1814module_param(fps, int, 0444);
1815module_param(fbufs, int, 0444);
1816module_param(mbufs, int, 0444);
1817#if CONFIG_PWC_DEBUG
1818module_param_named(trace, pwc_trace, int, 0644);
1819#endif
1820module_param(power_save, int, 0444);
1821module_param(compression, int, 0444);
1822module_param_array(leds, int, &leds_nargs, 0444);
1823module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
1824
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829MODULE_PARM_DESC(trace, "For debugging purposes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833MODULE_PARM_DESC(dev_hint, "Device node hints");
1834
1835MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
1836MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
1837MODULE_LICENSE("GPL");
Luc Saillard2b455db2006-04-24 10:29:46 -03001838MODULE_ALIAS("pwcx");
1839MODULE_VERSION( PWC_VERSION );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
1841static int __init usb_pwc_init(void)
1842{
1843 int i, sz;
1844 char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
1845
Luc Saillard2b455db2006-04-24 10:29:46 -03001846 PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
1847 PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
1848 PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
1849 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 -07001850
1851 if (fps) {
1852 if (fps < 4 || fps > 30) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001853 PWC_ERROR("Framerate out of bounds (4-30).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 return -EINVAL;
1855 }
1856 default_fps = fps;
Luc Saillard2b455db2006-04-24 10:29:46 -03001857 PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 }
1859
Luc Saillard2b455db2006-04-24 10:29:46 -03001860 if (size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 /* string; try matching with array */
1862 for (sz = 0; sz < PSZ_MAX; sz++) {
1863 if (!strcmp(sizenames[sz], size)) { /* Found! */
1864 default_size = sz;
1865 break;
1866 }
1867 }
1868 if (sz == PSZ_MAX) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001869 PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 return -EINVAL;
1871 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001872 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 -07001873 }
1874 if (mbufs) {
1875 if (mbufs < 1 || mbufs > MAX_IMAGES) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001876 PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 return -EINVAL;
1878 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001879 pwc_mbufs = mbufs;
1880 PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 }
1882 if (fbufs) {
1883 if (fbufs < 2 || fbufs > MAX_FRAMES) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001884 PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 return -EINVAL;
1886 }
1887 default_fbufs = fbufs;
Luc Saillard2b455db2006-04-24 10:29:46 -03001888 PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001890#if CONFIG_PWC_DEBUG
1891 if (pwc_trace >= 0) {
1892 PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001894#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if (compression >= 0) {
1896 if (compression > 3) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001897 PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 return -EINVAL;
1899 }
1900 pwc_preferred_compression = compression;
Luc Saillard2b455db2006-04-24 10:29:46 -03001901 PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 }
1903 if (power_save)
Luc Saillard2b455db2006-04-24 10:29:46 -03001904 PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 if (leds[0] >= 0)
1906 led_on = leds[0];
1907 if (leds[1] >= 0)
1908 led_off = leds[1];
1909
Steven Cole093cf722005-05-03 19:07:24 -06001910 /* Big device node whoopla. Basically, it allows you to assign a
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 device node (/dev/videoX) to a camera, based on its type
1912 & serial number. The format is [type[.serialnumber]:]node.
1913
1914 Any camera that isn't matched by these rules gets the next
1915 available free device node.
1916 */
1917 for (i = 0; i < MAX_DEV_HINTS; i++) {
1918 char *s, *colon, *dot;
1919
1920 /* This loop also initializes the array */
1921 device_hint[i].pdev = NULL;
1922 s = dev_hint[i];
1923 if (s != NULL && *s != '\0') {
1924 device_hint[i].type = -1; /* wildcard */
1925 strcpy(device_hint[i].serial_number, "*");
1926
1927 /* parse string: chop at ':' & '/' */
1928 colon = dot = s;
1929 while (*colon != '\0' && *colon != ':')
1930 colon++;
1931 while (*dot != '\0' && *dot != '.')
1932 dot++;
1933 /* Few sanity checks */
1934 if (*dot != '\0' && dot > colon) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001935 PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 return -EINVAL;
1937 }
1938
1939 if (*colon == '\0') {
1940 /* No colon */
1941 if (*dot != '\0') {
Luc Saillard2b455db2006-04-24 10:29:46 -03001942 PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 return -EINVAL;
1944 }
1945 else {
1946 /* No type or serial number specified, just a number. */
1947 device_hint[i].device_node = pwc_atoi(s);
1948 }
1949 }
1950 else {
1951 /* There's a colon, so we have at least a type and a device node */
1952 device_hint[i].type = pwc_atoi(s);
1953 device_hint[i].device_node = pwc_atoi(colon + 1);
1954 if (*dot != '\0') {
1955 /* There's a serial number as well */
1956 int k;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001957
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 dot++;
1959 k = 0;
1960 while (*dot != ':' && k < 29) {
1961 device_hint[i].serial_number[k++] = *dot;
1962 dot++;
1963 }
1964 device_hint[i].serial_number[k] = '\0';
1965 }
1966 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001967 PWC_TRACE("device_hint[%d]:\n", i);
1968 PWC_TRACE(" type : %d\n", device_hint[i].type);
1969 PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number);
1970 PWC_TRACE(" node : %d\n", device_hint[i].device_node);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 }
1972 else
1973 device_hint[i].type = 0; /* not filled */
1974 } /* ..for MAX_DEV_HINTS */
1975
Luc Saillard2b455db2006-04-24 10:29:46 -03001976 PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 return usb_register(&pwc_driver);
1978}
1979
1980static void __exit usb_pwc_exit(void)
1981{
Luc Saillard2b455db2006-04-24 10:29:46 -03001982 PWC_DEBUG_MODULE("Deregistering driver.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 usb_deregister(&pwc_driver);
Luc Saillard2b455db2006-04-24 10:29:46 -03001984 PWC_INFO("Philips webcam module removed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985}
1986
1987module_init(usb_pwc_init);
1988module_exit(usb_pwc_exit);
1989
Luc Saillard2b455db2006-04-24 10:29:46 -03001990/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */