Commit 51c57aab authored by Nemosoft Unv's avatar Nemosoft Unv Committed by Greg Kroah-Hartman

[PATCH] [PATCH] PWC 8.9

After a little absence, here's a patch to bring the Philips Webcam driver up
to version 8.9 (skipping 8.8 which has been available as a download on my
website for a while).

This patch is against 2.5.49, and includes some of the following:
* New USB IDs for Logitech and Visionite webcams.
* Better URB link/unlink sequence when opening/closing device
  and switching resolutions.
* Adding probe for CCD/CMOS sensor type.
* Removed remnants of YUV420 palette stuff.

Also updated the description in 'Kconfig'.
parent 0f4fe770
...@@ -120,15 +120,26 @@ config USB_PWC ...@@ -120,15 +120,26 @@ config USB_PWC
tristate "USB Philips Cameras" tristate "USB Philips Cameras"
depends on USB && VIDEO_DEV depends on USB && VIDEO_DEV
---help--- ---help---
Say Y or M here if you want to use one of these Philips USB webcams: Say Y or M here if you want to use one of these Philips & OEM
PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or webcams:
the Askey VC010. The PCA635, PCVC665 and PCVC720 are not supported * Philips PCA645, PCA646
by this driver and never will be. * Philips PCVC675, PCVC680, PCVC690
* Philips PCVC730, PCVC740, PCVC750
This driver has an optional plugin, which is distributed as a binary * Askey VC010
module only. It contains code that allow you to use higher * Logitech QuickCam Pro 3000, 4000, 'Zoom' and 'Notebook'
resolutions and framerates but may not be distributed as source. * Samsung MPC-C10, MPC-C30
But even without this plugin you can these cams for most * Creative Webcam 5
* SOTECT Afina Eye
* Visionite VCS-UC300, VCS-UM100
The PCA635, PCVC665 and PCVC720 are not supported by this driver
and never will be, but the 665 and 720 are supported by other
drivers.
This driver has an optional plugin (called PWCX), which is
distributed as a binary module only. It contains code that allow you
to use higher resolutions and framerates but may not be distributed
as source. But even without this plugin you can these cams for most
applications. applications.
See <file:Documentation/usb/philips.txt> for more information and See <file:Documentation/usb/philips.txt> for more information and
......
...@@ -256,8 +256,10 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra ...@@ -256,8 +256,10 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra
memcpy(buf, pEntry->mode, 3); memcpy(buf, pEntry->mode, 3);
ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
if (ret < 0) if (ret < 0) {
Debug("Failed to send video command... %d\n", ret);
return ret; return ret;
}
if (pEntry->compressed && pdev->decompressor != NULL) if (pEntry->compressed && pdev->decompressor != NULL)
pdev->decompressor->init(pdev->release, buf, pdev->decompress_data); pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
...@@ -1103,12 +1105,7 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) ...@@ -1103,12 +1105,7 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
buf[0] = on_value; buf[0] = on_value;
buf[1] = off_value; buf[1] = off_value;
return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
SET_STATUS_CTL,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
LED_FORMATTER,
pdev->vcinterface,
&buf, 2, HZ / 2);
} }
int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
...@@ -1122,13 +1119,7 @@ int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) ...@@ -1122,13 +1119,7 @@ int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
return 0; return 0;
} }
ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
GET_STATUS_CTL,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
LED_FORMATTER,
pdev->vcinterface,
&buf, 2, HZ / 2);
if (ret < 0) if (ret < 0)
return ret; return ret;
*on_value = buf[0] * 100; *on_value = buf[0] * 100;
...@@ -1279,7 +1270,6 @@ static inline int pwc_get_dynamic_noise(struct pwc_device *pdev) ...@@ -1279,7 +1270,6 @@ static inline int pwc_get_dynamic_noise(struct pwc_device *pdev)
ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
if (ret < 0) if (ret < 0)
return ret; return ret;
//Debug("pwc_get_dynamic_noise = %d\n", buf);
return buf; return buf;
} }
...@@ -1363,12 +1353,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) ...@@ -1363,12 +1353,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
case VIDIOCPWCPROBE: case VIDIOCPWCPROBE:
{ {
struct pwc_probe probe; struct pwc_probe *probe = arg;
strcpy(probe.name, pdev->vdev->name); strcpy(probe->name, pdev->vdev->name);
probe.type = pdev->type; probe->type = pdev->type;
if (copy_to_user(arg, &probe, sizeof(probe)))
ret = -EFAULT;
break; break;
} }
......
/* Linux driver for Philips webcam /* Linux driver for Philips webcam
USB and Video4Linux interface part. 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 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 it under the terms of the GNU General Public License as published by
...@@ -42,32 +42,31 @@ ...@@ -42,32 +42,31 @@
- Alistar Moire: QuickCam 3000 Pro device/product ID - Alistar Moire: QuickCam 3000 Pro device/product ID
- Tony Hoyle: Creative Labs Webcam 5 device/product ID - Tony Hoyle: Creative Labs Webcam 5 device/product ID
- Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged - 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/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/wrapper.h> #include <linux/wrapper.h>
#include <linux/mm.h>
#include <asm/io.h> #include <asm/io.h>
#include "pwc.h" #include "pwc.h"
#include "pwc-ioctl.h" #include "pwc-ioctl.h"
#include "pwc-uncompress.h" #include "pwc-uncompress.h"
#if !defined(MAP_NR)
#define MAP_NR(a) virt_to_page(a)
#endif
/* Function prototypes and driver templates */ /* Function prototypes and driver templates */
/* hotplug device table support */ /* hotplug device table support */
static struct usb_device_id pwc_device_table [] = { 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, 0x0303) },
{ USB_DEVICE(0x0471, 0x0304) }, { USB_DEVICE(0x0471, 0x0304) },
{ USB_DEVICE(0x0471, 0x0307) }, { USB_DEVICE(0x0471, 0x0307) },
...@@ -76,12 +75,17 @@ static struct usb_device_id pwc_device_table [] = { ...@@ -76,12 +75,17 @@ static struct usb_device_id pwc_device_table [] = {
{ USB_DEVICE(0x0471, 0x0310) }, { USB_DEVICE(0x0471, 0x0310) },
{ USB_DEVICE(0x0471, 0x0311) }, { USB_DEVICE(0x0471, 0x0311) },
{ USB_DEVICE(0x0471, 0x0312) }, { USB_DEVICE(0x0471, 0x0312) },
{ USB_DEVICE(0x069A, 0x0001) }, { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
{ USB_DEVICE(0x046D, 0x08b0) }, { USB_DEVICE(0x046D, 0x08b0) }, /* Logitech QuickCam Pro 3000 */
{ USB_DEVICE(0x055D, 0x9000) }, { 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(0x055D, 0x9001) },
{ USB_DEVICE(0x041E, 0x400C) }, { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
{ USB_DEVICE(0x04CC, 0x8116) }, { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
{ USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
{ USB_DEVICE(0x0d81, 0x1900) },
{ } { }
}; };
MODULE_DEVICE_TABLE(usb, pwc_device_table); MODULE_DEVICE_TABLE(usb, pwc_device_table);
...@@ -106,7 +110,7 @@ static int default_fbufs = 3; /* Default number of frame buffers */ ...@@ -106,7 +110,7 @@ static int default_fbufs = 3; /* Default number of frame buffers */
static int default_mbufs = 2; /* Default number of mmap() buffers */ static int default_mbufs = 2; /* Default number of mmap() buffers */
int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
static int power_save = 0; 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 */ int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
static struct { static struct {
int type; int type;
...@@ -167,7 +171,7 @@ static struct video_device pwc_template = { ...@@ -167,7 +171,7 @@ static struct video_device pwc_template = {
succeeded. The pwc_device struct links back to both structures. succeeded. The pwc_device struct links back to both structures.
When a device is unplugged while in use it will be removed from the 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 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 by the file descriptor. This free-ing is then deferend until the first
opportunity. Crude, but it works. opportunity. Crude, but it works.
...@@ -240,7 +244,7 @@ static int pwc_allocate_buffers(struct pwc_device *pdev) ...@@ -240,7 +244,7 @@ static int pwc_allocate_buffers(struct pwc_device *pdev)
int i; int i;
void *kbuf; 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) if (pdev == NULL)
return -ENXIO; return -ENXIO;
...@@ -315,7 +319,9 @@ static int pwc_allocate_buffers(struct pwc_device *pdev) ...@@ -315,7 +319,9 @@ static int pwc_allocate_buffers(struct pwc_device *pdev)
for (; i < MAX_IMAGES; i++) for (; i < MAX_IMAGES; i++)
pdev->image_ptr[i] = NULL; pdev->image_ptr[i] = NULL;
Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n"); kbuf = NULL;
Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
return 0; return 0;
} }
...@@ -369,6 +375,7 @@ static void pwc_free_buffers(struct pwc_device *pdev) ...@@ -369,6 +375,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
} }
pdev->image_data = NULL; pdev->image_data = NULL;
Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
} }
...@@ -570,12 +577,10 @@ static inline void pwc_next_image(struct pwc_device *pdev) ...@@ -570,12 +577,10 @@ static inline void pwc_next_image(struct pwc_device *pdev)
pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; 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 /* 2002-10-11: YUV420P is the only palette remaining. */
a program (YUV420P being the default) */
static int pwc_set_palette(struct pwc_device *pdev, int pal) static int pwc_set_palette(struct pwc_device *pdev, int pal)
{ {
if ( pal == VIDEO_PALETTE_YUV420 if ( pal == VIDEO_PALETTE_YUV420P
|| pal == VIDEO_PALETTE_YUV420P
#if PWC_DEBUG #if PWC_DEBUG
|| pal == VIDEO_PALETTE_RAW || pal == VIDEO_PALETTE_RAW
#endif #endif
...@@ -613,7 +618,7 @@ static void pwc_isoc_handler(struct urb *urb) ...@@ -613,7 +618,7 @@ static void pwc_isoc_handler(struct urb *urb)
} }
#endif #endif
if (urb->status == -ENOENT || urb->status == -ECONNRESET) { 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; return;
} }
if (urb->status != -EINPROGRESS && urb->status != 0) { if (urb->status != -EINPROGRESS && urb->status != 0) {
...@@ -686,9 +691,22 @@ static void pwc_isoc_handler(struct urb *urb) ...@@ -686,9 +691,22 @@ static void pwc_isoc_handler(struct urb *urb)
#if PWC_DEBUG #if PWC_DEBUG
Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
#endif #endif
pdev->drop_frames = 2; pdev->drop_frames += 2;
pdev->vframes_error++; 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 /* 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 after a short frame; this condition is filtered out specifically. A 4 byte
frame doesn't make sense anyway. frame doesn't make sense anyway.
...@@ -705,7 +723,7 @@ static void pwc_isoc_handler(struct urb *urb) ...@@ -705,7 +723,7 @@ static void pwc_isoc_handler(struct urb *urb)
/* In case we were instructed to drop the frame, do so silently. /* 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). 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--; pdev->drop_frames--;
else { else {
/* Check for underflow first */ /* Check for underflow first */
...@@ -741,17 +759,23 @@ static void pwc_isoc_handler(struct urb *urb) ...@@ -741,17 +759,23 @@ static void pwc_isoc_handler(struct urb *urb)
} /* .. flen < last_packet_size */ } /* .. flen < last_packet_size */
pdev->vlast_packet_size = flen; pdev->vlast_packet_size = flen;
} /* ..status == 0 */ } /* ..status == 0 */
#ifdef PWC_DEBUG #if PWC_DEBUG
/* This is normally not interesting to the user, unless you are really debugging something */ /* This is normally not interesting to the user, unless you are really debugging something */
else else {
Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); 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 #endif
} }
if (awake) if (awake)
wake_up_interruptible(&pdev->frameq); wake_up_interruptible(&pdev->frameq);
urb->dev = pdev->udev; 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);
} }
...@@ -762,7 +786,6 @@ static int pwc_isoc_init(struct pwc_device *pdev) ...@@ -762,7 +786,6 @@ static int pwc_isoc_init(struct pwc_device *pdev)
int i, j, ret; int i, j, ret;
struct usb_host_interface *idesc; struct usb_host_interface *idesc;
int cur_alt;
if (pdev == NULL) if (pdev == NULL)
return -EFAULT; return -EFAULT;
...@@ -770,12 +793,11 @@ static int pwc_isoc_init(struct pwc_device *pdev) ...@@ -770,12 +793,11 @@ static int pwc_isoc_init(struct pwc_device *pdev)
return 0; return 0;
pdev->vsync = 0; pdev->vsync = 0;
udev = pdev->udev; udev = pdev->udev;
/* Get the current alternate interface, adjust packet size */ /* Get the current alternate interface, adjust packet size */
if (!udev->actconfig) if (!udev->actconfig)
return -EFAULT; return -EFAULT;
cur_alt = udev->actconfig->interface[0].act_altsetting; idesc = &udev->actconfig->interface[0].altsetting[pdev->valternate];
idesc = &udev->actconfig->interface[0].altsetting[cur_alt];
if (!idesc) if (!idesc)
return -EFAULT; return -EFAULT;
...@@ -792,7 +814,13 @@ static int pwc_isoc_init(struct pwc_device *pdev) ...@@ -792,7 +814,13 @@ static int pwc_isoc_init(struct pwc_device *pdev)
return -ENFILE; /* Odd error, that should be noticable */ return -ENFILE; /* Odd error, that should be noticable */
} }
/* Set alternate interface */
ret = 0; 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++) { for (i = 0; i < MAX_ISO_BUFS; i++) {
urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
if (urb == NULL) { if (urb == NULL) {
...@@ -801,6 +829,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) ...@@ -801,6 +829,7 @@ static int pwc_isoc_init(struct pwc_device *pdev)
break; break;
} }
pdev->sbuf[i].urb = urb; pdev->sbuf[i].urb = urb;
Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
} }
if (ret) { if (ret) {
/* De-allocate in reverse order */ /* De-allocate in reverse order */
...@@ -812,8 +841,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) ...@@ -812,8 +841,7 @@ static int pwc_isoc_init(struct pwc_device *pdev)
} }
return ret; return ret;
} }
/* init URB structure */ /* init URB structure */
for (i = 0; i < MAX_ISO_BUFS; i++) { for (i = 0; i < MAX_ISO_BUFS; i++) {
urb = pdev->sbuf[i].urb; urb = pdev->sbuf[i].urb;
...@@ -829,7 +857,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) ...@@ -829,7 +857,7 @@ static int pwc_isoc_init(struct pwc_device *pdev)
urb->start_frame = 0; urb->start_frame = 0;
urb->number_of_packets = ISO_FRAMES_PER_DESC; urb->number_of_packets = ISO_FRAMES_PER_DESC;
for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { 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; urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
} }
} }
...@@ -840,11 +868,12 @@ static int pwc_isoc_init(struct pwc_device *pdev) ...@@ -840,11 +868,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
if (ret) if (ret)
Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
else 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; pdev->iso_init = 1;
Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
return 0; return 0;
} }
...@@ -852,21 +881,34 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev) ...@@ -852,21 +881,34 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
{ {
int i; int i;
Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
if (pdev == NULL) if (pdev == NULL)
return; 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 */ /* 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); 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; 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) int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
...@@ -881,11 +923,10 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f ...@@ -881,11 +923,10 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, 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) */ 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); 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) if (!ret)
ret = pwc_isoc_init(pdev); if (pwc_isoc_init(pdev) < 0)
pdev->drop_frames = 1; /* try to avoid garbage during switch */ Info("Failed to restart ISOC transfer in pwc_try_video_mode.\n");
pdev->drop_frames++; /* try to avoid garbage during switch */
return ret; return ret;
} }
...@@ -921,7 +962,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) ...@@ -921,7 +962,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct pwc_device *pdev; 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; pdev = (struct pwc_device *)vdev->priv;
if (pdev == NULL) if (pdev == NULL)
...@@ -932,10 +973,30 @@ static int pwc_video_open(struct inode *inode, struct file *file) ...@@ -932,10 +973,30 @@ static int pwc_video_open(struct inode *inode, struct file *file)
down(&pdev->modlock); down(&pdev->modlock);
if (!pdev->usb_init) { if (!pdev->usb_init) {
Trace(TRACE_OPEN, "Doing first time initialization.\n"); 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; 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 */ /* Turn on camera */
...@@ -1000,12 +1061,6 @@ static int pwc_video_open(struct inode *inode, struct file *file) ...@@ -1000,12 +1061,6 @@ static int pwc_video_open(struct inode *inode, struct file *file)
return i; 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); i = pwc_isoc_init(pdev);
if (i) { if (i) {
Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
...@@ -1023,7 +1078,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) ...@@ -1023,7 +1078,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
if (pdev->decompressor != NULL) if (pdev->decompressor != NULL)
pdev->decompressor->lock(); pdev->decompressor->lock();
up(&pdev->modlock); up(&pdev->modlock);
Trace(TRACE_OPEN, "video_open() returning 0.\n"); Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
return 0; return 0;
} }
...@@ -1034,15 +1089,12 @@ static int pwc_video_close(struct inode *inode, struct file *file) ...@@ -1034,15 +1089,12 @@ static int pwc_video_close(struct inode *inode, struct file *file)
struct pwc_device *pdev; struct pwc_device *pdev;
int i; 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; pdev = (struct pwc_device *)vdev->priv;
if (pdev->vopen == 0) if (pdev->vopen == 0)
Info("video_close() called on closed device?\n"); 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 /* Dump statistics, but only if a reasonable amount of frames were
processed (to prevent endless log-entries in case of snap-shot processed (to prevent endless log-entries in case of snap-shot
programs) programs)
...@@ -1050,15 +1102,14 @@ static int pwc_video_close(struct inode *inode, struct file *file) ...@@ -1050,15 +1102,14 @@ static int pwc_video_close(struct inode *inode, struct file *file)
if (pdev->vframe_count > 20) 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); 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) { /* Free isoc URBs, stop camera */
/* Normal close: stop isochronuous and interrupt endpoint */ pwc_isoc_cleanup(pdev);
Trace(TRACE_OPEN, "Normal close(): setting interface to 0.\n");
usb_set_interface(pdev->udev, 0, 0);
if (!pdev->unplugged) {
/* Turn LEDs off */ /* Turn LEDs off */
if (pwc_set_leds(pdev, 0, 0) < 0) if (pwc_set_leds(pdev, 0, 0) < 0)
Info("Failed to set LED on/off time..\n"); Info("Failed to set LED on/off time.\n");
/* Power down camere to save energy */ /* Power down camera to save energy */
if (power_save) { if (power_save) {
i = pwc_camera_power(pdev, 0); i = pwc_camera_power(pdev, 0);
if (i < 0) if (i < 0)
...@@ -1077,6 +1128,7 @@ static int pwc_video_close(struct inode *inode, struct file *file) ...@@ -1077,6 +1128,7 @@ static int pwc_video_close(struct inode *inode, struct file *file)
if (pdev->unplugged) if (pdev->unplugged)
wake_up(&pdev->remove_ok); wake_up(&pdev->remove_ok);
file->private_data = NULL; file->private_data = NULL;
Trace(TRACE_OPEN, "<< video_close()\n");
return 0; return 0;
} }
...@@ -1514,7 +1566,6 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -1514,7 +1566,6 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
pdev = vdev->priv; pdev = vdev->priv;
/* FIXME - audit mmap during a read */
pos = (unsigned long)pdev->image_data; pos = (unsigned long)pdev->image_data;
while (size > 0) { while (size > 0) {
page = kvirt_to_pa(pos); page = kvirt_to_pa(pos);
...@@ -1547,14 +1598,14 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1547,14 +1598,14 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
int vendor_id, product_id, type_id; int vendor_id, product_id, type_id;
int i, hint; int i, hint;
int video_nr = -1; /* default: use next available device */ int video_nr = -1; /* default: use next available device */
char serial_number[30]; char serial_number[30], *name;
free_mem_leak(); free_mem_leak();
/* Check if we can handle this device */ /* Check if we can handle this device */
Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n",
udev->descriptor.idVendor, udev->descriptor.idProduct, udev->descriptor.idVendor, udev->descriptor.idProduct,
intf->altsetting->desc.bInterfaceNumber); intf->altsetting->desc.bInterfaceNumber);
/* the interfaces are probed one by one. We are only interested in the /* the interfaces are probed one by one. We are only interested in the
video interface (0) now. video interface (0) now.
...@@ -1570,38 +1621,47 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1570,38 +1621,47 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
switch (product_id) { switch (product_id) {
case 0x0302: case 0x0302:
Info("Philips PCA645VC USB webcam detected.\n"); Info("Philips PCA645VC USB webcam detected.\n");
name = "Philips 645 webcam";
type_id = 645; type_id = 645;
break; break;
case 0x0303: case 0x0303:
Info("Philips PCA646VC USB webcam detected.\n"); Info("Philips PCA646VC USB webcam detected.\n");
name = "Philips 646 webcam";
type_id = 646; type_id = 646;
break; break;
case 0x0304: case 0x0304:
Info("Askey VC010 type 2 USB webcam detected.\n"); Info("Askey VC010 type 2 USB webcam detected.\n");
name = "Askey VC010 webcam";
type_id = 646; type_id = 646;
break; break;
case 0x0307: case 0x0307:
Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
name = "Philips 675 webcam";
type_id = 675; type_id = 675;
break; break;
case 0x0308: case 0x0308:
Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
name = "Philips 680 webcam";
type_id = 680; type_id = 680;
break; break;
case 0x030C: case 0x030C:
Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
name = "Philips 690 webcam";
type_id = 690; type_id = 690;
break; break;
case 0x0310: case 0x0310:
Info("Philips PCVC730K (ToUCam Fun) USB webcam detected.\n"); Info("Philips PCVC730K (ToUCam Fun) USB webcam detected.\n");
name = "Philips 730 webcam";
type_id = 730; type_id = 730;
break; break;
case 0x0311: case 0x0311:
Info("Philips PCVC740K (ToUCam Pro) USB webcam detected.\n"); Info("Philips PCVC740K (ToUCam Pro) USB webcam detected.\n");
name = "Philips 740 webcam";
type_id = 740; type_id = 740;
break; break;
case 0x0312: case 0x0312:
Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
name = "Philips 750 webcam";
type_id = 750; type_id = 750;
break; break;
default: default:
...@@ -1613,6 +1673,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1613,6 +1673,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
switch(product_id) { switch(product_id) {
case 0x0001: case 0x0001:
Info("Askey VC010 type 1 USB webcam detected.\n"); Info("Askey VC010 type 1 USB webcam detected.\n");
name = "Askey VC010 webcam";
type_id = 645; type_id = 645;
break; break;
default: default:
...@@ -1623,9 +1684,25 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1623,9 +1684,25 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x046d) { else if (vendor_id == 0x046d) {
switch(product_id) { switch(product_id) {
case 0x08b0: 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; 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: default:
return -ENODEV; return -ENODEV;
break; break;
...@@ -1639,10 +1716,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1639,10 +1716,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
switch(product_id) { switch(product_id) {
case 0x9000: case 0x9000:
Info("Samsung MPC-C10 USB webcam detected.\n"); Info("Samsung MPC-C10 USB webcam detected.\n");
name = "Samsung MPC-C10";
type_id = 675; type_id = 675;
break; break;
case 0x9001: case 0x9001:
Info("Samsung MPC-C30 USB webcam detected.\n"); Info("Samsung MPC-C30 USB webcam detected.\n");
name = "Samsung MPC-C30";
type_id = 675; type_id = 675;
break; break;
default: default:
...@@ -1654,6 +1733,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1654,6 +1733,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
switch(product_id) { switch(product_id) {
case 0x400c: case 0x400c:
Info("Creative Labs Webcam 5 detected.\n"); Info("Creative Labs Webcam 5 detected.\n");
name = "Creative Labs Webcam 5";
type_id = 730; type_id = 730;
break; break;
default: default:
...@@ -1664,7 +1744,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1664,7 +1744,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x04cc) { else if (vendor_id == 0x04cc) {
switch(product_id) { switch(product_id) {
case 0x8116: 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; type_id = 730;
break; break;
default: default:
...@@ -1672,7 +1753,25 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1672,7 +1753,25 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
break; 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); memset(serial_number, 0, 30);
usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
...@@ -1706,7 +1805,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1706,7 +1805,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
return -ENOMEM; return -ENOMEM;
} }
memcpy(vdev, &pwc_template, sizeof(pwc_template)); memcpy(vdev, &pwc_template, sizeof(pwc_template));
sprintf(vdev->name, "Philips %d webcam", pdev->type); strcpy(vdev->name, name);
SET_MODULE_OWNER(vdev); SET_MODULE_OWNER(vdev);
pdev->vdev = vdev; pdev->vdev = vdev;
vdev->priv = pdev; vdev->priv = pdev;
...@@ -1714,7 +1813,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1714,7 +1813,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->release = udev->descriptor.bcdDevice; pdev->release = udev->descriptor.bcdDevice;
Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
/* Now search device_hint[] table for a match, so we can hint a node number. */ /* Now search device_hint[] table for a match, so we can hint a node number. */
for (hint = 0; hint < MAX_DEV_HINTS; hint++) { for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
...@@ -1761,40 +1859,41 @@ static void usb_pwc_disconnect(struct usb_interface *intf) ...@@ -1761,40 +1859,41 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
dev_set_drvdata (&intf->dev, NULL); dev_set_drvdata (&intf->dev, NULL);
if (pdev == NULL) { if (pdev == NULL) {
Err("pwc_disconnect() Called without private pointer.\n"); Err("pwc_disconnect() Called without private pointer.\n");
goto out_err; goto disconnect_out;
} }
if (pdev->udev == NULL) { if (pdev->udev == NULL) {
Err("pwc_disconnect() already called for %p\n", pdev); Err("pwc_disconnect() already called for %p\n", pdev);
goto out_err; goto disconnect_out;
} }
if (pdev->udev != interface_to_usbdev(intf)) { if (pdev->udev != interface_to_usbdev(intf)) {
Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
goto out_err; goto disconnect_out;
} }
#ifdef PWC_MAGIC #ifdef PWC_MAGIC
if (pdev->magic != PWC_MAGIC) { if (pdev->magic != PWC_MAGIC) {
Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
goto out_err; goto disconnect_out;
} }
#endif #endif
pdev->unplugged = 1; pdev->unplugged = 1;
if (pdev->vdev != NULL) { if (pdev->vdev != NULL) {
video_unregister_device(pdev->vdev); Trace(TRACE_PROBE, "Unregistering video device.\n");
video_unregister_device(pdev->vdev);
if (pdev->vopen) { if (pdev->vopen) {
Info("Disconnected while device/video is open!\n"); Info("Disconnected while device/video is open!\n");
/* Wake up any processes that might be waiting for /* Wake up any processes that might be waiting for
a frame, let them return an error condition a frame, let them return an error condition
*/ */
wake_up(&pdev->frameq); wake_up(&pdev->frameq);
/* Wait until we get a 'go' from _close(). This used /* Wait until we get a 'go' from _close(). This used
to have a gigantic race condition, since we kfree() to have a gigantic race condition, since we kfree()
stuff here, but we have to wait until close() stuff here, but we have to wait until close()
is finished. is finished.
*/ */
Trace(TRACE_PROBE, "Sleeping on remove_ok.\n"); Trace(TRACE_PROBE, "Sleeping on remove_ok.\n");
add_wait_queue(&pdev->remove_ok, &wait); add_wait_queue(&pdev->remove_ok, &wait);
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
...@@ -1808,26 +1907,25 @@ static void usb_pwc_disconnect(struct usb_interface *intf) ...@@ -1808,26 +1907,25 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
} }
else { else {
/* Normal disconnect; remove from available devices */ /* Normal disconnect; remove from available devices */
Trace(TRACE_PROBE, "Unregistering video device normally.\n");
kfree(pdev->vdev); kfree(pdev->vdev);
pdev->vdev = NULL; pdev->vdev = NULL;
} }
} }
disconnect_out:
/* search device_hint[] table if we occupy a slot, by any chance */ /* search device_hint[] table if we occupy a slot, by any chance */
for (hint = 0; hint < MAX_DEV_HINTS; hint++) for (hint = 0; hint < MAX_DEV_HINTS; hint++)
if (device_hint[hint].pdev == pdev) if (device_hint[hint].pdev == pdev)
device_hint[hint].pdev = NULL; device_hint[hint].pdev = NULL;
pdev->udev = NULL; pdev->udev = NULL;
out_err:
unlock_kernel(); unlock_kernel();
kfree(pdev); kfree(pdev);
} }
/* *grunt* We have to do atoi ourselves :-( */ /* *grunt* We have to do atoi ourselves :-( */
static int pwc_atoi(char *s) static int pwc_atoi(const char *s)
{ {
int k = 0; int k = 0;
...@@ -1872,7 +1970,7 @@ MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); ...@@ -1872,7 +1970,7 @@ MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
MODULE_PARM(dev_hint, "0-10s"); MODULE_PARM(dev_hint, "0-10s");
MODULE_PARM_DESC(dev_hint, "Device node hints"); 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_AUTHOR("Nemosoft Unv. <nemosoft@smcc.demon.nl>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -1882,11 +1980,12 @@ static int __init usb_pwc_init(void) ...@@ -1882,11 +1980,12 @@ static int __init usb_pwc_init(void)
char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; 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("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) {
if (fps < 5 || fps > 30) { if (fps < 4 || fps > 30) {
Err("Framerate out of bounds (5-30).\n"); Err("Framerate out of bounds (4-30).\n");
return -EINVAL; return -EINVAL;
} }
default_fps = fps; default_fps = fps;
...@@ -1938,9 +2037,9 @@ static int __init usb_pwc_init(void) ...@@ -1938,9 +2037,9 @@ static int __init usb_pwc_init(void)
if (power_save) if (power_save)
Info("Enabling power save on open/close.\n"); Info("Enabling power save on open/close.\n");
if (leds[0] >= 0) if (leds[0] >= 0)
led_on = leds[0] / 100; led_on = leds[0];
if (leds[1] >= 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 /* Big device node whoopla. Basicly, it allows you to assign a
device node (/dev/videoX) to a camera, based on its type device node (/dev/videoX) to a camera, based on its type
...@@ -1999,7 +2098,7 @@ static int __init usb_pwc_init(void) ...@@ -1999,7 +2098,7 @@ static int __init usb_pwc_init(void)
device_hint[i].serial_number[k] = '\0'; device_hint[i].serial_number[k] = '\0';
} }
} }
#ifdef PWC_DEBUG #if PWC_DEBUG
Debug("device_hint[%d]:\n", i); Debug("device_hint[%d]:\n", i);
Debug(" type : %d\n", device_hint[i].type); Debug(" type : %d\n", device_hint[i].type);
Debug(" serial# : %s\n", device_hint[i].serial_number); Debug(" serial# : %s\n", device_hint[i].serial_number);
......
/* Linux driver for Philips webcam /* Linux driver for Philips webcam
Various miscellaneous functions and tables. Various miscellaneous functions and tables.
(C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
......
/* Linux driver for Philips webcam /* Linux driver for Philips webcam
Decompression frontend. Decompression frontend.
(C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -77,7 +77,7 @@ int pwc_decompress(struct pwc_device *pdev) ...@@ -77,7 +77,7 @@ int pwc_decompress(struct pwc_device *pdev)
{ {
struct pwc_frame_buf *fbuf; struct pwc_frame_buf *fbuf;
int n, line, col, stride; int n, line, col, stride;
void *yuv, *image, *dst; void *yuv, *image;
u16 *src; u16 *src;
u16 *dsty, *dstu, *dstv; u16 *dsty, *dstu, *dstv;
...@@ -114,19 +114,6 @@ int pwc_decompress(struct pwc_device *pdev) ...@@ -114,19 +114,6 @@ int pwc_decompress(struct pwc_device *pdev)
to get the desired output format/size. to get the desired output format/size.
*/ */
switch (pdev->vpalette) { switch (pdev->vpalette) {
case VIDEO_PALETTE_YUV420:
/* Calculate byte offsets per line in image & view */
n = (pdev->image.x * 3) / 2;
col = (pdev->view.x * 3) / 2;
/* Offset into image */
dst = image + (pdev->view.x * pdev->offset.y + pdev->offset.x) * 3 / 2;
for (line = 0; line < pdev->image.y; line++) {
memcpy(dst, yuv, n);
yuv += n;
dst += col;
}
break;
case VIDEO_PALETTE_YUV420P: case VIDEO_PALETTE_YUV420P:
/* /*
* We do some byte shuffling here to go from the * We do some byte shuffling here to go from the
...@@ -163,17 +150,20 @@ int pwc_decompress(struct pwc_device *pdev) ...@@ -163,17 +150,20 @@ int pwc_decompress(struct pwc_device *pdev)
dstu += (stride >> 1); dstu += (stride >> 1);
} }
break; break;
default:
Err("Unsupported palette!");
break;
} }
} }
else { else {
/* Compressed; the decompressor routines will write the data /* Compressed; the decompressor routines will write the data
in interlaced or planar format immediately. in planar format immediately.
*/ */
if (pdev->decompressor) if (pdev->decompressor)
pdev->decompressor->decompress( pdev->decompressor->decompress(
&pdev->image, &pdev->view, &pdev->offset, &pdev->image, &pdev->view, &pdev->offset,
yuv, image, yuv, image,
pdev->vpalette == VIDEO_PALETTE_YUV420P ? 1 : 0, 1,
pdev->decompress_data, pdev->vbandlength); pdev->decompress_data, pdev->vbandlength);
else else
return -ENXIO; /* No such device or address: missing decompressor */ return -ENXIO; /* No such device or address: missing decompressor */
......
/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) /* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
......
...@@ -60,8 +60,8 @@ ...@@ -60,8 +60,8 @@
/* Version block */ /* Version block */
#define PWC_MAJOR 8 #define PWC_MAJOR 8
#define PWC_MINOR 7 #define PWC_MINOR 9
#define PWC_VERSION "8.7" #define PWC_VERSION "8.9"
#define PWC_NAME "pwc" #define PWC_NAME "pwc"
/* Turn certain features on/off */ /* Turn certain features on/off */
...@@ -130,7 +130,7 @@ struct pwc_device ...@@ -130,7 +130,7 @@ struct pwc_device
int vcinterface; /* video control interface */ int vcinterface; /* video control interface */
int valternate; /* alternate interface needed */ int valternate; /* alternate interface needed */
int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ int vframes, vsize; /* frames-per-second & size (see PSZ_*) */
int vpalette; /* YUV, RGB24, RGB32, etc */ int vpalette; /* YUV */
int vframe_count; /* received frames */ int vframe_count; /* received frames */
int vframes_dumped; /* counter for dumped frames */ int vframes_dumped; /* counter for dumped frames */
int vframes_error; /* frames received in error */ int vframes_error; /* frames received in error */
...@@ -140,7 +140,8 @@ struct pwc_device ...@@ -140,7 +140,8 @@ struct pwc_device
int vbandlength; /* compressed band length; 0 is uncompressed */ int vbandlength; /* compressed band length; 0 is uncompressed */
char vsnapshot; /* snapshot mode */ char vsnapshot; /* snapshot mode */
char vsync; /* used by isoc handler */ char vsync; /* used by isoc handler */
char vmirror; /* for ToUCaM series */
/* The image acquisition requires 3 to 4 steps: /* The image acquisition requires 3 to 4 steps:
1. data is gathered in short packets from the USB controller 1. data is gathered in short packets from the USB controller
2. data is synchronized and packed into a frame buffer 2. data is synchronized and packed into a frame buffer
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment