Commit 75ee7f6d authored by Nemosoft Unv's avatar Nemosoft Unv Committed by Greg Kroah-Hartman

[PATCH] USB: PWC 8.12 driver update

Attached you will find patches that will bring the Philips Webcam driver
(PWC) up to version 8.12. The most important new feature is support for
the motorized pan & tilt feature of the new Logitech QuickCam
Orbit/Sphere, which I don't think is in the stores yet (at least it's
not on Logitech's website), but should be there soon. In addition, the
documentation in the kernel about the cams is updated.
parent 81c36114
...@@ -113,16 +113,17 @@ config USB_PWC ...@@ -113,16 +113,17 @@ config USB_PWC
webcams: webcams:
* Philips PCA645, PCA646 * Philips PCA645, PCA646
* Philips PCVC675, PCVC680, PCVC690 * Philips PCVC675, PCVC680, PCVC690
* Philips PCVC730, PCVC740, PCVC750 * Philips PCVC720/40, PCVC730, PCVC740, PCVC750
* Askey VC010 * Askey VC010
* Logitech QuickCam Pro 3000, 4000, 'Zoom' and 'Notebook' * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro'
* Samsung MPC-C10, MPC-C30 and 'Orbit'/'Sphere'
* Creative Webcam 5 * Samsung MPC-C10, MPC-C30
* SOTECT Afina Eye * Creative Webcam 5, Pro Ex
* SOTEC Afina Eye
* Visionite VCS-UC300, VCS-UM100 * Visionite VCS-UC300, VCS-UM100
The PCA635, PCVC665 and PCVC720 are not supported by this driver The PCA635, PCVC665 and PCVC720/20 are not supported by this driver
and never will be, but the 665 and 720 are supported by other and never will be, but the 665 and 720/20 are supported by other
drivers. drivers.
This driver has an optional plugin (called PWCX), which is This driver has an optional plugin (called PWCX), which is
......
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
#define GET_STATUS_CTL 0x06 #define GET_STATUS_CTL 0x06
#define SET_EP_STREAM_CTL 0x07 #define SET_EP_STREAM_CTL 0x07
#define GET_EP_STREAM_CTL 0x08 #define GET_EP_STREAM_CTL 0x08
#define SET_MPT_CTL 0x0D
#define GET_MPT_CTL 0x0E
/* Selectors for the Luminance controls [GS]ET_LUM_CTL */ /* Selectors for the Luminance controls [GS]ET_LUM_CTL */
#define AGC_MODE_FORMATTER 0x2000 #define AGC_MODE_FORMATTER 0x2000
...@@ -88,6 +90,11 @@ ...@@ -88,6 +90,11 @@
/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100
/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
#define PT_RELATIVE_CONTROL_FORMATTER 0x01
#define PT_RESET_CONTROL_FORMATTER 0x02
#define PT_STATUS_FORMATTER 0x03
static char *size2name[PSZ_MAX] = static char *size2name[PSZ_MAX] =
{ {
"subQCIF", "subQCIF",
...@@ -435,6 +442,7 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame ...@@ -435,6 +442,7 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame
ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
break; break;
case 720:
case 730: case 730:
case 740: case 740:
case 750: case 750:
...@@ -745,6 +753,7 @@ static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int v ...@@ -745,6 +753,7 @@ static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int v
buf[1] = speed >> 8; buf[1] = speed >> 8;
buf[0] = speed & 0xff; buf[0] = speed & 0xff;
break; break;
case 720:
case 730: case 730:
case 740: case 740:
case 750: case 750:
...@@ -1243,6 +1252,46 @@ static inline int pwc_get_dynamic_noise(struct pwc_device *pdev) ...@@ -1243,6 +1252,46 @@ static inline int pwc_get_dynamic_noise(struct pwc_device *pdev)
return buf; return buf;
} }
int pwc_mpt_reset(struct pwc_device *pdev, int flags)
{
unsigned char buf;
buf = flags & 0x03; // only lower two bits are currently used
return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
}
static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
{
unsigned char buf[4];
/* set new relative angle; angles are expressed in degrees * 100,
but cam as .5 degree resolution, hence devide by 200. Also
the angle must be multiplied by 64 before it's send to
the cam (??)
*/
pan = 64 * pan / 100;
tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */
buf[0] = pan & 0xFF;
buf[1] = (pan >> 8) & 0xFF;
buf[2] = tilt & 0xFF;
buf[3] = (tilt >> 8) & 0xFF;
return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
}
static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
{
int ret;
unsigned char buf[5];
ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5);
if (ret < 0)
return ret;
status->status = buf[0] & 0x7; // 3 bits are used for reporting
status->time_pan = (buf[1] << 8) + buf[2];
status->time_tilt = (buf[3] << 8) + buf[4];
return 0;
}
int pwc_get_cmos_sensor(struct pwc_device *pdev) int pwc_get_cmos_sensor(struct pwc_device *pdev)
{ {
...@@ -1512,8 +1561,128 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) ...@@ -1512,8 +1561,128 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
size->width = pdev->image.x; size->width = pdev->image.x;
size->height = pdev->image.y; size->height = pdev->image.y;
break; break;
} }
case VIDIOCPWCMPTRESET:
{
int *flags = arg;
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
ret = pwc_mpt_reset(pdev, *flags);
if (ret >= 0)
{
pdev->pan_angle = 0;
pdev->tilt_angle = 0;
}
}
else
{
ret = -ENXIO;
}
break;
}
case VIDIOCPWCMPTGRANGE:
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
memcpy(arg, &pdev->angle_range, sizeof(struct pwc_mpt_range));
}
else
{
ret = -ENXIO;
}
break;
}
case VIDIOCPWCMPTSANGLE:
{
struct pwc_mpt_angles *angles = arg;
int new_pan, new_tilt;
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
/* The camera can only set relative angles, so
do some calculations when getting an absolute angle .
*/
if (angles->absolute)
{
new_pan = angles->pan;
new_tilt = angles->tilt;
}
else
{
new_pan = pdev->pan_angle + angles->pan;
new_tilt = pdev->tilt_angle + angles->tilt;
}
/* check absolute ranges */
if (new_pan < pdev->angle_range.pan_min ||
new_pan > pdev->angle_range.pan_max ||
new_tilt < pdev->angle_range.tilt_min ||
new_tilt > pdev->angle_range.tilt_max)
{
ret = -ERANGE;
}
else
{
/* go to relative range, check again */
new_pan -= pdev->pan_angle;
new_tilt -= pdev->tilt_angle;
/* angles are specified in degrees * 100, thus the limit = 36000 */
if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
ret = -ERANGE;
}
if (ret == 0) /* no errors so far */
{
ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
if (ret >= 0)
{
pdev->pan_angle += new_pan;
pdev->tilt_angle += new_tilt;
}
if (ret == -EPIPE) /* stall -> out of range */
ret = -ERANGE;
}
}
else
{
ret = -ENXIO;
}
break;
}
case VIDIOCPWCMPTGANGLE:
{
struct pwc_mpt_angles *angles = arg;
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
angles->absolute = 1;
angles->pan = pdev->pan_angle;
angles->tilt = pdev->tilt_angle;
}
else
{
ret = -ENXIO;
}
break;
}
case VIDIOCPWCMPTSTATUS:
{
struct pwc_mpt_status *status = arg;
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
ret = pwc_mpt_get_status(pdev, status);
}
else
{
ret = -ENXIO;
}
break;
}
default: default:
ret = -ENOIOCTLCMD; ret = -ENOIOCTLCMD;
break; break;
......
...@@ -79,9 +79,9 @@ static struct usb_device_id pwc_device_table [] = { ...@@ -79,9 +79,9 @@ static struct usb_device_id pwc_device_table [] = {
{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
{ USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */ { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
{ USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom */ { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
{ USB_DEVICE(0x046D, 0x08B4) }, /* Logitech (reserved) */ { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
{ USB_DEVICE(0x046D, 0x08B5) }, /* Logitech (reserved) */ { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
{ USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
...@@ -129,6 +129,7 @@ static struct { ...@@ -129,6 +129,7 @@ static struct {
static int pwc_video_open(struct inode *inode, struct file *file); static int pwc_video_open(struct inode *inode, struct file *file);
static int pwc_video_close(struct inode *inode, struct file *file); static int pwc_video_close(struct inode *inode, struct file *file);
static int pwc_video_release(struct video_device *);
static ssize_t pwc_video_read(struct file *file, char *buf, static ssize_t pwc_video_read(struct file *file, char *buf,
size_t count, loff_t *ppos); size_t count, loff_t *ppos);
static unsigned int pwc_video_poll(struct file *file, poll_table *wait); static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
...@@ -918,21 +919,32 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev) ...@@ -918,21 +919,32 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
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)
{ {
int ret; int ret, start;
/* Stop isoc stuff */ /* Stop isoc stuff */
pwc_isoc_cleanup(pdev); pwc_isoc_cleanup(pdev);
/* Reset parameters */ /* Reset parameters */
pwc_reset_buffers(pdev); pwc_reset_buffers(pdev);
/* Try to set video mode... */ /* Try to set video mode... */
ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); start = 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) {
ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
if (!ret) /* That failed... restore old mode (we know that worked) */
if (pwc_isoc_init(pdev) < 0) start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
Info("Failed to restart ISOC transfer in pwc_try_video_mode.\n"); if (start) {
Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
}
}
if (start == 0)
{
if (pwc_isoc_init(pdev) < 0)
{
Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
ret = -EAGAIN; /* let's try again, who knows if it works a second time */
}
}
pdev->drop_frames++; /* try to avoid garbage during switch */ pdev->drop_frames++; /* try to avoid garbage during switch */
return ret; return ret; /* Return original error code */
} }
...@@ -997,6 +1009,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) ...@@ -997,6 +1009,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
#if PWC_DEBUG #if PWC_DEBUG
Debug("Found decompressor for %d at 0x%p\n", pdev->type, pdev->decompressor); Debug("Found decompressor for %d at 0x%p\n", pdev->type, pdev->decompressor);
#endif #endif
pwc_construct(pdev); /* set min/max sizes correct */
/* So far, so good. Allocate memory. */ /* So far, so good. Allocate memory. */
i = pwc_allocate_buffers(pdev); i = pwc_allocate_buffers(pdev);
...@@ -1018,6 +1031,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) ...@@ -1018,6 +1031,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
#if PWC_DEBUG #if PWC_DEBUG
pdev->sequence = 0; pdev->sequence = 0;
#endif #endif
pwc_construct(pdev); /* set min/max sizes correct */
/* Set some defaults */ /* Set some defaults */
pdev->vsnapshot = 0; pdev->vsnapshot = 0;
...@@ -1104,6 +1118,12 @@ static int pwc_video_close(struct inode *inode, struct file *file) ...@@ -1104,6 +1118,12 @@ static int pwc_video_close(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int pwc_video_release(struct video_device *vfd)
{
Trace(TRACE_OPEN, "pwc_video_release() called. Now what?\n");
}
/* /*
* FIXME: what about two parallel reads ???? * FIXME: what about two parallel reads ????
* ANSWER: Not supported. You can't open the device more than once, * ANSWER: Not supported. You can't open the device more than once,
...@@ -1124,7 +1144,7 @@ static ssize_t pwc_video_read(struct file *file, char *buf, ...@@ -1124,7 +1144,7 @@ static ssize_t pwc_video_read(struct file *file, char *buf,
int noblock = file->f_flags & O_NONBLOCK; int noblock = file->f_flags & O_NONBLOCK;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
Trace(TRACE_READ, "video_read(0x%p, %p, %Zd) called.\n", vdev, buf, count); Trace(TRACE_READ, "video_read(0x%p, %p, %d) called.\n", vdev, buf, count);
if (vdev == NULL) if (vdev == NULL)
return -EFAULT; return -EFAULT;
pdev = vdev->priv; pdev = vdev->priv;
...@@ -1568,6 +1588,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1568,6 +1588,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
struct pwc_device *pdev = NULL; struct pwc_device *pdev = NULL;
int vendor_id, product_id, type_id; int vendor_id, product_id, type_id;
int i, hint; int i, hint;
int features = 0;
int video_nr = -1; /* default: use next available device */ int video_nr = -1; /* default: use next available device */
char serial_number[30], *name; char serial_number[30], *name;
...@@ -1677,8 +1698,17 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1677,8 +1698,17 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
name = "Logitech QuickCam Zoom"; name = "Logitech QuickCam Zoom";
type_id = 740; /* CCD sensor */ type_id = 740; /* CCD sensor */
break; break;
case 0x08b4: case 0x08B4:
Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
name = "Logitech QuickCam Zoom";
type_id = 740; /* CCD sensor */
break;
case 0x08b5: case 0x08b5:
Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
name = "Logitech QuickCam Orbit";
type_id = 740; /* CCD sensor */
features |= FEATURE_MOTOR_PANTILT;
break;
case 0x08b6: case 0x08b6:
case 0x08b7: case 0x08b7:
case 0x08b8: case 0x08b8:
...@@ -1776,9 +1806,22 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1776,9 +1806,22 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
} }
memset(pdev, 0, sizeof(struct pwc_device)); memset(pdev, 0, sizeof(struct pwc_device));
pdev->type = type_id; pdev->type = type_id;
pwc_construct(pdev);
pdev->vsize = default_size; pdev->vsize = default_size;
pdev->vframes = default_fps; pdev->vframes = default_fps;
pdev->features = features;
if (vendor_id == 0x046D && product_id == 0x08B5)
{
/* Logitech QuickCam Orbit
The ranges have been determined experimentally; they may differ from cam to cam.
Also, the exact ranges left-right and up-down are different for my cam
*/
pdev->angle_range.pan_min = -7000;
pdev->angle_range.pan_max = 7000;
pdev->angle_range.tilt_min = -3000;
pdev->angle_range.tilt_max = 2500;
pdev->angle_range.zoom_min = -1;
pdev->angle_range.zoom_max = -1;
}
init_MUTEX(&pdev->modlock); init_MUTEX(&pdev->modlock);
pdev->ptrlock = SPIN_LOCK_UNLOCKED; pdev->ptrlock = SPIN_LOCK_UNLOCKED;
...@@ -1791,7 +1834,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1791,7 +1834,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
strcpy(pdev->vdev.name, name); strcpy(pdev->vdev.name, name);
pdev->vdev.owner = THIS_MODULE; pdev->vdev.owner = THIS_MODULE;
pdev->vdev.priv = pdev; pdev->vdev.priv = pdev;
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);
...@@ -1809,6 +1852,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1809,6 +1852,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
} }
} }
pdev->vdev.release = pwc_video_release;
i = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); i = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
if (i < 0) { if (i < 0) {
Err("Failed to register as video device (%d).\n", i); Err("Failed to register as video device (%d).\n", i);
...@@ -1818,6 +1862,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1818,6 +1862,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else { else {
Info("Registered as /dev/video%d.\n", pdev->vdev.minor & 0x3F); Info("Registered as /dev/video%d.\n", pdev->vdev.minor & 0x3F);
} }
/* occupy slot */ /* occupy slot */
if (hint < MAX_DEV_HINTS) if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = pdev; device_hint[hint].pdev = pdev;
......
...@@ -112,6 +112,43 @@ struct pwc_imagesize ...@@ -112,6 +112,43 @@ struct pwc_imagesize
int height; int height;
}; };
/* Defines and structures for Motorized Pan & Tilt */
#define PWC_MPT_PAN 0x01
#define PWC_MPT_TILT 0x02
#define PWC_MPT_TIMEOUT 0x04 /* for status */
/* Set angles; when absolute = 1, the angle is absolute and the
driver calculates the relative offset for you. This can only
be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
absolute angles.
*/
struct pwc_mpt_angles
{
int absolute; /* write-only */
int pan; /* degrees * 100 */
int tilt; /* degress * 100 */
int zoom; /* N/A, set to -1 */
};
/* Range of angles of the camera, both horizontally and vertically.
The zoom is not used, maybe in the future...
*/
struct pwc_mpt_range
{
int pan_min, pan_max; /* degrees * 100 */
int tilt_min, tilt_max;
int zoom_min, zoom_max; /* -1, -1 */
};
struct pwc_mpt_status
{
int status;
int time_pan;
int time_tilt;
};
/* Restore user settings */ /* Restore user settings */
#define VIDIOCPWCRUSER _IO('v', 192) #define VIDIOCPWCRUSER _IO('v', 192)
/* Save user settings */ /* Save user settings */
...@@ -181,5 +218,12 @@ struct pwc_imagesize ...@@ -181,5 +218,12 @@ struct pwc_imagesize
/* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) #define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize)
/* Motorized pan & tilt functions */
#define VIDIOCPWCMPTRESET _IOW('v', 211, int)
#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range)
#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles)
#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles)
#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status)
#endif #endif
...@@ -52,7 +52,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height) ...@@ -52,7 +52,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
return find; return find;
} }
/* initialize variables depending on type */ /* initialize variables depending on type and decompressor*/
void pwc_construct(struct pwc_device *pdev) void pwc_construct(struct pwc_device *pdev)
{ {
switch(pdev->type) { switch(pdev->type) {
...@@ -73,9 +73,17 @@ void pwc_construct(struct pwc_device *pdev) ...@@ -73,9 +73,17 @@ void pwc_construct(struct pwc_device *pdev)
case 690: case 690:
pdev->view_min.x = 128; pdev->view_min.x = 128;
pdev->view_min.y = 96; pdev->view_min.y = 96;
pdev->view_max.x = 640; /* Anthill bug #38: PWC always reports max size, even without PWCX */
pdev->view_max.y = 480; if (pdev->decompressor != NULL) {
pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; pdev->view_max.x = 640;
pdev->view_max.y = 480;
pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
}
else {
pdev->view_max.x = 352;
pdev->view_max.y = 288;
pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF;
}
pdev->vcinterface = 3; pdev->vcinterface = 3;
pdev->vendpoint = 4; pdev->vendpoint = 4;
pdev->frame_header_size = 0; pdev->frame_header_size = 0;
...@@ -87,9 +95,18 @@ void pwc_construct(struct pwc_device *pdev) ...@@ -87,9 +95,18 @@ void pwc_construct(struct pwc_device *pdev)
case 750: case 750:
pdev->view_min.x = 160; pdev->view_min.x = 160;
pdev->view_min.y = 120; pdev->view_min.y = 120;
pdev->view_max.x = 640; /* Anthill bug #38: PWC always reports max size, even without PWCX */
pdev->view_max.y = 480; if (pdev->decompressor != NULL) {
pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; pdev->view_max.x = 640;
pdev->view_max.y = 480;
pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
}
else {
/* Tell CIF, even though SIF really is the maximum, but some tools really need CIF */
pdev->view_max.x = 352;
pdev->view_max.y = 288;
pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF;
}
pdev->vcinterface = 3; pdev->vcinterface = 3;
pdev->vendpoint = 5; pdev->vendpoint = 5;
pdev->frame_header_size = TOUCAM_HEADER_SIZE; pdev->frame_header_size = TOUCAM_HEADER_SIZE;
......
...@@ -18,17 +18,21 @@ ...@@ -18,17 +18,21 @@
#ifndef PWC_H #ifndef PWC_H
#define PWC_H #define PWC_H
#include <linux/version.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb.h> #include <linux/smp_lock.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/videodev.h> #include <linux/videodev.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/smp_lock.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/errno.h> #include <asm/errno.h>
#include "pwc-ioctl.h"
/* Defines and structures for the Philips webcam */ /* Defines and structures for the Philips webcam */
/* Used for checking memory corruption/pointer validation */ /* Used for checking memory corruption/pointer validation */
#define PWC_MAGIC 0x89DC10ABUL #define PWC_MAGIC 0x89DC10ABUL
...@@ -58,10 +62,12 @@ ...@@ -58,10 +62,12 @@
#define TOUCAM_HEADER_SIZE 8 #define TOUCAM_HEADER_SIZE 8
#define TOUCAM_TRAILER_SIZE 4 #define TOUCAM_TRAILER_SIZE 4
#define FEATURE_MOTOR_PANTILT 0x0001
/* Version block */ /* Version block */
#define PWC_MAJOR 8 #define PWC_MAJOR 8
#define PWC_MINOR 11 #define PWC_MINOR 12
#define PWC_VERSION "8.11" #define PWC_VERSION "8.12"
#define PWC_NAME "pwc" #define PWC_NAME "pwc"
/* Turn certain features on/off */ /* Turn certain features on/off */
...@@ -119,8 +125,9 @@ struct pwc_device ...@@ -119,8 +125,9 @@ struct pwc_device
/* Pointer to our usb_device */ /* Pointer to our usb_device */
struct usb_device *udev; struct usb_device *udev;
int type; /* type of cam (645, 646, 675, 680, 690) */ int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
int release; /* release number */ int release; /* release number */
int features; /* feature bits */
int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */
int usb_init; /* set when the cam has been initialized over USB */ int usb_init; /* set when the cam has been initialized over USB */
...@@ -194,6 +201,11 @@ struct pwc_device ...@@ -194,6 +201,11 @@ struct pwc_device
struct semaphore modlock; /* to prevent races in video_open(), etc */ struct semaphore modlock; /* to prevent races in video_open(), etc */
spinlock_t ptrlock; /* for manipulating the buffer pointers */ spinlock_t ptrlock; /* for manipulating the buffer pointers */
/*** motorized pan/tilt feature */
struct pwc_mpt_range angle_range;
int pan_angle; /* in degrees * 100 */
int tilt_angle; /* absolute angle; 0,0 is home position */
/*** Misc. data ***/ /*** Misc. data ***/
wait_queue_head_t frameq; /* When waiting for a frame to finish... */ wait_queue_head_t frameq; /* When waiting for a frame to finish... */
#if PWC_INT_PIPE #if PWC_INT_PIPE
......
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