blob: a66f60cb8c3b3948d4752a8037ab99da217cc4e1 [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_close(struct file *file);
Luc Saillard2b455db2006-04-24 10:29:46 -0300148static ssize_t pwc_video_read(struct file *file, char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 size_t count, loff_t *ppos);
150static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
152
Hans Verkuilbec43662008-12-30 06:58:20 -0300153static const struct v4l2_file_operations pwc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 .owner = THIS_MODULE,
Hans de Goede76ae8532011-07-19 07:14:22 -0300155 .open = v4l2_fh_open,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 .release = pwc_video_close,
157 .read = pwc_video_read,
158 .poll = pwc_video_poll,
159 .mmap = pwc_video_mmap,
Hans Verkuilafa38522011-01-22 06:34:55 -0300160 .unlocked_ioctl = video_ioctl2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161};
162static struct video_device pwc_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 .name = "Philips Webcam", /* Filled in later */
Hans de Goede76ae8532011-07-19 07:14:22 -0300164 .release = video_device_release_empty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 .fops = &pwc_fops,
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300166 .ioctl_ops = &pwc_ioctl_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167};
168
169/***************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170/* Private functions */
171
Hans de Goede885fe182011-06-06 15:33:44 -0300172struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173{
Hans de Goede885fe182011-06-06 15:33:44 -0300174 unsigned long flags = 0;
175 struct pwc_frame_buf *buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Hans de Goede885fe182011-06-06 15:33:44 -0300177 spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
178 if (list_empty(&pdev->queued_bufs))
179 goto leave;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Hans de Goede885fe182011-06-06 15:33:44 -0300181 buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, list);
182 list_del(&buf->list);
183leave:
184 spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
185 return buf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300186}
187
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300188static void pwc_snapshot_button(struct pwc_device *pdev, int down)
189{
190 if (down) {
191 PWC_TRACE("Snapshot button pressed.\n");
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300192 } else {
193 PWC_TRACE("Snapshot button released.\n");
194 }
195
196#ifdef CONFIG_USB_PWC_INPUT_EVDEV
197 if (pdev->button_dev) {
Lennart Poetteringbcd3e4b2009-06-11 11:19:33 -0300198 input_report_key(pdev->button_dev, KEY_CAMERA, down);
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300199 input_sync(pdev->button_dev);
200 }
201#endif
202}
203
Hans de Goede885fe182011-06-06 15:33:44 -0300204static void pwc_frame_complete(struct pwc_device *pdev)
Luc Saillard2b455db2006-04-24 10:29:46 -0300205{
Hans de Goede885fe182011-06-06 15:33:44 -0300206 struct pwc_frame_buf *fbuf = pdev->fill_buf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300207
208 /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
209 frames on the USB wire after an exposure change. This conditition is
210 however detected in the cam and a bit is set in the header.
211 */
212 if (pdev->type == 730) {
213 unsigned char *ptr = (unsigned char *)fbuf->data;
214
215 if (ptr[1] == 1 && ptr[0] & 0x10) {
216 PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
217 pdev->drop_frames += 2;
Luc Saillard2b455db2006-04-24 10:29:46 -0300218 }
219 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300220 pwc_snapshot_button(pdev, ptr[0] & 0x01);
Luc Saillard2b455db2006-04-24 10:29:46 -0300221 }
222 if ((ptr[0] ^ pdev->vmirror) & 0x02) {
223 if (ptr[0] & 0x02)
224 PWC_TRACE("Image is mirrored.\n");
225 else
226 PWC_TRACE("Image is normal.\n");
227 }
228 pdev->vmirror = ptr[0] & 0x03;
229 /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
230 after a short frame; this condition is filtered out specifically. A 4 byte
231 frame doesn't make sense anyway.
232 So we get either this sequence:
233 drop_bit set -> 4 byte frame -> short frame -> good frame
234 Or this one:
235 drop_bit set -> short frame -> good frame
236 So we drop either 3 or 2 frames in all!
237 */
238 if (fbuf->filled == 4)
239 pdev->drop_frames++;
Hans de Goede885fe182011-06-06 15:33:44 -0300240 } else if (pdev->type == 740 || pdev->type == 720) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300241 unsigned char *ptr = (unsigned char *)fbuf->data;
242 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300243 pwc_snapshot_button(pdev, ptr[0] & 0x01);
Luc Saillard2b455db2006-04-24 10:29:46 -0300244 }
245 pdev->vmirror = ptr[0] & 0x03;
246 }
247
Hans de Goede885fe182011-06-06 15:33:44 -0300248 /* In case we were instructed to drop the frame, do so silently. */
249 if (pdev->drop_frames > 0) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300250 pdev->drop_frames--;
Hans de Goede885fe182011-06-06 15:33:44 -0300251 } else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300252 /* Check for underflow first */
253 if (fbuf->filled < pdev->frame_total_size) {
254 PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
255 " discarded.\n", fbuf->filled);
Hans de Goede885fe182011-06-06 15:33:44 -0300256 } else {
257 fbuf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
258 fbuf->vb.v4l2_buf.sequence = pdev->vframe_count;
259 vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
260 pdev->fill_buf = NULL;
261 pdev->vsync = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300262 }
263 } /* !drop_frames */
264 pdev->vframe_count++;
Luc Saillard2b455db2006-04-24 10:29:46 -0300265}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267/* This gets called for the Isochronous pipe (video). This is done in
268 * interrupt time, so it has to be fast, not crash, and not stall. Neat.
269 */
David Howells7d12e782006-10-05 14:55:46 +0100270static void pwc_isoc_handler(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
Hans de Goede885fe182011-06-06 15:33:44 -0300272 struct pwc_device *pdev = (struct pwc_device *)urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 int i, fst, flen;
Hans de Goede885fe182011-06-06 15:33:44 -0300274 unsigned char *iso_buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
Hans de Goede885fe182011-06-06 15:33:44 -0300276 if (urb->status == -ENOENT || urb->status == -ECONNRESET ||
277 urb->status == -ESHUTDOWN) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300278 PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return;
280 }
Hans de Goede885fe182011-06-06 15:33:44 -0300281
282 if (pdev->fill_buf == NULL)
283 pdev->fill_buf = pwc_get_next_fill_buf(pdev);
284
285 if (urb->status != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 const char *errmsg;
287
288 errmsg = "Unknown";
289 switch(urb->status) {
290 case -ENOSR: errmsg = "Buffer error (overrun)"; break;
291 case -EPIPE: errmsg = "Stalled (device not responding)"; break;
292 case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break;
293 case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break;
294 case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
Pete Zaitcev38e2bfc2006-09-18 22:49:02 -0700295 case -ETIME: errmsg = "Device does not respond"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 }
Hans de Goede885fe182011-06-06 15:33:44 -0300297 PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n",
298 urb->status, errmsg);
299 /* Give up after a number of contiguous errors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
301 {
Hans de Goede885fe182011-06-06 15:33:44 -0300302 PWC_ERROR("Too many ISOC errors, bailing out.\n");
303 if (pdev->fill_buf) {
304 vb2_buffer_done(&pdev->fill_buf->vb,
305 VB2_BUF_STATE_ERROR);
306 pdev->fill_buf = NULL;
307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
Hans de Goede885fe182011-06-06 15:33:44 -0300309 pdev->vsync = 0; /* Drop the current frame */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 goto handler_end;
311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 /* Reset ISOC error counter. We did get here, after all. */
314 pdev->visoc_errors = 0;
315
316 /* vsync: 0 = don't copy data
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300317 1 = sync-hunt
318 2 = synched
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 */
320 /* Compact data */
321 for (i = 0; i < urb->number_of_packets; i++) {
322 fst = urb->iso_frame_desc[i].status;
323 flen = urb->iso_frame_desc[i].actual_length;
324 iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
Hans de Goede885fe182011-06-06 15:33:44 -0300325 if (fst != 0) {
326 PWC_ERROR("Iso frame %d has error %d\n", i, fst);
327 continue;
328 }
329 if (flen > 0 && pdev->vsync) {
330 struct pwc_frame_buf *fbuf = pdev->fill_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Hans de Goede885fe182011-06-06 15:33:44 -0300332 if (pdev->vsync == 1) {
333 do_gettimeofday(&fbuf->vb.v4l2_buf.timestamp);
334 pdev->vsync = 2;
Luc Saillard2b455db2006-04-24 10:29:46 -0300335 }
336
Hans de Goede885fe182011-06-06 15:33:44 -0300337 if (flen + fbuf->filled > pdev->frame_total_size) {
338 PWC_ERROR("Frame overflow (%d > %d)\n",
339 flen + fbuf->filled,
340 pdev->frame_total_size);
341 pdev->vsync = 0; /* Let's wait for an EOF */
342 } else {
343 memcpy(fbuf->data + fbuf->filled, iso_buf,
344 flen);
345 fbuf->filled += flen;
346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 }
Hans de Goede885fe182011-06-06 15:33:44 -0300348 if (flen < pdev->vlast_packet_size) {
349 /* Shorter packet... end of frame */
350 if (pdev->vsync == 2)
351 pwc_frame_complete(pdev);
352 if (pdev->fill_buf == NULL)
353 pdev->fill_buf = pwc_get_next_fill_buf(pdev);
354 if (pdev->fill_buf) {
355 pdev->fill_buf->filled = 0;
356 pdev->vsync = 1;
357 }
358 }
359 pdev->vlast_packet_size = flen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 }
361
362handler_end:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 i = usb_submit_urb(urb, GFP_ATOMIC);
364 if (i != 0)
Luc Saillard2b455db2006-04-24 10:29:46 -0300365 PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366}
367
Hans de Goede885fe182011-06-06 15:33:44 -0300368static int pwc_isoc_init(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
370 struct usb_device *udev;
371 struct urb *urb;
372 int i, j, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 struct usb_interface *intf;
374 struct usb_host_interface *idesc = NULL;
375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 if (pdev->iso_init)
377 return 0;
Hans de Goede6eba9352011-06-26 06:49:59 -0300378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 pdev->vsync = 0;
Hans de Goede6eba9352011-06-26 06:49:59 -0300380 pdev->vlast_packet_size = 0;
Hans de Goede885fe182011-06-06 15:33:44 -0300381 pdev->fill_buf = NULL;
382 pdev->vframe_count = 0;
Hans de Goede6eba9352011-06-26 06:49:59 -0300383 pdev->visoc_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 udev = pdev->udev;
385
386 /* Get the current alternate interface, adjust packet size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 intf = usb_ifnum_to_if(udev, 0);
388 if (intf)
389 idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 if (!idesc)
Hans de Goedec2464122011-06-06 15:25:18 -0300391 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393 /* Search video endpoint */
394 pdev->vmax_packet_size = -1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300395 for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
397 pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
398 break;
399 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300400 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300403 PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
Steven Cole093cf722005-05-03 19:07:24 -0600404 return -ENFILE; /* Odd error, that should be noticeable */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 }
406
407 /* Set alternate interface */
408 ret = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300409 PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
411 if (ret < 0)
412 return ret;
413
Hans de Goede04613c52011-06-26 13:57:15 -0300414 /* Allocate and init Isochronuous urbs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 for (i = 0; i < MAX_ISO_BUFS; i++) {
416 urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
417 if (urb == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300418 PWC_ERROR("Failed to allocate urb %d\n", i);
Hans de Goede6eba9352011-06-26 06:49:59 -0300419 pdev->iso_init = 1;
420 pwc_isoc_cleanup(pdev);
421 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 }
Hans de Goede04613c52011-06-26 13:57:15 -0300423 pdev->urbs[i] = urb;
Luc Saillard2b455db2006-04-24 10:29:46 -0300424 PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 urb->interval = 1; // devik
427 urb->dev = udev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300428 urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
Hans de Goede04613c52011-06-26 13:57:15 -0300429 urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
430 urb->transfer_buffer = usb_alloc_coherent(udev,
431 ISO_BUFFER_SIZE,
432 GFP_KERNEL,
433 &urb->transfer_dma);
434 if (urb->transfer_buffer == NULL) {
435 PWC_ERROR("Failed to allocate urb buffer %d\n", i);
436 pdev->iso_init = 1;
437 pwc_isoc_cleanup(pdev);
438 return -ENOMEM;
439 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300440 urb->transfer_buffer_length = ISO_BUFFER_SIZE;
441 urb->complete = pwc_isoc_handler;
442 urb->context = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 urb->start_frame = 0;
444 urb->number_of_packets = ISO_FRAMES_PER_DESC;
445 for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
446 urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
447 urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
448 }
449 }
450
451 /* link */
452 for (i = 0; i < MAX_ISO_BUFS; i++) {
Hans de Goede04613c52011-06-26 13:57:15 -0300453 ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL);
Hans de Goede622d9f52010-11-16 12:32:09 -0300454 if (ret) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300455 PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
Hans de Goede622d9f52010-11-16 12:32:09 -0300456 pdev->iso_init = 1;
457 pwc_isoc_cleanup(pdev);
458 return ret;
459 }
Hans de Goede04613c52011-06-26 13:57:15 -0300460 PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->urbs[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 }
462
463 /* All is done... */
464 pdev->iso_init = 1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300465 PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 return 0;
467}
468
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300469static void pwc_iso_stop(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
471 int i;
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 /* Unlinking ISOC buffers one by one */
474 for (i = 0; i < MAX_ISO_BUFS; i++) {
Hans de Goede04613c52011-06-26 13:57:15 -0300475 if (pdev->urbs[i]) {
476 PWC_DEBUG_MEMORY("Unlinking URB %p\n", pdev->urbs[i]);
477 usb_kill_urb(pdev->urbs[i]);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300478 }
479 }
480}
481
482static void pwc_iso_free(struct pwc_device *pdev)
483{
484 int i;
485
486 /* Freeing ISOC buffers one by one */
487 for (i = 0; i < MAX_ISO_BUFS; i++) {
Hans de Goede04613c52011-06-26 13:57:15 -0300488 if (pdev->urbs[i]) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300489 PWC_DEBUG_MEMORY("Freeing URB\n");
Hans de Goede04613c52011-06-26 13:57:15 -0300490 if (pdev->urbs[i]->transfer_buffer) {
491 usb_free_coherent(pdev->udev,
492 pdev->urbs[i]->transfer_buffer_length,
493 pdev->urbs[i]->transfer_buffer,
494 pdev->urbs[i]->transfer_dma);
495 }
496 usb_free_urb(pdev->urbs[i]);
497 pdev->urbs[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 }
499 }
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300500}
501
Hans de Goede885fe182011-06-06 15:33:44 -0300502static void pwc_isoc_cleanup(struct pwc_device *pdev)
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300503{
504 PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
Hans de Goedec2464122011-06-06 15:25:18 -0300505
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300506 if (pdev->iso_init == 0)
507 return;
508
509 pwc_iso_stop(pdev);
510 pwc_iso_free(pdev);
Hans de Goedeb824bb42011-06-25 17:39:19 -0300511 usb_set_interface(pdev->udev, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 pdev->iso_init = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300514 PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515}
516
Hans de Goede885fe182011-06-06 15:33:44 -0300517static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
518{
Hans de Goedec20d78c2011-10-09 09:16:46 -0300519 unsigned long flags = 0;
520
521 spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
Hans de Goede885fe182011-06-06 15:33:44 -0300522 while (!list_empty(&pdev->queued_bufs)) {
523 struct pwc_frame_buf *buf;
524
525 buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf,
526 list);
527 list_del(&buf->list);
528 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
529 }
Hans de Goedec20d78c2011-10-09 09:16:46 -0300530 spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
Hans de Goede885fe182011-06-06 15:33:44 -0300531}
532
Trent Piepho05ad3902007-01-30 23:26:01 -0300533#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -0300534static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
535{
536 switch(sensor_type) {
537 case 0x00:
538 return "Hyundai CMOS sensor";
539 case 0x20:
540 return "Sony CCD sensor + TDA8787";
541 case 0x2E:
542 return "Sony CCD sensor + Exas 98L59";
543 case 0x2F:
544 return "Sony CCD sensor + ADI 9804";
545 case 0x30:
546 return "Sharp CCD sensor + TDA8787";
547 case 0x3E:
548 return "Sharp CCD sensor + Exas 98L59";
549 case 0x3F:
550 return "Sharp CCD sensor + ADI 9804";
551 case 0x40:
552 return "UPA 1021 sensor";
553 case 0x100:
554 return "VGA sensor";
555 case 0x101:
556 return "PAL MR sensor";
557 default:
Trent Piepho657de3c2006-06-20 00:30:57 -0300558 return "unknown type of sensor";
Luc Saillard2b455db2006-04-24 10:29:46 -0300559 }
560}
561#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563/***************************************************************************/
564/* Video4Linux functions */
565
Hans de Goedec20d78c2011-10-09 09:16:46 -0300566int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file)
567{
568 int r = 0;
569
570 mutex_lock(&pdev->capt_file_lock);
571 if (pdev->capt_file != NULL &&
572 pdev->capt_file != file) {
573 r = -EBUSY;
574 goto leave;
575 }
576 pdev->capt_file = file;
577leave:
578 mutex_unlock(&pdev->capt_file_lock);
579 return r;
580}
581
Hans de Goede76ae8532011-07-19 07:14:22 -0300582static void pwc_video_release(struct v4l2_device *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
Hans de Goede76ae8532011-07-19 07:14:22 -0300584 struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300585 int hint;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -0300586
Hans de Goede9a7b2d12011-06-06 14:43:39 -0300587 /* search device_hint[] table if we occupy a slot, by any chance */
588 for (hint = 0; hint < MAX_DEV_HINTS; hint++)
589 if (device_hint[hint].pdev == pdev)
590 device_hint[hint].pdev = NULL;
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300591
Hans de Goede6eba9352011-06-26 06:49:59 -0300592 /* Free intermediate decompression buffer & tables */
593 if (pdev->decompress_data != NULL) {
594 PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n",
595 pdev->decompress_data);
596 kfree(pdev->decompress_data);
597 pdev->decompress_data = NULL;
598 }
599
Hans de Goede6c9cac82011-06-26 12:52:01 -0300600 v4l2_ctrl_handler_free(&pdev->ctrl_handler);
601
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300602 kfree(pdev);
Oliver Neukum85237f22007-08-21 07:10:42 +0200603}
604
Hans Verkuilbec43662008-12-30 06:58:20 -0300605static int pwc_video_close(struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606{
Hans de Goede76ae8532011-07-19 07:14:22 -0300607 struct pwc_device *pdev = video_drvdata(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Hans de Goede4fba4712011-06-26 12:13:44 -0300609 if (pdev->capt_file == file) {
610 vb2_queue_release(&pdev->vb_queue);
611 pdev->capt_file = NULL;
612 }
Hans de Goede76ae8532011-07-19 07:14:22 -0300613 return v4l2_fh_release(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614}
615
Luc Saillard2b455db2006-04-24 10:29:46 -0300616static ssize_t pwc_video_read(struct file *file, char __user *buf,
Hans de Goede885fe182011-06-06 15:33:44 -0300617 size_t count, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
Hans de Goede76ae8532011-07-19 07:14:22 -0300619 struct pwc_device *pdev = video_drvdata(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Hans de Goedeb824bb42011-06-25 17:39:19 -0300621 if (!pdev->udev)
622 return -ENODEV;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300623
Hans de Goedec20d78c2011-10-09 09:16:46 -0300624 if (pwc_test_n_set_capt_file(pdev, file))
Hans de Goede4fba4712011-06-26 12:13:44 -0300625 return -EBUSY;
626
Hans de Goede885fe182011-06-06 15:33:44 -0300627 return vb2_read(&pdev->vb_queue, buf, count, ppos,
628 file->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629}
630
631static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
632{
Hans de Goede76ae8532011-07-19 07:14:22 -0300633 struct pwc_device *pdev = video_drvdata(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Hans de Goedeb824bb42011-06-25 17:39:19 -0300635 if (!pdev->udev)
Hans de Goede885fe182011-06-06 15:33:44 -0300636 return POLL_ERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Hans de Goede885fe182011-06-06 15:33:44 -0300638 return vb2_poll(&pdev->vb_queue, file, wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639}
640
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
642{
Hans de Goede76ae8532011-07-19 07:14:22 -0300643 struct pwc_device *pdev = video_drvdata(file);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300644
Hans de Goede4fba4712011-06-26 12:13:44 -0300645 if (pdev->capt_file != file)
646 return -EBUSY;
647
Hans de Goede885fe182011-06-06 15:33:44 -0300648 return vb2_mmap(&pdev->vb_queue, vma);
649}
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300650
Hans de Goede885fe182011-06-06 15:33:44 -0300651/***************************************************************************/
652/* Videobuf2 operations */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Guennadi Liakhovetskifc714e72011-08-24 10:30:21 -0300654static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
655 unsigned int *nbuffers, unsigned int *nplanes,
656 unsigned int sizes[], void *alloc_ctxs[])
Hans de Goede885fe182011-06-06 15:33:44 -0300657{
658 struct pwc_device *pdev = vb2_get_drv_priv(vq);
Luc Saillard2b455db2006-04-24 10:29:46 -0300659
Hans de Goede885fe182011-06-06 15:33:44 -0300660 if (*nbuffers < MIN_FRAMES)
661 *nbuffers = MIN_FRAMES;
662 else if (*nbuffers > MAX_FRAMES)
663 *nbuffers = MAX_FRAMES;
664
665 *nplanes = 1;
666
667 sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
668
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 return 0;
670}
671
Hans de Goede885fe182011-06-06 15:33:44 -0300672static int buffer_init(struct vb2_buffer *vb)
673{
674 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
675
676 /* need vmalloc since frame buffer > 128K */
677 buf->data = vzalloc(PWC_FRAME_SIZE);
678 if (buf->data == NULL)
679 return -ENOMEM;
680
681 return 0;
682}
683
684static int buffer_prepare(struct vb2_buffer *vb)
685{
686 struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
687
688 /* Don't allow queing new buffers after device disconnection */
Hans de Goedeb824bb42011-06-25 17:39:19 -0300689 if (!pdev->udev)
690 return -ENODEV;
Hans de Goede885fe182011-06-06 15:33:44 -0300691
692 return 0;
693}
694
695static int buffer_finish(struct vb2_buffer *vb)
696{
697 struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
698 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
699
700 /*
701 * Application has called dqbuf and is getting back a buffer we've
702 * filled, take the pwc data we've stored in buf->data and decompress
703 * it into a usable format, storing the result in the vb2_buffer
704 */
705 return pwc_decompress(pdev, buf);
706}
707
708static void buffer_cleanup(struct vb2_buffer *vb)
709{
710 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
711
712 vfree(buf->data);
713}
714
715static void buffer_queue(struct vb2_buffer *vb)
716{
717 struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
718 struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
719 unsigned long flags = 0;
720
721 spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
Hans de Goedec20d78c2011-10-09 09:16:46 -0300722 /* Check the device has not disconnected between prep and queuing */
723 if (pdev->udev)
724 list_add_tail(&buf->list, &pdev->queued_bufs);
725 else
726 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
Hans de Goede885fe182011-06-06 15:33:44 -0300727 spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
728}
729
Marek Szyprowskibd323e22011-08-29 08:51:49 -0300730static int start_streaming(struct vb2_queue *vq, unsigned int count)
Hans de Goede885fe182011-06-06 15:33:44 -0300731{
732 struct pwc_device *pdev = vb2_get_drv_priv(vq);
Hans de Goedec20d78c2011-10-09 09:16:46 -0300733 int r;
Hans de Goede885fe182011-06-06 15:33:44 -0300734
Hans de Goedec20d78c2011-10-09 09:16:46 -0300735 mutex_lock(&pdev->udevlock);
736 if (!pdev->udev) {
737 r = -ENODEV;
738 goto leave;
739 }
Hans de Goedeb824bb42011-06-25 17:39:19 -0300740
Hans de Goede6eba9352011-06-26 06:49:59 -0300741 /* Turn on camera and set LEDS on */
742 pwc_camera_power(pdev, 1);
743 if (pdev->power_save) {
744 /* Restore video mode */
745 pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y,
Hans de Goededc8a7e82011-12-31 10:52:02 -0300746 pdev->vframes, pdev->vcompression);
Hans de Goede6eba9352011-06-26 06:49:59 -0300747 }
748 pwc_set_leds(pdev, led_on, led_off);
749
Hans de Goedec20d78c2011-10-09 09:16:46 -0300750 r = pwc_isoc_init(pdev);
751leave:
752 mutex_unlock(&pdev->udevlock);
753 return r;
Hans de Goede885fe182011-06-06 15:33:44 -0300754}
755
756static int stop_streaming(struct vb2_queue *vq)
757{
758 struct pwc_device *pdev = vb2_get_drv_priv(vq);
759
Hans de Goedec20d78c2011-10-09 09:16:46 -0300760 mutex_lock(&pdev->udevlock);
Hans de Goede6eba9352011-06-26 06:49:59 -0300761 if (pdev->udev) {
762 pwc_set_leds(pdev, 0, 0);
763 pwc_camera_power(pdev, 0);
Hans de Goedeb824bb42011-06-25 17:39:19 -0300764 pwc_isoc_cleanup(pdev);
Hans de Goede6eba9352011-06-26 06:49:59 -0300765 }
Hans de Goedec20d78c2011-10-09 09:16:46 -0300766 mutex_unlock(&pdev->udevlock);
767
Hans de Goede885fe182011-06-06 15:33:44 -0300768 pwc_cleanup_queued_bufs(pdev);
769
770 return 0;
771}
772
Hans de Goede885fe182011-06-06 15:33:44 -0300773static struct vb2_ops pwc_vb_queue_ops = {
774 .queue_setup = queue_setup,
775 .buf_init = buffer_init,
776 .buf_prepare = buffer_prepare,
777 .buf_finish = buffer_finish,
778 .buf_cleanup = buffer_cleanup,
779 .buf_queue = buffer_queue,
780 .start_streaming = start_streaming,
781 .stop_streaming = stop_streaming,
Hans de Goede885fe182011-06-06 15:33:44 -0300782};
783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784/***************************************************************************/
785/* USB functions */
786
787/* This function gets called when a new device is plugged in or the usb core
788 * is loaded.
789 */
790
791static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
792{
793 struct usb_device *udev = interface_to_usbdev(intf);
794 struct pwc_device *pdev = NULL;
795 int vendor_id, product_id, type_id;
Dmitry Torokhov89dec012009-08-14 02:22:52 -0300796 int hint, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 int features = 0;
798 int video_nr = -1; /* default: use next available device */
Hans de Goede3b4d0ec2011-06-26 03:51:19 -0300799 int my_power_save = power_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 char serial_number[30], *name;
801
Luc Saillard2b455db2006-04-24 10:29:46 -0300802 vendor_id = le16_to_cpu(udev->descriptor.idVendor);
803 product_id = le16_to_cpu(udev->descriptor.idProduct);
804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 /* Check if we can handle this device */
Luc Saillard2b455db2006-04-24 10:29:46 -0300806 PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
807 vendor_id, product_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 intf->altsetting->desc.bInterfaceNumber);
809
810 /* the interfaces are probed one by one. We are only interested in the
811 video interface (0) now.
812 Interface 1 is the Audio Control, and interface 2 Audio itself.
813 */
814 if (intf->altsetting->desc.bInterfaceNumber > 0)
815 return -ENODEV;
816
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (vendor_id == 0x0471) {
818 switch (product_id) {
819 case 0x0302:
Luc Saillard2b455db2006-04-24 10:29:46 -0300820 PWC_INFO("Philips PCA645VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 name = "Philips 645 webcam";
822 type_id = 645;
823 break;
824 case 0x0303:
Luc Saillard2b455db2006-04-24 10:29:46 -0300825 PWC_INFO("Philips PCA646VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 name = "Philips 646 webcam";
827 type_id = 646;
828 break;
829 case 0x0304:
Luc Saillard2b455db2006-04-24 10:29:46 -0300830 PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 name = "Askey VC010 webcam";
832 type_id = 646;
833 break;
834 case 0x0307:
Luc Saillard2b455db2006-04-24 10:29:46 -0300835 PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 name = "Philips 675 webcam";
837 type_id = 675;
838 break;
839 case 0x0308:
Luc Saillard2b455db2006-04-24 10:29:46 -0300840 PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 name = "Philips 680 webcam";
842 type_id = 680;
843 break;
844 case 0x030C:
Luc Saillard2b455db2006-04-24 10:29:46 -0300845 PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 name = "Philips 690 webcam";
847 type_id = 690;
848 break;
849 case 0x0310:
Luc Saillard2b455db2006-04-24 10:29:46 -0300850 PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 name = "Philips 730 webcam";
852 type_id = 730;
853 break;
854 case 0x0311:
Luc Saillard2b455db2006-04-24 10:29:46 -0300855 PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 name = "Philips 740 webcam";
857 type_id = 740;
858 break;
859 case 0x0312:
Luc Saillard2b455db2006-04-24 10:29:46 -0300860 PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 name = "Philips 750 webcam";
862 type_id = 750;
863 break;
864 case 0x0313:
Luc Saillard2b455db2006-04-24 10:29:46 -0300865 PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 name = "Philips 720K/40 webcam";
867 type_id = 720;
868 break;
Luc Saillard2b455db2006-04-24 10:29:46 -0300869 case 0x0329:
870 PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
871 name = "Philips SPC 900NC webcam";
Luc Saillard9ee6d782007-04-22 23:54:36 -0300872 type_id = 740;
Luc Saillard2b455db2006-04-24 10:29:46 -0300873 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 default:
875 return -ENODEV;
876 break;
877 }
878 }
879 else if (vendor_id == 0x069A) {
880 switch(product_id) {
881 case 0x0001:
Luc Saillard2b455db2006-04-24 10:29:46 -0300882 PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 name = "Askey VC010 webcam";
884 type_id = 645;
885 break;
886 default:
887 return -ENODEV;
888 break;
889 }
890 }
891 else if (vendor_id == 0x046d) {
892 switch(product_id) {
893 case 0x08b0:
Luc Saillard2b455db2006-04-24 10:29:46 -0300894 PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 name = "Logitech QuickCam Pro 3000";
896 type_id = 740; /* CCD sensor */
897 break;
898 case 0x08b1:
Luc Saillard2b455db2006-04-24 10:29:46 -0300899 PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 name = "Logitech QuickCam Notebook Pro";
901 type_id = 740; /* CCD sensor */
902 break;
903 case 0x08b2:
Luc Saillard2b455db2006-04-24 10:29:46 -0300904 PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 name = "Logitech QuickCam Pro 4000";
906 type_id = 740; /* CCD sensor */
Hans de Goede51886df2011-07-03 15:52:54 -0300907 if (my_power_save == -1)
908 my_power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 break;
910 case 0x08b3:
Luc Saillard2b455db2006-04-24 10:29:46 -0300911 PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 name = "Logitech QuickCam Zoom";
913 type_id = 740; /* CCD sensor */
914 break;
915 case 0x08B4:
Luc Saillard2b455db2006-04-24 10:29:46 -0300916 PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 name = "Logitech QuickCam Zoom";
918 type_id = 740; /* CCD sensor */
Hans de Goede3b4d0ec2011-06-26 03:51:19 -0300919 if (my_power_save == -1)
920 my_power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 break;
922 case 0x08b5:
Luc Saillard2b455db2006-04-24 10:29:46 -0300923 PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 name = "Logitech QuickCam Orbit";
925 type_id = 740; /* CCD sensor */
Hans de Goede51886df2011-07-03 15:52:54 -0300926 if (my_power_save == -1)
927 my_power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 features |= FEATURE_MOTOR_PANTILT;
929 break;
930 case 0x08b6:
Jean Tourrilhesa63e1572007-03-21 16:29:16 -0300931 PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n");
932 name = "Cisco VT Camera";
933 type_id = 740; /* CCD sensor */
934 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 case 0x08b7:
Mauro Carvalho Chehab6b1ce3c2007-03-21 16:35:28 -0300936 PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n");
937 name = "Logitech ViewPort AV 100";
938 type_id = 740; /* CCD sensor */
939 break;
940 case 0x08b8: /* Where this released? */
Luc Saillard2b455db2006-04-24 10:29:46 -0300941 PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 name = "Logitech QuickCam (res.)";
943 type_id = 730; /* Assuming CMOS */
944 break;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300945 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300947 break;
948 }
949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 else if (vendor_id == 0x055d) {
951 /* I don't know the difference between the C10 and the C30;
952 I suppose the difference is the sensor, but both cameras
953 work equally well with a type_id of 675
954 */
955 switch(product_id) {
956 case 0x9000:
Luc Saillard2b455db2006-04-24 10:29:46 -0300957 PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 name = "Samsung MPC-C10";
959 type_id = 675;
960 break;
961 case 0x9001:
Luc Saillard2b455db2006-04-24 10:29:46 -0300962 PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 name = "Samsung MPC-C30";
964 type_id = 675;
965 break;
Luc Saillard2b455db2006-04-24 10:29:46 -0300966 case 0x9002:
967 PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
968 name = "Samsung MPC-C30";
969 type_id = 740;
970 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 default:
972 return -ENODEV;
973 break;
974 }
975 }
976 else if (vendor_id == 0x041e) {
977 switch(product_id) {
978 case 0x400c:
Luc Saillard2b455db2006-04-24 10:29:46 -0300979 PWC_INFO("Creative Labs Webcam 5 detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 name = "Creative Labs Webcam 5";
981 type_id = 730;
Hans de Goede51886df2011-07-03 15:52:54 -0300982 if (my_power_save == -1)
983 my_power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 break;
985 case 0x4011:
Luc Saillard2b455db2006-04-24 10:29:46 -0300986 PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 name = "Creative Labs Webcam Pro Ex";
988 type_id = 740;
989 break;
990 default:
991 return -ENODEV;
992 break;
993 }
994 }
995 else if (vendor_id == 0x04cc) {
996 switch(product_id) {
997 case 0x8116:
Luc Saillard2b455db2006-04-24 10:29:46 -0300998 PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 name = "Sotec Afina Eye";
1000 type_id = 730;
1001 break;
1002 default:
1003 return -ENODEV;
1004 break;
1005 }
1006 }
1007 else if (vendor_id == 0x06be) {
1008 switch(product_id) {
1009 case 0x8116:
1010 /* This is essentially the same cam as the Sotec Afina Eye */
Luc Saillard2b455db2006-04-24 10:29:46 -03001011 PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 name = "AME Co. Afina Eye";
1013 type_id = 750;
1014 break;
1015 default:
1016 return -ENODEV;
1017 break;
1018 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 }
1021 else if (vendor_id == 0x0d81) {
1022 switch(product_id) {
1023 case 0x1900:
Luc Saillard2b455db2006-04-24 10:29:46 -03001024 PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 name = "Visionite VCS-UC300";
1026 type_id = 740; /* CCD sensor */
1027 break;
1028 case 0x1910:
Luc Saillard2b455db2006-04-24 10:29:46 -03001029 PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 name = "Visionite VCS-UM100";
1031 type_id = 730; /* CMOS sensor */
1032 break;
1033 default:
1034 return -ENODEV;
1035 break;
1036 }
1037 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001038 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 return -ENODEV; /* Not any of the know types; but the list keeps growing. */
1040
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001041 if (my_power_save == -1)
1042 my_power_save = 0;
1043
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 memset(serial_number, 0, 30);
1045 usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
Luc Saillard2b455db2006-04-24 10:29:46 -03001046 PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
1048 if (udev->descriptor.bNumConfigurations > 1)
Luc Saillard2b455db2006-04-24 10:29:46 -03001049 PWC_WARNING("Warning: more than 1 configuration available.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
1051 /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01001052 pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001054 PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 return -ENOMEM;
1056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 pdev->type = type_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 pdev->vframes = default_fps;
1059 strcpy(pdev->serial, serial_number);
1060 pdev->features = features;
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001061 if (vendor_id == 0x046D && product_id == 0x08B5) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 /* Logitech QuickCam Orbit
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001063 The ranges have been determined experimentally; they may differ from cam to cam.
1064 Also, the exact ranges left-right and up-down are different for my cam
1065 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 pdev->angle_range.pan_min = -7000;
1067 pdev->angle_range.pan_max = 7000;
1068 pdev->angle_range.tilt_min = -3000;
1069 pdev->angle_range.tilt_max = 2500;
1070 }
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001071 pwc_construct(pdev); /* set min/max sizes correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Hans de Goedec20d78c2011-10-09 09:16:46 -03001073 mutex_init(&pdev->capt_file_lock);
Hans de Goedec1127132011-07-03 11:50:51 -03001074 mutex_init(&pdev->udevlock);
Hans de Goede885fe182011-06-06 15:33:44 -03001075 spin_lock_init(&pdev->queued_bufs_lock);
1076 INIT_LIST_HEAD(&pdev->queued_bufs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078 pdev->udev = udev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 pdev->vcompression = pwc_preferred_compression;
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001080 pdev->power_save = my_power_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Hans de Goede885fe182011-06-06 15:33:44 -03001082 /* Init videobuf2 queue structure */
1083 memset(&pdev->vb_queue, 0, sizeof(pdev->vb_queue));
1084 pdev->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1085 pdev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1086 pdev->vb_queue.drv_priv = pdev;
1087 pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf);
1088 pdev->vb_queue.ops = &pwc_vb_queue_ops;
1089 pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
1090 vb2_queue_init(&pdev->vb_queue);
1091
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001092 /* Init video_device structure */
1093 memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001094 strcpy(pdev->vdev.name, name);
Hans de Goede76ae8532011-07-19 07:14:22 -03001095 set_bit(V4L2_FL_USE_FH_PRIO, &pdev->vdev.flags);
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001096 video_set_drvdata(&pdev->vdev, pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
1098 pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
Luc Saillard2b455db2006-04-24 10:29:46 -03001099 PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101 /* Now search device_hint[] table for a match, so we can hint a node number. */
1102 for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
1103 if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
1104 (device_hint[hint].pdev == NULL)) {
1105 /* so far, so good... try serial number */
1106 if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
Trent Piepho657de3c2006-06-20 00:30:57 -03001107 /* match! */
1108 video_nr = device_hint[hint].device_node;
1109 PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
1110 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 }
1112 }
1113 }
1114
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 /* occupy slot */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001116 if (hint < MAX_DEV_HINTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 device_hint[hint].pdev = pdev;
1118
Hans de Goede6eba9352011-06-26 06:49:59 -03001119#ifdef CONFIG_USB_PWC_DEBUG
1120 /* Query sensor type */
1121 if (pwc_get_cmos_sensor(pdev, &rc) >= 0) {
1122 PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
1123 pdev->vdev.name,
1124 pwc_sensor_type_to_string(rc), rc);
1125 }
1126#endif
1127
Luc Saillard2b455db2006-04-24 10:29:46 -03001128 /* Set the leds off */
1129 pwc_set_leds(pdev, 0, 0);
Hans de Goede6eba9352011-06-26 06:49:59 -03001130
1131 /* Setup intial videomode */
1132 rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y,
Hans de Goededc8a7e82011-12-31 10:52:02 -03001133 pdev->vframes, pdev->vcompression);
Hans de Goede6eba9352011-06-26 06:49:59 -03001134 if (rc)
1135 goto err_free_mem;
1136
Hans de Goede6c9cac82011-06-26 12:52:01 -03001137 /* Register controls (and read default values from camera */
1138 rc = pwc_init_controls(pdev);
1139 if (rc) {
1140 PWC_ERROR("Failed to register v4l2 controls (%d).\n", rc);
1141 goto err_free_mem;
1142 }
1143
Hans de Goede6eba9352011-06-26 06:49:59 -03001144 /* And powerdown the camera until streaming starts */
Luc Saillard2b455db2006-04-24 10:29:46 -03001145 pwc_camera_power(pdev, 0);
1146
Hans de Goede76ae8532011-07-19 07:14:22 -03001147 /* Register the v4l2_device structure */
1148 pdev->v4l2_dev.release = pwc_video_release;
1149 rc = v4l2_device_register(&intf->dev, &pdev->v4l2_dev);
1150 if (rc) {
1151 PWC_ERROR("Failed to register v4l2-device (%d).\n", rc);
1152 goto err_free_controls;
1153 }
1154
1155 pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler;
1156 pdev->vdev.v4l2_dev = &pdev->v4l2_dev;
1157
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001158 rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
Hans Verkuil479567c2010-09-12 17:05:11 -03001159 if (rc < 0) {
1160 PWC_ERROR("Failed to register as video device (%d).\n", rc);
Hans de Goede76ae8532011-07-19 07:14:22 -03001161 goto err_unregister_v4l2_dev;
Hans Verkuil479567c2010-09-12 17:05:11 -03001162 }
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001163 PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev));
Hans Verkuil479567c2010-09-12 17:05:11 -03001164
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001165#ifdef CONFIG_USB_PWC_INPUT_EVDEV
1166 /* register webcam snapshot button input device */
1167 pdev->button_dev = input_allocate_device();
1168 if (!pdev->button_dev) {
1169 PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001170 rc = -ENOMEM;
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001171 goto err_video_unreg;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001172 }
1173
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001174 usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys));
1175 strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys));
1176
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001177 pdev->button_dev->name = "PWC snapshot button";
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001178 pdev->button_dev->phys = pdev->button_phys;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001179 usb_to_input_id(pdev->udev, &pdev->button_dev->id);
1180 pdev->button_dev->dev.parent = &pdev->udev->dev;
1181 pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY);
Lennart Poetteringbcd3e4b2009-06-11 11:19:33 -03001182 pdev->button_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001183
1184 rc = input_register_device(pdev->button_dev);
1185 if (rc) {
1186 input_free_device(pdev->button_dev);
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001187 pdev->button_dev = NULL;
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001188 goto err_video_unreg;
Nam Phạm Thànhe32a7ecc2009-01-12 02:50:17 -03001189 }
1190#endif
1191
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 return 0;
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001193
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001194err_video_unreg:
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001195 video_unregister_device(&pdev->vdev);
Hans de Goede76ae8532011-07-19 07:14:22 -03001196err_unregister_v4l2_dev:
1197 v4l2_device_unregister(&pdev->v4l2_dev);
Hans de Goede6c9cac82011-06-26 12:52:01 -03001198err_free_controls:
1199 v4l2_ctrl_handler_free(&pdev->ctrl_handler);
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001200err_free_mem:
Hans de Goede32c67ec2011-07-19 09:05:49 -03001201 if (hint < MAX_DEV_HINTS)
1202 device_hint[hint].pdev = NULL;
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001203 kfree(pdev);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001204 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205}
1206
Dmitry Torokhov89dec012009-08-14 02:22:52 -03001207/* The user yanked out the cable... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208static void usb_pwc_disconnect(struct usb_interface *intf)
1209{
Hans de Goede76ae8532011-07-19 07:14:22 -03001210 struct v4l2_device *v = usb_get_intfdata(intf);
1211 struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
Hans de Goedec1127132011-07-03 11:50:51 -03001213 mutex_lock(&pdev->udevlock);
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001214 /* No need to keep the urbs around after disconnection */
1215 pwc_isoc_cleanup(pdev);
Hans de Goedeb824bb42011-06-25 17:39:19 -03001216 pdev->udev = NULL;
Hans de Goedec1127132011-07-03 11:50:51 -03001217 mutex_unlock(&pdev->udevlock);
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001218
Hans de Goedec20d78c2011-10-09 09:16:46 -03001219 pwc_cleanup_queued_bufs(pdev);
1220
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001221 video_unregister_device(&pdev->vdev);
Hans de Goede76ae8532011-07-19 07:14:22 -03001222 v4l2_device_unregister(&pdev->v4l2_dev);
Hans de Goede9a7b2d12011-06-06 14:43:39 -03001223
1224#ifdef CONFIG_USB_PWC_INPUT_EVDEV
1225 if (pdev->button_dev)
1226 input_unregister_device(pdev->button_dev);
1227#endif
Hans de Goede76ae8532011-07-19 07:14:22 -03001228
1229 v4l2_device_put(&pdev->v4l2_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230}
1231
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001233/*
1234 * Initialization code & module stuff
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 */
1236
Luc Saillard2b455db2006-04-24 10:29:46 -03001237static int fps;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238static int compression = -1;
1239static int leds[2] = { -1, -1 };
Al Viro64a6f952007-10-14 19:35:30 +01001240static unsigned int leds_nargs;
Luc Saillard2b455db2006-04-24 10:29:46 -03001241static char *dev_hint[MAX_DEV_HINTS];
Al Viro64a6f952007-10-14 19:35:30 +01001242static unsigned int dev_hint_nargs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
Luc Saillard2b455db2006-04-24 10:29:46 -03001244module_param(fps, int, 0444);
Trent Piepho05ad3902007-01-30 23:26:01 -03001245#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001246module_param_named(trace, pwc_trace, int, 0644);
1247#endif
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001248module_param(power_save, int, 0644);
Luc Saillard2b455db2006-04-24 10:29:46 -03001249module_param(compression, int, 0444);
1250module_param_array(leds, int, &leds_nargs, 0444);
1251module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
1252
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
Andrea Odetti4315c412009-12-10 16:26:10 -03001254#ifdef CONFIG_USB_PWC_DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255MODULE_PARM_DESC(trace, "For debugging purposes");
Andrea Odetti4315c412009-12-10 16:26:10 -03001256#endif
Hans de Goede3b4d0ec2011-06-26 03:51:19 -03001257MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260MODULE_PARM_DESC(dev_hint, "Device node hints");
1261
1262MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
1263MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
1264MODULE_LICENSE("GPL");
Luc Saillard2b455db2006-04-24 10:29:46 -03001265MODULE_ALIAS("pwcx");
1266MODULE_VERSION( PWC_VERSION );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267
1268static int __init usb_pwc_init(void)
1269{
Hans de Goede6eba9352011-06-26 06:49:59 -03001270 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
Hans de Goede6eba9352011-06-26 06:49:59 -03001272#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001273 PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
1274 PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
1275 PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
1276 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 -07001277
Hans de Goede6eba9352011-06-26 06:49:59 -03001278 if (pwc_trace >= 0) {
1279 PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
1280 }
1281#endif
1282
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 if (fps) {
1284 if (fps < 4 || fps > 30) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001285 PWC_ERROR("Framerate out of bounds (4-30).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 return -EINVAL;
1287 }
1288 default_fps = fps;
Luc Saillard2b455db2006-04-24 10:29:46 -03001289 PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 }
1291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 if (compression >= 0) {
1293 if (compression > 3) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001294 PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 return -EINVAL;
1296 }
1297 pwc_preferred_compression = compression;
Luc Saillard2b455db2006-04-24 10:29:46 -03001298 PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (leds[0] >= 0)
1301 led_on = leds[0];
1302 if (leds[1] >= 0)
1303 led_off = leds[1];
1304
Steven Cole093cf722005-05-03 19:07:24 -06001305 /* Big device node whoopla. Basically, it allows you to assign a
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 device node (/dev/videoX) to a camera, based on its type
1307 & serial number. The format is [type[.serialnumber]:]node.
1308
1309 Any camera that isn't matched by these rules gets the next
1310 available free device node.
1311 */
1312 for (i = 0; i < MAX_DEV_HINTS; i++) {
1313 char *s, *colon, *dot;
1314
1315 /* This loop also initializes the array */
1316 device_hint[i].pdev = NULL;
1317 s = dev_hint[i];
1318 if (s != NULL && *s != '\0') {
1319 device_hint[i].type = -1; /* wildcard */
1320 strcpy(device_hint[i].serial_number, "*");
1321
1322 /* parse string: chop at ':' & '/' */
1323 colon = dot = s;
1324 while (*colon != '\0' && *colon != ':')
1325 colon++;
1326 while (*dot != '\0' && *dot != '.')
1327 dot++;
1328 /* Few sanity checks */
1329 if (*dot != '\0' && dot > colon) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001330 PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 return -EINVAL;
1332 }
1333
1334 if (*colon == '\0') {
1335 /* No colon */
1336 if (*dot != '\0') {
Luc Saillard2b455db2006-04-24 10:29:46 -03001337 PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 return -EINVAL;
1339 }
1340 else {
1341 /* No type or serial number specified, just a number. */
Andy Shevchenko2d8d7762009-09-24 07:58:09 -03001342 device_hint[i].device_node =
1343 simple_strtol(s, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 }
1345 }
1346 else {
1347 /* There's a colon, so we have at least a type and a device node */
Andy Shevchenko2d8d7762009-09-24 07:58:09 -03001348 device_hint[i].type =
1349 simple_strtol(s, NULL, 10);
1350 device_hint[i].device_node =
1351 simple_strtol(colon + 1, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 if (*dot != '\0') {
1353 /* There's a serial number as well */
1354 int k;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001355
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 dot++;
1357 k = 0;
1358 while (*dot != ':' && k < 29) {
1359 device_hint[i].serial_number[k++] = *dot;
1360 dot++;
1361 }
1362 device_hint[i].serial_number[k] = '\0';
1363 }
1364 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001365 PWC_TRACE("device_hint[%d]:\n", i);
1366 PWC_TRACE(" type : %d\n", device_hint[i].type);
1367 PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number);
1368 PWC_TRACE(" node : %d\n", device_hint[i].device_node);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
1370 else
1371 device_hint[i].type = 0; /* not filled */
1372 } /* ..for MAX_DEV_HINTS */
1373
Luc Saillard2b455db2006-04-24 10:29:46 -03001374 PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 return usb_register(&pwc_driver);
1376}
1377
1378static void __exit usb_pwc_exit(void)
1379{
Luc Saillard2b455db2006-04-24 10:29:46 -03001380 PWC_DEBUG_MODULE("Deregistering driver.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 usb_deregister(&pwc_driver);
Luc Saillard2b455db2006-04-24 10:29:46 -03001382 PWC_INFO("Philips webcam module removed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383}
1384
1385module_init(usb_pwc_init);
1386module_exit(usb_pwc_exit);
1387
Luc Saillard2b455db2006-04-24 10:29:46 -03001388/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */