blob: a6b5fde5c3ad20dd007bb4304ccc844505771e26 [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#include "pwc-uncompress.h"
79
80/* Function prototypes and driver templates */
81
82/* hotplug device table support */
Luc Saillard2b455db2006-04-24 10:29:46 -030083static const struct usb_device_id pwc_device_table [] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
85 { USB_DEVICE(0x0471, 0x0303) },
86 { USB_DEVICE(0x0471, 0x0304) },
87 { USB_DEVICE(0x0471, 0x0307) },
88 { USB_DEVICE(0x0471, 0x0308) },
89 { USB_DEVICE(0x0471, 0x030C) },
90 { USB_DEVICE(0x0471, 0x0310) },
Luc Saillard2b455db2006-04-24 10:29:46 -030091 { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 { USB_DEVICE(0x0471, 0x0312) },
93 { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
Luc Saillard2b455db2006-04-24 10:29:46 -030094 { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
96 { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
97 { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
98 { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
99 { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
100 { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
101 { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
Mauro Carvalho Chehab6b1ce3c2007-03-21 16:35:28 -0300102 { USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */
103 { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
Luc Saillard2b455db2006-04-24 10:29:46 -0300105 { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
106 { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
107 { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
109 { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
110 { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
111 { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
112 { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
113 { USB_DEVICE(0x0d81, 0x1900) },
114 { }
115};
116MODULE_DEVICE_TABLE(usb, pwc_device_table);
117
118static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
119static void usb_pwc_disconnect(struct usb_interface *intf);
Hans de Goede885fe182011-06-06 15:33:44 -0300120static void pwc_isoc_cleanup(struct pwc_device *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122static struct usb_driver pwc_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 .name = "Philips webcam", /* name */
124 .id_table = pwc_device_table,
125 .probe = usb_pwc_probe, /* probe() */
126 .disconnect = usb_pwc_disconnect, /* disconnect() */
127};
128
129#define MAX_DEV_HINTS 20
130#define MAX_ISOC_ERRORS 20
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static int default_fps = 10;
Trent Piepho05ad3902007-01-30 23:26:01 -0300133#ifdef CONFIG_USB_PWC_DEBUG
Michael Krufkyb930e1d2007-08-27 18:16:54 -0300134 int pwc_trace = PWC_DEBUG_LEVEL;
Luc Saillard2b455db2006-04-24 10:29:46 -0300135#endif
Hans de Goede3b4d0ec2011-06-26 03:51:19 -0300136static int power_save = -1;
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300137static int led_on = 100, led_off; /* defaults to LED that is on while in use */
Adrian Bunkb20c3cf2006-06-23 06:49:34 -0300138static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static struct {
140 int type;
141 char serial_number[30];
142 int device_node;
143 struct pwc_device *pdev;
144} device_hint[MAX_DEV_HINTS];
145
146/***/
147
Hans Verkuilbec43662008-12-30 06:58:20 -0300148static int pwc_video_open(struct file *file);
149static int pwc_video_close(struct file *file);
Luc Saillard2b455db2006-04-24 10:29:46 -0300150static ssize_t pwc_video_read(struct file *file, char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 size_t count, loff_t *ppos);
152static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300154static void pwc_video_release(struct video_device *vfd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
Hans Verkuilbec43662008-12-30 06:58:20 -0300156static const struct v4l2_file_operations pwc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 .owner = THIS_MODULE,
158 .open = pwc_video_open,
159 .release = pwc_video_close,
160 .read = pwc_video_read,
161 .poll = pwc_video_poll,
162 .mmap = pwc_video_mmap,
Hans Verkuilafa38522011-01-22 06:34:55 -0300163 .unlocked_ioctl = video_ioctl2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164};
165static struct video_device pwc_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 .name = "Philips Webcam", /* Filled in later */
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300167 .release = pwc_video_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 .fops = &pwc_fops,
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300169 .ioctl_ops = &pwc_ioctl_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170};
171
172/***************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173/* Private functions */
174
Hans de Goede885fe182011-06-06 15:33:44 -0300175struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
Hans de Goede885fe182011-06-06 15:33:44 -0300177 unsigned long flags = 0;
178 struct pwc_frame_buf *buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Hans de Goede885fe182011-06-06 15:33:44 -0300180 spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
181 if (list_empty(&pdev->queued_bufs))
182 goto leave;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Hans de Goede885fe182011-06-06 15:33:44 -0300184 buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, list);
185 list_del(&buf->list);
186leave:
187 spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
188 return buf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300189}
190
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300191static void pwc_snapshot_button(struct pwc_device *pdev, int down)
192{
193 if (down) {
194 PWC_TRACE("Snapshot button pressed.\n");
195 pdev->snapshot_button_status = 1;
196 } else {
197 PWC_TRACE("Snapshot button released.\n");
198 }
199
200#ifdef CONFIG_USB_PWC_INPUT_EVDEV
201 if (pdev->button_dev) {
Lennart Poetteringbcd3e4b2009-06-11 11:19:33 -0300202 input_report_key(pdev->button_dev, KEY_CAMERA, down);
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300203 input_sync(pdev->button_dev);
204 }
205#endif
206}
207
Hans de Goede885fe182011-06-06 15:33:44 -0300208static void pwc_frame_complete(struct pwc_device *pdev)
Luc Saillard2b455db2006-04-24 10:29:46 -0300209{
Hans de Goede885fe182011-06-06 15:33:44 -0300210 struct pwc_frame_buf *fbuf = pdev->fill_buf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300211
212 /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
213 frames on the USB wire after an exposure change. This conditition is
214 however detected in the cam and a bit is set in the header.
215 */
216 if (pdev->type == 730) {
217 unsigned char *ptr = (unsigned char *)fbuf->data;
218
219 if (ptr[1] == 1 && ptr[0] & 0x10) {
220 PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
221 pdev->drop_frames += 2;
Luc Saillard2b455db2006-04-24 10:29:46 -0300222 }
223 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300224 pwc_snapshot_button(pdev, ptr[0] & 0x01);
Luc Saillard2b455db2006-04-24 10:29:46 -0300225 }
226 if ((ptr[0] ^ pdev->vmirror) & 0x02) {
227 if (ptr[0] & 0x02)
228 PWC_TRACE("Image is mirrored.\n");
229 else
230 PWC_TRACE("Image is normal.\n");
231 }
232 pdev->vmirror = ptr[0] & 0x03;
233 /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
234 after a short frame; this condition is filtered out specifically. A 4 byte
235 frame doesn't make sense anyway.
236 So we get either this sequence:
237 drop_bit set -> 4 byte frame -> short frame -> good frame
238 Or this one:
239 drop_bit set -> short frame -> good frame
240 So we drop either 3 or 2 frames in all!
241 */
242 if (fbuf->filled == 4)
243 pdev->drop_frames++;
Hans de Goede885fe182011-06-06 15:33:44 -0300244 } else if (pdev->type == 740 || pdev->type == 720) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300245 unsigned char *ptr = (unsigned char *)fbuf->data;
246 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300247 pwc_snapshot_button(pdev, ptr[0] & 0x01);
Luc Saillard2b455db2006-04-24 10:29:46 -0300248 }
249 pdev->vmirror = ptr[0] & 0x03;
250 }
251
Hans de Goede885fe182011-06-06 15:33:44 -0300252 /* In case we were instructed to drop the frame, do so silently. */
253 if (pdev->drop_frames > 0) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300254 pdev->drop_frames--;
Hans de Goede885fe182011-06-06 15:33:44 -0300255 } else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300256 /* Check for underflow first */
257 if (fbuf->filled < pdev->frame_total_size) {
258 PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
259 " discarded.\n", fbuf->filled);
Hans de Goede885fe182011-06-06 15:33:44 -0300260 } else {
261 fbuf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
262 fbuf->vb.v4l2_buf.sequence = pdev->vframe_count;
263 vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
264 pdev->fill_buf = NULL;
265 pdev->vsync = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300266 }
267 } /* !drop_frames */
268 pdev->vframe_count++;
Luc Saillard2b455db2006-04-24 10:29:46 -0300269}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
271/* This gets called for the Isochronous pipe (video). This is done in
272 * interrupt time, so it has to be fast, not crash, and not stall. Neat.
273 */
David Howells7d12e782006-10-05 14:55:46 +0100274static void pwc_isoc_handler(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
Hans de Goede885fe182011-06-06 15:33:44 -0300276 struct pwc_device *pdev = (struct pwc_device *)urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 int i, fst, flen;
Hans de Goede885fe182011-06-06 15:33:44 -0300278 unsigned char *iso_buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Hans de Goede885fe182011-06-06 15:33:44 -0300280 if (urb->status == -ENOENT || urb->status == -ECONNRESET ||
281 urb->status == -ESHUTDOWN) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300282 PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 return;
284 }
Hans de Goede885fe182011-06-06 15:33:44 -0300285
286 if (pdev->fill_buf == NULL)
287 pdev->fill_buf = pwc_get_next_fill_buf(pdev);
288
289 if (urb->status != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 const char *errmsg;
291
292 errmsg = "Unknown";
293 switch(urb->status) {
294 case -ENOSR: errmsg = "Buffer error (overrun)"; break;
295 case -EPIPE: errmsg = "Stalled (device not responding)"; break;
296 case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break;
297 case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break;
298 case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
Pete Zaitcev38e2bfc2006-09-18 22:49:02 -0700299 case -ETIME: errmsg = "Device does not respond"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
Hans de Goede885fe182011-06-06 15:33:44 -0300301 PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n",
302 urb->status, errmsg);
303 /* Give up after a number of contiguous errors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
305 {
Hans de Goede885fe182011-06-06 15:33:44 -0300306 PWC_ERROR("Too many ISOC errors, bailing out.\n");
307 if (pdev->fill_buf) {
308 vb2_buffer_done(&pdev->fill_buf->vb,
309 VB2_BUF_STATE_ERROR);
310 pdev->fill_buf = NULL;
311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 }
Hans de Goede885fe182011-06-06 15:33:44 -0300313 pdev->vsync = 0; /* Drop the current frame */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 goto handler_end;
315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 /* Reset ISOC error counter. We did get here, after all. */
318 pdev->visoc_errors = 0;
319
320 /* vsync: 0 = don't copy data
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300321 1 = sync-hunt
322 2 = synched
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 */
324 /* Compact data */
325 for (i = 0; i < urb->number_of_packets; i++) {
326 fst = urb->iso_frame_desc[i].status;
327 flen = urb->iso_frame_desc[i].actual_length;
328 iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
Hans de Goede885fe182011-06-06 15:33:44 -0300329 if (fst != 0) {
330 PWC_ERROR("Iso frame %d has error %d\n", i, fst);
331 continue;
332 }
333 if (flen > 0 && pdev->vsync) {
334 struct pwc_frame_buf *fbuf = pdev->fill_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Hans de Goede885fe182011-06-06 15:33:44 -0300336 if (pdev->vsync == 1) {
337 do_gettimeofday(&fbuf->vb.v4l2_buf.timestamp);
338 pdev->vsync = 2;
Luc Saillard2b455db2006-04-24 10:29:46 -0300339 }
340
Hans de Goede885fe182011-06-06 15:33:44 -0300341 if (flen + fbuf->filled > pdev->frame_total_size) {
342 PWC_ERROR("Frame overflow (%d > %d)\n",
343 flen + fbuf->filled,
344 pdev->frame_total_size);
345 pdev->vsync = 0; /* Let's wait for an EOF */
346 } else {
347 memcpy(fbuf->data + fbuf->filled, iso_buf,
348 flen);
349 fbuf->filled += flen;
350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 }
Hans de Goede885fe182011-06-06 15:33:44 -0300352 if (flen < pdev->vlast_packet_size) {
353 /* Shorter packet... end of frame */
354 if (pdev->vsync == 2)
355 pwc_frame_complete(pdev);
356 if (pdev->fill_buf == NULL)
357 pdev->fill_buf = pwc_get_next_fill_buf(pdev);
358 if (pdev->fill_buf) {
359 pdev->fill_buf->filled = 0;
360 pdev->vsync = 1;
361 }
362 }
363 pdev->vlast_packet_size = flen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 }
365
366handler_end:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 i = usb_submit_urb(urb, GFP_ATOMIC);
368 if (i != 0)
Luc Saillard2b455db2006-04-24 10:29:46 -0300369 PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370}
371
Hans de Goede885fe182011-06-06 15:33:44 -0300372static int pwc_isoc_init(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
374 struct usb_device *udev;
375 struct urb *urb;
376 int i, j, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 struct usb_interface *intf;
378 struct usb_host_interface *idesc = NULL;
Hans de Goede6eba9352011-06-26 06:49:59 -0300379 void *kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 if (pdev->iso_init)
382 return 0;
Hans de Goede6eba9352011-06-26 06:49:59 -0300383
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 pdev->vsync = 0;
Hans de Goede6eba9352011-06-26 06:49:59 -0300385 pdev->vlast_packet_size = 0;
Hans de Goede885fe182011-06-06 15:33:44 -0300386 pdev->fill_buf = NULL;
387 pdev->vframe_count = 0;
Hans de Goede6eba9352011-06-26 06:49:59 -0300388 pdev->visoc_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 udev = pdev->udev;
390
391 /* Get the current alternate interface, adjust packet size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 intf = usb_ifnum_to_if(udev, 0);
393 if (intf)
394 idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 if (!idesc)
Hans de Goedec2464122011-06-06 15:25:18 -0300396 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 /* Search video endpoint */
399 pdev->vmax_packet_size = -1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300400 for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
402 pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
403 break;
404 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300405 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300408 PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
Steven Cole093cf722005-05-03 19:07:24 -0600409 return -ENFILE; /* Odd error, that should be noticeable */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 }
411
412 /* Set alternate interface */
413 ret = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300414 PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
416 if (ret < 0)
417 return ret;
418
Hans de Goede6eba9352011-06-26 06:49:59 -0300419 /* Allocate Isochronuous pipe buffers */
420 for (i = 0; i < MAX_ISO_BUFS; i++) {
421 kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
422 if (kbuf == NULL) {
423 PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
424 pdev->iso_init = 1;
425 pwc_isoc_cleanup(pdev);
426 return -ENOMEM;
427 }
428 PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
429 pdev->sbuf[i].data = kbuf;
430 }
431
432 /* Allocate Isochronuous urbs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 for (i = 0; i < MAX_ISO_BUFS; i++) {
434 urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
435 if (urb == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300436 PWC_ERROR("Failed to allocate urb %d\n", i);
Hans de Goede6eba9352011-06-26 06:49:59 -0300437 pdev->iso_init = 1;
438 pwc_isoc_cleanup(pdev);
439 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 }
441 pdev->sbuf[i].urb = urb;
Luc Saillard2b455db2006-04-24 10:29:46 -0300442 PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300445 /* init URB structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 for (i = 0; i < MAX_ISO_BUFS; i++) {
447 urb = pdev->sbuf[i].urb;
448
449 urb->interval = 1; // devik
450 urb->dev = udev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300451 urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 urb->transfer_flags = URB_ISO_ASAP;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300453 urb->transfer_buffer = pdev->sbuf[i].data;
454 urb->transfer_buffer_length = ISO_BUFFER_SIZE;
455 urb->complete = pwc_isoc_handler;
456 urb->context = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 urb->start_frame = 0;
458 urb->number_of_packets = ISO_FRAMES_PER_DESC;
459 for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
460 urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
461 urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
462 }
463 }
464
465 /* link */
466 for (i = 0; i < MAX_ISO_BUFS; i++) {
467 ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
Hans de Goede622d9f52010-11-16 12:32:09 -0300468 if (ret) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300469 PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
Hans de Goede622d9f52010-11-16 12:32:09 -0300470 pdev->iso_init = 1;
471 pwc_isoc_cleanup(pdev);
472 return ret;
473 }
474 PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 }
476
477 /* All is done... */
478 pdev->iso_init = 1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300479 PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 return 0;
481}
482
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300483static void pwc_iso_stop(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 int i;
486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 /* Unlinking ISOC buffers one by one */
488 for (i = 0; i < MAX_ISO_BUFS; i++) {
489 struct urb *urb;
490
491 urb = pdev->sbuf[i].urb;
Al Viro5fa12472008-03-29 03:07:38 +0000492 if (urb) {
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300493 PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
494 usb_kill_urb(urb);
495 }
496 }
497}
498
499static void pwc_iso_free(struct pwc_device *pdev)
500{
501 int i;
502
503 /* Freeing ISOC buffers one by one */
504 for (i = 0; i < MAX_ISO_BUFS; i++) {
505 struct urb *urb;
506
507 urb = pdev->sbuf[i].urb;
Al Viro5fa12472008-03-29 03:07:38 +0000508 if (urb) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300509 PWC_DEBUG_MEMORY("Freeing URB\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 usb_free_urb(urb);
511 pdev->sbuf[i].urb = NULL;
512 }
513 }
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300514}
515
Hans de Goede885fe182011-06-06 15:33:44 -0300516static void pwc_isoc_cleanup(struct pwc_device *pdev)
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300517{
Hans de Goede6eba9352011-06-26 06:49:59 -0300518 int i;
519
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300520 PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
Hans de Goedec2464122011-06-06 15:25:18 -0300521
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300522 if (pdev->iso_init == 0)
523 return;
524
525 pwc_iso_stop(pdev);
526 pwc_iso_free(pdev);
Hans de Goedeb824bb42011-06-25 17:39:19 -0300527 usb_set_interface(pdev->udev, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Hans de Goede6eba9352011-06-26 06:49:59 -0300529 /* Release Iso-pipe buffers */
530 for (i = 0; i < MAX_ISO_BUFS; i++) {
531 if (pdev->sbuf[i].data != NULL) {
532 PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n",
533 pdev->sbuf[i].data);
534 kfree(pdev->sbuf[i].data);
535 pdev->sbuf[i].data = NULL;
536 }
537 }
538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 pdev->iso_init = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300540 PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541}
542
Hans de Goede885fe182011-06-06 15:33:44 -0300543/*
544 * Release all queued buffers, no need to take queued_bufs_lock, since all
545 * iso urbs have been killed when we're called so pwc_isoc_handler won't run.
546 */
547static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
548{
549 while (!list_empty(&pdev->queued_bufs)) {
550 struct pwc_frame_buf *buf;
551
552 buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf,
553 list);
554 list_del(&buf->list);
555 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
556 }
557}
558
Luc Saillard2b455db2006-04-24 10:29:46 -0300559/*********
560 * sysfs
561 *********/
Kay Sievers54bd5b62007-10-08 16:26:13 -0300562static struct pwc_device *cd_to_pwc(struct device *cd)
Luc Saillard2b455db2006-04-24 10:29:46 -0300563{
564 struct video_device *vdev = to_video_device(cd);
565 return video_get_drvdata(vdev);
566}
567
Kay Sievers54bd5b62007-10-08 16:26:13 -0300568static ssize_t show_pan_tilt(struct device *class_dev,
569 struct device_attribute *attr, char *buf)
Luc Saillard2b455db2006-04-24 10:29:46 -0300570{
571 struct pwc_device *pdev = cd_to_pwc(class_dev);
572 return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
573}
574
Kay Sievers54bd5b62007-10-08 16:26:13 -0300575static ssize_t store_pan_tilt(struct device *class_dev,
576 struct device_attribute *attr,
577 const char *buf, size_t count)
Luc Saillard2b455db2006-04-24 10:29:46 -0300578{
579 struct pwc_device *pdev = cd_to_pwc(class_dev);
580 int pan, tilt;
581 int ret = -EINVAL;
582
583 if (strncmp(buf, "reset", 5) == 0)
584 ret = pwc_mpt_reset(pdev, 0x3);
585
586 else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
587 ret = pwc_mpt_set_angle(pdev, pan, tilt);
588
589 if (ret < 0)
590 return ret;
591 return strlen(buf);
592}
Kay Sievers54bd5b62007-10-08 16:26:13 -0300593static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
594 store_pan_tilt);
Luc Saillard2b455db2006-04-24 10:29:46 -0300595
Kay Sievers54bd5b62007-10-08 16:26:13 -0300596static ssize_t show_snapshot_button_status(struct device *class_dev,
597 struct device_attribute *attr, char *buf)
Luc Saillard2b455db2006-04-24 10:29:46 -0300598{
599 struct pwc_device *pdev = cd_to_pwc(class_dev);
600 int status = pdev->snapshot_button_status;
601 pdev->snapshot_button_status = 0;
602 return sprintf(buf, "%d\n", status);
603}
604
Kay Sievers54bd5b62007-10-08 16:26:13 -0300605static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
606 NULL);
Luc Saillard2b455db2006-04-24 10:29:46 -0300607
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300608static int pwc_create_sysfs_files(struct pwc_device *pdev)
Luc Saillard2b455db2006-04-24 10:29:46 -0300609{
Jeff Garzikc12e3be2006-10-13 07:17:32 -0300610 int rc;
611
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300612 rc = device_create_file(&pdev->vdev.dev, &dev_attr_button);
Jeff Garzikc12e3be2006-10-13 07:17:32 -0300613 if (rc)
614 goto err;
615 if (pdev->features & FEATURE_MOTOR_PANTILT) {
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300616 rc = device_create_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300617 if (rc)
618 goto err_button;
Jeff Garzikc12e3be2006-10-13 07:17:32 -0300619 }
620
621 return 0;
622
623err_button:
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300624 device_remove_file(&pdev->vdev.dev, &dev_attr_button);
Jeff Garzikc12e3be2006-10-13 07:17:32 -0300625err:
Hans Verkuilf894dfd2008-07-25 07:39:54 -0300626 PWC_ERROR("Could not create sysfs files.\n");
Jeff Garzikc12e3be2006-10-13 07:17:32 -0300627 return rc;
Luc Saillard2b455db2006-04-24 10:29:46 -0300628}
629
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300630static void pwc_remove_sysfs_files(struct pwc_device *pdev)
Luc Saillard2b455db2006-04-24 10:29:46 -0300631{
Luc Saillard2b455db2006-04-24 10:29:46 -0300632 if (pdev->features & FEATURE_MOTOR_PANTILT)
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300633 device_remove_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
634 device_remove_file(&pdev->vdev.dev, &dev_attr_button);
Luc Saillard2b455db2006-04-24 10:29:46 -0300635}
636
Trent Piepho05ad3902007-01-30 23:26:01 -0300637#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -0300638static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
639{
640 switch(sensor_type) {
641 case 0x00:
642 return "Hyundai CMOS sensor";
643 case 0x20:
644 return "Sony CCD sensor + TDA8787";
645 case 0x2E:
646 return "Sony CCD sensor + Exas 98L59";
647 case 0x2F:
648 return "Sony CCD sensor + ADI 9804";
649 case 0x30:
650 return "Sharp CCD sensor + TDA8787";
651 case 0x3E:
652 return "Sharp CCD sensor + Exas 98L59";
653 case 0x3F:
654 return "Sharp CCD sensor + ADI 9804";
655 case 0x40:
656 return "UPA 1021 sensor";
657 case 0x100:
658 return "VGA sensor";
659 case 0x101:
660 return "PAL MR sensor";
661 default:
Trent Piepho657de3c2006-06-20 00:30:57 -0300662 return "unknown type of sensor";
Luc Saillard2b455db2006-04-24 10:29:46 -0300663 }
664}
665#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667/***************************************************************************/
668/* Video4Linux functions */
669
Hans Verkuilbec43662008-12-30 06:58:20 -0300670static int pwc_video_open(struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 struct video_device *vdev = video_devdata(file);
673 struct pwc_device *pdev;
674
Luc Saillard2b455db2006-04-24 10:29:46 -0300675 PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300676
Hans Verkuil601e9442008-08-23 07:24:07 -0300677 pdev = video_get_drvdata(vdev);
Hans de Goedeb824bb42011-06-25 17:39:19 -0300678 if (!pdev->udev)
679 return -ENODEV;
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 file->private_data = vdev;
Luc Saillard2b455db2006-04-24 10:29:46 -0300682 PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 return 0;
684}
685
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300686static void pwc_video_release(struct video_device *vfd)
Oliver Neukum85237f22007-08-21 07:10:42 +0200687{
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300688 struct pwc_device *pdev = container_of(vfd, struct pwc_device, vdev);
689 int hint;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300690
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300691 /* search device_hint[] table if we occupy a slot, by any chance */
692 for (hint = 0; hint < MAX_DEV_HINTS; hint++)
693 if (device_hint[hint].pdev == pdev)
694 device_hint[hint].pdev = NULL;
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300695
Hans de Goede6eba9352011-06-26 06:49:59 -0300696 /* Free intermediate decompression buffer & tables */
697 if (pdev->decompress_data != NULL) {
698 PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n",
699 pdev->decompress_data);
700 kfree(pdev->decompress_data);
701 pdev->decompress_data = NULL;
702 }
703
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300704 kfree(pdev);
Oliver Neukum85237f22007-08-21 07:10:42 +0200705}
706
Hans Verkuilbec43662008-12-30 06:58:20 -0300707static int pwc_video_close(struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709 struct video_device *vdev = file->private_data;
710 struct pwc_device *pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Luc Saillard2b455db2006-04-24 10:29:46 -0300712 PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Hans Verkuil601e9442008-08-23 07:24:07 -0300714 pdev = video_get_drvdata(vdev);
Hans de Goede4fba4712011-06-26 12:13:44 -0300715 if (pdev->capt_file == file) {
716 vb2_queue_release(&pdev->vb_queue);
717 pdev->capt_file = NULL;
718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Hans de Goede4fba4712011-06-26 12:13:44 -0300720 PWC_DEBUG_OPEN("<< video_close()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 return 0;
722}
723
Luc Saillard2b455db2006-04-24 10:29:46 -0300724static ssize_t pwc_video_read(struct file *file, char __user *buf,
Hans de Goede885fe182011-06-06 15:33:44 -0300725 size_t count, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726{
727 struct video_device *vdev = file->private_data;
Hans de Goede885fe182011-06-06 15:33:44 -0300728 struct pwc_device *pdev = video_get_drvdata(vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Hans de Goedeb824bb42011-06-25 17:39:19 -0300730 if (!pdev->udev)
731 return -ENODEV;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300732
Hans de Goede4fba4712011-06-26 12:13:44 -0300733 if (pdev->capt_file != NULL &&
734 pdev->capt_file != file)
735 return -EBUSY;
736
737 pdev->capt_file = file;
738
Hans de Goede885fe182011-06-06 15:33:44 -0300739 return vb2_read(&pdev->vb_queue, buf, count, ppos,
740 file->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741}
742
743static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
744{
745 struct video_device *vdev = file->private_data;
Hans de Goede885fe182011-06-06 15:33:44 -0300746 struct pwc_device *pdev = video_get_drvdata(vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
Hans de Goedeb824bb42011-06-25 17:39:19 -0300748 if (!pdev->udev)
Hans de Goede885fe182011-06-06 15:33:44 -0300749 return POLL_ERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Hans de Goede885fe182011-06-06 15:33:44 -0300751 return vb2_poll(&pdev->vb_queue, file, wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
755{
756 struct video_device *vdev = file->private_data;
Hans de Goede885fe182011-06-06 15:33:44 -0300757 struct pwc_device *pdev = video_get_drvdata(vdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300758
Hans de Goede4fba4712011-06-26 12:13:44 -0300759 if (pdev->capt_file != file)
760 return -EBUSY;
761
Hans de Goede885fe182011-06-06 15:33:44 -0300762 return vb2_mmap(&pdev->vb_queue, vma);
763}
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300764
Hans de Goede885fe182011-06-06 15:33:44 -0300765/***************************************************************************/
766/* Videobuf2 operations */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Hans de Goede885fe182011-06-06 15:33:44 -0300768static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
769 unsigned int *nplanes, unsigned long sizes[],
770 void *alloc_ctxs[])
771{
772 struct pwc_device *pdev = vb2_get_drv_priv(vq);
Luc Saillard2b455db2006-04-24 10:29:46 -0300773
Hans de Goede885fe182011-06-06 15:33:44 -0300774 if (*nbuffers < MIN_FRAMES)
775 *nbuffers = MIN_FRAMES;
776 else if (*nbuffers > MAX_FRAMES)
777 *nbuffers = MAX_FRAMES;
778
779 *nplanes = 1;
780
781 sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
782
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return 0;
784}
785
Hans de Goede885fe182011-06-06 15:33:44 -0300786static int buffer_init(struct vb2_buffer *vb)
787{
788 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
789
790 /* need vmalloc since frame buffer > 128K */
791 buf->data = vzalloc(PWC_FRAME_SIZE);
792 if (buf->data == NULL)
793 return -ENOMEM;
794
795 return 0;
796}
797
798static int buffer_prepare(struct vb2_buffer *vb)
799{
800 struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
801
802 /* Don't allow queing new buffers after device disconnection */
Hans de Goedeb824bb42011-06-25 17:39:19 -0300803 if (!pdev->udev)
804 return -ENODEV;
Hans de Goede885fe182011-06-06 15:33:44 -0300805
806 return 0;
807}
808
809static int buffer_finish(struct vb2_buffer *vb)
810{
811 struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
812 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
813
814 /*
815 * Application has called dqbuf and is getting back a buffer we've
816 * filled, take the pwc data we've stored in buf->data and decompress
817 * it into a usable format, storing the result in the vb2_buffer
818 */
819 return pwc_decompress(pdev, buf);
820}
821
822static void buffer_cleanup(struct vb2_buffer *vb)
823{
824 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
825
826 vfree(buf->data);
827}
828
829static void buffer_queue(struct vb2_buffer *vb)
830{
831 struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
832 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
833 unsigned long flags = 0;
834
835 spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
836 list_add_tail(&buf->list, &pdev->queued_bufs);
837 spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
838}
839
840static int start_streaming(struct vb2_queue *vq)
841{
842 struct pwc_device *pdev = vb2_get_drv_priv(vq);
843
Hans de Goedeb824bb42011-06-25 17:39:19 -0300844 if (!pdev->udev)
845 return -ENODEV;
846
Hans de Goede6eba9352011-06-26 06:49:59 -0300847 /* Turn on camera and set LEDS on */
848 pwc_camera_power(pdev, 1);
849 if (pdev->power_save) {
850 /* Restore video mode */
851 pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y,
852 pdev->vframes, pdev->vcompression,
853 pdev->vsnapshot);
854 }
855 pwc_set_leds(pdev, led_on, led_off);
856
Hans de Goede885fe182011-06-06 15:33:44 -0300857 return pwc_isoc_init(pdev);
858}
859
860static int stop_streaming(struct vb2_queue *vq)
861{
862 struct pwc_device *pdev = vb2_get_drv_priv(vq);
863
Hans de Goede6eba9352011-06-26 06:49:59 -0300864 if (pdev->udev) {
865 pwc_set_leds(pdev, 0, 0);
866 pwc_camera_power(pdev, 0);
Hans de Goedeb824bb42011-06-25 17:39:19 -0300867 pwc_isoc_cleanup(pdev);
Hans de Goede6eba9352011-06-26 06:49:59 -0300868 }
Hans de Goede885fe182011-06-06 15:33:44 -0300869 pwc_cleanup_queued_bufs(pdev);
870
871 return 0;
872}
873
874static void pwc_lock(struct vb2_queue *vq)
875{
876 struct pwc_device *pdev = vb2_get_drv_priv(vq);
877 mutex_lock(&pdev->modlock);
878}
879
880static void pwc_unlock(struct vb2_queue *vq)
881{
882 struct pwc_device *pdev = vb2_get_drv_priv(vq);
883 mutex_unlock(&pdev->modlock);
884}
885
886static struct vb2_ops pwc_vb_queue_ops = {
887 .queue_setup = queue_setup,
888 .buf_init = buffer_init,
889 .buf_prepare = buffer_prepare,
890 .buf_finish = buffer_finish,
891 .buf_cleanup = buffer_cleanup,
892 .buf_queue = buffer_queue,
893 .start_streaming = start_streaming,
894 .stop_streaming = stop_streaming,
895 .wait_prepare = pwc_unlock,
896 .wait_finish = pwc_lock,
897};
898
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899/***************************************************************************/
900/* USB functions */
901
902/* This function gets called when a new device is plugged in or the usb core
903 * is loaded.
904 */
905
906static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
907{
908 struct usb_device *udev = interface_to_usbdev(intf);
909 struct pwc_device *pdev = NULL;
910 int vendor_id, product_id, type_id;
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300911 int hint, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 int features = 0;
913 int video_nr = -1; /* default: use next available device */
Hans de Goede3b4d0ec2011-06-26 03:51:19 -0300914 int my_power_save = power_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 char serial_number[30], *name;
916
Luc Saillard2b455db2006-04-24 10:29:46 -0300917 vendor_id = le16_to_cpu(udev->descriptor.idVendor);
918 product_id = le16_to_cpu(udev->descriptor.idProduct);
919
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 /* Check if we can handle this device */
Luc Saillard2b455db2006-04-24 10:29:46 -0300921 PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
922 vendor_id, product_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 intf->altsetting->desc.bInterfaceNumber);
924
925 /* the interfaces are probed one by one. We are only interested in the
926 video interface (0) now.
927 Interface 1 is the Audio Control, and interface 2 Audio itself.
928 */
929 if (intf->altsetting->desc.bInterfaceNumber > 0)
930 return -ENODEV;
931
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 if (vendor_id == 0x0471) {
933 switch (product_id) {
934 case 0x0302:
Luc Saillard2b455db2006-04-24 10:29:46 -0300935 PWC_INFO("Philips PCA645VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 name = "Philips 645 webcam";
937 type_id = 645;
938 break;
939 case 0x0303:
Luc Saillard2b455db2006-04-24 10:29:46 -0300940 PWC_INFO("Philips PCA646VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 name = "Philips 646 webcam";
942 type_id = 646;
943 break;
944 case 0x0304:
Luc Saillard2b455db2006-04-24 10:29:46 -0300945 PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 name = "Askey VC010 webcam";
947 type_id = 646;
948 break;
949 case 0x0307:
Luc Saillard2b455db2006-04-24 10:29:46 -0300950 PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 name = "Philips 675 webcam";
952 type_id = 675;
953 break;
954 case 0x0308:
Luc Saillard2b455db2006-04-24 10:29:46 -0300955 PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 name = "Philips 680 webcam";
957 type_id = 680;
958 break;
959 case 0x030C:
Luc Saillard2b455db2006-04-24 10:29:46 -0300960 PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 name = "Philips 690 webcam";
962 type_id = 690;
963 break;
964 case 0x0310:
Luc Saillard2b455db2006-04-24 10:29:46 -0300965 PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 name = "Philips 730 webcam";
967 type_id = 730;
968 break;
969 case 0x0311:
Luc Saillard2b455db2006-04-24 10:29:46 -0300970 PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 name = "Philips 740 webcam";
972 type_id = 740;
973 break;
974 case 0x0312:
Luc Saillard2b455db2006-04-24 10:29:46 -0300975 PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 name = "Philips 750 webcam";
977 type_id = 750;
978 break;
979 case 0x0313:
Luc Saillard2b455db2006-04-24 10:29:46 -0300980 PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 name = "Philips 720K/40 webcam";
982 type_id = 720;
983 break;
Luc Saillard2b455db2006-04-24 10:29:46 -0300984 case 0x0329:
985 PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
986 name = "Philips SPC 900NC webcam";
Luc Saillard9ee6d782007-04-22 23:54:36 -0300987 type_id = 740;
Luc Saillard2b455db2006-04-24 10:29:46 -0300988 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 default:
990 return -ENODEV;
991 break;
992 }
993 }
994 else if (vendor_id == 0x069A) {
995 switch(product_id) {
996 case 0x0001:
Luc Saillard2b455db2006-04-24 10:29:46 -0300997 PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 name = "Askey VC010 webcam";
999 type_id = 645;
1000 break;
1001 default:
1002 return -ENODEV;
1003 break;
1004 }
1005 }
1006 else if (vendor_id == 0x046d) {
1007 switch(product_id) {
1008 case 0x08b0:
Luc Saillard2b455db2006-04-24 10:29:46 -03001009 PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 name = "Logitech QuickCam Pro 3000";
1011 type_id = 740; /* CCD sensor */
1012 break;
1013 case 0x08b1:
Luc Saillard2b455db2006-04-24 10:29:46 -03001014 PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 name = "Logitech QuickCam Notebook Pro";
1016 type_id = 740; /* CCD sensor */
1017 break;
1018 case 0x08b2:
Luc Saillard2b455db2006-04-24 10:29:46 -03001019 PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 name = "Logitech QuickCam Pro 4000";
1021 type_id = 740; /* CCD sensor */
1022 break;
1023 case 0x08b3:
Luc Saillard2b455db2006-04-24 10:29:46 -03001024 PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 name = "Logitech QuickCam Zoom";
1026 type_id = 740; /* CCD sensor */
1027 break;
1028 case 0x08B4:
Luc Saillard2b455db2006-04-24 10:29:46 -03001029 PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 name = "Logitech QuickCam Zoom";
1031 type_id = 740; /* CCD sensor */
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001032 if (my_power_save == -1)
1033 my_power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 break;
1035 case 0x08b5:
Luc Saillard2b455db2006-04-24 10:29:46 -03001036 PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 name = "Logitech QuickCam Orbit";
1038 type_id = 740; /* CCD sensor */
1039 features |= FEATURE_MOTOR_PANTILT;
1040 break;
1041 case 0x08b6:
Jean Tourrilhesa63e1572007-03-21 16:29:16 -03001042 PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n");
1043 name = "Cisco VT Camera";
1044 type_id = 740; /* CCD sensor */
1045 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 case 0x08b7:
Mauro Carvalho Chehab6b1ce3c2007-03-21 16:35:28 -03001047 PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n");
1048 name = "Logitech ViewPort AV 100";
1049 type_id = 740; /* CCD sensor */
1050 break;
1051 case 0x08b8: /* Where this released? */
Luc Saillard2b455db2006-04-24 10:29:46 -03001052 PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 name = "Logitech QuickCam (res.)";
1054 type_id = 730; /* Assuming CMOS */
1055 break;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001056 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001058 break;
1059 }
1060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 else if (vendor_id == 0x055d) {
1062 /* I don't know the difference between the C10 and the C30;
1063 I suppose the difference is the sensor, but both cameras
1064 work equally well with a type_id of 675
1065 */
1066 switch(product_id) {
1067 case 0x9000:
Luc Saillard2b455db2006-04-24 10:29:46 -03001068 PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 name = "Samsung MPC-C10";
1070 type_id = 675;
1071 break;
1072 case 0x9001:
Luc Saillard2b455db2006-04-24 10:29:46 -03001073 PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 name = "Samsung MPC-C30";
1075 type_id = 675;
1076 break;
Luc Saillard2b455db2006-04-24 10:29:46 -03001077 case 0x9002:
1078 PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
1079 name = "Samsung MPC-C30";
1080 type_id = 740;
1081 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 default:
1083 return -ENODEV;
1084 break;
1085 }
1086 }
1087 else if (vendor_id == 0x041e) {
1088 switch(product_id) {
1089 case 0x400c:
Luc Saillard2b455db2006-04-24 10:29:46 -03001090 PWC_INFO("Creative Labs Webcam 5 detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 name = "Creative Labs Webcam 5";
1092 type_id = 730;
1093 break;
1094 case 0x4011:
Luc Saillard2b455db2006-04-24 10:29:46 -03001095 PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 name = "Creative Labs Webcam Pro Ex";
1097 type_id = 740;
1098 break;
1099 default:
1100 return -ENODEV;
1101 break;
1102 }
1103 }
1104 else if (vendor_id == 0x04cc) {
1105 switch(product_id) {
1106 case 0x8116:
Luc Saillard2b455db2006-04-24 10:29:46 -03001107 PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 name = "Sotec Afina Eye";
1109 type_id = 730;
1110 break;
1111 default:
1112 return -ENODEV;
1113 break;
1114 }
1115 }
1116 else if (vendor_id == 0x06be) {
1117 switch(product_id) {
1118 case 0x8116:
1119 /* This is essentially the same cam as the Sotec Afina Eye */
Luc Saillard2b455db2006-04-24 10:29:46 -03001120 PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 name = "AME Co. Afina Eye";
1122 type_id = 750;
1123 break;
1124 default:
1125 return -ENODEV;
1126 break;
1127 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001128
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 }
1130 else if (vendor_id == 0x0d81) {
1131 switch(product_id) {
1132 case 0x1900:
Luc Saillard2b455db2006-04-24 10:29:46 -03001133 PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 name = "Visionite VCS-UC300";
1135 type_id = 740; /* CCD sensor */
1136 break;
1137 case 0x1910:
Luc Saillard2b455db2006-04-24 10:29:46 -03001138 PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 name = "Visionite VCS-UM100";
1140 type_id = 730; /* CMOS sensor */
1141 break;
1142 default:
1143 return -ENODEV;
1144 break;
1145 }
1146 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001147 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 return -ENODEV; /* Not any of the know types; but the list keeps growing. */
1149
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001150 if (my_power_save == -1)
1151 my_power_save = 0;
1152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 memset(serial_number, 0, 30);
1154 usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
Luc Saillard2b455db2006-04-24 10:29:46 -03001155 PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
1157 if (udev->descriptor.bNumConfigurations > 1)
Luc Saillard2b455db2006-04-24 10:29:46 -03001158 PWC_WARNING("Warning: more than 1 configuration available.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
1160 /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01001161 pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001163 PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 return -ENOMEM;
1165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 pdev->type = type_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 pdev->vframes = default_fps;
1168 strcpy(pdev->serial, serial_number);
1169 pdev->features = features;
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001170 if (vendor_id == 0x046D && product_id == 0x08B5) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 /* Logitech QuickCam Orbit
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001172 The ranges have been determined experimentally; they may differ from cam to cam.
1173 Also, the exact ranges left-right and up-down are different for my cam
1174 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 pdev->angle_range.pan_min = -7000;
1176 pdev->angle_range.pan_max = 7000;
1177 pdev->angle_range.tilt_min = -3000;
1178 pdev->angle_range.tilt_max = 2500;
1179 }
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001180 pwc_construct(pdev); /* set min/max sizes correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001182 mutex_init(&pdev->modlock);
Hans de Goede885fe182011-06-06 15:33:44 -03001183 spin_lock_init(&pdev->queued_bufs_lock);
1184 INIT_LIST_HEAD(&pdev->queued_bufs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185
1186 pdev->udev = udev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 pdev->vcompression = pwc_preferred_compression;
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001188 pdev->power_save = my_power_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
Hans de Goede885fe182011-06-06 15:33:44 -03001190 /* Init videobuf2 queue structure */
1191 memset(&pdev->vb_queue, 0, sizeof(pdev->vb_queue));
1192 pdev->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1193 pdev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1194 pdev->vb_queue.drv_priv = pdev;
1195 pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf);
1196 pdev->vb_queue.ops = &pwc_vb_queue_ops;
1197 pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
1198 vb2_queue_init(&pdev->vb_queue);
1199
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001200 /* Init video_device structure */
1201 memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
1202 pdev->vdev.parent = &intf->dev;
1203 pdev->vdev.lock = &pdev->modlock;
1204 strcpy(pdev->vdev.name, name);
1205 video_set_drvdata(&pdev->vdev, pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
1207 pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
Luc Saillard2b455db2006-04-24 10:29:46 -03001208 PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
1210 /* Now search device_hint[] table for a match, so we can hint a node number. */
1211 for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
1212 if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
1213 (device_hint[hint].pdev == NULL)) {
1214 /* so far, so good... try serial number */
1215 if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
Trent Piepho657de3c2006-06-20 00:30:57 -03001216 /* match! */
1217 video_nr = device_hint[hint].device_node;
1218 PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
1219 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 }
1221 }
1222 }
1223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 /* occupy slot */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001225 if (hint < MAX_DEV_HINTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 device_hint[hint].pdev = pdev;
1227
Luc Saillard2b455db2006-04-24 10:29:46 -03001228 PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001229 usb_set_intfdata(intf, pdev);
Luc Saillard2b455db2006-04-24 10:29:46 -03001230
Hans de Goede6eba9352011-06-26 06:49:59 -03001231#ifdef CONFIG_USB_PWC_DEBUG
1232 /* Query sensor type */
1233 if (pwc_get_cmos_sensor(pdev, &rc) >= 0) {
1234 PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
1235 pdev->vdev.name,
1236 pwc_sensor_type_to_string(rc), rc);
1237 }
1238#endif
1239
Luc Saillard2b455db2006-04-24 10:29:46 -03001240 /* Set the leds off */
1241 pwc_set_leds(pdev, 0, 0);
Hans de Goede6eba9352011-06-26 06:49:59 -03001242
1243 /* Setup intial videomode */
1244 rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y,
1245 pdev->vframes, pdev->vcompression, 0);
1246 if (rc)
1247 goto err_free_mem;
1248
1249 /* Initialize the webcam to sane values */
1250 pwc_set_brightness(pdev, 0x7fff);
1251 pwc_set_agc(pdev, 1, 0);
1252
1253 /* And powerdown the camera until streaming starts */
Luc Saillard2b455db2006-04-24 10:29:46 -03001254 pwc_camera_power(pdev, 0);
1255
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001256 rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
Hans Verkuil479567c2010-09-12 17:05:11 -03001257 if (rc < 0) {
1258 PWC_ERROR("Failed to register as video device (%d).\n", rc);
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001259 goto err_free_mem;
Hans Verkuil479567c2010-09-12 17:05:11 -03001260 }
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001261 rc = pwc_create_sysfs_files(pdev);
Hans Verkuil479567c2010-09-12 17:05:11 -03001262 if (rc)
1263 goto err_video_unreg;
1264
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001265 PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev));
Hans Verkuil479567c2010-09-12 17:05:11 -03001266
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001267#ifdef CONFIG_USB_PWC_INPUT_EVDEV
1268 /* register webcam snapshot button input device */
1269 pdev->button_dev = input_allocate_device();
1270 if (!pdev->button_dev) {
1271 PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001272 rc = -ENOMEM;
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001273 pwc_remove_sysfs_files(pdev);
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001274 goto err_video_unreg;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001275 }
1276
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001277 usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys));
1278 strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys));
1279
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001280 pdev->button_dev->name = "PWC snapshot button";
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001281 pdev->button_dev->phys = pdev->button_phys;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001282 usb_to_input_id(pdev->udev, &pdev->button_dev->id);
1283 pdev->button_dev->dev.parent = &pdev->udev->dev;
1284 pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY);
Lennart Poetteringbcd3e4b2009-06-11 11:19:33 -03001285 pdev->button_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001286
1287 rc = input_register_device(pdev->button_dev);
1288 if (rc) {
1289 input_free_device(pdev->button_dev);
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001290 pdev->button_dev = NULL;
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001291 pwc_remove_sysfs_files(pdev);
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001292 goto err_video_unreg;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001293 }
1294#endif
1295
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 return 0;
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001297
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001298err_video_unreg:
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001299 if (hint < MAX_DEV_HINTS)
1300 device_hint[hint].pdev = NULL;
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001301 video_unregister_device(&pdev->vdev);
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001302err_free_mem:
1303 kfree(pdev);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001304 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305}
1306
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001307/* The user yanked out the cable... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308static void usb_pwc_disconnect(struct usb_interface *intf)
1309{
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001310 struct pwc_device *pdev = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Hans Verkuil7074f402010-09-15 14:49:07 -03001312 mutex_lock(&pdev->modlock);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001313
Hans de Goedeb824bb42011-06-25 17:39:19 -03001314 usb_set_intfdata(intf, NULL);
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001315 /* No need to keep the urbs around after disconnection */
1316 pwc_isoc_cleanup(pdev);
Hans de Goede885fe182011-06-06 15:33:44 -03001317 pwc_cleanup_queued_bufs(pdev);
Hans de Goedeb824bb42011-06-25 17:39:19 -03001318 pdev->udev = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
Hans Verkuil7074f402010-09-15 14:49:07 -03001320 mutex_unlock(&pdev->modlock);
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001321
1322 pwc_remove_sysfs_files(pdev);
1323 video_unregister_device(&pdev->vdev);
1324
1325#ifdef CONFIG_USB_PWC_INPUT_EVDEV
1326 if (pdev->button_dev)
1327 input_unregister_device(pdev->button_dev);
1328#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329}
1330
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001332/*
1333 * Initialization code & module stuff
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 */
1335
Luc Saillard2b455db2006-04-24 10:29:46 -03001336static int fps;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337static int compression = -1;
1338static int leds[2] = { -1, -1 };
Al Viro64a6f952007-10-14 19:35:30 +01001339static unsigned int leds_nargs;
Luc Saillard2b455db2006-04-24 10:29:46 -03001340static char *dev_hint[MAX_DEV_HINTS];
Al Viro64a6f952007-10-14 19:35:30 +01001341static unsigned int dev_hint_nargs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
Luc Saillard2b455db2006-04-24 10:29:46 -03001343module_param(fps, int, 0444);
Trent Piepho05ad3902007-01-30 23:26:01 -03001344#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001345module_param_named(trace, pwc_trace, int, 0644);
1346#endif
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001347module_param(power_save, int, 0644);
Luc Saillard2b455db2006-04-24 10:29:46 -03001348module_param(compression, int, 0444);
1349module_param_array(leds, int, &leds_nargs, 0444);
1350module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
1351
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
Andrea Odetti4315c412009-12-10 16:26:10 -03001353#ifdef CONFIG_USB_PWC_DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354MODULE_PARM_DESC(trace, "For debugging purposes");
Andrea Odetti4315c412009-12-10 16:26:10 -03001355#endif
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001356MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359MODULE_PARM_DESC(dev_hint, "Device node hints");
1360
1361MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
1362MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
1363MODULE_LICENSE("GPL");
Luc Saillard2b455db2006-04-24 10:29:46 -03001364MODULE_ALIAS("pwcx");
1365MODULE_VERSION( PWC_VERSION );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
1367static int __init usb_pwc_init(void)
1368{
Hans de Goede6eba9352011-06-26 06:49:59 -03001369 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Hans de Goede6eba9352011-06-26 06:49:59 -03001371#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001372 PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
1373 PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
1374 PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
1375 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 -07001376
Hans de Goede6eba9352011-06-26 06:49:59 -03001377 if (pwc_trace >= 0) {
1378 PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
1379 }
1380#endif
1381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 if (fps) {
1383 if (fps < 4 || fps > 30) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001384 PWC_ERROR("Framerate out of bounds (4-30).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 return -EINVAL;
1386 }
1387 default_fps = fps;
Luc Saillard2b455db2006-04-24 10:29:46 -03001388 PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 }
1390
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 if (compression >= 0) {
1392 if (compression > 3) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001393 PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 return -EINVAL;
1395 }
1396 pwc_preferred_compression = compression;
Luc Saillard2b455db2006-04-24 10:29:46 -03001397 PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 if (leds[0] >= 0)
1400 led_on = leds[0];
1401 if (leds[1] >= 0)
1402 led_off = leds[1];
1403
Steven Cole093cf722005-05-03 19:07:24 -06001404 /* Big device node whoopla. Basically, it allows you to assign a
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 device node (/dev/videoX) to a camera, based on its type
1406 & serial number. The format is [type[.serialnumber]:]node.
1407
1408 Any camera that isn't matched by these rules gets the next
1409 available free device node.
1410 */
1411 for (i = 0; i < MAX_DEV_HINTS; i++) {
1412 char *s, *colon, *dot;
1413
1414 /* This loop also initializes the array */
1415 device_hint[i].pdev = NULL;
1416 s = dev_hint[i];
1417 if (s != NULL && *s != '\0') {
1418 device_hint[i].type = -1; /* wildcard */
1419 strcpy(device_hint[i].serial_number, "*");
1420
1421 /* parse string: chop at ':' & '/' */
1422 colon = dot = s;
1423 while (*colon != '\0' && *colon != ':')
1424 colon++;
1425 while (*dot != '\0' && *dot != '.')
1426 dot++;
1427 /* Few sanity checks */
1428 if (*dot != '\0' && dot > colon) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001429 PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 return -EINVAL;
1431 }
1432
1433 if (*colon == '\0') {
1434 /* No colon */
1435 if (*dot != '\0') {
Luc Saillard2b455db2006-04-24 10:29:46 -03001436 PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 return -EINVAL;
1438 }
1439 else {
1440 /* No type or serial number specified, just a number. */
Andy Shevchenko2d8d7762009-09-24 07:58:09 -03001441 device_hint[i].device_node =
1442 simple_strtol(s, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 }
1444 }
1445 else {
1446 /* There's a colon, so we have at least a type and a device node */
Andy Shevchenko2d8d7762009-09-24 07:58:09 -03001447 device_hint[i].type =
1448 simple_strtol(s, NULL, 10);
1449 device_hint[i].device_node =
1450 simple_strtol(colon + 1, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 if (*dot != '\0') {
1452 /* There's a serial number as well */
1453 int k;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001454
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 dot++;
1456 k = 0;
1457 while (*dot != ':' && k < 29) {
1458 device_hint[i].serial_number[k++] = *dot;
1459 dot++;
1460 }
1461 device_hint[i].serial_number[k] = '\0';
1462 }
1463 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001464 PWC_TRACE("device_hint[%d]:\n", i);
1465 PWC_TRACE(" type : %d\n", device_hint[i].type);
1466 PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number);
1467 PWC_TRACE(" node : %d\n", device_hint[i].device_node);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 }
1469 else
1470 device_hint[i].type = 0; /* not filled */
1471 } /* ..for MAX_DEV_HINTS */
1472
Luc Saillard2b455db2006-04-24 10:29:46 -03001473 PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 return usb_register(&pwc_driver);
1475}
1476
1477static void __exit usb_pwc_exit(void)
1478{
Luc Saillard2b455db2006-04-24 10:29:46 -03001479 PWC_DEBUG_MODULE("Deregistering driver.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 usb_deregister(&pwc_driver);
Luc Saillard2b455db2006-04-24 10:29:46 -03001481 PWC_INFO("Philips webcam module removed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482}
1483
1484module_init(usb_pwc_init);
1485module_exit(usb_pwc_exit);
1486
Luc Saillard2b455db2006-04-24 10:29:46 -03001487/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */