/* Linux driver for Philips webcam
USB and Video4Linux interface part.
- (C) 1999-2001 Nemosoft Unv.
+ (C) 1999-2002 Nemosoft Unv.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- Alistar Moire: QuickCam 3000 Pro device/product ID
- Tony Hoyle: Creative Labs Webcam 5 device/product ID
- Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
- - Jk Fang: SOTEC device/product ID
+ - Jk Fang: SOTEC Afina Eye ID
+ - Xavier Roche: QuickCam Pro 4000 ID
+ - Jens Knudsen: QuickCam Zoom ID
+ - J. Debert: QuickCam for Notebooks ID
*/
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/mm.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/wrapper.h>
-#include <linux/mm.h>
#include <asm/io.h>
#include "pwc.h"
#include "pwc-ioctl.h"
#include "pwc-uncompress.h"
-#if !defined(MAP_NR)
-#define MAP_NR(a) virt_to_page(a)
-#endif
-
/* Function prototypes and driver templates */
/* hotplug device table support */
static struct usb_device_id pwc_device_table [] = {
- { USB_DEVICE(0x0471, 0x0302) },
+ { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
{ USB_DEVICE(0x0471, 0x0303) },
{ USB_DEVICE(0x0471, 0x0304) },
{ USB_DEVICE(0x0471, 0x0307) },
{ USB_DEVICE(0x0471, 0x0310) },
{ USB_DEVICE(0x0471, 0x0311) },
{ USB_DEVICE(0x0471, 0x0312) },
- { USB_DEVICE(0x069A, 0x0001) },
- { USB_DEVICE(0x046D, 0x08b0) },
- { USB_DEVICE(0x055D, 0x9000) },
+ { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
+ { USB_DEVICE(0x046D, 0x08b0) }, /* Logitech QuickCam Pro 3000 */
+ { USB_DEVICE(0x046D, 0x08b1) }, /* Logitech QuickCam for Notebooks */
+ { USB_DEVICE(0x046D, 0x08b2) }, /* Logitech QuickCam Pro 4000 */
+ { USB_DEVICE(0x046D, 0x08b3) }, /* Logitech QuickCam Zoom */
+ { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
{ USB_DEVICE(0x055D, 0x9001) },
- { USB_DEVICE(0x041E, 0x400C) },
- { USB_DEVICE(0x04CC, 0x8116) },
+ { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
+ { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
+ { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
+ { USB_DEVICE(0x0d81, 0x1900) },
{ }
};
MODULE_DEVICE_TABLE(usb, pwc_device_table);
static int default_mbufs = 2; /* Default number of mmap() buffers */
int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
static int power_save = 0;
-static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */
+static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
static struct {
int type;
succeeded. The pwc_device struct links back to both structures.
When a device is unplugged while in use it will be removed from the
- list of known USB devices; I also de-register as a V4L device, but
+ list of known USB devices; I also de-register it as a V4L device, but
unfortunately I can't free the memory since the struct is still in use
by the file descriptor. This free-ing is then deferend until the first
opportunity. Crude, but it works.
int i;
void *kbuf;
- Trace(TRACE_MEMORY, "Entering allocate_buffers(%p).\n", pdev);
+ Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
if (pdev == NULL)
return -ENXIO;
for (; i < MAX_IMAGES; i++)
pdev->image_ptr[i] = NULL;
- Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n");
+ kbuf = NULL;
+
+ Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
return 0;
}
rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
}
pdev->image_data = NULL;
+
Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
}
pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
}
-/* 2001-10-14: The YUV420 is still there, but you can only set it from within
- a program (YUV420P being the default) */
+/* 2002-10-11: YUV420P is the only palette remaining. */
static int pwc_set_palette(struct pwc_device *pdev, int pal)
{
- if ( pal == VIDEO_PALETTE_YUV420
- || pal == VIDEO_PALETTE_YUV420P
+ if ( pal == VIDEO_PALETTE_YUV420P
#if PWC_DEBUG
|| pal == VIDEO_PALETTE_RAW
#endif
}
#endif
if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
- Trace(TRACE_OPEN, "pwc_isoc_handler(): URB unlinked.\n");
+ Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
return;
}
if (urb->status != -EINPROGRESS && urb->status != 0) {
#if PWC_DEBUG
Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
#endif
- pdev->drop_frames = 2;
+ pdev->drop_frames += 2;
pdev->vframes_error++;
}
+ if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+ if (ptr[0] & 0x01)
+ Info("Snapshot button pressed.\n");
+ else
+ Info("Snapshot button released.\n");
+ }
+ if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+ if (ptr[0] & 0x02)
+ Info("Image is mirrored.\n");
+ else
+ Info("Image is normal.\n");
+ }
+ pdev->vmirror = ptr[0] & 0x03;
/* Sometimes the trailer of the 730 is still sent as a 4 byte packet
after a short frame; this condition is filtered out specifically. A 4 byte
frame doesn't make sense anyway.
/* In case we were instructed to drop the frame, do so silently.
The buffer pointers are not updated either (but the counters are reset below).
*/
- if (pdev->drop_frames)
+ if (pdev->drop_frames > 0)
pdev->drop_frames--;
else {
/* Check for underflow first */
} /* .. flen < last_packet_size */
pdev->vlast_packet_size = flen;
} /* ..status == 0 */
-#ifdef PWC_DEBUG
+#if PWC_DEBUG
/* This is normally not interesting to the user, unless you are really debugging something */
- else
- Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+ else {
+ static int iso_error = 0;
+ iso_error++;
+ if (iso_error < 20)
+ Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+ }
#endif
}
if (awake)
wake_up_interruptible(&pdev->frameq);
urb->dev = pdev->udev;
- usb_submit_urb(urb, GFP_ATOMIC);
+ i = usb_submit_urb(urb, GFP_ATOMIC);
+ if (i != 0)
+ Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
}
int i, j, ret;
struct usb_host_interface *idesc;
- int cur_alt;
if (pdev == NULL)
return -EFAULT;
return 0;
pdev->vsync = 0;
udev = pdev->udev;
-
+
/* Get the current alternate interface, adjust packet size */
if (!udev->actconfig)
return -EFAULT;
- cur_alt = udev->actconfig->interface[0].act_altsetting;
- idesc = &udev->actconfig->interface[0].altsetting[cur_alt];
+ idesc = &udev->actconfig->interface[0].altsetting[pdev->valternate];
if (!idesc)
return -EFAULT;
return -ENFILE; /* Odd error, that should be noticable */
}
+ /* Set alternate interface */
ret = 0;
+ Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+ ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
+ if (ret < 0)
+ return ret;
+
for (i = 0; i < MAX_ISO_BUFS; i++) {
urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
if (urb == NULL) {
break;
}
pdev->sbuf[i].urb = urb;
+ Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
}
if (ret) {
/* De-allocate in reverse order */
}
return ret;
}
-
-
+
/* init URB structure */
for (i = 0; i < MAX_ISO_BUFS; i++) {
urb = pdev->sbuf[i].urb;
urb->start_frame = 0;
urb->number_of_packets = ISO_FRAMES_PER_DESC;
for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
- urb->iso_frame_desc[j].offset = j * pdev->vmax_packet_size;
+ urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
}
}
if (ret)
Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
else
- Trace(TRACE_OPEN, "pwc_isoc_init(): URB submitted.\n");
+ Trace(TRACE_OPEN, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
}
- /* data should stream in now */
+ /* All is done... */
pdev->iso_init = 1;
+ Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
return 0;
}
{
int i;
+ Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
if (pdev == NULL)
return;
- if (!pdev->iso_init)
- return;
+
+ /* Unlinking ISOC buffers one by one */
+ for (i = 0; i < MAX_ISO_BUFS; i++) {
+ struct urb *urb;
+
+ urb = pdev->sbuf[i].urb;
+ if (urb != 0) {
+ if (pdev->iso_init) {
+ Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+ usb_unlink_urb(urb);
+ }
+ Trace(TRACE_MEMORY, "Freeing URB\n");
+ usb_free_urb(urb);
+ pdev->sbuf[i].urb = NULL;
+ }
+ }
+
/* Stop camera, but only if we are sure the camera is still there */
- if (!pdev->unplugged)
+ if (!pdev->unplugged) {
+ Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
usb_set_interface(pdev->udev, 0, 0);
- /* Unlinking ISOC buffers one by one */
- for (i = MAX_ISO_BUFS - 1; i >= 0; i--) {
- //pdev->sbuf[i].urb->next = NULL;
- usb_unlink_urb(pdev->sbuf[i].urb);
- usb_free_urb(pdev->sbuf[i].urb);
- pdev->sbuf[i].urb = NULL;
}
+
pdev->iso_init = 0;
+ Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
}
int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
if (ret) /* That failed... restore old mode (we know that worked) */
ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- else /* Set (new) alternate interface */
- ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
if (!ret)
- ret = pwc_isoc_init(pdev);
- pdev->drop_frames = 1; /* try to avoid garbage during switch */
+ if (pwc_isoc_init(pdev) < 0)
+ Info("Failed to restart ISOC transfer in pwc_try_video_mode.\n");
+ pdev->drop_frames++; /* try to avoid garbage during switch */
return ret;
}
struct video_device *vdev = video_devdata(file);
struct pwc_device *pdev;
- Trace(TRACE_OPEN, "video_open called(0x%p).\n", vdev);
+ Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
pdev = (struct pwc_device *)vdev->priv;
if (pdev == NULL)
down(&pdev->modlock);
if (!pdev->usb_init) {
Trace(TRACE_OPEN, "Doing first time initialization.\n");
- /* Reset camera */
- if (usb_set_interface(pdev->udev, 0, 0))
- Info("Failed to set alternate interface to 0.\n");
pdev->usb_init = 1;
+
+ if (pwc_trace & TRACE_OPEN) {
+ /* Query CMOS sensor type */
+ const char *sensor_type = NULL;
+
+ i = pwc_get_cmos_sensor(pdev);
+ switch(i) {
+ case -1: /* Unknown, show nothing */; break;
+ case 0x00: sensor_type = "Hyundai CMOS sensor"; break;
+ case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break;
+ case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break;
+ case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break;
+ case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break;
+ case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
+ case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break;
+ case 0x40: sensor_type = "UPA 1021 sensor"; break;
+ case 0x100: sensor_type = "VGA sensor"; break;
+ case 0x101: sensor_type = "PAL MR sensor"; break;
+ default: sensor_type = "unknown type of sensor"; break;
+ }
+ if (sensor_type != NULL)
+ Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+ }
}
/* Turn on camera */
return i;
}
- i = usb_set_interface(pdev->udev, 0, pdev->valternate);
- if (i) {
- Trace(TRACE_OPEN, "Failed to set alternate interface = %d.\n", i);
- up(&pdev->modlock);
- return -EINVAL;
- }
i = pwc_isoc_init(pdev);
if (i) {
Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
if (pdev->decompressor != NULL)
pdev->decompressor->lock();
up(&pdev->modlock);
- Trace(TRACE_OPEN, "video_open() returning 0.\n");
+ Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
return 0;
}
struct pwc_device *pdev;
int i;
- Trace(TRACE_OPEN, "video_close called(0x%p).\n", vdev);
+ Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
pdev = (struct pwc_device *)vdev->priv;
if (pdev->vopen == 0)
Info("video_close() called on closed device?\n");
- /* Free isoc URBs */
- pwc_isoc_cleanup(pdev);
-
/* Dump statistics, but only if a reasonable amount of frames were
processed (to prevent endless log-entries in case of snap-shot
programs)
if (pdev->vframe_count > 20)
Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
- if (!pdev->unplugged) {
- /* Normal close: stop isochronuous and interrupt endpoint */
- Trace(TRACE_OPEN, "Normal close(): setting interface to 0.\n");
- usb_set_interface(pdev->udev, 0, 0);
+ /* Free isoc URBs, stop camera */
+ pwc_isoc_cleanup(pdev);
+ if (!pdev->unplugged) {
/* Turn LEDs off */
if (pwc_set_leds(pdev, 0, 0) < 0)
- Info("Failed to set LED on/off time..\n");
- /* Power down camere to save energy */
+ Info("Failed to set LED on/off time.\n");
+ /* Power down camera to save energy */
if (power_save) {
i = pwc_camera_power(pdev, 0);
if (i < 0)
if (pdev->unplugged)
wake_up(&pdev->remove_ok);
file->private_data = NULL;
+ Trace(TRACE_OPEN, "<< video_close()\n");
return 0;
}
Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
pdev = vdev->priv;
- /* FIXME - audit mmap during a read */
pos = (unsigned long)pdev->image_data;
while (size > 0) {
page = kvirt_to_pa(pos);
int vendor_id, product_id, type_id;
int i, hint;
int video_nr = -1; /* default: use next available device */
- char serial_number[30];
+ char serial_number[30], *name;
free_mem_leak();
/* Check if we can handle this device */
- Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n",
- udev->descriptor.idVendor, udev->descriptor.idProduct,
- intf->altsetting->desc.bInterfaceNumber);
+ Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n",
+ udev->descriptor.idVendor, udev->descriptor.idProduct,
+ intf->altsetting->desc.bInterfaceNumber);
/* the interfaces are probed one by one. We are only interested in the
video interface (0) now.
switch (product_id) {
case 0x0302:
Info("Philips PCA645VC USB webcam detected.\n");
+ name = "Philips 645 webcam";
type_id = 645;
break;
case 0x0303:
Info("Philips PCA646VC USB webcam detected.\n");
+ name = "Philips 646 webcam";
type_id = 646;
break;
case 0x0304:
Info("Askey VC010 type 2 USB webcam detected.\n");
+ name = "Askey VC010 webcam";
type_id = 646;
break;
case 0x0307:
Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
+ name = "Philips 675 webcam";
type_id = 675;
break;
case 0x0308:
Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+ name = "Philips 680 webcam";
type_id = 680;
break;
case 0x030C:
Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+ name = "Philips 690 webcam";
type_id = 690;
break;
case 0x0310:
Info("Philips PCVC730K (ToUCam Fun) USB webcam detected.\n");
+ name = "Philips 730 webcam";
type_id = 730;
break;
case 0x0311:
Info("Philips PCVC740K (ToUCam Pro) USB webcam detected.\n");
+ name = "Philips 740 webcam";
type_id = 740;
break;
case 0x0312:
Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+ name = "Philips 750 webcam";
type_id = 750;
break;
default:
switch(product_id) {
case 0x0001:
Info("Askey VC010 type 1 USB webcam detected.\n");
+ name = "Askey VC010 webcam";
type_id = 645;
break;
default:
else if (vendor_id == 0x046d) {
switch(product_id) {
case 0x08b0:
- Info("Logitech QuickCam 3000 Pro detected.\n");
+ Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+ name = "Logitech QuickCam Pro 3000";
type_id = 730;
- break;
+ break;
+ case 0x08b1:
+ Info("Logitech QuickCam for Noteboos USB webcam detected.\n");
+ name = "Logitech QuickCam Notebook";
+ type_id = 740; /* ?? unknown sensor */
+ break;
+ case 0x08b2:
+ Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+ name = "Logitech QuickCam Pro 4000";
+ type_id = 740; /* CCD sensor */
+ break;
+ case 0x08b3:
+ Info("Logitech QuickCam Zoom USB webcam detected.\n");
+ name = "Logitech QuickCam Zoom";
+ type_id = 740; /* ?? unknown sensor */
+ break;
default:
return -ENODEV;
break;
switch(product_id) {
case 0x9000:
Info("Samsung MPC-C10 USB webcam detected.\n");
+ name = "Samsung MPC-C10";
type_id = 675;
break;
case 0x9001:
Info("Samsung MPC-C30 USB webcam detected.\n");
+ name = "Samsung MPC-C30";
type_id = 675;
break;
default:
switch(product_id) {
case 0x400c:
Info("Creative Labs Webcam 5 detected.\n");
+ name = "Creative Labs Webcam 5";
type_id = 730;
break;
default:
else if (vendor_id == 0x04cc) {
switch(product_id) {
case 0x8116:
- Info("SOTEC CMS-001 USB webcam detected.\n");
+ Info("Sotec Afina Eye USB webcam detected.\n");
+ name = "Sotec Afina Eye";
type_id = 730;
break;
default:
break;
}
}
- else return -ENODEV; /* Not Philips, Askey, Logitech, Samsung, Creative or SOTEC, for sure. */
+ else if (vendor_id == 0x0d81) {
+ switch(product_id) {
+ case 0x1900:
+ Info("Visionite VCS-UC300 USB webcam detected.\n");
+ name = "Visionite VCS-UC300";
+ type_id = 740; /* CCD sensor */
+ break;
+ case 0x1910:
+ Info("Visionite VCS-UM100 USB webcam detected.\n");
+ name = "Visionite VCS-UM100";
+ type_id = 730; /* CMOS sensor */
+ break;
+ default:
+ return -ENODEV;
+ break;
+ }
+ }
+ else
+ return -ENODEV; /* Not any of the know types; but the list keeps growing. */
memset(serial_number, 0, 30);
usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
return -ENOMEM;
}
memcpy(vdev, &pwc_template, sizeof(pwc_template));
- sprintf(vdev->name, "Philips %d webcam", pdev->type);
+ strcpy(vdev->name, name);
SET_MODULE_OWNER(vdev);
pdev->vdev = vdev;
vdev->priv = pdev;
pdev->release = udev->descriptor.bcdDevice;
Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
-
/* Now search device_hint[] table for a match, so we can hint a node number. */
for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
dev_set_drvdata (&intf->dev, NULL);
if (pdev == NULL) {
Err("pwc_disconnect() Called without private pointer.\n");
- goto out_err;
+ goto disconnect_out;
}
if (pdev->udev == NULL) {
Err("pwc_disconnect() already called for %p\n", pdev);
- goto out_err;
+ goto disconnect_out;
}
if (pdev->udev != interface_to_usbdev(intf)) {
Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
- goto out_err;
+ goto disconnect_out;
}
#ifdef PWC_MAGIC
if (pdev->magic != PWC_MAGIC) {
Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
- goto out_err;
+ goto disconnect_out;
}
-#endif
-
+#endif
+
pdev->unplugged = 1;
if (pdev->vdev != NULL) {
- video_unregister_device(pdev->vdev);
+ Trace(TRACE_PROBE, "Unregistering video device.\n");
+ video_unregister_device(pdev->vdev);
if (pdev->vopen) {
Info("Disconnected while device/video is open!\n");
-
+
/* Wake up any processes that might be waiting for
a frame, let them return an error condition
*/
wake_up(&pdev->frameq);
-
+
/* Wait until we get a 'go' from _close(). This used
to have a gigantic race condition, since we kfree()
- stuff here, but we have to wait until close()
- is finished.
+ stuff here, but we have to wait until close()
+ is finished.
*/
-
+
Trace(TRACE_PROBE, "Sleeping on remove_ok.\n");
add_wait_queue(&pdev->remove_ok, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
}
else {
/* Normal disconnect; remove from available devices */
- Trace(TRACE_PROBE, "Unregistering video device normally.\n");
kfree(pdev->vdev);
pdev->vdev = NULL;
}
}
+disconnect_out:
/* search device_hint[] table if we occupy a slot, by any chance */
for (hint = 0; hint < MAX_DEV_HINTS; hint++)
if (device_hint[hint].pdev == pdev)
device_hint[hint].pdev = NULL;
pdev->udev = NULL;
-out_err:
unlock_kernel();
kfree(pdev);
}
/* *grunt* We have to do atoi ourselves :-( */
-static int pwc_atoi(char *s)
+static int pwc_atoi(const char *s)
{
int k = 0;
MODULE_PARM(dev_hint, "0-10s");
MODULE_PARM_DESC(dev_hint, "Device node hints");
-MODULE_DESCRIPTION("Philips USB webcam driver");
+MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
MODULE_AUTHOR("Nemosoft Unv. <nemosoft@smcc.demon.nl>");
MODULE_LICENSE("GPL");
char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n");
- Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30, the Creative WebCam 5 and the SOTEC CMS-001.\n");
+ Info("Also supports the Askey VC010, various Logitech QuickCams, Samsung MPC-C10 and MPC-C30,\n");
+ Info("the Creative WebCam 5, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
if (fps) {
- if (fps < 5 || fps > 30) {
- Err("Framerate out of bounds (5-30).\n");
+ if (fps < 4 || fps > 30) {
+ Err("Framerate out of bounds (4-30).\n");
return -EINVAL;
}
default_fps = fps;
if (power_save)
Info("Enabling power save on open/close.\n");
if (leds[0] >= 0)
- led_on = leds[0] / 100;
+ led_on = leds[0];
if (leds[1] >= 0)
- led_off = leds[1] / 100;
+ led_off = leds[1];
/* Big device node whoopla. Basicly, it allows you to assign a
device node (/dev/videoX) to a camera, based on its type
device_hint[i].serial_number[k] = '\0';
}
}
-#ifdef PWC_DEBUG
+#if PWC_DEBUG
Debug("device_hint[%d]:\n", i);
Debug(" type : %d\n", device_hint[i].type);
Debug(" serial# : %s\n", device_hint[i].serial_number);