blob: 01ff643e682dd8a7c9c20a79c980d8509b4b90a1 [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)
Hans de Goede6eba9352011-06-26 06:49:59 -03005 (C) 2011 Hans de Goede <hdegoede@redhat.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
7 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
8 driver and thus may have bugs that are not present in the original version.
9 Please send bug reports and support requests to <luc@saillard.org>.
10 The decompression routines have been implemented by reverse-engineering the
11 Nemosoft binary pwcx module. Caveat emptor.
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
27*/
28
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030029/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 This code forms the interface between the USB layers and the Philips
31 specific stuff. Some adanved stuff of the driver falls under an
32 NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030033 is thus not distributed in source form. The binary pwcx.o module
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 contains the code that falls under the NDA.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030035
36 In case you're wondering: 'pwc' stands for "Philips WebCam", but
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 I really didn't want to type 'philips_web_cam' every time (I'm lazy as
38 any Linux kernel hacker, but I don't like uncomprehensible abbreviations
39 without explanation).
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030040
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 Oh yes, convention: to disctinguish between all the various pointers to
42 device-structures, I use these names for the pointer variables:
43 udev: struct usb_device *
Hans de Goede9a7b2d12011-06-06 14:43:39 -030044 vdev: struct video_device (member of pwc_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 pdev: struct pwc_devive *
46*/
47
48/* Contributors:
49 - Alvarado: adding whitebalance code
50 - Alistar Moire: QuickCam 3000 Pro device/product ID
51 - Tony Hoyle: Creative Labs Webcam 5 device/product ID
52 - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
53 - Jk Fang: Sotec Afina Eye ID
54 - Xavier Roche: QuickCam Pro 4000 ID
55 - Jens Knudsen: QuickCam Zoom ID
56 - J. Debert: QuickCam for Notebooks ID
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -030057 - Pham Thanh Nam: webcam snapshot button as an event input device
Linus Torvalds1da177e2005-04-16 15:20:36 -070058*/
59
60#include <linux/errno.h>
61#include <linux/init.h>
62#include <linux/mm.h>
63#include <linux/module.h>
64#include <linux/poll.h>
65#include <linux/slab.h>
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -030066#ifdef CONFIG_USB_PWC_INPUT_EVDEV
67#include <linux/usb/input.h>
68#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#include <linux/vmalloc.h>
70#include <asm/io.h>
Andy Shevchenko2d8d7762009-09-24 07:58:09 -030071#include <linux/kernel.h> /* simple_strtol() */
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73#include "pwc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#include "pwc-kiara.h"
75#include "pwc-timon.h"
Luc Saillard2b455db2006-04-24 10:29:46 -030076#include "pwc-dec23.h"
77#include "pwc-dec1.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/* Function prototypes and driver templates */
80
81/* hotplug device table support */
Luc Saillard2b455db2006-04-24 10:29:46 -030082static const struct usb_device_id pwc_device_table [] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
84 { USB_DEVICE(0x0471, 0x0303) },
85 { USB_DEVICE(0x0471, 0x0304) },
86 { USB_DEVICE(0x0471, 0x0307) },
87 { USB_DEVICE(0x0471, 0x0308) },
88 { USB_DEVICE(0x0471, 0x030C) },
89 { USB_DEVICE(0x0471, 0x0310) },
Luc Saillard2b455db2006-04-24 10:29:46 -030090 { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 { USB_DEVICE(0x0471, 0x0312) },
92 { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
Luc Saillard2b455db2006-04-24 10:29:46 -030093 { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
95 { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
96 { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
97 { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
98 { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
99 { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
100 { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
Mauro Carvalho Chehab6b1ce3c2007-03-21 16:35:28 -0300101 { USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */
102 { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
Luc Saillard2b455db2006-04-24 10:29:46 -0300104 { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
105 { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
106 { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
108 { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
109 { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
110 { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
111 { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
112 { USB_DEVICE(0x0d81, 0x1900) },
113 { }
114};
115MODULE_DEVICE_TABLE(usb, pwc_device_table);
116
117static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
118static void usb_pwc_disconnect(struct usb_interface *intf);
Hans de Goede885fe182011-06-06 15:33:44 -0300119static void pwc_isoc_cleanup(struct pwc_device *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
121static struct usb_driver pwc_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 .name = "Philips webcam", /* name */
123 .id_table = pwc_device_table,
124 .probe = usb_pwc_probe, /* probe() */
125 .disconnect = usb_pwc_disconnect, /* disconnect() */
126};
127
128#define MAX_DEV_HINTS 20
129#define MAX_ISOC_ERRORS 20
130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131static int default_fps = 10;
Trent Piepho05ad3902007-01-30 23:26:01 -0300132#ifdef CONFIG_USB_PWC_DEBUG
Michael Krufkyb930e1d2007-08-27 18:16:54 -0300133 int pwc_trace = PWC_DEBUG_LEVEL;
Luc Saillard2b455db2006-04-24 10:29:46 -0300134#endif
Hans de Goede3b4d0ec2011-06-26 03:51:19 -0300135static int power_save = -1;
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300136static int led_on = 100, led_off; /* defaults to LED that is on while in use */
Adrian Bunkb20c3cf2006-06-23 06:49:34 -0300137static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static struct {
139 int type;
140 char serial_number[30];
141 int device_node;
142 struct pwc_device *pdev;
143} device_hint[MAX_DEV_HINTS];
144
145/***/
146
Hans Verkuilbec43662008-12-30 06:58:20 -0300147static int pwc_video_open(struct file *file);
148static int pwc_video_close(struct file *file);
Luc Saillard2b455db2006-04-24 10:29:46 -0300149static ssize_t pwc_video_read(struct file *file, char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 size_t count, loff_t *ppos);
151static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300153static void pwc_video_release(struct video_device *vfd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
Hans Verkuilbec43662008-12-30 06:58:20 -0300155static const struct v4l2_file_operations pwc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 .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,
Hans Verkuilafa38522011-01-22 06:34:55 -0300162 .unlocked_ioctl = video_ioctl2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163};
164static struct video_device pwc_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 .name = "Philips Webcam", /* Filled in later */
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300166 .release = pwc_video_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 .fops = &pwc_fops,
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300168 .ioctl_ops = &pwc_ioctl_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169};
170
171/***************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172/* Private functions */
173
Hans de Goede885fe182011-06-06 15:33:44 -0300174struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175{
Hans de Goede885fe182011-06-06 15:33:44 -0300176 unsigned long flags = 0;
177 struct pwc_frame_buf *buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Hans de Goede885fe182011-06-06 15:33:44 -0300179 spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
180 if (list_empty(&pdev->queued_bufs))
181 goto leave;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Hans de Goede885fe182011-06-06 15:33:44 -0300183 buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, list);
184 list_del(&buf->list);
185leave:
186 spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
187 return buf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300188}
189
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300190static void pwc_snapshot_button(struct pwc_device *pdev, int down)
191{
192 if (down) {
193 PWC_TRACE("Snapshot button pressed.\n");
194 pdev->snapshot_button_status = 1;
195 } else {
196 PWC_TRACE("Snapshot button released.\n");
197 }
198
199#ifdef CONFIG_USB_PWC_INPUT_EVDEV
200 if (pdev->button_dev) {
Lennart Poetteringbcd3e4b2009-06-11 11:19:33 -0300201 input_report_key(pdev->button_dev, KEY_CAMERA, down);
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300202 input_sync(pdev->button_dev);
203 }
204#endif
205}
206
Hans de Goede885fe182011-06-06 15:33:44 -0300207static void pwc_frame_complete(struct pwc_device *pdev)
Luc Saillard2b455db2006-04-24 10:29:46 -0300208{
Hans de Goede885fe182011-06-06 15:33:44 -0300209 struct pwc_frame_buf *fbuf = pdev->fill_buf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300210
211 /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
212 frames on the USB wire after an exposure change. This conditition is
213 however detected in the cam and a bit is set in the header.
214 */
215 if (pdev->type == 730) {
216 unsigned char *ptr = (unsigned char *)fbuf->data;
217
218 if (ptr[1] == 1 && ptr[0] & 0x10) {
219 PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
220 pdev->drop_frames += 2;
Luc Saillard2b455db2006-04-24 10:29:46 -0300221 }
222 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300223 pwc_snapshot_button(pdev, ptr[0] & 0x01);
Luc Saillard2b455db2006-04-24 10:29:46 -0300224 }
225 if ((ptr[0] ^ pdev->vmirror) & 0x02) {
226 if (ptr[0] & 0x02)
227 PWC_TRACE("Image is mirrored.\n");
228 else
229 PWC_TRACE("Image is normal.\n");
230 }
231 pdev->vmirror = ptr[0] & 0x03;
232 /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
233 after a short frame; this condition is filtered out specifically. A 4 byte
234 frame doesn't make sense anyway.
235 So we get either this sequence:
236 drop_bit set -> 4 byte frame -> short frame -> good frame
237 Or this one:
238 drop_bit set -> short frame -> good frame
239 So we drop either 3 or 2 frames in all!
240 */
241 if (fbuf->filled == 4)
242 pdev->drop_frames++;
Hans de Goede885fe182011-06-06 15:33:44 -0300243 } else if (pdev->type == 740 || pdev->type == 720) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300244 unsigned char *ptr = (unsigned char *)fbuf->data;
245 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300246 pwc_snapshot_button(pdev, ptr[0] & 0x01);
Luc Saillard2b455db2006-04-24 10:29:46 -0300247 }
248 pdev->vmirror = ptr[0] & 0x03;
249 }
250
Hans de Goede885fe182011-06-06 15:33:44 -0300251 /* In case we were instructed to drop the frame, do so silently. */
252 if (pdev->drop_frames > 0) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300253 pdev->drop_frames--;
Hans de Goede885fe182011-06-06 15:33:44 -0300254 } else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300255 /* Check for underflow first */
256 if (fbuf->filled < pdev->frame_total_size) {
257 PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
258 " discarded.\n", fbuf->filled);
Hans de Goede885fe182011-06-06 15:33:44 -0300259 } else {
260 fbuf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
261 fbuf->vb.v4l2_buf.sequence = pdev->vframe_count;
262 vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
263 pdev->fill_buf = NULL;
264 pdev->vsync = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300265 }
266 } /* !drop_frames */
267 pdev->vframe_count++;
Luc Saillard2b455db2006-04-24 10:29:46 -0300268}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
270/* This gets called for the Isochronous pipe (video). This is done in
271 * interrupt time, so it has to be fast, not crash, and not stall. Neat.
272 */
David Howells7d12e782006-10-05 14:55:46 +0100273static void pwc_isoc_handler(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
Hans de Goede885fe182011-06-06 15:33:44 -0300275 struct pwc_device *pdev = (struct pwc_device *)urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 int i, fst, flen;
Hans de Goede885fe182011-06-06 15:33:44 -0300277 unsigned char *iso_buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Hans de Goede885fe182011-06-06 15:33:44 -0300279 if (urb->status == -ENOENT || urb->status == -ECONNRESET ||
280 urb->status == -ESHUTDOWN) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300281 PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 return;
283 }
Hans de Goede885fe182011-06-06 15:33:44 -0300284
285 if (pdev->fill_buf == NULL)
286 pdev->fill_buf = pwc_get_next_fill_buf(pdev);
287
288 if (urb->status != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 const char *errmsg;
290
291 errmsg = "Unknown";
292 switch(urb->status) {
293 case -ENOSR: errmsg = "Buffer error (overrun)"; break;
294 case -EPIPE: errmsg = "Stalled (device not responding)"; break;
295 case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break;
296 case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break;
297 case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
Pete Zaitcev38e2bfc2006-09-18 22:49:02 -0700298 case -ETIME: errmsg = "Device does not respond"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
Hans de Goede885fe182011-06-06 15:33:44 -0300300 PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n",
301 urb->status, errmsg);
302 /* Give up after a number of contiguous errors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
304 {
Hans de Goede885fe182011-06-06 15:33:44 -0300305 PWC_ERROR("Too many ISOC errors, bailing out.\n");
306 if (pdev->fill_buf) {
307 vb2_buffer_done(&pdev->fill_buf->vb,
308 VB2_BUF_STATE_ERROR);
309 pdev->fill_buf = NULL;
310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 }
Hans de Goede885fe182011-06-06 15:33:44 -0300312 pdev->vsync = 0; /* Drop the current frame */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 goto handler_end;
314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 /* Reset ISOC error counter. We did get here, after all. */
317 pdev->visoc_errors = 0;
318
319 /* vsync: 0 = don't copy data
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300320 1 = sync-hunt
321 2 = synched
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 */
323 /* Compact data */
324 for (i = 0; i < urb->number_of_packets; i++) {
325 fst = urb->iso_frame_desc[i].status;
326 flen = urb->iso_frame_desc[i].actual_length;
327 iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
Hans de Goede885fe182011-06-06 15:33:44 -0300328 if (fst != 0) {
329 PWC_ERROR("Iso frame %d has error %d\n", i, fst);
330 continue;
331 }
332 if (flen > 0 && pdev->vsync) {
333 struct pwc_frame_buf *fbuf = pdev->fill_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Hans de Goede885fe182011-06-06 15:33:44 -0300335 if (pdev->vsync == 1) {
336 do_gettimeofday(&fbuf->vb.v4l2_buf.timestamp);
337 pdev->vsync = 2;
Luc Saillard2b455db2006-04-24 10:29:46 -0300338 }
339
Hans de Goede885fe182011-06-06 15:33:44 -0300340 if (flen + fbuf->filled > pdev->frame_total_size) {
341 PWC_ERROR("Frame overflow (%d > %d)\n",
342 flen + fbuf->filled,
343 pdev->frame_total_size);
344 pdev->vsync = 0; /* Let's wait for an EOF */
345 } else {
346 memcpy(fbuf->data + fbuf->filled, iso_buf,
347 flen);
348 fbuf->filled += flen;
349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 }
Hans de Goede885fe182011-06-06 15:33:44 -0300351 if (flen < pdev->vlast_packet_size) {
352 /* Shorter packet... end of frame */
353 if (pdev->vsync == 2)
354 pwc_frame_complete(pdev);
355 if (pdev->fill_buf == NULL)
356 pdev->fill_buf = pwc_get_next_fill_buf(pdev);
357 if (pdev->fill_buf) {
358 pdev->fill_buf->filled = 0;
359 pdev->vsync = 1;
360 }
361 }
362 pdev->vlast_packet_size = flen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 }
364
365handler_end:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 i = usb_submit_urb(urb, GFP_ATOMIC);
367 if (i != 0)
Luc Saillard2b455db2006-04-24 10:29:46 -0300368 PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369}
370
Hans de Goede885fe182011-06-06 15:33:44 -0300371static int pwc_isoc_init(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373 struct usb_device *udev;
374 struct urb *urb;
375 int i, j, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 struct usb_interface *intf;
377 struct usb_host_interface *idesc = NULL;
378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (pdev->iso_init)
380 return 0;
Hans de Goede6eba9352011-06-26 06:49:59 -0300381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 pdev->vsync = 0;
Hans de Goede6eba9352011-06-26 06:49:59 -0300383 pdev->vlast_packet_size = 0;
Hans de Goede885fe182011-06-06 15:33:44 -0300384 pdev->fill_buf = NULL;
385 pdev->vframe_count = 0;
Hans de Goede6eba9352011-06-26 06:49:59 -0300386 pdev->visoc_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 udev = pdev->udev;
388
389 /* Get the current alternate interface, adjust packet size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 intf = usb_ifnum_to_if(udev, 0);
391 if (intf)
392 idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 if (!idesc)
Hans de Goedec2464122011-06-06 15:25:18 -0300394 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
396 /* Search video endpoint */
397 pdev->vmax_packet_size = -1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300398 for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
400 pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
401 break;
402 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300403 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300406 PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
Steven Cole093cf722005-05-03 19:07:24 -0600407 return -ENFILE; /* Odd error, that should be noticeable */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 }
409
410 /* Set alternate interface */
411 ret = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300412 PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
414 if (ret < 0)
415 return ret;
416
Hans de Goede04613c52011-06-26 13:57:15 -0300417 /* Allocate and init Isochronuous urbs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 for (i = 0; i < MAX_ISO_BUFS; i++) {
419 urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
420 if (urb == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300421 PWC_ERROR("Failed to allocate urb %d\n", i);
Hans de Goede6eba9352011-06-26 06:49:59 -0300422 pdev->iso_init = 1;
423 pwc_isoc_cleanup(pdev);
424 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 }
Hans de Goede04613c52011-06-26 13:57:15 -0300426 pdev->urbs[i] = urb;
Luc Saillard2b455db2006-04-24 10:29:46 -0300427 PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429 urb->interval = 1; // devik
430 urb->dev = udev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300431 urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
Hans de Goede04613c52011-06-26 13:57:15 -0300432 urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
433 urb->transfer_buffer = usb_alloc_coherent(udev,
434 ISO_BUFFER_SIZE,
435 GFP_KERNEL,
436 &urb->transfer_dma);
437 if (urb->transfer_buffer == NULL) {
438 PWC_ERROR("Failed to allocate urb buffer %d\n", i);
439 pdev->iso_init = 1;
440 pwc_isoc_cleanup(pdev);
441 return -ENOMEM;
442 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300443 urb->transfer_buffer_length = ISO_BUFFER_SIZE;
444 urb->complete = pwc_isoc_handler;
445 urb->context = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 urb->start_frame = 0;
447 urb->number_of_packets = ISO_FRAMES_PER_DESC;
448 for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
449 urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
450 urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
451 }
452 }
453
454 /* link */
455 for (i = 0; i < MAX_ISO_BUFS; i++) {
Hans de Goede04613c52011-06-26 13:57:15 -0300456 ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL);
Hans de Goede622d9f52010-11-16 12:32:09 -0300457 if (ret) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300458 PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
Hans de Goede622d9f52010-11-16 12:32:09 -0300459 pdev->iso_init = 1;
460 pwc_isoc_cleanup(pdev);
461 return ret;
462 }
Hans de Goede04613c52011-06-26 13:57:15 -0300463 PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->urbs[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 }
465
466 /* All is done... */
467 pdev->iso_init = 1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300468 PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 return 0;
470}
471
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300472static void pwc_iso_stop(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
474 int i;
475
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 /* Unlinking ISOC buffers one by one */
477 for (i = 0; i < MAX_ISO_BUFS; i++) {
Hans de Goede04613c52011-06-26 13:57:15 -0300478 if (pdev->urbs[i]) {
479 PWC_DEBUG_MEMORY("Unlinking URB %p\n", pdev->urbs[i]);
480 usb_kill_urb(pdev->urbs[i]);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300481 }
482 }
483}
484
485static void pwc_iso_free(struct pwc_device *pdev)
486{
487 int i;
488
489 /* Freeing ISOC buffers one by one */
490 for (i = 0; i < MAX_ISO_BUFS; i++) {
Hans de Goede04613c52011-06-26 13:57:15 -0300491 if (pdev->urbs[i]) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300492 PWC_DEBUG_MEMORY("Freeing URB\n");
Hans de Goede04613c52011-06-26 13:57:15 -0300493 if (pdev->urbs[i]->transfer_buffer) {
494 usb_free_coherent(pdev->udev,
495 pdev->urbs[i]->transfer_buffer_length,
496 pdev->urbs[i]->transfer_buffer,
497 pdev->urbs[i]->transfer_dma);
498 }
499 usb_free_urb(pdev->urbs[i]);
500 pdev->urbs[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
502 }
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300503}
504
Hans de Goede885fe182011-06-06 15:33:44 -0300505static void pwc_isoc_cleanup(struct pwc_device *pdev)
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300506{
507 PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
Hans de Goedec2464122011-06-06 15:25:18 -0300508
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300509 if (pdev->iso_init == 0)
510 return;
511
512 pwc_iso_stop(pdev);
513 pwc_iso_free(pdev);
Hans de Goedeb824bb42011-06-25 17:39:19 -0300514 usb_set_interface(pdev->udev, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516 pdev->iso_init = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300517 PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518}
519
Hans de Goede885fe182011-06-06 15:33:44 -0300520/*
521 * Release all queued buffers, no need to take queued_bufs_lock, since all
522 * iso urbs have been killed when we're called so pwc_isoc_handler won't run.
523 */
524static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
525{
526 while (!list_empty(&pdev->queued_bufs)) {
527 struct pwc_frame_buf *buf;
528
529 buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf,
530 list);
531 list_del(&buf->list);
532 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
533 }
534}
535
Luc Saillard2b455db2006-04-24 10:29:46 -0300536/*********
537 * sysfs
538 *********/
Kay Sievers54bd5b62007-10-08 16:26:13 -0300539static struct pwc_device *cd_to_pwc(struct device *cd)
Luc Saillard2b455db2006-04-24 10:29:46 -0300540{
541 struct video_device *vdev = to_video_device(cd);
542 return video_get_drvdata(vdev);
543}
544
Kay Sievers54bd5b62007-10-08 16:26:13 -0300545static ssize_t show_pan_tilt(struct device *class_dev,
546 struct device_attribute *attr, char *buf)
Luc Saillard2b455db2006-04-24 10:29:46 -0300547{
548 struct pwc_device *pdev = cd_to_pwc(class_dev);
549 return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
550}
551
Kay Sievers54bd5b62007-10-08 16:26:13 -0300552static ssize_t store_pan_tilt(struct device *class_dev,
553 struct device_attribute *attr,
554 const char *buf, size_t count)
Luc Saillard2b455db2006-04-24 10:29:46 -0300555{
556 struct pwc_device *pdev = cd_to_pwc(class_dev);
557 int pan, tilt;
558 int ret = -EINVAL;
559
560 if (strncmp(buf, "reset", 5) == 0)
561 ret = pwc_mpt_reset(pdev, 0x3);
562
563 else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
564 ret = pwc_mpt_set_angle(pdev, pan, tilt);
565
566 if (ret < 0)
567 return ret;
568 return strlen(buf);
569}
Kay Sievers54bd5b62007-10-08 16:26:13 -0300570static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
571 store_pan_tilt);
Luc Saillard2b455db2006-04-24 10:29:46 -0300572
Kay Sievers54bd5b62007-10-08 16:26:13 -0300573static ssize_t show_snapshot_button_status(struct device *class_dev,
574 struct device_attribute *attr, char *buf)
Luc Saillard2b455db2006-04-24 10:29:46 -0300575{
576 struct pwc_device *pdev = cd_to_pwc(class_dev);
577 int status = pdev->snapshot_button_status;
578 pdev->snapshot_button_status = 0;
579 return sprintf(buf, "%d\n", status);
580}
581
Kay Sievers54bd5b62007-10-08 16:26:13 -0300582static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
583 NULL);
Luc Saillard2b455db2006-04-24 10:29:46 -0300584
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300585static int pwc_create_sysfs_files(struct pwc_device *pdev)
Luc Saillard2b455db2006-04-24 10:29:46 -0300586{
Jeff Garzikc12e3be2006-10-13 07:17:32 -0300587 int rc;
588
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300589 rc = device_create_file(&pdev->vdev.dev, &dev_attr_button);
Jeff Garzikc12e3be2006-10-13 07:17:32 -0300590 if (rc)
591 goto err;
592 if (pdev->features & FEATURE_MOTOR_PANTILT) {
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300593 rc = device_create_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300594 if (rc)
595 goto err_button;
Jeff Garzikc12e3be2006-10-13 07:17:32 -0300596 }
597
598 return 0;
599
600err_button:
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300601 device_remove_file(&pdev->vdev.dev, &dev_attr_button);
Jeff Garzikc12e3be2006-10-13 07:17:32 -0300602err:
Hans Verkuilf894dfd2008-07-25 07:39:54 -0300603 PWC_ERROR("Could not create sysfs files.\n");
Jeff Garzikc12e3be2006-10-13 07:17:32 -0300604 return rc;
Luc Saillard2b455db2006-04-24 10:29:46 -0300605}
606
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300607static void pwc_remove_sysfs_files(struct pwc_device *pdev)
Luc Saillard2b455db2006-04-24 10:29:46 -0300608{
Luc Saillard2b455db2006-04-24 10:29:46 -0300609 if (pdev->features & FEATURE_MOTOR_PANTILT)
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300610 device_remove_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
611 device_remove_file(&pdev->vdev.dev, &dev_attr_button);
Luc Saillard2b455db2006-04-24 10:29:46 -0300612}
613
Trent Piepho05ad3902007-01-30 23:26:01 -0300614#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -0300615static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
616{
617 switch(sensor_type) {
618 case 0x00:
619 return "Hyundai CMOS sensor";
620 case 0x20:
621 return "Sony CCD sensor + TDA8787";
622 case 0x2E:
623 return "Sony CCD sensor + Exas 98L59";
624 case 0x2F:
625 return "Sony CCD sensor + ADI 9804";
626 case 0x30:
627 return "Sharp CCD sensor + TDA8787";
628 case 0x3E:
629 return "Sharp CCD sensor + Exas 98L59";
630 case 0x3F:
631 return "Sharp CCD sensor + ADI 9804";
632 case 0x40:
633 return "UPA 1021 sensor";
634 case 0x100:
635 return "VGA sensor";
636 case 0x101:
637 return "PAL MR sensor";
638 default:
Trent Piepho657de3c2006-06-20 00:30:57 -0300639 return "unknown type of sensor";
Luc Saillard2b455db2006-04-24 10:29:46 -0300640 }
641}
642#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644/***************************************************************************/
645/* Video4Linux functions */
646
Hans Verkuilbec43662008-12-30 06:58:20 -0300647static int pwc_video_open(struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 struct video_device *vdev = video_devdata(file);
650 struct pwc_device *pdev;
651
Luc Saillard2b455db2006-04-24 10:29:46 -0300652 PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300653
Hans Verkuil601e9442008-08-23 07:24:07 -0300654 pdev = video_get_drvdata(vdev);
Hans de Goedeb824bb42011-06-25 17:39:19 -0300655 if (!pdev->udev)
656 return -ENODEV;
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 file->private_data = vdev;
Luc Saillard2b455db2006-04-24 10:29:46 -0300659 PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 return 0;
661}
662
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300663static void pwc_video_release(struct video_device *vfd)
Oliver Neukum85237f22007-08-21 07:10:42 +0200664{
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300665 struct pwc_device *pdev = container_of(vfd, struct pwc_device, vdev);
666 int hint;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300667
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300668 /* search device_hint[] table if we occupy a slot, by any chance */
669 for (hint = 0; hint < MAX_DEV_HINTS; hint++)
670 if (device_hint[hint].pdev == pdev)
671 device_hint[hint].pdev = NULL;
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300672
Hans de Goede6eba9352011-06-26 06:49:59 -0300673 /* Free intermediate decompression buffer & tables */
674 if (pdev->decompress_data != NULL) {
675 PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n",
676 pdev->decompress_data);
677 kfree(pdev->decompress_data);
678 pdev->decompress_data = NULL;
679 }
680
Hans de Goede6c9cac82011-06-26 12:52:01 -0300681 v4l2_ctrl_handler_free(&pdev->ctrl_handler);
682
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300683 kfree(pdev);
Oliver Neukum85237f22007-08-21 07:10:42 +0200684}
685
Hans Verkuilbec43662008-12-30 06:58:20 -0300686static int pwc_video_close(struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
688 struct video_device *vdev = file->private_data;
689 struct pwc_device *pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
Luc Saillard2b455db2006-04-24 10:29:46 -0300691 PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Hans Verkuil601e9442008-08-23 07:24:07 -0300693 pdev = video_get_drvdata(vdev);
Hans de Goede4fba4712011-06-26 12:13:44 -0300694 if (pdev->capt_file == file) {
695 vb2_queue_release(&pdev->vb_queue);
696 pdev->capt_file = NULL;
697 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
Hans de Goede4fba4712011-06-26 12:13:44 -0300699 PWC_DEBUG_OPEN("<< video_close()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 return 0;
701}
702
Luc Saillard2b455db2006-04-24 10:29:46 -0300703static ssize_t pwc_video_read(struct file *file, char __user *buf,
Hans de Goede885fe182011-06-06 15:33:44 -0300704 size_t count, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
706 struct video_device *vdev = file->private_data;
Hans de Goede885fe182011-06-06 15:33:44 -0300707 struct pwc_device *pdev = video_get_drvdata(vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Hans de Goedeb824bb42011-06-25 17:39:19 -0300709 if (!pdev->udev)
710 return -ENODEV;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300711
Hans de Goede4fba4712011-06-26 12:13:44 -0300712 if (pdev->capt_file != NULL &&
713 pdev->capt_file != file)
714 return -EBUSY;
715
716 pdev->capt_file = file;
717
Hans de Goede885fe182011-06-06 15:33:44 -0300718 return vb2_read(&pdev->vb_queue, buf, count, ppos,
719 file->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720}
721
722static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
723{
724 struct video_device *vdev = file->private_data;
Hans de Goede885fe182011-06-06 15:33:44 -0300725 struct pwc_device *pdev = video_get_drvdata(vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Hans de Goedeb824bb42011-06-25 17:39:19 -0300727 if (!pdev->udev)
Hans de Goede885fe182011-06-06 15:33:44 -0300728 return POLL_ERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Hans de Goede885fe182011-06-06 15:33:44 -0300730 return vb2_poll(&pdev->vb_queue, file, wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
734{
735 struct video_device *vdev = file->private_data;
Hans de Goede885fe182011-06-06 15:33:44 -0300736 struct pwc_device *pdev = video_get_drvdata(vdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300737
Hans de Goede4fba4712011-06-26 12:13:44 -0300738 if (pdev->capt_file != file)
739 return -EBUSY;
740
Hans de Goede885fe182011-06-06 15:33:44 -0300741 return vb2_mmap(&pdev->vb_queue, vma);
742}
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300743
Hans de Goede885fe182011-06-06 15:33:44 -0300744/***************************************************************************/
745/* Videobuf2 operations */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Guennadi Liakhovetskifc714e702011-08-24 10:30:21 -0300747static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
748 unsigned int *nbuffers, unsigned int *nplanes,
749 unsigned int sizes[], void *alloc_ctxs[])
Hans de Goede885fe182011-06-06 15:33:44 -0300750{
751 struct pwc_device *pdev = vb2_get_drv_priv(vq);
Luc Saillard2b455db2006-04-24 10:29:46 -0300752
Hans de Goede885fe182011-06-06 15:33:44 -0300753 if (*nbuffers < MIN_FRAMES)
754 *nbuffers = MIN_FRAMES;
755 else if (*nbuffers > MAX_FRAMES)
756 *nbuffers = MAX_FRAMES;
757
758 *nplanes = 1;
759
760 sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return 0;
763}
764
Hans de Goede885fe182011-06-06 15:33:44 -0300765static int buffer_init(struct vb2_buffer *vb)
766{
767 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
768
769 /* need vmalloc since frame buffer > 128K */
770 buf->data = vzalloc(PWC_FRAME_SIZE);
771 if (buf->data == NULL)
772 return -ENOMEM;
773
774 return 0;
775}
776
777static int buffer_prepare(struct vb2_buffer *vb)
778{
779 struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
780
781 /* Don't allow queing new buffers after device disconnection */
Hans de Goedeb824bb42011-06-25 17:39:19 -0300782 if (!pdev->udev)
783 return -ENODEV;
Hans de Goede885fe182011-06-06 15:33:44 -0300784
785 return 0;
786}
787
788static int buffer_finish(struct vb2_buffer *vb)
789{
790 struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
791 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
792
793 /*
794 * Application has called dqbuf and is getting back a buffer we've
795 * filled, take the pwc data we've stored in buf->data and decompress
796 * it into a usable format, storing the result in the vb2_buffer
797 */
798 return pwc_decompress(pdev, buf);
799}
800
801static void buffer_cleanup(struct vb2_buffer *vb)
802{
803 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
804
805 vfree(buf->data);
806}
807
808static void buffer_queue(struct vb2_buffer *vb)
809{
810 struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
811 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
812 unsigned long flags = 0;
813
814 spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
815 list_add_tail(&buf->list, &pdev->queued_bufs);
816 spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
817}
818
Marek Szyprowskibd323e22011-08-29 08:51:49 -0300819static int start_streaming(struct vb2_queue *vq, unsigned int count)
Hans de Goede885fe182011-06-06 15:33:44 -0300820{
821 struct pwc_device *pdev = vb2_get_drv_priv(vq);
822
Hans de Goedeb824bb42011-06-25 17:39:19 -0300823 if (!pdev->udev)
824 return -ENODEV;
825
Hans de Goede6eba9352011-06-26 06:49:59 -0300826 /* Turn on camera and set LEDS on */
827 pwc_camera_power(pdev, 1);
828 if (pdev->power_save) {
829 /* Restore video mode */
830 pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y,
831 pdev->vframes, pdev->vcompression,
832 pdev->vsnapshot);
833 }
834 pwc_set_leds(pdev, led_on, led_off);
835
Hans de Goede885fe182011-06-06 15:33:44 -0300836 return pwc_isoc_init(pdev);
837}
838
839static int stop_streaming(struct vb2_queue *vq)
840{
841 struct pwc_device *pdev = vb2_get_drv_priv(vq);
842
Hans de Goede6eba9352011-06-26 06:49:59 -0300843 if (pdev->udev) {
844 pwc_set_leds(pdev, 0, 0);
845 pwc_camera_power(pdev, 0);
Hans de Goedeb824bb42011-06-25 17:39:19 -0300846 pwc_isoc_cleanup(pdev);
Hans de Goede6eba9352011-06-26 06:49:59 -0300847 }
Hans de Goede885fe182011-06-06 15:33:44 -0300848 pwc_cleanup_queued_bufs(pdev);
849
850 return 0;
851}
852
853static void pwc_lock(struct vb2_queue *vq)
854{
855 struct pwc_device *pdev = vb2_get_drv_priv(vq);
856 mutex_lock(&pdev->modlock);
857}
858
859static void pwc_unlock(struct vb2_queue *vq)
860{
861 struct pwc_device *pdev = vb2_get_drv_priv(vq);
862 mutex_unlock(&pdev->modlock);
863}
864
865static struct vb2_ops pwc_vb_queue_ops = {
866 .queue_setup = queue_setup,
867 .buf_init = buffer_init,
868 .buf_prepare = buffer_prepare,
869 .buf_finish = buffer_finish,
870 .buf_cleanup = buffer_cleanup,
871 .buf_queue = buffer_queue,
872 .start_streaming = start_streaming,
873 .stop_streaming = stop_streaming,
874 .wait_prepare = pwc_unlock,
875 .wait_finish = pwc_lock,
876};
877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878/***************************************************************************/
879/* USB functions */
880
881/* This function gets called when a new device is plugged in or the usb core
882 * is loaded.
883 */
884
885static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
886{
887 struct usb_device *udev = interface_to_usbdev(intf);
888 struct pwc_device *pdev = NULL;
889 int vendor_id, product_id, type_id;
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300890 int hint, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 int features = 0;
892 int video_nr = -1; /* default: use next available device */
Hans de Goede3b4d0ec2011-06-26 03:51:19 -0300893 int my_power_save = power_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 char serial_number[30], *name;
895
Luc Saillard2b455db2006-04-24 10:29:46 -0300896 vendor_id = le16_to_cpu(udev->descriptor.idVendor);
897 product_id = le16_to_cpu(udev->descriptor.idProduct);
898
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 /* Check if we can handle this device */
Luc Saillard2b455db2006-04-24 10:29:46 -0300900 PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
901 vendor_id, product_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 intf->altsetting->desc.bInterfaceNumber);
903
904 /* the interfaces are probed one by one. We are only interested in the
905 video interface (0) now.
906 Interface 1 is the Audio Control, and interface 2 Audio itself.
907 */
908 if (intf->altsetting->desc.bInterfaceNumber > 0)
909 return -ENODEV;
910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 if (vendor_id == 0x0471) {
912 switch (product_id) {
913 case 0x0302:
Luc Saillard2b455db2006-04-24 10:29:46 -0300914 PWC_INFO("Philips PCA645VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 name = "Philips 645 webcam";
916 type_id = 645;
917 break;
918 case 0x0303:
Luc Saillard2b455db2006-04-24 10:29:46 -0300919 PWC_INFO("Philips PCA646VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 name = "Philips 646 webcam";
921 type_id = 646;
922 break;
923 case 0x0304:
Luc Saillard2b455db2006-04-24 10:29:46 -0300924 PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 name = "Askey VC010 webcam";
926 type_id = 646;
927 break;
928 case 0x0307:
Luc Saillard2b455db2006-04-24 10:29:46 -0300929 PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 name = "Philips 675 webcam";
931 type_id = 675;
932 break;
933 case 0x0308:
Luc Saillard2b455db2006-04-24 10:29:46 -0300934 PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 name = "Philips 680 webcam";
936 type_id = 680;
937 break;
938 case 0x030C:
Luc Saillard2b455db2006-04-24 10:29:46 -0300939 PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 name = "Philips 690 webcam";
941 type_id = 690;
942 break;
943 case 0x0310:
Luc Saillard2b455db2006-04-24 10:29:46 -0300944 PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 name = "Philips 730 webcam";
946 type_id = 730;
947 break;
948 case 0x0311:
Luc Saillard2b455db2006-04-24 10:29:46 -0300949 PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 name = "Philips 740 webcam";
951 type_id = 740;
952 break;
953 case 0x0312:
Luc Saillard2b455db2006-04-24 10:29:46 -0300954 PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 name = "Philips 750 webcam";
956 type_id = 750;
957 break;
958 case 0x0313:
Luc Saillard2b455db2006-04-24 10:29:46 -0300959 PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 name = "Philips 720K/40 webcam";
961 type_id = 720;
962 break;
Luc Saillard2b455db2006-04-24 10:29:46 -0300963 case 0x0329:
964 PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
965 name = "Philips SPC 900NC webcam";
Luc Saillard9ee6d782007-04-22 23:54:36 -0300966 type_id = 740;
Luc Saillard2b455db2006-04-24 10:29:46 -0300967 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 default:
969 return -ENODEV;
970 break;
971 }
972 }
973 else if (vendor_id == 0x069A) {
974 switch(product_id) {
975 case 0x0001:
Luc Saillard2b455db2006-04-24 10:29:46 -0300976 PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 name = "Askey VC010 webcam";
978 type_id = 645;
979 break;
980 default:
981 return -ENODEV;
982 break;
983 }
984 }
985 else if (vendor_id == 0x046d) {
986 switch(product_id) {
987 case 0x08b0:
Luc Saillard2b455db2006-04-24 10:29:46 -0300988 PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 name = "Logitech QuickCam Pro 3000";
990 type_id = 740; /* CCD sensor */
991 break;
992 case 0x08b1:
Luc Saillard2b455db2006-04-24 10:29:46 -0300993 PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 name = "Logitech QuickCam Notebook Pro";
995 type_id = 740; /* CCD sensor */
996 break;
997 case 0x08b2:
Luc Saillard2b455db2006-04-24 10:29:46 -0300998 PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 name = "Logitech QuickCam Pro 4000";
1000 type_id = 740; /* CCD sensor */
Hans de Goede51886df2011-07-03 15:52:54 -03001001 if (my_power_save == -1)
1002 my_power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 break;
1004 case 0x08b3:
Luc Saillard2b455db2006-04-24 10:29:46 -03001005 PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 name = "Logitech QuickCam Zoom";
1007 type_id = 740; /* CCD sensor */
1008 break;
1009 case 0x08B4:
Luc Saillard2b455db2006-04-24 10:29:46 -03001010 PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 name = "Logitech QuickCam Zoom";
1012 type_id = 740; /* CCD sensor */
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001013 if (my_power_save == -1)
1014 my_power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 break;
1016 case 0x08b5:
Luc Saillard2b455db2006-04-24 10:29:46 -03001017 PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 name = "Logitech QuickCam Orbit";
1019 type_id = 740; /* CCD sensor */
Hans de Goede51886df2011-07-03 15:52:54 -03001020 if (my_power_save == -1)
1021 my_power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 features |= FEATURE_MOTOR_PANTILT;
1023 break;
1024 case 0x08b6:
Jean Tourrilhesa63e1572007-03-21 16:29:16 -03001025 PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n");
1026 name = "Cisco VT Camera";
1027 type_id = 740; /* CCD sensor */
1028 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 case 0x08b7:
Mauro Carvalho Chehab6b1ce3c2007-03-21 16:35:28 -03001030 PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n");
1031 name = "Logitech ViewPort AV 100";
1032 type_id = 740; /* CCD sensor */
1033 break;
1034 case 0x08b8: /* Where this released? */
Luc Saillard2b455db2006-04-24 10:29:46 -03001035 PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 name = "Logitech QuickCam (res.)";
1037 type_id = 730; /* Assuming CMOS */
1038 break;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001039 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001041 break;
1042 }
1043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 else if (vendor_id == 0x055d) {
1045 /* I don't know the difference between the C10 and the C30;
1046 I suppose the difference is the sensor, but both cameras
1047 work equally well with a type_id of 675
1048 */
1049 switch(product_id) {
1050 case 0x9000:
Luc Saillard2b455db2006-04-24 10:29:46 -03001051 PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 name = "Samsung MPC-C10";
1053 type_id = 675;
1054 break;
1055 case 0x9001:
Luc Saillard2b455db2006-04-24 10:29:46 -03001056 PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 name = "Samsung MPC-C30";
1058 type_id = 675;
1059 break;
Luc Saillard2b455db2006-04-24 10:29:46 -03001060 case 0x9002:
1061 PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
1062 name = "Samsung MPC-C30";
1063 type_id = 740;
1064 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 default:
1066 return -ENODEV;
1067 break;
1068 }
1069 }
1070 else if (vendor_id == 0x041e) {
1071 switch(product_id) {
1072 case 0x400c:
Luc Saillard2b455db2006-04-24 10:29:46 -03001073 PWC_INFO("Creative Labs Webcam 5 detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 name = "Creative Labs Webcam 5";
1075 type_id = 730;
Hans de Goede51886df2011-07-03 15:52:54 -03001076 if (my_power_save == -1)
1077 my_power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 break;
1079 case 0x4011:
Luc Saillard2b455db2006-04-24 10:29:46 -03001080 PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 name = "Creative Labs Webcam Pro Ex";
1082 type_id = 740;
1083 break;
1084 default:
1085 return -ENODEV;
1086 break;
1087 }
1088 }
1089 else if (vendor_id == 0x04cc) {
1090 switch(product_id) {
1091 case 0x8116:
Luc Saillard2b455db2006-04-24 10:29:46 -03001092 PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 name = "Sotec Afina Eye";
1094 type_id = 730;
1095 break;
1096 default:
1097 return -ENODEV;
1098 break;
1099 }
1100 }
1101 else if (vendor_id == 0x06be) {
1102 switch(product_id) {
1103 case 0x8116:
1104 /* This is essentially the same cam as the Sotec Afina Eye */
Luc Saillard2b455db2006-04-24 10:29:46 -03001105 PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 name = "AME Co. Afina Eye";
1107 type_id = 750;
1108 break;
1109 default:
1110 return -ENODEV;
1111 break;
1112 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001113
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
1115 else if (vendor_id == 0x0d81) {
1116 switch(product_id) {
1117 case 0x1900:
Luc Saillard2b455db2006-04-24 10:29:46 -03001118 PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 name = "Visionite VCS-UC300";
1120 type_id = 740; /* CCD sensor */
1121 break;
1122 case 0x1910:
Luc Saillard2b455db2006-04-24 10:29:46 -03001123 PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 name = "Visionite VCS-UM100";
1125 type_id = 730; /* CMOS sensor */
1126 break;
1127 default:
1128 return -ENODEV;
1129 break;
1130 }
1131 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001132 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 return -ENODEV; /* Not any of the know types; but the list keeps growing. */
1134
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001135 if (my_power_save == -1)
1136 my_power_save = 0;
1137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 memset(serial_number, 0, 30);
1139 usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
Luc Saillard2b455db2006-04-24 10:29:46 -03001140 PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
1142 if (udev->descriptor.bNumConfigurations > 1)
Luc Saillard2b455db2006-04-24 10:29:46 -03001143 PWC_WARNING("Warning: more than 1 configuration available.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
1145 /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01001146 pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001148 PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 return -ENOMEM;
1150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 pdev->type = type_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 pdev->vframes = default_fps;
1153 strcpy(pdev->serial, serial_number);
1154 pdev->features = features;
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001155 if (vendor_id == 0x046D && product_id == 0x08B5) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 /* Logitech QuickCam Orbit
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001157 The ranges have been determined experimentally; they may differ from cam to cam.
1158 Also, the exact ranges left-right and up-down are different for my cam
1159 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 pdev->angle_range.pan_min = -7000;
1161 pdev->angle_range.pan_max = 7000;
1162 pdev->angle_range.tilt_min = -3000;
1163 pdev->angle_range.tilt_max = 2500;
1164 }
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001165 pwc_construct(pdev); /* set min/max sizes correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001167 mutex_init(&pdev->modlock);
Hans de Goedec1127132011-07-03 11:50:51 -03001168 mutex_init(&pdev->udevlock);
Hans de Goede885fe182011-06-06 15:33:44 -03001169 spin_lock_init(&pdev->queued_bufs_lock);
1170 INIT_LIST_HEAD(&pdev->queued_bufs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
1172 pdev->udev = udev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 pdev->vcompression = pwc_preferred_compression;
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001174 pdev->power_save = my_power_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
Hans de Goede885fe182011-06-06 15:33:44 -03001176 /* Init videobuf2 queue structure */
1177 memset(&pdev->vb_queue, 0, sizeof(pdev->vb_queue));
1178 pdev->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1179 pdev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1180 pdev->vb_queue.drv_priv = pdev;
1181 pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf);
1182 pdev->vb_queue.ops = &pwc_vb_queue_ops;
1183 pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
1184 vb2_queue_init(&pdev->vb_queue);
1185
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001186 /* Init video_device structure */
1187 memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
1188 pdev->vdev.parent = &intf->dev;
1189 pdev->vdev.lock = &pdev->modlock;
1190 strcpy(pdev->vdev.name, name);
1191 video_set_drvdata(&pdev->vdev, pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
Luc Saillard2b455db2006-04-24 10:29:46 -03001194 PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
1196 /* Now search device_hint[] table for a match, so we can hint a node number. */
1197 for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
1198 if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
1199 (device_hint[hint].pdev == NULL)) {
1200 /* so far, so good... try serial number */
1201 if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
Trent Piepho657de3c2006-06-20 00:30:57 -03001202 /* match! */
1203 video_nr = device_hint[hint].device_node;
1204 PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
1205 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 }
1207 }
1208 }
1209
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 /* occupy slot */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001211 if (hint < MAX_DEV_HINTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 device_hint[hint].pdev = pdev;
1213
Luc Saillard2b455db2006-04-24 10:29:46 -03001214 PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001215 usb_set_intfdata(intf, pdev);
Luc Saillard2b455db2006-04-24 10:29:46 -03001216
Hans de Goede6eba9352011-06-26 06:49:59 -03001217#ifdef CONFIG_USB_PWC_DEBUG
1218 /* Query sensor type */
1219 if (pwc_get_cmos_sensor(pdev, &rc) >= 0) {
1220 PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
1221 pdev->vdev.name,
1222 pwc_sensor_type_to_string(rc), rc);
1223 }
1224#endif
1225
Luc Saillard2b455db2006-04-24 10:29:46 -03001226 /* Set the leds off */
1227 pwc_set_leds(pdev, 0, 0);
Hans de Goede6eba9352011-06-26 06:49:59 -03001228
1229 /* Setup intial videomode */
1230 rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y,
1231 pdev->vframes, pdev->vcompression, 0);
1232 if (rc)
1233 goto err_free_mem;
1234
Hans de Goede6c9cac82011-06-26 12:52:01 -03001235 /* Register controls (and read default values from camera */
1236 rc = pwc_init_controls(pdev);
1237 if (rc) {
1238 PWC_ERROR("Failed to register v4l2 controls (%d).\n", rc);
1239 goto err_free_mem;
1240 }
1241
1242 pdev->vdev.ctrl_handler = &pdev->ctrl_handler;
Hans de Goede6eba9352011-06-26 06:49:59 -03001243
1244 /* And powerdown the camera until streaming starts */
Luc Saillard2b455db2006-04-24 10:29:46 -03001245 pwc_camera_power(pdev, 0);
1246
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001247 rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
Hans Verkuil479567c2010-09-12 17:05:11 -03001248 if (rc < 0) {
1249 PWC_ERROR("Failed to register as video device (%d).\n", rc);
Hans de Goede6c9cac82011-06-26 12:52:01 -03001250 goto err_free_controls;
Hans Verkuil479567c2010-09-12 17:05:11 -03001251 }
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001252 rc = pwc_create_sysfs_files(pdev);
Hans Verkuil479567c2010-09-12 17:05:11 -03001253 if (rc)
1254 goto err_video_unreg;
1255
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001256 PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev));
Hans Verkuil479567c2010-09-12 17:05:11 -03001257
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001258#ifdef CONFIG_USB_PWC_INPUT_EVDEV
1259 /* register webcam snapshot button input device */
1260 pdev->button_dev = input_allocate_device();
1261 if (!pdev->button_dev) {
1262 PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001263 rc = -ENOMEM;
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001264 pwc_remove_sysfs_files(pdev);
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001265 goto err_video_unreg;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001266 }
1267
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001268 usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys));
1269 strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys));
1270
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001271 pdev->button_dev->name = "PWC snapshot button";
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001272 pdev->button_dev->phys = pdev->button_phys;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001273 usb_to_input_id(pdev->udev, &pdev->button_dev->id);
1274 pdev->button_dev->dev.parent = &pdev->udev->dev;
1275 pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY);
Lennart Poetteringbcd3e4b2009-06-11 11:19:33 -03001276 pdev->button_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001277
1278 rc = input_register_device(pdev->button_dev);
1279 if (rc) {
1280 input_free_device(pdev->button_dev);
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001281 pdev->button_dev = NULL;
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001282 pwc_remove_sysfs_files(pdev);
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001283 goto err_video_unreg;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001284 }
1285#endif
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 return 0;
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001288
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001289err_video_unreg:
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001290 if (hint < MAX_DEV_HINTS)
1291 device_hint[hint].pdev = NULL;
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001292 video_unregister_device(&pdev->vdev);
Hans de Goede6c9cac82011-06-26 12:52:01 -03001293err_free_controls:
1294 v4l2_ctrl_handler_free(&pdev->ctrl_handler);
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001295err_free_mem:
Hans de Goede6c9cac82011-06-26 12:52:01 -03001296 usb_set_intfdata(intf, NULL);
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001297 kfree(pdev);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001298 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299}
1300
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001301/* The user yanked out the cable... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302static void usb_pwc_disconnect(struct usb_interface *intf)
1303{
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001304 struct pwc_device *pdev = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
Hans de Goedec1127132011-07-03 11:50:51 -03001306 mutex_lock(&pdev->udevlock);
Hans Verkuil7074f402010-09-15 14:49:07 -03001307 mutex_lock(&pdev->modlock);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001308
Hans de Goedeb824bb42011-06-25 17:39:19 -03001309 usb_set_intfdata(intf, NULL);
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001310 /* No need to keep the urbs around after disconnection */
1311 pwc_isoc_cleanup(pdev);
Hans de Goede885fe182011-06-06 15:33:44 -03001312 pwc_cleanup_queued_bufs(pdev);
Hans de Goedeb824bb42011-06-25 17:39:19 -03001313 pdev->udev = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
Hans Verkuil7074f402010-09-15 14:49:07 -03001315 mutex_unlock(&pdev->modlock);
Hans de Goedec1127132011-07-03 11:50:51 -03001316 mutex_unlock(&pdev->udevlock);
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001317
1318 pwc_remove_sysfs_files(pdev);
1319 video_unregister_device(&pdev->vdev);
1320
1321#ifdef CONFIG_USB_PWC_INPUT_EVDEV
1322 if (pdev->button_dev)
1323 input_unregister_device(pdev->button_dev);
1324#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325}
1326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001328/*
1329 * Initialization code & module stuff
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 */
1331
Luc Saillard2b455db2006-04-24 10:29:46 -03001332static int fps;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333static int compression = -1;
1334static int leds[2] = { -1, -1 };
Al Viro64a6f952007-10-14 19:35:30 +01001335static unsigned int leds_nargs;
Luc Saillard2b455db2006-04-24 10:29:46 -03001336static char *dev_hint[MAX_DEV_HINTS];
Al Viro64a6f952007-10-14 19:35:30 +01001337static unsigned int dev_hint_nargs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
Luc Saillard2b455db2006-04-24 10:29:46 -03001339module_param(fps, int, 0444);
Trent Piepho05ad3902007-01-30 23:26:01 -03001340#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001341module_param_named(trace, pwc_trace, int, 0644);
1342#endif
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001343module_param(power_save, int, 0644);
Luc Saillard2b455db2006-04-24 10:29:46 -03001344module_param(compression, int, 0444);
1345module_param_array(leds, int, &leds_nargs, 0444);
1346module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
1347
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
Andrea Odetti4315c412009-12-10 16:26:10 -03001349#ifdef CONFIG_USB_PWC_DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350MODULE_PARM_DESC(trace, "For debugging purposes");
Andrea Odetti4315c412009-12-10 16:26:10 -03001351#endif
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001352MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355MODULE_PARM_DESC(dev_hint, "Device node hints");
1356
1357MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
1358MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
1359MODULE_LICENSE("GPL");
Luc Saillard2b455db2006-04-24 10:29:46 -03001360MODULE_ALIAS("pwcx");
1361MODULE_VERSION( PWC_VERSION );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
1363static int __init usb_pwc_init(void)
1364{
Hans de Goede6eba9352011-06-26 06:49:59 -03001365 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
Hans de Goede6eba9352011-06-26 06:49:59 -03001367#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001368 PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
1369 PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
1370 PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
1371 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 -07001372
Hans de Goede6eba9352011-06-26 06:49:59 -03001373 if (pwc_trace >= 0) {
1374 PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
1375 }
1376#endif
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 if (fps) {
1379 if (fps < 4 || fps > 30) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001380 PWC_ERROR("Framerate out of bounds (4-30).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 return -EINVAL;
1382 }
1383 default_fps = fps;
Luc Saillard2b455db2006-04-24 10:29:46 -03001384 PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 }
1386
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 if (compression >= 0) {
1388 if (compression > 3) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001389 PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 return -EINVAL;
1391 }
1392 pwc_preferred_compression = compression;
Luc Saillard2b455db2006-04-24 10:29:46 -03001393 PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 if (leds[0] >= 0)
1396 led_on = leds[0];
1397 if (leds[1] >= 0)
1398 led_off = leds[1];
1399
Steven Cole093cf722005-05-03 19:07:24 -06001400 /* Big device node whoopla. Basically, it allows you to assign a
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 device node (/dev/videoX) to a camera, based on its type
1402 & serial number. The format is [type[.serialnumber]:]node.
1403
1404 Any camera that isn't matched by these rules gets the next
1405 available free device node.
1406 */
1407 for (i = 0; i < MAX_DEV_HINTS; i++) {
1408 char *s, *colon, *dot;
1409
1410 /* This loop also initializes the array */
1411 device_hint[i].pdev = NULL;
1412 s = dev_hint[i];
1413 if (s != NULL && *s != '\0') {
1414 device_hint[i].type = -1; /* wildcard */
1415 strcpy(device_hint[i].serial_number, "*");
1416
1417 /* parse string: chop at ':' & '/' */
1418 colon = dot = s;
1419 while (*colon != '\0' && *colon != ':')
1420 colon++;
1421 while (*dot != '\0' && *dot != '.')
1422 dot++;
1423 /* Few sanity checks */
1424 if (*dot != '\0' && dot > colon) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001425 PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 return -EINVAL;
1427 }
1428
1429 if (*colon == '\0') {
1430 /* No colon */
1431 if (*dot != '\0') {
Luc Saillard2b455db2006-04-24 10:29:46 -03001432 PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 return -EINVAL;
1434 }
1435 else {
1436 /* No type or serial number specified, just a number. */
Andy Shevchenko2d8d7762009-09-24 07:58:09 -03001437 device_hint[i].device_node =
1438 simple_strtol(s, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 }
1440 }
1441 else {
1442 /* There's a colon, so we have at least a type and a device node */
Andy Shevchenko2d8d7762009-09-24 07:58:09 -03001443 device_hint[i].type =
1444 simple_strtol(s, NULL, 10);
1445 device_hint[i].device_node =
1446 simple_strtol(colon + 1, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 if (*dot != '\0') {
1448 /* There's a serial number as well */
1449 int k;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001450
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 dot++;
1452 k = 0;
1453 while (*dot != ':' && k < 29) {
1454 device_hint[i].serial_number[k++] = *dot;
1455 dot++;
1456 }
1457 device_hint[i].serial_number[k] = '\0';
1458 }
1459 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001460 PWC_TRACE("device_hint[%d]:\n", i);
1461 PWC_TRACE(" type : %d\n", device_hint[i].type);
1462 PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number);
1463 PWC_TRACE(" node : %d\n", device_hint[i].device_node);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 }
1465 else
1466 device_hint[i].type = 0; /* not filled */
1467 } /* ..for MAX_DEV_HINTS */
1468
Luc Saillard2b455db2006-04-24 10:29:46 -03001469 PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 return usb_register(&pwc_driver);
1471}
1472
1473static void __exit usb_pwc_exit(void)
1474{
Luc Saillard2b455db2006-04-24 10:29:46 -03001475 PWC_DEBUG_MODULE("Deregistering driver.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 usb_deregister(&pwc_driver);
Luc Saillard2b455db2006-04-24 10:29:46 -03001477 PWC_INFO("Philips webcam module removed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478}
1479
1480module_init(usb_pwc_init);
1481module_exit(usb_pwc_exit);
1482
Luc Saillard2b455db2006-04-24 10:29:46 -03001483/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */