Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
304ac4a5
Commit
304ac4a5
authored
Aug 25, 2004
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
USB: rip out the whole pwc driver as the author wishes to have done.
Signed-off-by:
Greg Kroah-Hartman
<
greg@kroah.com
>
parent
0335cce0
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
0 additions
and
5367 deletions
+0
-5367
Documentation/usb/philips.txt
Documentation/usb/philips.txt
+0
-236
drivers/usb/media/Kconfig
drivers/usb/media/Kconfig
+0
-40
drivers/usb/media/Makefile
drivers/usb/media/Makefile
+0
-2
drivers/usb/media/pwc-ctrl.c
drivers/usb/media/pwc-ctrl.c
+0
-1635
drivers/usb/media/pwc-if.c
drivers/usb/media/pwc-if.c
+0
-2158
drivers/usb/media/pwc-ioctl.h
drivers/usb/media/pwc-ioctl.h
+0
-279
drivers/usb/media/pwc-misc.c
drivers/usb/media/pwc-misc.c
+0
-146
drivers/usb/media/pwc.h
drivers/usb/media/pwc.h
+0
-265
drivers/usb/media/pwc_kiara.h
drivers/usb/media/pwc_kiara.h
+0
-270
drivers/usb/media/pwc_nala.h
drivers/usb/media/pwc_nala.h
+0
-66
drivers/usb/media/pwc_timon.h
drivers/usb/media/pwc_timon.h
+0
-270
No files found.
Documentation/usb/philips.txt
deleted
100644 → 0
View file @
0335cce0
This file contains some additional information for the Philips and OEM webcams.
E-mail: webcam@smcc.demon.nl Last updated: 2004-01-19
Site: http://www.smcc.demon.nl/webcam/
As of this moment, the following cameras are supported:
* Philips PCA645
* Philips PCA646
* Philips PCVC675
* Philips PCVC680
* Philips PCVC690
* Philips PCVC720/40
* Philips PCVC730
* Philips PCVC740
* Philips PCVC750
* Askey VC010
* Creative Labs Webcam 5
* Creative Labs Webcam Pro Ex
* Logitech QuickCam 3000 Pro
* Logitech QuickCam 4000 Pro
* Logitech QuickCam Notebook Pro
* Logitech QuickCam Zoom
* Logitech QuickCam Orbit
* Logitech QuickCam Sphere
* Samsung MPC-C10
* Samsung MPC-C30
* Sotec Afina Eye
* AME CU-001
* Visionite VCS-UM100
* Visionite VCS-UC300
The main webpage for the Philips driver is at the address above. It contains
a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin
contains decompression routines that allow you to use higher image sizes and
framerates; in addition the webcam uses less bandwidth on the USB bus (handy
if you want to run more than 1 camera simultaneously). These routines fall
under a NDA, and may therefor not be distributed as source; however, its use
is completely optional.
You can build this code either into your kernel, or as a module. I recommend
the latter, since it makes troubleshooting a lot easier. The built-in
microphone is supported through the USB Audio class.
When you load the module you can set some default settings for the
camera; some programs depend on a particular image-size or -format and
don't know how to set it properly in the driver. The options are:
size
Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or
'vga', for an image size of resp. 128x96, 160x120, 176x144,
320x240, 352x288 and 640x480 (of course, only for those cameras that
support these resolutions).
fps
Specifies the desired framerate. Is an integer in the range of 4-30.
fbufs
This paramter specifies the number of internal buffers to use for storing
frames from the cam. This will help if the process that reads images from
the cam is a bit slow or momentarely busy. However, on slow machines it
only introduces lag, so choose carefully. The default is 3, which is
reasonable. You can set it between 2 and 5.
mbufs
This is an integer between 1 and 10. It will tell the module the number of
buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends.
The default is 2, which is adequate for most applications (double
buffering).
Should you experience a lot of 'Dumping frame...' messages during
grabbing with a tool that uses mmap(), you might want to increase if.
However, it doesn't really buffer images, it just gives you a bit more
slack when your program is behind. But you need a multi-threaded or
forked program to really take advantage of these buffers.
The absolute maximum is 10, but don't set it too high! Every buffer takes
up 460 KB of RAM, so unless you have a lot of memory setting this to
something more than 4 is an absolute waste. This memory is only
allocated during open(), so nothing is wasted when the camera is not in
use.
power_save
When power_save is enabled (set to 1), the module will try to shut down
the cam on close() and re-activate on open(). This will save power and
turn off the LED. Not all cameras support this though (the 645 and 646
don't have power saving at all), and some models don't work either (they
will shut down, but never wake up). Consider this experimental. By
default this option is disabled.
compression (only useful with the plugin)
With this option you can control the compression factor that the camera
uses to squeeze the image through the USB bus. You can set the
parameter between 0 and 3:
0 = prefer uncompressed images; if the requested mode is not available
in an uncompressed format, the driver will silently switch to low
compression.
1 = low compression.
2 = medium compression.
3 = high compression.
High compression takes less bandwidth of course, but it could also
introduce some unwanted artefacts. The default is 2, medium compression.
See the FAQ on the website for an overview of which modes require
compression.
The compression parameter does not apply to the 645 and 646 cameras
and OEM models derived from those (only a few). Most cams honour this
parameter.
leds
This settings takes 2 integers, that define the on/off time for the LED
(in milliseconds). One of the interesting things that you can do with
this is let the LED blink while the camera is in use. This:
leds=500,500
will blink the LED once every second. But with:
leds=0,0
the LED never goes on, making it suitable for silent surveillance.
By default the camera's LED is on solid while in use, and turned off
when the camera is not used anymore.
This parameter works only with the ToUCam range of cameras (720, 730, 740,
750) and OEMs. For other cameras this command is silently ignored, and
the LED cannot be controlled.
Finally: this parameters does not take effect UNTIL the first time you
open the camera device. Until then, the LED remains on.
dev_hint
A long standing problem with USB devices is their dynamic nature: you
never know what device a camera gets assigned; it depends on module load
order, the hub configuration, the order in which devices are plugged in,
and the phase of the moon (i.e. it can be random). With this option you
can give the driver a hint as to what video device node (/dev/videoX) it
should use with a specific camera. This is also handy if you have two
cameras of the same model.
A camera is specified by its type (the number from the camera model,
like PCA645, PCVC750VC, etc) and optionally the serial number (visible
in /proc/bus/usb/devices). A hint consists of a string with the following
format:
[type[.serialnumber]:]node
The square brackets mean that both the type and the serialnumber are
optional, but a serialnumber cannot be specified without a type (which
would be rather pointless). The serialnumber is separated from the type
by a '.'; the node number by a ':'.
This somewhat cryptic syntax is best explained by a few examples:
dev_hint=3,5 The first detected cam gets assigned
/dev/video3, the second /dev/video5. Any
other cameras will get the first free
available slot (see below).
dev_hint=645:1,680:2 The PCA645 camera will get /dev/video1,
and a PCVC680 /dev/video2.
dev_hint=645.0123:3,645.4567:0 The PCA645 camera with serialnumber
0123 goes to /dev/video3, the same
camera model with the 4567 serial
gets /dev/video0.
dev_hint=750:1,4,5,6 The PCVC750 camera will get /dev/video1, the
next 3 Philips cams will use /dev/video4
through /dev/video6.
Some points worth knowing:
- Serialnumbers are case sensitive and must be written full, including
leading zeroes (it's treated as a string).
- If a device node is already occupied, registration will fail and
the webcam is not available.
- You can have up to 64 video devices; be sure to make enough device
nodes in /dev if you want to spread the numbers (this does not apply
to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA).
- If a camera does not match any dev_hint, it will simply get assigned
the first available device node, just as it used to be.
trace
In order to better detect problems, it is now possible to turn on a
'trace' of some of the calls the module makes; it logs all items in your
kernel log at debug level.
The trace variable is a bitmask; each bit represents a certain feature.
If you want to trace something, look up the bit value(s) in the table
below, add the values together and supply that to the trace variable.
Value Value Description Default
(dec) (hex)
1 0x1 Module initialization; this will log messages On
while loading and unloading the module
2 0x2 probe() and disconnect() traces On
4 0x4 Trace open() and close() calls Off
8 0x8 read(), mmap() and associated ioctl() calls Off
16 0x10 Memory allocation of buffers, etc. Off
32 0x20 Showing underflow, overflow and Dumping frame On
messages
64 0x40 Show viewport and image sizes Off
128 0x80 PWCX debugging Off
For example, to trace the open() & read() fuctions, sum 8 + 4 = 12,
so you would supply trace=12 during insmod or modprobe. If
you want to turn the initialization and probing tracing off, set trace=0.
The default value for trace is 35 (0x23).
Example:
# modprobe pwc size=cif fps=15 power_save=1
The fbufs, mbufs and trace parameters are global and apply to all connected
cameras. Each camera has its own set of buffers.
size and fps only specify defaults when you open() the device; this is to
accommodate some tools that don't set the size. You can change these
settings after open() with the Video4Linux ioctl() calls. The default of
defaults is QCIF size at 10 fps.
The compression parameter is semiglobal; it sets the initial compression
preference for all camera's, but this parameter can be set per camera with
the VIDIOCPWCSCQUAL ioctl() call.
All parameters are optional.
drivers/usb/media/Kconfig
View file @
304ac4a5
...
...
@@ -106,46 +106,6 @@ config USB_OV511
To compile this driver as a module, choose M here: the
module will be called ov511.
config USB_PWC
tristate "USB Philips Cameras"
depends on USB && VIDEO_DEV
---help---
Say Y or M here if you want to use one of these Philips & OEM
webcams:
* Philips PCA645, PCA646
* Philips PCVC675, PCVC680, PCVC690
* Philips PCVC720/40, PCVC730, PCVC740, PCVC750
* Askey VC010
* Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro'
and 'Orbit'/'Sphere'
* Samsung MPC-C10, MPC-C30
* Creative Webcam 5, Pro Ex
* SOTEC Afina Eye
* Visionite VCS-UC300, VCS-UM100
The PCA635, PCVC665 and PCVC720/20 are not supported by this driver
and never will be, but the 665 and 720/20 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.
See <file:Documentation/usb/philips.txt> for more information and
installation instructions.
The built-in microphone is enabled by selecting USB Audio support.
This driver uses the Video For Linux API. You must say Y or M to
"Video For Linux" (under Character Devices) to use this driver.
Information on this API and pointers to "v4l" programs may be found
at <file:Documentation/video4linux/API.html>.
To compile this driver as a module, choose M here: the
module will be called pwc.
config USB_SE401
tristate "USB SE401 Camera support"
depends on USB && VIDEO_DEV
...
...
drivers/usb/media/Makefile
View file @
304ac4a5
...
...
@@ -2,7 +2,6 @@
# Makefile for USB Media drivers
#
pwc-objs
:=
pwc-if.o pwc-misc.o pwc-ctrl.o
sn9c102-objs
:=
sn9c102_core.o sn9c102_pas106b.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o sn9c102_pas202bcb.o
obj-$(CONFIG_USB_DABUSB)
+=
dabusb.o
...
...
@@ -10,7 +9,6 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_USB_IBMCAM)
+=
ibmcam.o usbvideo.o ultracam.o
obj-$(CONFIG_USB_KONICAWC)
+=
konicawc.o usbvideo.o
obj-$(CONFIG_USB_OV511)
+=
ov511.o
obj-$(CONFIG_USB_PWC)
+=
pwc.o
obj-$(CONFIG_USB_SE401)
+=
se401.o
obj-$(CONFIG_USB_SN9C102)
+=
sn9c102.o
obj-$(CONFIG_USB_STV680)
+=
stv680.o
...
...
drivers/usb/media/pwc-ctrl.c
deleted
100644 → 0
View file @
0335cce0
/* Driver for Philips webcam
Functions that send various control messages to the webcam, including
video modes.
(C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl)
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
Changes
2001/08/03 Alvarado Added methods for changing white balance and
red/green gains
*/
/* Control functions for the cam; brightness, contrast, video mode, etc. */
#ifdef __KERNEL__
#include <asm/uaccess.h>
#endif
#include <asm/errno.h>
#include <linux/version.h>
#include "pwc.h"
#include "pwc-ioctl.h"
/* Request types: video */
#define SET_LUM_CTL 0x01
#define GET_LUM_CTL 0x02
#define SET_CHROM_CTL 0x03
#define GET_CHROM_CTL 0x04
#define SET_STATUS_CTL 0x05
#define GET_STATUS_CTL 0x06
#define SET_EP_STREAM_CTL 0x07
#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 */
#define AGC_MODE_FORMATTER 0x2000
#define PRESET_AGC_FORMATTER 0x2100
#define SHUTTER_MODE_FORMATTER 0x2200
#define PRESET_SHUTTER_FORMATTER 0x2300
#define PRESET_CONTOUR_FORMATTER 0x2400
#define AUTO_CONTOUR_FORMATTER 0x2500
#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600
#define CONTRAST_FORMATTER 0x2700
#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800
#define FLICKERLESS_MODE_FORMATTER 0x2900
#define AE_CONTROL_SPEED 0x2A00
#define BRIGHTNESS_FORMATTER 0x2B00
#define GAMMA_FORMATTER 0x2C00
/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
#define WB_MODE_FORMATTER 0x1000
#define AWB_CONTROL_SPEED_FORMATTER 0x1100
#define AWB_CONTROL_DELAY_FORMATTER 0x1200
#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300
#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400
#define COLOUR_MODE_FORMATTER 0x1500
#define SATURATION_MODE_FORMATTER1 0x1600
#define SATURATION_MODE_FORMATTER2 0x1700
/* Selectors for the Status controls [GS]ET_STATUS_CTL */
#define SAVE_USER_DEFAULTS_FORMATTER 0x0200
#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300
#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400
#define READ_AGC_FORMATTER 0x0500
#define READ_SHUTTER_FORMATTER 0x0600
#define READ_RED_GAIN_FORMATTER 0x0700
#define READ_BLUE_GAIN_FORMATTER 0x0800
#define SENSOR_TYPE_FORMATTER1 0x0C00
#define READ_RAW_Y_MEAN_FORMATTER 0x3100
#define SET_POWER_SAVE_MODE_FORMATTER 0x3200
#define MIRROR_IMAGE_FORMATTER 0x3300
#define LED_FORMATTER 0x3400
#define SENSOR_TYPE_FORMATTER2 0x3700
/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
#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
]
=
{
"subQCIF"
,
"QSIF"
,
"QCIF"
,
"SIF"
,
"CIF"
,
"VGA"
,
};
/********/
/* Entries for the Nala (645/646) camera; the Nala doesn't have compression
preferences, so you either get compressed or non-compressed streams.
An alternate value of 0 means this mode is not available at all.
*/
struct
Nala_table_entry
{
char
alternate
;
/* USB alternate setting */
int
compressed
;
/* Compressed yes/no */
unsigned
char
mode
[
3
];
/* precomputed mode table */
};
static
struct
Nala_table_entry
Nala_table
[
PSZ_MAX
][
8
]
=
{
#include "pwc_nala.h"
};
/* This tables contains entries for the 675/680/690 (Timon) camera, with
4 different qualities (no compression, low, medium, high).
It lists the bandwidth requirements for said mode by its alternate interface
number. An alternate of 0 means that the mode is unavailable.
There are 6 * 4 * 4 entries:
6 different resolutions subqcif, qsif, qcif, sif, cif, vga
6 framerates: 5, 10, 15, 20, 25, 30
4 compression modi: none, low, medium, high
When an uncompressed mode is not available, the next available compressed mode
will be chosen (unless the decompressor is absent). Sometimes there are only
1 or 2 compressed modes available; in that case entries are duplicated.
*/
struct
Timon_table_entry
{
char
alternate
;
/* USB alternate interface */
unsigned
short
packetsize
;
/* Normal packet size */
unsigned
short
bandlength
;
/* Bandlength when decompressing */
unsigned
char
mode
[
13
];
/* precomputed mode settings for cam */
};
static
struct
Timon_table_entry
Timon_table
[
PSZ_MAX
][
6
][
4
]
=
{
#include "pwc_timon.h"
};
/* Entries for the Kiara (730/740/750) camera */
struct
Kiara_table_entry
{
char
alternate
;
/* USB alternate interface */
unsigned
short
packetsize
;
/* Normal packet size */
unsigned
short
bandlength
;
/* Bandlength when decompressing */
unsigned
char
mode
[
12
];
/* precomputed mode settings for cam */
};
static
struct
Kiara_table_entry
Kiara_table
[
PSZ_MAX
][
6
][
4
]
=
{
#include "pwc_kiara.h"
};
/****************************************************************************/
#define SendControlMsg(request, value, buflen) \
usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \
request, \
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
value, \
pdev->vcinterface, \
&buf, buflen, HZ / 2)
#define RecvControlMsg(request, value, buflen) \
usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \
request, \
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
value, \
pdev->vcinterface, \
&buf, buflen, HZ / 2)
#if PWC_DEBUG
void
pwc_hexdump
(
void
*
p
,
int
len
)
{
int
i
;
unsigned
char
*
s
;
char
buf
[
100
],
*
d
;
s
=
(
unsigned
char
*
)
p
;
d
=
buf
;
*
d
=
'\0'
;
Debug
(
"Doing hexdump @ %p, %d bytes.
\n
"
,
p
,
len
);
for
(
i
=
0
;
i
<
len
;
i
++
)
{
d
+=
sprintf
(
d
,
"%02X "
,
*
s
++
);
if
((
i
&
0xF
)
==
0xF
)
{
Debug
(
"%s
\n
"
,
buf
);
d
=
buf
;
*
d
=
'\0'
;
}
}
if
((
i
&
0xF
)
!=
0
)
Debug
(
"%s
\n
"
,
buf
);
}
#endif
static
inline
int
send_video_command
(
struct
usb_device
*
udev
,
int
index
,
void
*
buf
,
int
buflen
)
{
return
usb_control_msg
(
udev
,
usb_sndctrlpipe
(
udev
,
0
),
SET_EP_STREAM_CTL
,
USB_DIR_OUT
|
USB_TYPE_VENDOR
|
USB_RECIP_DEVICE
,
VIDEO_OUTPUT_CONTROL_FORMATTER
,
index
,
buf
,
buflen
,
HZ
);
}
static
inline
int
set_video_mode_Nala
(
struct
pwc_device
*
pdev
,
int
size
,
int
frames
)
{
unsigned
char
buf
[
3
];
int
ret
,
fps
;
struct
Nala_table_entry
*
pEntry
;
int
frames2frames
[
31
]
=
{
/* closest match of framerate */
0
,
0
,
0
,
0
,
4
,
/* 0-4 */
5
,
5
,
7
,
7
,
10
,
/* 5-9 */
10
,
10
,
12
,
12
,
15
,
/* 10-14 */
15
,
15
,
15
,
20
,
20
,
/* 15-19 */
20
,
20
,
20
,
24
,
24
,
/* 20-24 */
24
,
24
,
24
,
24
,
24
,
/* 25-29 */
24
/* 30 */
};
int
frames2table
[
31
]
=
{
0
,
0
,
0
,
0
,
0
,
/* 0-4 */
1
,
1
,
1
,
2
,
2
,
/* 5-9 */
3
,
3
,
4
,
4
,
4
,
/* 10-14 */
5
,
5
,
5
,
5
,
5
,
/* 15-19 */
6
,
6
,
6
,
6
,
7
,
/* 20-24 */
7
,
7
,
7
,
7
,
7
,
/* 25-29 */
7
/* 30 */
};
if
(
size
<
0
||
size
>
PSZ_CIF
||
frames
<
4
||
frames
>
25
)
return
-
EINVAL
;
frames
=
frames2frames
[
frames
];
fps
=
frames2table
[
frames
];
pEntry
=
&
Nala_table
[
size
][
fps
];
if
(
pEntry
->
alternate
==
0
)
return
-
EINVAL
;
if
(
pEntry
->
compressed
&&
pdev
->
decompressor
==
NULL
)
return
-
ENOENT
;
/* Not supported. */
memcpy
(
buf
,
pEntry
->
mode
,
3
);
ret
=
send_video_command
(
pdev
->
udev
,
pdev
->
vendpoint
,
buf
,
3
);
if
(
ret
<
0
)
{
Debug
(
"Failed to send video command... %d
\n
"
,
ret
);
return
ret
;
}
pdev
->
cmd_len
=
3
;
memcpy
(
pdev
->
cmd_buf
,
buf
,
3
);
/* Set various parameters */
pdev
->
vframes
=
frames
;
pdev
->
vsize
=
size
;
pdev
->
valternate
=
pEntry
->
alternate
;
pdev
->
image
=
pwc_image_sizes
[
size
];
pdev
->
frame_size
=
(
pdev
->
image
.
x
*
pdev
->
image
.
y
*
3
)
/
2
;
if
(
pEntry
->
compressed
)
{
if
(
pdev
->
release
<
5
)
{
/* 4 fold compression */
pdev
->
vbandlength
=
528
;
pdev
->
frame_size
/=
4
;
}
else
{
pdev
->
vbandlength
=
704
;
pdev
->
frame_size
/=
3
;
}
}
else
pdev
->
vbandlength
=
0
;
return
0
;
}
static
inline
int
set_video_mode_Timon
(
struct
pwc_device
*
pdev
,
int
size
,
int
frames
,
int
compression
,
int
snapshot
)
{
unsigned
char
buf
[
13
];
struct
Timon_table_entry
*
pChoose
;
int
ret
,
fps
;
if
(
size
>=
PSZ_MAX
||
frames
<
5
||
frames
>
30
||
compression
<
0
||
compression
>
3
)
return
-
EINVAL
;
if
(
size
==
PSZ_VGA
&&
frames
>
15
)
return
-
EINVAL
;
fps
=
(
frames
/
5
)
-
1
;
/* Find a supported framerate with progressively higher compression ratios
if the preferred ratio is not available.
*/
pChoose
=
NULL
;
if
(
pdev
->
decompressor
==
NULL
)
{
#if PWC_DEBUG
Debug
(
"Trying to find uncompressed mode.
\n
"
);
#endif
pChoose
=
&
Timon_table
[
size
][
fps
][
0
];
}
else
{
while
(
compression
<=
3
)
{
pChoose
=
&
Timon_table
[
size
][
fps
][
compression
];
if
(
pChoose
->
alternate
!=
0
)
break
;
compression
++
;
}
}
if
(
pChoose
==
NULL
||
pChoose
->
alternate
==
0
)
return
-
ENOENT
;
/* Not supported. */
memcpy
(
buf
,
pChoose
->
mode
,
13
);
if
(
snapshot
)
buf
[
0
]
|=
0x80
;
ret
=
send_video_command
(
pdev
->
udev
,
pdev
->
vendpoint
,
buf
,
13
);
if
(
ret
<
0
)
return
ret
;
pdev
->
cmd_len
=
13
;
memcpy
(
pdev
->
cmd_buf
,
buf
,
13
);
/* Set various parameters */
pdev
->
vframes
=
frames
;
pdev
->
vsize
=
size
;
pdev
->
vsnapshot
=
snapshot
;
pdev
->
valternate
=
pChoose
->
alternate
;
pdev
->
image
=
pwc_image_sizes
[
size
];
pdev
->
vbandlength
=
pChoose
->
bandlength
;
if
(
pChoose
->
bandlength
>
0
)
pdev
->
frame_size
=
(
pChoose
->
bandlength
*
pdev
->
image
.
y
)
/
4
;
else
pdev
->
frame_size
=
(
pdev
->
image
.
x
*
pdev
->
image
.
y
*
12
)
/
8
;
return
0
;
}
static
inline
int
set_video_mode_Kiara
(
struct
pwc_device
*
pdev
,
int
size
,
int
frames
,
int
compression
,
int
snapshot
)
{
struct
Kiara_table_entry
*
pChoose
=
NULL
;
int
fps
,
ret
;
unsigned
char
buf
[
12
];
struct
Kiara_table_entry
RawEntry
=
{
6
,
773
,
1272
,
{
0xAD
,
0xF4
,
0x10
,
0x27
,
0xB6
,
0x24
,
0x96
,
0x02
,
0x30
,
0x05
,
0x03
,
0x80
}};
if
(
size
>=
PSZ_MAX
||
frames
<
5
||
frames
>
30
||
compression
<
0
||
compression
>
3
)
return
-
EINVAL
;
if
(
size
==
PSZ_VGA
&&
frames
>
15
)
return
-
EINVAL
;
fps
=
(
frames
/
5
)
-
1
;
/* special case: VGA @ 5 fps and snapshot is raw bayer mode */
if
(
size
==
PSZ_VGA
&&
frames
==
5
&&
snapshot
)
{
/* Only available in case the raw palette is selected or
we have the decompressor available. This mode is
only available in compressed form
*/
if
(
pdev
->
vpalette
==
VIDEO_PALETTE_RAW
||
pdev
->
decompressor
!=
NULL
)
{
Info
(
"Choosing VGA/5 BAYER mode (%d).
\n
"
,
pdev
->
vpalette
);
pChoose
=
&
RawEntry
;
}
else
{
Info
(
"VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.
\n
"
);
}
}
else
{
/* Find a supported framerate with progressively higher compression ratios
if the preferred ratio is not available.
Skip this step when using RAW modes.
*/
if
(
pdev
->
decompressor
==
NULL
&&
pdev
->
vpalette
!=
VIDEO_PALETTE_RAW
)
{
#if PWC_DEBUG
Debug
(
"Trying to find uncompressed mode.
\n
"
);
#endif
pChoose
=
&
Kiara_table
[
size
][
fps
][
0
];
}
else
{
while
(
compression
<=
3
)
{
pChoose
=
&
Kiara_table
[
size
][
fps
][
compression
];
if
(
pChoose
->
alternate
!=
0
)
break
;
compression
++
;
}
}
}
if
(
pChoose
==
NULL
||
pChoose
->
alternate
==
0
)
return
-
ENOENT
;
/* Not supported. */
/* usb_control_msg won't take staticly allocated arrays as argument?? */
memcpy
(
buf
,
pChoose
->
mode
,
12
);
if
(
snapshot
)
buf
[
0
]
|=
0x80
;
/* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
ret
=
send_video_command
(
pdev
->
udev
,
4
/* pdev->vendpoint */
,
buf
,
12
);
if
(
ret
<
0
)
return
ret
;
pdev
->
cmd_len
=
12
;
memcpy
(
pdev
->
cmd_buf
,
buf
,
12
);
/* All set and go */
pdev
->
vframes
=
frames
;
pdev
->
vsize
=
size
;
pdev
->
vsnapshot
=
snapshot
;
pdev
->
valternate
=
pChoose
->
alternate
;
pdev
->
image
=
pwc_image_sizes
[
size
];
pdev
->
vbandlength
=
pChoose
->
bandlength
;
if
(
pdev
->
vbandlength
>
0
)
pdev
->
frame_size
=
(
pdev
->
vbandlength
*
pdev
->
image
.
y
)
/
4
;
else
pdev
->
frame_size
=
(
pdev
->
image
.
x
*
pdev
->
image
.
y
*
12
)
/
8
;
return
0
;
}
/**
@pdev: device structure
@width: viewport width
@height: viewport height
@frame: framerate, in fps
@compression: preferred compression ratio
@snapshot: snapshot mode or streaming
*/
int
pwc_set_video_mode
(
struct
pwc_device
*
pdev
,
int
width
,
int
height
,
int
frames
,
int
compression
,
int
snapshot
)
{
int
ret
,
size
;
Trace
(
TRACE_FLOW
,
"set_video_mode(%dx%d @ %d, palette %d).
\n
"
,
width
,
height
,
frames
,
pdev
->
vpalette
);
size
=
pwc_decode_size
(
pdev
,
width
,
height
);
if
(
size
<
0
)
{
Debug
(
"Could not find suitable size.
\n
"
);
return
-
ERANGE
;
}
Debug
(
"decode_size = %d.
\n
"
,
size
);
ret
=
-
EINVAL
;
switch
(
pdev
->
type
)
{
case
645
:
case
646
:
ret
=
set_video_mode_Nala
(
pdev
,
size
,
frames
);
break
;
case
675
:
case
680
:
case
690
:
ret
=
set_video_mode_Timon
(
pdev
,
size
,
frames
,
compression
,
snapshot
);
break
;
case
720
:
case
730
:
case
740
:
case
750
:
ret
=
set_video_mode_Kiara
(
pdev
,
size
,
frames
,
compression
,
snapshot
);
break
;
}
if
(
ret
<
0
)
{
if
(
ret
==
-
ENOENT
)
Info
(
"Video mode %s@%d fps is only supported with the decompressor module (pwcx).
\n
"
,
size2name
[
size
],
frames
);
else
{
Err
(
"Failed to set video mode %s@%d fps; return code = %d
\n
"
,
size2name
[
size
],
frames
,
ret
);
}
return
ret
;
}
pdev
->
view
.
x
=
width
;
pdev
->
view
.
y
=
height
;
pdev
->
frame_total_size
=
pdev
->
frame_size
+
pdev
->
frame_header_size
+
pdev
->
frame_trailer_size
;
pwc_set_image_buffer_size
(
pdev
);
Trace
(
TRACE_SIZE
,
"Set viewport to %dx%d, image size is %dx%d.
\n
"
,
width
,
height
,
pwc_image_sizes
[
size
].
x
,
pwc_image_sizes
[
size
].
y
);
return
0
;
}
void
pwc_set_image_buffer_size
(
struct
pwc_device
*
pdev
)
{
int
i
,
factor
=
0
,
filler
=
0
;
/* for PALETTE_YUV420P */
switch
(
pdev
->
vpalette
)
{
case
VIDEO_PALETTE_YUV420P
:
factor
=
6
;
filler
=
128
;
break
;
case
VIDEO_PALETTE_RAW
:
factor
=
6
;
/* can be uncompressed YUV420P */
filler
=
0
;
break
;
}
/* Set sizes in bytes */
pdev
->
image
.
size
=
pdev
->
image
.
x
*
pdev
->
image
.
y
*
factor
/
4
;
pdev
->
view
.
size
=
pdev
->
view
.
x
*
pdev
->
view
.
y
*
factor
/
4
;
/* Align offset, or you'll get some very weird results in
YUV420 mode... x must be multiple of 4 (to get the Y's in
place), and y even (or you'll mixup U & V). This is less of a
problem for YUV420P.
*/
pdev
->
offset
.
x
=
((
pdev
->
view
.
x
-
pdev
->
image
.
x
)
/
2
)
&
0xFFFC
;
pdev
->
offset
.
y
=
((
pdev
->
view
.
y
-
pdev
->
image
.
y
)
/
2
)
&
0xFFFE
;
/* Fill buffers with gray or black */
for
(
i
=
0
;
i
<
MAX_IMAGES
;
i
++
)
{
if
(
pdev
->
image_ptr
[
i
]
!=
NULL
)
memset
(
pdev
->
image_ptr
[
i
],
filler
,
pdev
->
view
.
size
);
}
}
/* BRIGHTNESS */
int
pwc_get_brightness
(
struct
pwc_device
*
pdev
)
{
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_LUM_CTL
,
BRIGHTNESS_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
return
buf
<<
9
;
}
int
pwc_set_brightness
(
struct
pwc_device
*
pdev
,
int
value
)
{
char
buf
;
if
(
value
<
0
)
value
=
0
;
if
(
value
>
0xffff
)
value
=
0xffff
;
buf
=
(
value
>>
9
)
&
0x7f
;
return
SendControlMsg
(
SET_LUM_CTL
,
BRIGHTNESS_FORMATTER
,
1
);
}
/* CONTRAST */
int
pwc_get_contrast
(
struct
pwc_device
*
pdev
)
{
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_LUM_CTL
,
CONTRAST_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
return
buf
<<
10
;
}
int
pwc_set_contrast
(
struct
pwc_device
*
pdev
,
int
value
)
{
char
buf
;
if
(
value
<
0
)
value
=
0
;
if
(
value
>
0xffff
)
value
=
0xffff
;
buf
=
(
value
>>
10
)
&
0x3f
;
return
SendControlMsg
(
SET_LUM_CTL
,
CONTRAST_FORMATTER
,
1
);
}
/* GAMMA */
int
pwc_get_gamma
(
struct
pwc_device
*
pdev
)
{
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_LUM_CTL
,
GAMMA_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
return
buf
<<
11
;
}
int
pwc_set_gamma
(
struct
pwc_device
*
pdev
,
int
value
)
{
char
buf
;
if
(
value
<
0
)
value
=
0
;
if
(
value
>
0xffff
)
value
=
0xffff
;
buf
=
(
value
>>
11
)
&
0x1f
;
return
SendControlMsg
(
SET_LUM_CTL
,
GAMMA_FORMATTER
,
1
);
}
/* SATURATION */
int
pwc_get_saturation
(
struct
pwc_device
*
pdev
)
{
char
buf
;
int
ret
;
if
(
pdev
->
type
<
675
)
return
-
1
;
ret
=
RecvControlMsg
(
GET_CHROM_CTL
,
pdev
->
type
<
730
?
SATURATION_MODE_FORMATTER2
:
SATURATION_MODE_FORMATTER1
,
1
);
if
(
ret
<
0
)
return
ret
;
return
32768
+
buf
*
327
;
}
int
pwc_set_saturation
(
struct
pwc_device
*
pdev
,
int
value
)
{
char
buf
;
if
(
pdev
->
type
<
675
)
return
-
EINVAL
;
if
(
value
<
0
)
value
=
0
;
if
(
value
>
0xffff
)
value
=
0xffff
;
/* saturation ranges from -100 to +100 */
buf
=
(
value
-
32768
)
/
327
;
return
SendControlMsg
(
SET_CHROM_CTL
,
pdev
->
type
<
730
?
SATURATION_MODE_FORMATTER2
:
SATURATION_MODE_FORMATTER1
,
1
);
}
/* AGC */
static
inline
int
pwc_set_agc
(
struct
pwc_device
*
pdev
,
int
mode
,
int
value
)
{
char
buf
;
int
ret
;
if
(
mode
)
buf
=
0x0
;
/* auto */
else
buf
=
0xff
;
/* fixed */
ret
=
SendControlMsg
(
SET_LUM_CTL
,
AGC_MODE_FORMATTER
,
1
);
if
(
!
mode
&&
ret
>=
0
)
{
if
(
value
<
0
)
value
=
0
;
if
(
value
>
0xffff
)
value
=
0xffff
;
buf
=
(
value
>>
10
)
&
0x3F
;
ret
=
SendControlMsg
(
SET_LUM_CTL
,
PRESET_AGC_FORMATTER
,
1
);
}
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
inline
int
pwc_get_agc
(
struct
pwc_device
*
pdev
,
int
*
value
)
{
unsigned
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_LUM_CTL
,
AGC_MODE_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
if
(
buf
!=
0
)
{
/* fixed */
ret
=
RecvControlMsg
(
GET_LUM_CTL
,
PRESET_AGC_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
if
(
buf
>
0x3F
)
buf
=
0x3F
;
*
value
=
(
buf
<<
10
);
}
else
{
/* auto */
ret
=
RecvControlMsg
(
GET_STATUS_CTL
,
READ_AGC_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
/* Gah... this value ranges from 0x00 ... 0x9F */
if
(
buf
>
0x9F
)
buf
=
0x9F
;
*
value
=
-
(
48
+
buf
*
409
);
}
return
0
;
}
static
inline
int
pwc_set_shutter_speed
(
struct
pwc_device
*
pdev
,
int
mode
,
int
value
)
{
char
buf
[
2
];
int
speed
,
ret
;
if
(
mode
)
buf
[
0
]
=
0x0
;
/* auto */
else
buf
[
0
]
=
0xff
;
/* fixed */
ret
=
SendControlMsg
(
SET_LUM_CTL
,
SHUTTER_MODE_FORMATTER
,
1
);
if
(
!
mode
&&
ret
>=
0
)
{
if
(
value
<
0
)
value
=
0
;
if
(
value
>
0xffff
)
value
=
0xffff
;
switch
(
pdev
->
type
)
{
case
675
:
case
680
:
case
690
:
/* speed ranges from 0x0 to 0x290 (656) */
speed
=
(
value
/
100
);
buf
[
1
]
=
speed
>>
8
;
buf
[
0
]
=
speed
&
0xff
;
break
;
case
720
:
case
730
:
case
740
:
case
750
:
/* speed seems to range from 0x0 to 0xff */
buf
[
1
]
=
0
;
buf
[
0
]
=
value
>>
8
;
break
;
}
ret
=
SendControlMsg
(
SET_LUM_CTL
,
PRESET_SHUTTER_FORMATTER
,
2
);
}
return
ret
;
}
/* POWER */
int
pwc_camera_power
(
struct
pwc_device
*
pdev
,
int
power
)
{
char
buf
;
if
(
pdev
->
type
<
675
||
(
pdev
->
type
<
730
&&
pdev
->
release
<
6
))
return
0
;
/* Not supported by Nala or Timon < release 6 */
if
(
power
)
buf
=
0x00
;
/* active */
else
buf
=
0xFF
;
/* power save */
return
SendControlMsg
(
SET_STATUS_CTL
,
SET_POWER_SAVE_MODE_FORMATTER
,
1
);
}
/* private calls */
static
inline
int
pwc_restore_user
(
struct
pwc_device
*
pdev
)
{
char
buf
;
/* dummy */
return
SendControlMsg
(
SET_STATUS_CTL
,
RESTORE_USER_DEFAULTS_FORMATTER
,
0
);
}
static
inline
int
pwc_save_user
(
struct
pwc_device
*
pdev
)
{
char
buf
;
/* dummy */
return
SendControlMsg
(
SET_STATUS_CTL
,
SAVE_USER_DEFAULTS_FORMATTER
,
0
);
}
static
inline
int
pwc_restore_factory
(
struct
pwc_device
*
pdev
)
{
char
buf
;
/* dummy */
return
SendControlMsg
(
SET_STATUS_CTL
,
RESTORE_FACTORY_DEFAULTS_FORMATTER
,
0
);
}
/* ************************************************* */
/* Patch by Alvarado: (not in the original version */
/*
* the camera recognizes modes from 0 to 4:
*
* 00: indoor (incandescant lighting)
* 01: outdoor (sunlight)
* 02: fluorescent lighting
* 03: manual
* 04: auto
*/
static
inline
int
pwc_set_awb
(
struct
pwc_device
*
pdev
,
int
mode
)
{
char
buf
;
int
ret
;
if
(
mode
<
0
)
mode
=
0
;
if
(
mode
>
4
)
mode
=
4
;
buf
=
mode
&
0x07
;
/* just the lowest three bits */
ret
=
SendControlMsg
(
SET_CHROM_CTL
,
WB_MODE_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
inline
int
pwc_get_awb
(
struct
pwc_device
*
pdev
)
{
unsigned
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_CHROM_CTL
,
WB_MODE_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
return
buf
;
}
static
inline
int
pwc_set_red_gain
(
struct
pwc_device
*
pdev
,
int
value
)
{
unsigned
char
buf
;
if
(
value
<
0
)
value
=
0
;
if
(
value
>
0xffff
)
value
=
0xffff
;
/* only the msb is considered */
buf
=
value
>>
8
;
return
SendControlMsg
(
SET_CHROM_CTL
,
PRESET_MANUAL_RED_GAIN_FORMATTER
,
1
);
}
static
inline
int
pwc_get_red_gain
(
struct
pwc_device
*
pdev
,
int
*
value
)
{
unsigned
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_CHROM_CTL
,
PRESET_MANUAL_RED_GAIN_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
*
value
=
buf
<<
8
;
return
0
;
}
static
inline
int
pwc_set_blue_gain
(
struct
pwc_device
*
pdev
,
int
value
)
{
unsigned
char
buf
;
if
(
value
<
0
)
value
=
0
;
if
(
value
>
0xffff
)
value
=
0xffff
;
/* only the msb is considered */
buf
=
value
>>
8
;
return
SendControlMsg
(
SET_CHROM_CTL
,
PRESET_MANUAL_BLUE_GAIN_FORMATTER
,
1
);
}
static
inline
int
pwc_get_blue_gain
(
struct
pwc_device
*
pdev
,
int
*
value
)
{
unsigned
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_CHROM_CTL
,
PRESET_MANUAL_BLUE_GAIN_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
*
value
=
buf
<<
8
;
return
0
;
}
/* The following two functions are different, since they only read the
internal red/blue gains, which may be different from the manual
gains set or read above.
*/
static
inline
int
pwc_read_red_gain
(
struct
pwc_device
*
pdev
,
int
*
value
)
{
unsigned
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_STATUS_CTL
,
READ_RED_GAIN_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
*
value
=
buf
<<
8
;
return
0
;
}
static
inline
int
pwc_read_blue_gain
(
struct
pwc_device
*
pdev
,
int
*
value
)
{
unsigned
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_STATUS_CTL
,
READ_BLUE_GAIN_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
*
value
=
buf
<<
8
;
return
0
;
}
static
inline
int
pwc_set_wb_speed
(
struct
pwc_device
*
pdev
,
int
speed
)
{
unsigned
char
buf
;
/* useful range is 0x01..0x20 */
buf
=
speed
/
0x7f0
;
return
SendControlMsg
(
SET_CHROM_CTL
,
AWB_CONTROL_SPEED_FORMATTER
,
1
);
}
static
inline
int
pwc_get_wb_speed
(
struct
pwc_device
*
pdev
,
int
*
value
)
{
unsigned
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_CHROM_CTL
,
AWB_CONTROL_SPEED_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
*
value
=
buf
*
0x7f0
;
return
0
;
}
static
inline
int
pwc_set_wb_delay
(
struct
pwc_device
*
pdev
,
int
delay
)
{
unsigned
char
buf
;
/* useful range is 0x01..0x3F */
buf
=
(
delay
>>
10
);
return
SendControlMsg
(
SET_CHROM_CTL
,
AWB_CONTROL_DELAY_FORMATTER
,
1
);
}
static
inline
int
pwc_get_wb_delay
(
struct
pwc_device
*
pdev
,
int
*
value
)
{
unsigned
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_CHROM_CTL
,
AWB_CONTROL_DELAY_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
*
value
=
buf
<<
10
;
return
0
;
}
int
pwc_set_leds
(
struct
pwc_device
*
pdev
,
int
on_value
,
int
off_value
)
{
unsigned
char
buf
[
2
];
if
(
pdev
->
type
<
730
)
return
0
;
on_value
/=
100
;
off_value
/=
100
;
if
(
on_value
<
0
)
on_value
=
0
;
if
(
on_value
>
0xff
)
on_value
=
0xff
;
if
(
off_value
<
0
)
off_value
=
0
;
if
(
off_value
>
0xff
)
off_value
=
0xff
;
buf
[
0
]
=
on_value
;
buf
[
1
]
=
off_value
;
return
SendControlMsg
(
SET_STATUS_CTL
,
LED_FORMATTER
,
2
);
}
int
pwc_get_leds
(
struct
pwc_device
*
pdev
,
int
*
on_value
,
int
*
off_value
)
{
unsigned
char
buf
[
2
];
int
ret
;
if
(
pdev
->
type
<
730
)
{
*
on_value
=
-
1
;
*
off_value
=
-
1
;
return
0
;
}
ret
=
RecvControlMsg
(
GET_STATUS_CTL
,
LED_FORMATTER
,
2
);
if
(
ret
<
0
)
return
ret
;
*
on_value
=
buf
[
0
]
*
100
;
*
off_value
=
buf
[
1
]
*
100
;
return
0
;
}
static
inline
int
pwc_set_contour
(
struct
pwc_device
*
pdev
,
int
contour
)
{
unsigned
char
buf
;
int
ret
;
if
(
contour
<
0
)
buf
=
0xff
;
/* auto contour on */
else
buf
=
0x0
;
/* auto contour off */
ret
=
SendControlMsg
(
SET_LUM_CTL
,
AUTO_CONTOUR_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
if
(
contour
<
0
)
return
0
;
if
(
contour
>
0xffff
)
contour
=
0xffff
;
buf
=
(
contour
>>
10
);
/* contour preset is [0..3f] */
ret
=
SendControlMsg
(
SET_LUM_CTL
,
PRESET_CONTOUR_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
inline
int
pwc_get_contour
(
struct
pwc_device
*
pdev
,
int
*
contour
)
{
unsigned
char
buf
;
int
ret
;
ret
=
RecvControlMsg
(
GET_LUM_CTL
,
AUTO_CONTOUR_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
if
(
buf
==
0
)
{
/* auto mode off, query current preset value */
ret
=
RecvControlMsg
(
GET_LUM_CTL
,
PRESET_CONTOUR_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
*
contour
=
buf
<<
10
;
}
else
*
contour
=
-
1
;
return
0
;
}
static
inline
int
pwc_set_backlight
(
struct
pwc_device
*
pdev
,
int
backlight
)
{
unsigned
char
buf
;
if
(
backlight
)
buf
=
0xff
;
else
buf
=
0x0
;
return
SendControlMsg
(
SET_LUM_CTL
,
BACK_LIGHT_COMPENSATION_FORMATTER
,
1
);
}
static
inline
int
pwc_get_backlight
(
struct
pwc_device
*
pdev
,
int
*
backlight
)
{
int
ret
;
unsigned
char
buf
;
ret
=
RecvControlMsg
(
GET_LUM_CTL
,
BACK_LIGHT_COMPENSATION_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
*
backlight
=
buf
;
return
0
;
}
static
inline
int
pwc_set_flicker
(
struct
pwc_device
*
pdev
,
int
flicker
)
{
unsigned
char
buf
;
if
(
flicker
)
buf
=
0xff
;
else
buf
=
0x0
;
return
SendControlMsg
(
SET_LUM_CTL
,
FLICKERLESS_MODE_FORMATTER
,
1
);
}
static
inline
int
pwc_get_flicker
(
struct
pwc_device
*
pdev
,
int
*
flicker
)
{
int
ret
;
unsigned
char
buf
;
ret
=
RecvControlMsg
(
GET_LUM_CTL
,
FLICKERLESS_MODE_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
*
flicker
=
buf
;
return
0
;
}
static
inline
int
pwc_set_dynamic_noise
(
struct
pwc_device
*
pdev
,
int
noise
)
{
unsigned
char
buf
;
if
(
noise
<
0
)
noise
=
0
;
if
(
noise
>
3
)
noise
=
3
;
buf
=
noise
;
return
SendControlMsg
(
SET_LUM_CTL
,
DYNAMIC_NOISE_CONTROL_FORMATTER
,
1
);
}
static
inline
int
pwc_get_dynamic_noise
(
struct
pwc_device
*
pdev
,
int
*
noise
)
{
int
ret
;
unsigned
char
buf
;
ret
=
RecvControlMsg
(
GET_LUM_CTL
,
DYNAMIC_NOISE_CONTROL_FORMATTER
,
1
);
if
(
ret
<
0
)
return
ret
;
*
noise
=
buf
;
return
0
;
}
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
*
sensor
)
{
unsigned
char
buf
;
int
ret
=
-
1
,
request
;
if
(
pdev
->
type
<
675
)
request
=
SENSOR_TYPE_FORMATTER1
;
else
if
(
pdev
->
type
<
730
)
return
-
1
;
/* The Vesta series doesn't have this call */
else
request
=
SENSOR_TYPE_FORMATTER2
;
ret
=
RecvControlMsg
(
GET_STATUS_CTL
,
request
,
1
);
if
(
ret
<
0
)
return
ret
;
if
(
pdev
->
type
<
675
)
*
sensor
=
buf
|
0x100
;
else
*
sensor
=
buf
;
return
0
;
}
/* End of Add-Ons */
/* ************************************************* */
/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
ioctl() calls. With 2.4, you have to do tedious copy_from_user()
and copy_to_user() calls. With these macros we circumvent this,
and let me maintain only one source file. The functionality is
exactly the same otherwise.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
/* define local variable for arg */
#define ARG_DEF(ARG_type, ARG_name)\
ARG_type *ARG_name = arg;
/* copy arg to local variable */
#define ARG_IN(ARG_name)
/* nothing */
/* argument itself (referenced) */
#define ARGR(ARG_name) (*ARG_name)
/* argument address */
#define ARGA(ARG_name) ARG_name
/* copy local variable to arg */
#define ARG_OUT(ARG_name)
/* nothing */
#else
#define ARG_DEF(ARG_type, ARG_name)\
ARG_type ARG_name;
#define ARG_IN(ARG_name)\
if (copy_from_user(&ARG_name, arg, sizeof(ARG_name))) {\
ret = -EFAULT;\
break;\
}
#define ARGR(ARG_name) ARG_name
#define ARGA(ARG_name) &ARG_name
#define ARG_OUT(ARG_name)\
if (copy_to_user(arg, &ARG_name, sizeof(ARG_name))) {\
ret = -EFAULT;\
break;\
}
#endif
int
pwc_ioctl
(
struct
pwc_device
*
pdev
,
unsigned
int
cmd
,
void
*
arg
)
{
int
ret
=
0
;
switch
(
cmd
)
{
case
VIDIOCPWCRUSER
:
{
if
(
pwc_restore_user
(
pdev
))
ret
=
-
EINVAL
;
break
;
}
case
VIDIOCPWCSUSER
:
{
if
(
pwc_save_user
(
pdev
))
ret
=
-
EINVAL
;
break
;
}
case
VIDIOCPWCFACTORY
:
{
if
(
pwc_restore_factory
(
pdev
))
ret
=
-
EINVAL
;
break
;
}
case
VIDIOCPWCSCQUAL
:
{
ARG_DEF
(
int
,
qual
)
ARG_IN
(
qual
)
if
(
ARGR
(
qual
)
<
0
||
ARGR
(
qual
)
>
3
)
ret
=
-
EINVAL
;
else
ret
=
pwc_try_video_mode
(
pdev
,
pdev
->
view
.
x
,
pdev
->
view
.
y
,
pdev
->
vframes
,
ARGR
(
qual
),
pdev
->
vsnapshot
);
if
(
ret
>=
0
)
pdev
->
vcompression
=
ARGR
(
qual
);
break
;
}
case
VIDIOCPWCGCQUAL
:
{
ARG_DEF
(
int
,
qual
)
ARGR
(
qual
)
=
pdev
->
vcompression
;
ARG_OUT
(
qual
)
break
;
}
case
VIDIOCPWCPROBE
:
{
ARG_DEF
(
struct
pwc_probe
,
probe
)
strcpy
(
ARGR
(
probe
).
name
,
pdev
->
vdev
->
name
);
ARGR
(
probe
).
type
=
pdev
->
type
;
ARG_OUT
(
probe
)
break
;
}
case
VIDIOCPWCGSERIAL
:
{
ARG_DEF
(
struct
pwc_serial
,
serial
)
strcpy
(
ARGR
(
serial
).
serial
,
pdev
->
serial
);
ARG_OUT
(
serial
)
break
;
}
case
VIDIOCPWCSAGC
:
{
ARG_DEF
(
int
,
agc
)
ARG_IN
(
agc
)
if
(
pwc_set_agc
(
pdev
,
ARGR
(
agc
)
<
0
?
1
:
0
,
ARGR
(
agc
)))
ret
=
-
EINVAL
;
break
;
}
case
VIDIOCPWCGAGC
:
{
ARG_DEF
(
int
,
agc
)
if
(
pwc_get_agc
(
pdev
,
ARGA
(
agc
)))
ret
=
-
EINVAL
;
ARG_OUT
(
agc
)
break
;
}
case
VIDIOCPWCSSHUTTER
:
{
ARG_DEF
(
int
,
shutter_speed
)
ARG_IN
(
shutter_speed
)
ret
=
pwc_set_shutter_speed
(
pdev
,
ARGR
(
shutter_speed
)
<
0
?
1
:
0
,
ARGR
(
shutter_speed
));
break
;
}
case
VIDIOCPWCSAWB
:
{
ARG_DEF
(
struct
pwc_whitebalance
,
wb
)
ARG_IN
(
wb
)
ret
=
pwc_set_awb
(
pdev
,
ARGR
(
wb
).
mode
);
if
(
ret
>=
0
&&
ARGR
(
wb
).
mode
==
PWC_WB_MANUAL
)
{
pwc_set_red_gain
(
pdev
,
ARGR
(
wb
).
manual_red
);
pwc_set_blue_gain
(
pdev
,
ARGR
(
wb
).
manual_blue
);
}
break
;
}
case
VIDIOCPWCGAWB
:
{
ARG_DEF
(
struct
pwc_whitebalance
,
wb
)
memset
(
ARGA
(
wb
),
0
,
sizeof
(
struct
pwc_whitebalance
));
ARGR
(
wb
).
mode
=
pwc_get_awb
(
pdev
);
if
(
ARGR
(
wb
).
mode
<
0
)
ret
=
-
EINVAL
;
else
{
if
(
ARGR
(
wb
).
mode
==
PWC_WB_MANUAL
)
{
ret
=
pwc_get_red_gain
(
pdev
,
&
ARGR
(
wb
).
manual_red
);
if
(
ret
<
0
)
break
;
ret
=
pwc_get_blue_gain
(
pdev
,
&
ARGR
(
wb
).
manual_blue
);
if
(
ret
<
0
)
break
;
}
if
(
ARGR
(
wb
).
mode
==
PWC_WB_AUTO
)
{
ret
=
pwc_read_red_gain
(
pdev
,
&
ARGR
(
wb
).
read_red
);
if
(
ret
<
0
)
break
;
ret
=
pwc_read_blue_gain
(
pdev
,
&
ARGR
(
wb
).
read_blue
);
if
(
ret
<
0
)
break
;
}
}
ARG_OUT
(
wb
)
break
;
}
case
VIDIOCPWCSAWBSPEED
:
{
ARG_DEF
(
struct
pwc_wb_speed
,
wbs
)
if
(
ARGR
(
wbs
).
control_speed
>
0
)
{
ret
=
pwc_set_wb_speed
(
pdev
,
ARGR
(
wbs
).
control_speed
);
}
if
(
ARGR
(
wbs
).
control_delay
>
0
)
{
ret
=
pwc_set_wb_delay
(
pdev
,
ARGR
(
wbs
).
control_delay
);
}
break
;
}
case
VIDIOCPWCGAWBSPEED
:
{
ARG_DEF
(
struct
pwc_wb_speed
,
wbs
)
ret
=
pwc_get_wb_speed
(
pdev
,
&
ARGR
(
wbs
).
control_speed
);
if
(
ret
<
0
)
break
;
ret
=
pwc_get_wb_delay
(
pdev
,
&
ARGR
(
wbs
).
control_delay
);
if
(
ret
<
0
)
break
;
ARG_OUT
(
wbs
)
break
;
}
case
VIDIOCPWCSLED
:
{
ARG_DEF
(
struct
pwc_leds
,
leds
)
ARG_IN
(
leds
)
ret
=
pwc_set_leds
(
pdev
,
ARGR
(
leds
).
led_on
,
ARGR
(
leds
).
led_off
);
break
;
}
case
VIDIOCPWCGLED
:
{
ARG_DEF
(
struct
pwc_leds
,
leds
)
ret
=
pwc_get_leds
(
pdev
,
&
ARGR
(
leds
).
led_on
,
&
ARGR
(
leds
).
led_off
);
ARG_OUT
(
leds
)
break
;
}
case
VIDIOCPWCSCONTOUR
:
{
ARG_DEF
(
int
,
contour
)
ARG_IN
(
contour
)
ret
=
pwc_set_contour
(
pdev
,
ARGR
(
contour
));
break
;
}
case
VIDIOCPWCGCONTOUR
:
{
ARG_DEF
(
int
,
contour
)
ret
=
pwc_get_contour
(
pdev
,
ARGA
(
contour
));
ARG_OUT
(
contour
)
break
;
}
case
VIDIOCPWCSBACKLIGHT
:
{
ARG_DEF
(
int
,
backlight
)
ARG_IN
(
backlight
)
ret
=
pwc_set_backlight
(
pdev
,
ARGR
(
backlight
));
break
;
}
case
VIDIOCPWCGBACKLIGHT
:
{
ARG_DEF
(
int
,
backlight
)
ret
=
pwc_get_backlight
(
pdev
,
ARGA
(
backlight
));
ARG_OUT
(
backlight
)
break
;
}
case
VIDIOCPWCSFLICKER
:
{
ARG_DEF
(
int
,
flicker
)
ARG_IN
(
flicker
)
ret
=
pwc_set_flicker
(
pdev
,
ARGR
(
flicker
));
break
;
}
case
VIDIOCPWCGFLICKER
:
{
ARG_DEF
(
int
,
flicker
)
ret
=
pwc_get_flicker
(
pdev
,
ARGA
(
flicker
));
ARG_OUT
(
flicker
)
break
;
}
case
VIDIOCPWCSDYNNOISE
:
{
ARG_DEF
(
int
,
dynnoise
)
ARG_IN
(
dynnoise
)
ret
=
pwc_set_dynamic_noise
(
pdev
,
ARGR
(
dynnoise
));
break
;
}
case
VIDIOCPWCGDYNNOISE
:
{
ARG_DEF
(
int
,
dynnoise
)
ret
=
pwc_get_dynamic_noise
(
pdev
,
ARGA
(
dynnoise
));
ARG_OUT
(
dynnoise
);
break
;
}
case
VIDIOCPWCGREALSIZE
:
{
ARG_DEF
(
struct
pwc_imagesize
,
size
)
ARGR
(
size
).
width
=
pdev
->
image
.
x
;
ARGR
(
size
).
height
=
pdev
->
image
.
y
;
ARG_OUT
(
size
)
break
;
}
case
VIDIOCPWCMPTRESET
:
{
if
(
pdev
->
features
&
FEATURE_MOTOR_PANTILT
)
{
ARG_DEF
(
int
,
flags
)
ARG_IN
(
flags
)
ret
=
pwc_mpt_reset
(
pdev
,
ARGR
(
flags
));
if
(
ret
>=
0
)
{
pdev
->
pan_angle
=
0
;
pdev
->
tilt_angle
=
0
;
}
}
else
{
ret
=
-
ENXIO
;
}
break
;
}
case
VIDIOCPWCMPTGRANGE
:
{
if
(
pdev
->
features
&
FEATURE_MOTOR_PANTILT
)
{
ARG_DEF
(
struct
pwc_mpt_range
,
range
)
ARGR
(
range
)
=
pdev
->
angle_range
;
ARG_OUT
(
range
)
}
else
{
ret
=
-
ENXIO
;
}
break
;
}
case
VIDIOCPWCMPTSANGLE
:
{
int
new_pan
,
new_tilt
;
if
(
pdev
->
features
&
FEATURE_MOTOR_PANTILT
)
{
ARG_DEF
(
struct
pwc_mpt_angles
,
angles
)
ARG_IN
(
angles
)
/* The camera can only set relative angles, so
do some calculations when getting an absolute angle .
*/
if
(
ARGR
(
angles
).
absolute
)
{
new_pan
=
ARGR
(
angles
).
pan
;
new_tilt
=
ARGR
(
angles
).
tilt
;
}
else
{
new_pan
=
pdev
->
pan_angle
+
ARGR
(
angles
).
pan
;
new_tilt
=
pdev
->
tilt_angle
+
ARGR
(
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
:
{
if
(
pdev
->
features
&
FEATURE_MOTOR_PANTILT
)
{
ARG_DEF
(
struct
pwc_mpt_angles
,
angles
)
ARGR
(
angles
).
absolute
=
1
;
ARGR
(
angles
).
pan
=
pdev
->
pan_angle
;
ARGR
(
angles
).
tilt
=
pdev
->
tilt_angle
;
ARG_OUT
(
angles
)
}
else
{
ret
=
-
ENXIO
;
}
break
;
}
case
VIDIOCPWCMPTSTATUS
:
{
if
(
pdev
->
features
&
FEATURE_MOTOR_PANTILT
)
{
ARG_DEF
(
struct
pwc_mpt_status
,
status
)
ret
=
pwc_mpt_get_status
(
pdev
,
ARGA
(
status
));
ARG_OUT
(
status
)
}
else
{
ret
=
-
ENXIO
;
}
break
;
}
case
VIDIOCPWCGVIDCMD
:
{
ARG_DEF
(
struct
pwc_video_command
,
cmd
);
ARGR
(
cmd
).
type
=
pdev
->
type
;
ARGR
(
cmd
).
release
=
pdev
->
release
;
ARGR
(
cmd
).
command_len
=
pdev
->
cmd_len
;
memcpy
(
&
ARGR
(
cmd
).
command_buf
,
pdev
->
cmd_buf
,
pdev
->
cmd_len
);
ARGR
(
cmd
).
bandlength
=
pdev
->
vbandlength
;
ARGR
(
cmd
).
frame_size
=
pdev
->
frame_size
;
ARG_OUT
(
cmd
)
break
;
}
default:
ret
=
-
ENOIOCTLCMD
;
break
;
}
if
(
ret
>
0
)
return
0
;
return
ret
;
}
drivers/usb/media/pwc-if.c
deleted
100644 → 0
View file @
0335cce0
/* Linux driver for Philips webcam
USB and Video4Linux interface part.
(C) 1999-2004 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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
This code forms the interface between the USB layers and the Philips
specific stuff. Some adanved stuff of the driver falls under an
NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and
is thus not distributed in source form. The binary pwcx.o module
contains the code that falls under the NDA.
In case you're wondering: 'pwc' stands for "Philips WebCam", but
I really didn't want to type 'philips_web_cam' every time (I'm lazy as
any Linux kernel hacker, but I don't like uncomprehensible abbreviations
without explanation).
Oh yes, convention: to disctinguish between all the various pointers to
device-structures, I use these names for the pointer variables:
udev: struct usb_device *
vdev: struct video_device *
pdev: struct pwc_devive *
*/
/* Contributors:
- Alvarado: adding whitebalance code
- 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 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 <asm/io.h>
#include "pwc.h"
#include "pwc-ioctl.h"
/* Function prototypes and driver templates */
/* hotplug device table support */
static
struct
usb_device_id
pwc_device_table
[]
=
{
{
USB_DEVICE
(
0x0471
,
0x0302
)
},
/* Philips models */
{
USB_DEVICE
(
0x0471
,
0x0303
)
},
{
USB_DEVICE
(
0x0471
,
0x0304
)
},
{
USB_DEVICE
(
0x0471
,
0x0307
)
},
{
USB_DEVICE
(
0x0471
,
0x0308
)
},
{
USB_DEVICE
(
0x0471
,
0x030C
)
},
{
USB_DEVICE
(
0x0471
,
0x0310
)
},
{
USB_DEVICE
(
0x0471
,
0x0311
)
},
{
USB_DEVICE
(
0x0471
,
0x0312
)
},
{
USB_DEVICE
(
0x0471
,
0x0313
)
},
/* the 'new' 720K */
{
USB_DEVICE
(
0x069A
,
0x0001
)
},
/* Askey */
{
USB_DEVICE
(
0x046D
,
0x08B0
)
},
/* Logitech QuickCam Pro 3000 */
{
USB_DEVICE
(
0x046D
,
0x08B1
)
},
/* Logitech QuickCam Notebook Pro */
{
USB_DEVICE
(
0x046D
,
0x08B2
)
},
/* Logitech QuickCam Pro 4000 */
{
USB_DEVICE
(
0x046D
,
0x08B3
)
},
/* Logitech QuickCam Zoom (old model) */
{
USB_DEVICE
(
0x046D
,
0x08B4
)
},
/* Logitech QuickCam Zoom (new model) */
{
USB_DEVICE
(
0x046D
,
0x08B5
)
},
/* Logitech QuickCam Orbit/Sphere */
{
USB_DEVICE
(
0x046D
,
0x08B6
)
},
/* Logitech (reserved) */
{
USB_DEVICE
(
0x046D
,
0x08B7
)
},
/* Logitech (reserved) */
{
USB_DEVICE
(
0x046D
,
0x08B8
)
},
/* Logitech (reserved) */
{
USB_DEVICE
(
0x055D
,
0x9000
)
},
/* Samsung */
{
USB_DEVICE
(
0x055D
,
0x9001
)
},
{
USB_DEVICE
(
0x041E
,
0x400C
)
},
/* Creative Webcam 5 */
{
USB_DEVICE
(
0x041E
,
0x4011
)
},
/* Creative Webcam Pro Ex */
{
USB_DEVICE
(
0x04CC
,
0x8116
)
},
/* Afina Eye */
{
USB_DEVICE
(
0x06BE
,
0x8116
)
},
/* new Afina Eye */
{
USB_DEVICE
(
0x0d81
,
0x1910
)
},
/* Visionite */
{
USB_DEVICE
(
0x0d81
,
0x1900
)
},
{
}
};
MODULE_DEVICE_TABLE
(
usb
,
pwc_device_table
);
static
int
usb_pwc_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
);
static
void
usb_pwc_disconnect
(
struct
usb_interface
*
intf
);
static
struct
usb_driver
pwc_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"Philips webcam"
,
/* name */
.
id_table
=
pwc_device_table
,
.
probe
=
usb_pwc_probe
,
/* probe() */
.
disconnect
=
usb_pwc_disconnect
,
/* disconnect() */
};
#define MAX_DEV_HINTS 20
#define MAX_ISOC_ERRORS 20
static
int
default_size
=
PSZ_QCIF
;
static
int
default_fps
=
10
;
static
int
default_fbufs
=
3
;
/* Default number of frame buffers */
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
=
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
;
char
serial_number
[
30
];
int
device_node
;
struct
pwc_device
*
pdev
;
}
device_hint
[
MAX_DEV_HINTS
];
/***/
static
int
pwc_video_open
(
struct
inode
*
inode
,
struct
file
*
file
);
static
int
pwc_video_close
(
struct
inode
*
inode
,
struct
file
*
file
);
static
ssize_t
pwc_video_read
(
struct
file
*
file
,
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
);
static
unsigned
int
pwc_video_poll
(
struct
file
*
file
,
poll_table
*
wait
);
static
int
pwc_video_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
ioctlnr
,
unsigned
long
arg
);
static
int
pwc_video_mmap
(
struct
file
*
file
,
struct
vm_area_struct
*
vma
);
static
struct
file_operations
pwc_fops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
pwc_video_open
,
.
release
=
pwc_video_close
,
.
read
=
pwc_video_read
,
.
poll
=
pwc_video_poll
,
.
mmap
=
pwc_video_mmap
,
.
ioctl
=
pwc_video_ioctl
,
.
llseek
=
no_llseek
,
};
static
struct
video_device
pwc_template
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"Philips Webcam"
,
/* Filled in later */
.
type
=
VID_TYPE_CAPTURE
,
.
hardware
=
VID_HARDWARE_PWC
,
.
release
=
video_device_release
,
.
fops
=
&
pwc_fops
,
.
minor
=
-
1
,
};
/***************************************************************************/
/* Okay, this is some magic that I worked out and the reasoning behind it...
The biggest problem with any USB device is of course: "what to do
when the user unplugs the device while it is in use by an application?"
We have several options:
1) Curse them with the 7 plagues when they do (requires divine intervention)
2) Tell them not to (won't work: they'll do it anyway)
3) Oops the kernel (this will have a negative effect on a user's uptime)
4) Do something sensible.
Of course, we go for option 4.
It happens that this device will be linked to two times, once from
usb_device and once from the video_device in their respective 'private'
pointers. This is done when the device is probed() and all initialization
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 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.
A small 'advantage' is that if a user unplugs the cam and plugs it back
in, it should get assigned the same video device minor, but unfortunately
it's non-trivial to re-link the cam back to the video device... (that
would surely be magic! :))
*/
/***************************************************************************/
/* Private functions */
/* Here we want the physical address of the memory.
* This is used when initializing the contents of the area.
*/
static
inline
unsigned
long
kvirt_to_pa
(
unsigned
long
adr
)
{
unsigned
long
kva
,
ret
;
kva
=
(
unsigned
long
)
page_address
(
vmalloc_to_page
((
void
*
)
adr
));
kva
|=
adr
&
(
PAGE_SIZE
-
1
);
/* restore the offset */
ret
=
__pa
(
kva
);
return
ret
;
}
static
void
*
rvmalloc
(
unsigned
long
size
)
{
void
*
mem
;
unsigned
long
adr
;
size
=
PAGE_ALIGN
(
size
);
mem
=
vmalloc_32
(
size
);
if
(
mem
)
{
memset
(
mem
,
0
,
size
);
/* Clear the ram out, no junk to the user */
adr
=
(
unsigned
long
)
mem
;
while
(
size
>
0
)
{
SetPageReserved
(
vmalloc_to_page
((
void
*
)
adr
));
adr
+=
PAGE_SIZE
;
size
-=
PAGE_SIZE
;
}
}
return
mem
;
}
static
void
rvfree
(
void
*
mem
,
unsigned
long
size
)
{
unsigned
long
adr
;
if
(
mem
)
{
adr
=
(
unsigned
long
)
mem
;
while
((
long
)
size
>
0
)
{
ClearPageReserved
(
vmalloc_to_page
((
void
*
)
adr
));
adr
+=
PAGE_SIZE
;
size
-=
PAGE_SIZE
;
}
vfree
(
mem
);
}
}
static
int
pwc_allocate_buffers
(
struct
pwc_device
*
pdev
)
{
int
i
;
void
*
kbuf
;
Trace
(
TRACE_MEMORY
,
">> pwc_allocate_buffers(pdev = 0x%p)
\n
"
,
pdev
);
if
(
pdev
==
NULL
)
return
-
ENXIO
;
#ifdef PWC_MAGIC
if
(
pdev
->
magic
!=
PWC_MAGIC
)
{
Err
(
"allocate_buffers(): magic failed.
\n
"
);
return
-
ENXIO
;
}
#endif
/* Allocate Isochronuous pipe buffers */
for
(
i
=
0
;
i
<
MAX_ISO_BUFS
;
i
++
)
{
if
(
pdev
->
sbuf
[
i
].
data
==
NULL
)
{
kbuf
=
kmalloc
(
ISO_BUFFER_SIZE
,
GFP_KERNEL
);
if
(
kbuf
==
NULL
)
{
Err
(
"Failed to allocate iso buffer %d.
\n
"
,
i
);
return
-
ENOMEM
;
}
Trace
(
TRACE_MEMORY
,
"Allocated iso buffer at %p.
\n
"
,
kbuf
);
pdev
->
sbuf
[
i
].
data
=
kbuf
;
memset
(
kbuf
,
0
,
ISO_BUFFER_SIZE
);
}
}
/* Allocate frame buffer structure */
if
(
pdev
->
fbuf
==
NULL
)
{
kbuf
=
kmalloc
(
default_fbufs
*
sizeof
(
struct
pwc_frame_buf
),
GFP_KERNEL
);
if
(
kbuf
==
NULL
)
{
Err
(
"Failed to allocate frame buffer structure.
\n
"
);
return
-
ENOMEM
;
}
Trace
(
TRACE_MEMORY
,
"Allocated frame buffer structure at %p.
\n
"
,
kbuf
);
pdev
->
fbuf
=
kbuf
;
memset
(
kbuf
,
0
,
default_fbufs
*
sizeof
(
struct
pwc_frame_buf
));
}
/* create frame buffers, and make circular ring */
for
(
i
=
0
;
i
<
default_fbufs
;
i
++
)
{
if
(
pdev
->
fbuf
[
i
].
data
==
NULL
)
{
kbuf
=
vmalloc
(
PWC_FRAME_SIZE
);
/* need vmalloc since frame buffer > 128K */
if
(
kbuf
==
NULL
)
{
Err
(
"Failed to allocate frame buffer %d.
\n
"
,
i
);
return
-
ENOMEM
;
}
Trace
(
TRACE_MEMORY
,
"Allocated frame buffer %d at %p.
\n
"
,
i
,
kbuf
);
pdev
->
fbuf
[
i
].
data
=
kbuf
;
memset
(
kbuf
,
128
,
PWC_FRAME_SIZE
);
}
}
/* Allocate decompressor table space */
kbuf
=
NULL
;
pdev
->
decompress_data
=
kbuf
;
/* Allocate image buffer; double buffer for mmap() */
kbuf
=
rvmalloc
(
default_mbufs
*
pdev
->
len_per_image
);
if
(
kbuf
==
NULL
)
{
Err
(
"Failed to allocate image buffer(s).
\n
"
);
return
-
ENOMEM
;
}
Trace
(
TRACE_MEMORY
,
"Allocated image buffer at %p.
\n
"
,
kbuf
);
pdev
->
image_data
=
kbuf
;
for
(
i
=
0
;
i
<
default_mbufs
;
i
++
)
pdev
->
image_ptr
[
i
]
=
kbuf
+
i
*
pdev
->
len_per_image
;
for
(;
i
<
MAX_IMAGES
;
i
++
)
pdev
->
image_ptr
[
i
]
=
NULL
;
kbuf
=
NULL
;
Trace
(
TRACE_MEMORY
,
"<< pwc_allocate_buffers()
\n
"
);
return
0
;
}
static
void
pwc_free_buffers
(
struct
pwc_device
*
pdev
)
{
int
i
;
Trace
(
TRACE_MEMORY
,
"Entering free_buffers(%p).
\n
"
,
pdev
);
if
(
pdev
==
NULL
)
return
;
#ifdef PWC_MAGIC
if
(
pdev
->
magic
!=
PWC_MAGIC
)
{
Err
(
"free_buffers(): magic failed.
\n
"
);
return
;
}
#endif
/* Release Iso-pipe buffers */
for
(
i
=
0
;
i
<
MAX_ISO_BUFS
;
i
++
)
if
(
pdev
->
sbuf
[
i
].
data
!=
NULL
)
{
Trace
(
TRACE_MEMORY
,
"Freeing ISO buffer at %p.
\n
"
,
pdev
->
sbuf
[
i
].
data
);
kfree
(
pdev
->
sbuf
[
i
].
data
);
pdev
->
sbuf
[
i
].
data
=
NULL
;
}
/* The same for frame buffers */
if
(
pdev
->
fbuf
!=
NULL
)
{
for
(
i
=
0
;
i
<
default_fbufs
;
i
++
)
{
if
(
pdev
->
fbuf
[
i
].
data
!=
NULL
)
{
Trace
(
TRACE_MEMORY
,
"Freeing frame buffer %d at %p.
\n
"
,
i
,
pdev
->
fbuf
[
i
].
data
);
vfree
(
pdev
->
fbuf
[
i
].
data
);
pdev
->
fbuf
[
i
].
data
=
NULL
;
}
}
kfree
(
pdev
->
fbuf
);
pdev
->
fbuf
=
NULL
;
}
/* Intermediate decompression buffer & tables */
if
(
pdev
->
decompress_data
!=
NULL
)
{
Trace
(
TRACE_MEMORY
,
"Freeing decompression buffer at %p.
\n
"
,
pdev
->
decompress_data
);
kfree
(
pdev
->
decompress_data
);
pdev
->
decompress_data
=
NULL
;
}
pdev
->
decompressor
=
NULL
;
/* Release image buffers */
if
(
pdev
->
image_data
!=
NULL
)
{
Trace
(
TRACE_MEMORY
,
"Freeing image buffer at %p.
\n
"
,
pdev
->
image_data
);
rvfree
(
pdev
->
image_data
,
default_mbufs
*
pdev
->
len_per_image
);
}
pdev
->
image_data
=
NULL
;
Trace
(
TRACE_MEMORY
,
"Leaving free_buffers().
\n
"
);
}
/* The frame & image buffer mess.
Yes, this is a mess. Well, it used to be simple, but alas... In this
module, 3 buffers schemes are used to get the data from the USB bus to
the user program. The first scheme involves the ISO buffers (called thus
since they transport ISO data from the USB controller), and not really
interesting. Suffices to say the data from this buffer is quickly
gathered in an interrupt handler (pwc_isoc_handler) and placed into the
frame buffer.
The frame buffer is the second scheme, and is the central element here.
It collects the data from a single frame from the camera (hence, the
name). Frames are delimited by the USB camera with a short USB packet,
so that's easy to detect. The frame buffers form a list that is filled
by the camera+USB controller and drained by the user process through
either read() or mmap().
The image buffer is the third scheme, in which frames are decompressed
and converted into planar format. For mmap() there is more than
one image buffer available.
The frame buffers provide the image buffering. In case the user process
is a bit slow, this introduces lag and some undesired side-effects.
The problem arises when the frame buffer is full. I used to drop the last
frame, which makes the data in the queue stale very quickly. But dropping
the frame at the head of the queue proved to be a litte bit more difficult.
I tried a circular linked scheme, but this introduced more problems than
it solved.
Because filling and draining are completely asynchronous processes, this
requires some fiddling with pointers and mutexes.
Eventually, I came up with a system with 2 lists: an 'empty' frame list
and a 'full' frame list:
* Initially, all frame buffers but one are on the 'empty' list; the one
remaining buffer is our initial fill frame.
* If a frame is needed for filling, we try to take it from the 'empty'
list, unless that list is empty, in which case we take the buffer at
the head of the 'full' list.
* When our fill buffer has been filled, it is appended to the 'full'
list.
* If a frame is needed by read() or mmap(), it is taken from the head of
the 'full' list, handled, and then appended to the 'empty' list. If no
buffer is present on the 'full' list, we wait.
The advantage is that the buffer that is currently being decompressed/
converted, is on neither list, and thus not in our way (any other scheme
I tried had the problem of old data lingering in the queue).
Whatever strategy you choose, it always remains a tradeoff: with more
frame buffers the chances of a missed frame are reduced. On the other
hand, on slower machines it introduces lag because the queue will
always be full.
*/
/**
\brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
*/
static
inline
int
pwc_next_fill_frame
(
struct
pwc_device
*
pdev
)
{
int
ret
;
unsigned
long
flags
;
ret
=
0
;
spin_lock_irqsave
(
&
pdev
->
ptrlock
,
flags
);
if
(
pdev
->
fill_frame
!=
NULL
)
{
/* append to 'full' list */
if
(
pdev
->
full_frames
==
NULL
)
{
pdev
->
full_frames
=
pdev
->
fill_frame
;
pdev
->
full_frames_tail
=
pdev
->
full_frames
;
}
else
{
pdev
->
full_frames_tail
->
next
=
pdev
->
fill_frame
;
pdev
->
full_frames_tail
=
pdev
->
fill_frame
;
}
}
if
(
pdev
->
empty_frames
!=
NULL
)
{
/* We have empty frames available. That's easy */
pdev
->
fill_frame
=
pdev
->
empty_frames
;
pdev
->
empty_frames
=
pdev
->
empty_frames
->
next
;
}
else
{
/* Hmm. Take it from the full list */
#if PWC_DEBUG
/* sanity check */
if
(
pdev
->
full_frames
==
NULL
)
{
Err
(
"Neither empty or full frames available!
\n
"
);
spin_unlock_irqrestore
(
&
pdev
->
ptrlock
,
flags
);
return
-
EINVAL
;
}
#endif
pdev
->
fill_frame
=
pdev
->
full_frames
;
pdev
->
full_frames
=
pdev
->
full_frames
->
next
;
ret
=
1
;
}
pdev
->
fill_frame
->
next
=
NULL
;
#if PWC_DEBUG
Trace
(
TRACE_SEQUENCE
,
"Assigning sequence number %d.
\n
"
,
pdev
->
sequence
);
pdev
->
fill_frame
->
sequence
=
pdev
->
sequence
++
;
#endif
spin_unlock_irqrestore
(
&
pdev
->
ptrlock
,
flags
);
return
ret
;
}
/**
\brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
*/
static
void
pwc_reset_buffers
(
struct
pwc_device
*
pdev
)
{
int
i
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
pdev
->
ptrlock
,
flags
);
pdev
->
full_frames
=
NULL
;
pdev
->
full_frames_tail
=
NULL
;
for
(
i
=
0
;
i
<
default_fbufs
;
i
++
)
{
pdev
->
fbuf
[
i
].
filled
=
0
;
if
(
i
>
0
)
pdev
->
fbuf
[
i
].
next
=
&
pdev
->
fbuf
[
i
-
1
];
else
pdev
->
fbuf
->
next
=
NULL
;
}
pdev
->
empty_frames
=
&
pdev
->
fbuf
[
default_fbufs
-
1
];
pdev
->
empty_frames_tail
=
pdev
->
fbuf
;
pdev
->
read_frame
=
NULL
;
pdev
->
fill_frame
=
pdev
->
empty_frames
;
pdev
->
empty_frames
=
pdev
->
empty_frames
->
next
;
pdev
->
image_read_pos
=
0
;
pdev
->
fill_image
=
0
;
spin_unlock_irqrestore
(
&
pdev
->
ptrlock
,
flags
);
}
/**
\brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
*/
static
int
pwc_handle_frame
(
struct
pwc_device
*
pdev
)
{
int
ret
=
0
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
pdev
->
ptrlock
,
flags
);
/* First grab our read_frame; this is removed from all lists, so
we can release the lock after this without problems */
if
(
pdev
->
read_frame
!=
NULL
)
{
/* This can't theoretically happen */
Err
(
"Huh? Read frame still in use?
\n
"
);
}
else
{
if
(
pdev
->
full_frames
==
NULL
)
{
Err
(
"Woops. No frames ready.
\n
"
);
}
else
{
pdev
->
read_frame
=
pdev
->
full_frames
;
pdev
->
full_frames
=
pdev
->
full_frames
->
next
;
pdev
->
read_frame
->
next
=
NULL
;
}
if
(
pdev
->
read_frame
!=
NULL
)
{
#if PWC_DEBUG
Trace
(
TRACE_SEQUENCE
,
"Decompressing frame %d
\n
"
,
pdev
->
read_frame
->
sequence
);
#endif
/* We're done with read_buffer, tack it to the end of the empty buffer list */
if
(
pdev
->
empty_frames
==
NULL
)
{
pdev
->
empty_frames
=
pdev
->
read_frame
;
pdev
->
empty_frames_tail
=
pdev
->
empty_frames
;
}
else
{
pdev
->
empty_frames_tail
->
next
=
pdev
->
read_frame
;
pdev
->
empty_frames_tail
=
pdev
->
read_frame
;
}
pdev
->
read_frame
=
NULL
;
}
}
spin_unlock_irqrestore
(
&
pdev
->
ptrlock
,
flags
);
return
ret
;
}
/**
\brief Advance pointers of image buffer (after each user request)
*/
static
inline
void
pwc_next_image
(
struct
pwc_device
*
pdev
)
{
pdev
->
image_used
[
pdev
->
fill_image
]
=
0
;
pdev
->
fill_image
=
(
pdev
->
fill_image
+
1
)
%
default_mbufs
;
}
/* This gets called for the Isochronous pipe (video). This is done in
* interrupt time, so it has to be fast, not crash, and not stall. Neat.
*/
static
void
pwc_isoc_handler
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
struct
pwc_device
*
pdev
;
int
i
,
fst
,
flen
;
int
awake
;
struct
pwc_frame_buf
*
fbuf
;
unsigned
char
*
fillptr
=
NULL
;
unsigned
char
*
iso_buf
=
NULL
;
awake
=
0
;
pdev
=
(
struct
pwc_device
*
)
urb
->
context
;
if
(
pdev
==
NULL
)
{
Err
(
"isoc_handler() called with NULL device?!
\n
"
);
return
;
}
#ifdef PWC_MAGIC
if
(
pdev
->
magic
!=
PWC_MAGIC
)
{
Err
(
"isoc_handler() called with bad magic!
\n
"
);
return
;
}
#endif
if
(
urb
->
status
==
-
ENOENT
||
urb
->
status
==
-
ECONNRESET
)
{
Trace
(
TRACE_OPEN
,
"pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.
\n
"
,
urb
,
urb
->
status
==
-
ENOENT
?
""
:
"a"
);
return
;
}
if
(
urb
->
status
!=
-
EINPROGRESS
&&
urb
->
status
!=
0
)
{
const
char
*
errmsg
;
errmsg
=
"Unknown"
;
switch
(
urb
->
status
)
{
case
-
ENOSR
:
errmsg
=
"Buffer error (overrun)"
;
break
;
case
-
EPIPE
:
errmsg
=
"Stalled (device not responding)"
;
break
;
case
-
EOVERFLOW
:
errmsg
=
"Babble (bad cable?)"
;
break
;
case
-
EPROTO
:
errmsg
=
"Bit-stuff error (bad cable?)"
;
break
;
case
-
EILSEQ
:
errmsg
=
"CRC/Timeout (could be anything)"
;
break
;
case
-
ETIMEDOUT
:
errmsg
=
"NAK (device does not respond)"
;
break
;
}
Trace
(
TRACE_FLOW
,
"pwc_isoc_handler() called with status %d [%s].
\n
"
,
urb
->
status
,
errmsg
);
/* Give up after a number of contiguous errors on the USB bus.
Appearantly something is wrong so we simulate an unplug event.
*/
if
(
++
pdev
->
visoc_errors
>
MAX_ISOC_ERRORS
)
{
Info
(
"Too many ISOC errors, bailing out.
\n
"
);
pdev
->
error_status
=
EIO
;
awake
=
1
;
wake_up_interruptible
(
&
pdev
->
frameq
);
}
goto
handler_end
;
// ugly, but practical
}
fbuf
=
pdev
->
fill_frame
;
if
(
fbuf
==
NULL
)
{
Err
(
"pwc_isoc_handler without valid fill frame.
\n
"
);
awake
=
1
;
goto
handler_end
;
}
else
{
fillptr
=
fbuf
->
data
+
fbuf
->
filled
;
}
/* Reset ISOC error counter. We did get here, after all. */
pdev
->
visoc_errors
=
0
;
/* vsync: 0 = don't copy data
1 = sync-hunt
2 = synched
*/
/* Compact data */
for
(
i
=
0
;
i
<
urb
->
number_of_packets
;
i
++
)
{
fst
=
urb
->
iso_frame_desc
[
i
].
status
;
flen
=
urb
->
iso_frame_desc
[
i
].
actual_length
;
iso_buf
=
urb
->
transfer_buffer
+
urb
->
iso_frame_desc
[
i
].
offset
;
if
(
fst
==
0
)
{
if
(
flen
>
0
)
{
/* if valid data... */
if
(
pdev
->
vsync
>
0
)
{
/* ...and we are not sync-hunting... */
pdev
->
vsync
=
2
;
/* ...copy data to frame buffer, if possible */
if
(
flen
+
fbuf
->
filled
>
pdev
->
frame_total_size
)
{
Trace
(
TRACE_FLOW
,
"Frame buffer overflow (flen = %d, frame_total_size = %d).
\n
"
,
flen
,
pdev
->
frame_total_size
);
pdev
->
vsync
=
0
;
/* Hmm, let's wait for an EOF (end-of-frame) */
pdev
->
vframes_error
++
;
}
else
{
memmove
(
fillptr
,
iso_buf
,
flen
);
fillptr
+=
flen
;
}
}
fbuf
->
filled
+=
flen
;
}
/* ..flen > 0 */
if
(
flen
<
pdev
->
vlast_packet_size
)
{
/* Shorter packet... We probably have the end of an image-frame;
wake up read() process and let select()/poll() do something.
Decompression is done in user time over there.
*/
if
(
pdev
->
vsync
==
2
)
{
/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
frames on the USB wire after an exposure change. This conditition is
however detected in the cam and a bit is set in the header.
*/
if
(
pdev
->
type
==
730
)
{
unsigned
char
*
ptr
=
(
unsigned
char
*
)
fbuf
->
data
;
if
(
ptr
[
1
]
==
1
&&
ptr
[
0
]
&
0x10
)
{
#if PWC_DEBUG
Debug
(
"Hyundai CMOS sensor bug. Dropping frame %d.
\n
"
,
fbuf
->
sequence
);
#endif
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.
So we get either this sequence:
drop_bit set -> 4 byte frame -> short frame -> good frame
Or this one:
drop_bit set -> short frame -> good frame
So we drop either 3 or 2 frames in all!
*/
if
(
fbuf
->
filled
==
4
)
pdev
->
drop_frames
++
;
}
/* 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
>
0
)
pdev
->
drop_frames
--
;
else
{
/* Check for underflow first */
if
(
fbuf
->
filled
<
pdev
->
frame_total_size
)
{
Trace
(
TRACE_FLOW
,
"Frame buffer underflow (%d bytes); discarded.
\n
"
,
fbuf
->
filled
);
pdev
->
vframes_error
++
;
}
else
{
/* Send only once per EOF */
awake
=
1
;
/* delay wake_ups */
/* Find our next frame to fill. This will always succeed, since we
* nick a frame from either empty or full list, but if we had to
* take it from the full list, it means a frame got dropped.
*/
if
(
pwc_next_fill_frame
(
pdev
))
{
pdev
->
vframes_dumped
++
;
if
((
pdev
->
vframe_count
>
FRAME_LOWMARK
)
&&
(
pwc_trace
&
TRACE_FLOW
))
{
if
(
pdev
->
vframes_dumped
<
20
)
Trace
(
TRACE_FLOW
,
"Dumping frame %d.
\n
"
,
pdev
->
vframe_count
);
if
(
pdev
->
vframes_dumped
==
20
)
Trace
(
TRACE_FLOW
,
"Dumping frame %d (last message).
\n
"
,
pdev
->
vframe_count
);
}
}
fbuf
=
pdev
->
fill_frame
;
}
}
/* !drop_frames */
pdev
->
vframe_count
++
;
}
fbuf
->
filled
=
0
;
fillptr
=
fbuf
->
data
;
pdev
->
vsync
=
1
;
}
/* .. flen < last_packet_size */
pdev
->
vlast_packet_size
=
flen
;
}
/* ..status == 0 */
#if PWC_DEBUG
/* This is normally not interesting to the user, unless you are really debugging something */
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
}
handler_end:
if
(
awake
)
wake_up_interruptible
(
&
pdev
->
frameq
);
urb
->
dev
=
pdev
->
udev
;
i
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
i
!=
0
)
Err
(
"Error (%d) re-submitting urb in pwc_isoc_handler.
\n
"
,
i
);
}
static
int
pwc_isoc_init
(
struct
pwc_device
*
pdev
)
{
struct
usb_device
*
udev
;
struct
urb
*
urb
;
int
i
,
j
,
ret
;
struct
usb_interface
*
intf
;
struct
usb_host_interface
*
idesc
=
NULL
;
if
(
pdev
==
NULL
)
return
-
EFAULT
;
if
(
pdev
->
iso_init
)
return
0
;
pdev
->
vsync
=
0
;
udev
=
pdev
->
udev
;
/* Get the current alternate interface, adjust packet size */
if
(
!
udev
->
actconfig
)
return
-
EFAULT
;
intf
=
usb_ifnum_to_if
(
udev
,
0
);
if
(
intf
)
idesc
=
usb_altnum_to_altsetting
(
intf
,
pdev
->
valternate
);
if
(
!
idesc
)
return
-
EFAULT
;
/* Search video endpoint */
pdev
->
vmax_packet_size
=
-
1
;
for
(
i
=
0
;
i
<
idesc
->
desc
.
bNumEndpoints
;
i
++
)
if
((
idesc
->
endpoint
[
i
].
desc
.
bEndpointAddress
&
0xF
)
==
pdev
->
vendpoint
)
{
pdev
->
vmax_packet_size
=
idesc
->
endpoint
[
i
].
desc
.
wMaxPacketSize
;
break
;
}
if
(
pdev
->
vmax_packet_size
<
0
||
pdev
->
vmax_packet_size
>
ISO_MAX_FRAME_SIZE
)
{
Err
(
"Failed to find packet size for video endpoint in current alternate setting.
\n
"
);
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
)
{
Err
(
"Failed to allocate urb %d
\n
"
,
i
);
ret
=
-
ENOMEM
;
break
;
}
pdev
->
sbuf
[
i
].
urb
=
urb
;
Trace
(
TRACE_MEMORY
,
"Allocated URB at 0x%p
\n
"
,
urb
);
}
if
(
ret
)
{
/* De-allocate in reverse order */
while
(
i
>=
0
)
{
if
(
pdev
->
sbuf
[
i
].
urb
!=
NULL
)
usb_free_urb
(
pdev
->
sbuf
[
i
].
urb
);
pdev
->
sbuf
[
i
].
urb
=
NULL
;
i
--
;
}
return
ret
;
}
/* init URB structure */
for
(
i
=
0
;
i
<
MAX_ISO_BUFS
;
i
++
)
{
urb
=
pdev
->
sbuf
[
i
].
urb
;
urb
->
interval
=
1
;
// devik
urb
->
dev
=
udev
;
urb
->
pipe
=
usb_rcvisocpipe
(
udev
,
pdev
->
vendpoint
);
urb
->
transfer_flags
=
URB_ISO_ASAP
;
urb
->
transfer_buffer
=
pdev
->
sbuf
[
i
].
data
;
urb
->
transfer_buffer_length
=
ISO_BUFFER_SIZE
;
urb
->
complete
=
pwc_isoc_handler
;
urb
->
context
=
pdev
;
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
*
ISO_MAX_FRAME_SIZE
;
urb
->
iso_frame_desc
[
j
].
length
=
pdev
->
vmax_packet_size
;
}
}
/* link */
for
(
i
=
0
;
i
<
MAX_ISO_BUFS
;
i
++
)
{
ret
=
usb_submit_urb
(
pdev
->
sbuf
[
i
].
urb
,
GFP_KERNEL
);
if
(
ret
)
Err
(
"isoc_init() submit_urb %d failed with error %d
\n
"
,
i
,
ret
);
else
Trace
(
TRACE_MEMORY
,
"URB 0x%p submitted.
\n
"
,
pdev
->
sbuf
[
i
].
urb
);
}
/* All is done... */
pdev
->
iso_init
=
1
;
Trace
(
TRACE_OPEN
,
"<< pwc_isoc_init()
\n
"
);
return
0
;
}
static
void
pwc_isoc_cleanup
(
struct
pwc_device
*
pdev
)
{
int
i
;
Trace
(
TRACE_OPEN
,
">> pwc_isoc_cleanup()
\n
"
);
if
(
pdev
==
NULL
)
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 (unplug
is signalled by EPIPE)
*/
if
(
pdev
->
error_status
&&
pdev
->
error_status
!=
EPIPE
)
{
Trace
(
TRACE_OPEN
,
"Setting alternate interface 0.
\n
"
);
usb_set_interface
(
pdev
->
udev
,
0
,
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
ret
,
start
;
/* Stop isoc stuff */
pwc_isoc_cleanup
(
pdev
);
/* Reset parameters */
pwc_reset_buffers
(
pdev
);
/* Try to set video mode... */
start
=
ret
=
pwc_set_video_mode
(
pdev
,
width
,
height
,
new_fps
,
new_compression
,
new_snapshot
);
if
(
ret
)
{
Trace
(
TRACE_FLOW
,
"pwc_set_video_mode attempt 1 failed.
\n
"
);
/* That failed... restore old mode (we know that worked) */
start
=
pwc_set_video_mode
(
pdev
,
pdev
->
view
.
x
,
pdev
->
view
.
y
,
pdev
->
vframes
,
pdev
->
vcompression
,
pdev
->
vsnapshot
);
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 */
return
ret
;
/* Return original error code */
}
/***************************************************************************/
/* Video4Linux functions */
static
int
pwc_video_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
int
i
;
struct
video_device
*
vdev
=
video_devdata
(
file
);
struct
pwc_device
*
pdev
;
Trace
(
TRACE_OPEN
,
">> video_open called(vdev = 0x%p).
\n
"
,
vdev
);
pdev
=
(
struct
pwc_device
*
)
vdev
->
priv
;
if
(
pdev
==
NULL
)
BUG
();
if
(
pdev
->
vopen
)
return
-
EBUSY
;
down
(
&
pdev
->
modlock
);
if
(
!
pdev
->
usb_init
)
{
Trace
(
TRACE_OPEN
,
"Doing first time initialization.
\n
"
);
pdev
->
usb_init
=
1
;
if
(
pwc_trace
&
TRACE_OPEN
)
{
/* Query sensor type */
const
char
*
sensor_type
=
NULL
;
int
ret
;
ret
=
pwc_get_cmos_sensor
(
pdev
,
&
i
);
if
(
ret
>=
0
)
{
switch
(
i
)
{
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 */
if
(
power_save
)
{
i
=
pwc_camera_power
(
pdev
,
1
);
if
(
i
<
0
)
Info
(
"Failed to restore power to the camera! (%d)
\n
"
,
i
);
}
/* Set LED on/off time */
if
(
pwc_set_leds
(
pdev
,
led_on
,
led_off
)
<
0
)
Info
(
"Failed to set LED on/off time.
\n
"
);
pdev
->
decompressor
=
NULL
;
pwc_construct
(
pdev
);
/* set min/max sizes correct */
/* So far, so good. Allocate memory. */
i
=
pwc_allocate_buffers
(
pdev
);
if
(
i
<
0
)
{
Trace
(
TRACE_OPEN
,
"Failed to allocate buffer memory.
\n
"
);
up
(
&
pdev
->
modlock
);
return
i
;
}
/* Reset buffers & parameters */
pwc_reset_buffers
(
pdev
);
for
(
i
=
0
;
i
<
default_mbufs
;
i
++
)
pdev
->
image_used
[
i
]
=
0
;
pdev
->
vframe_count
=
0
;
pdev
->
vframes_dumped
=
0
;
pdev
->
vframes_error
=
0
;
pdev
->
visoc_errors
=
0
;
pdev
->
error_status
=
0
;
#if PWC_DEBUG
pdev
->
sequence
=
0
;
#endif
pwc_construct
(
pdev
);
/* set min/max sizes correct */
/* Set some defaults */
pdev
->
vsnapshot
=
0
;
/* Start iso pipe for video; first try the last used video size
(or the default one); if that fails try QCIF/10 or QSIF/10;
it that fails too, give up.
*/
i
=
pwc_set_video_mode
(
pdev
,
pwc_image_sizes
[
pdev
->
vsize
].
x
,
pwc_image_sizes
[
pdev
->
vsize
].
y
,
pdev
->
vframes
,
pdev
->
vcompression
,
0
);
if
(
i
)
{
Trace
(
TRACE_OPEN
,
"First attempt at set_video_mode failed.
\n
"
);
if
(
pdev
->
type
==
730
||
pdev
->
type
==
740
||
pdev
->
type
==
750
)
i
=
pwc_set_video_mode
(
pdev
,
pwc_image_sizes
[
PSZ_QSIF
].
x
,
pwc_image_sizes
[
PSZ_QSIF
].
y
,
10
,
pdev
->
vcompression
,
0
);
else
i
=
pwc_set_video_mode
(
pdev
,
pwc_image_sizes
[
PSZ_QCIF
].
x
,
pwc_image_sizes
[
PSZ_QCIF
].
y
,
10
,
pdev
->
vcompression
,
0
);
}
if
(
i
)
{
Trace
(
TRACE_OPEN
,
"Second attempt at set_video_mode failed.
\n
"
);
up
(
&
pdev
->
modlock
);
return
i
;
}
i
=
pwc_isoc_init
(
pdev
);
if
(
i
)
{
Trace
(
TRACE_OPEN
,
"Failed to init ISOC stuff = %d.
\n
"
,
i
);
up
(
&
pdev
->
modlock
);
return
i
;
}
pdev
->
vopen
++
;
file
->
private_data
=
vdev
;
up
(
&
pdev
->
modlock
);
Trace
(
TRACE_OPEN
,
"<< video_open() returns 0.
\n
"
);
return
0
;
}
/* Note that all cleanup is done in the reverse order as in _open */
static
int
pwc_video_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
video_device
*
vdev
=
file
->
private_data
;
struct
pwc_device
*
pdev
;
int
i
;
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
"
);
/* 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
);
pwc_isoc_cleanup
(
pdev
);
pwc_free_buffers
(
pdev
);
/* Turn off LEDS and power down camera, but only when not unplugged */
if
(
pdev
->
error_status
!=
EPIPE
)
{
/* Turn LEDs off */
if
(
pwc_set_leds
(
pdev
,
0
,
0
)
<
0
)
Info
(
"Failed to set LED on/off time.
\n
"
);
if
(
power_save
)
{
i
=
pwc_camera_power
(
pdev
,
0
);
if
(
i
<
0
)
Err
(
"Failed to power down camera (%d)
\n
"
,
i
);
}
}
pdev
->
vopen
=
0
;
Trace
(
TRACE_OPEN
,
"<< video_close()
\n
"
);
return
0
;
}
/*
* FIXME: what about two parallel reads ????
* ANSWER: Not supported. You can't open the device more than once,
despite what the V4L1 interface says. First, I don't see
the need, second there's no mechanism of alerting the
2nd/3rd/... process of events like changing image size.
And I don't see the point of blocking that for the
2nd/3rd/... process.
In multi-threaded environments reading parallel from any
device is tricky anyhow.
*/
static
ssize_t
pwc_video_read
(
struct
file
*
file
,
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
video_device
*
vdev
=
file
->
private_data
;
struct
pwc_device
*
pdev
;
int
noblock
=
file
->
f_flags
&
O_NONBLOCK
;
DECLARE_WAITQUEUE
(
wait
,
current
);
int
bytes_to_read
;
Trace
(
TRACE_READ
,
"video_read(0x%p, %p, %zd) called.
\n
"
,
vdev
,
buf
,
count
);
if
(
vdev
==
NULL
)
return
-
EFAULT
;
pdev
=
vdev
->
priv
;
if
(
pdev
==
NULL
)
return
-
EFAULT
;
if
(
pdev
->
error_status
)
return
-
pdev
->
error_status
;
/* Something happened, report what. */
/* In case we're doing partial reads, we don't have to wait for a frame */
if
(
pdev
->
image_read_pos
==
0
)
{
/* Do wait queueing according to the (doc)book */
add_wait_queue
(
&
pdev
->
frameq
,
&
wait
);
while
(
pdev
->
full_frames
==
NULL
)
{
/* Check for unplugged/etc. here */
if
(
pdev
->
error_status
)
{
remove_wait_queue
(
&
pdev
->
frameq
,
&
wait
);
set_current_state
(
TASK_RUNNING
);
return
-
pdev
->
error_status
;
}
if
(
noblock
)
{
remove_wait_queue
(
&
pdev
->
frameq
,
&
wait
);
set_current_state
(
TASK_RUNNING
);
return
-
EWOULDBLOCK
;
}
if
(
signal_pending
(
current
))
{
remove_wait_queue
(
&
pdev
->
frameq
,
&
wait
);
set_current_state
(
TASK_RUNNING
);
return
-
ERESTARTSYS
;
}
schedule
();
set_current_state
(
TASK_INTERRUPTIBLE
);
}
remove_wait_queue
(
&
pdev
->
frameq
,
&
wait
);
set_current_state
(
TASK_RUNNING
);
/* Decompress and release frame */
if
(
pwc_handle_frame
(
pdev
))
return
-
EFAULT
;
}
Trace
(
TRACE_READ
,
"Copying data to user space.
\n
"
);
if
(
pdev
->
vpalette
==
VIDEO_PALETTE_RAW
)
bytes_to_read
=
pdev
->
frame_size
;
else
bytes_to_read
=
pdev
->
view
.
size
;
/* copy bytes to user space; we allow for partial reads */
if
(
count
+
pdev
->
image_read_pos
>
bytes_to_read
)
count
=
bytes_to_read
-
pdev
->
image_read_pos
;
if
(
copy_to_user
(
buf
,
pdev
->
image_ptr
[
pdev
->
fill_image
]
+
pdev
->
image_read_pos
,
count
))
return
-
EFAULT
;
pdev
->
image_read_pos
+=
count
;
if
(
pdev
->
image_read_pos
>=
bytes_to_read
)
{
/* All data has been read */
pdev
->
image_read_pos
=
0
;
pwc_next_image
(
pdev
);
}
return
count
;
}
static
unsigned
int
pwc_video_poll
(
struct
file
*
file
,
poll_table
*
wait
)
{
struct
video_device
*
vdev
=
file
->
private_data
;
struct
pwc_device
*
pdev
;
if
(
vdev
==
NULL
)
return
-
EFAULT
;
pdev
=
vdev
->
priv
;
if
(
pdev
==
NULL
)
return
-
EFAULT
;
poll_wait
(
file
,
&
pdev
->
frameq
,
wait
);
if
(
pdev
->
error_status
)
return
POLLERR
;
if
(
pdev
->
full_frames
!=
NULL
)
/* we have frames waiting */
return
(
POLLIN
|
POLLRDNORM
);
return
0
;
}
static
int
pwc_video_do_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
void
*
arg
)
{
struct
video_device
*
vdev
=
file
->
private_data
;
struct
pwc_device
*
pdev
;
DECLARE_WAITQUEUE
(
wait
,
current
);
if
(
vdev
==
NULL
)
return
-
EFAULT
;
pdev
=
vdev
->
priv
;
if
(
pdev
==
NULL
)
return
-
EFAULT
;
switch
(
cmd
)
{
/* Query cabapilities */
case
VIDIOCGCAP
:
{
struct
video_capability
*
caps
=
arg
;
strcpy
(
caps
->
name
,
vdev
->
name
);
caps
->
type
=
VID_TYPE_CAPTURE
;
caps
->
channels
=
1
;
caps
->
audios
=
1
;
caps
->
minwidth
=
pdev
->
view_min
.
x
;
caps
->
minheight
=
pdev
->
view_min
.
y
;
caps
->
maxwidth
=
pdev
->
view_max
.
x
;
caps
->
maxheight
=
pdev
->
view_max
.
y
;
break
;
}
/* Channel functions (simulate 1 channel) */
case
VIDIOCGCHAN
:
{
struct
video_channel
*
v
=
arg
;
if
(
v
->
channel
!=
0
)
return
-
EINVAL
;
v
->
flags
=
0
;
v
->
tuners
=
0
;
v
->
type
=
VIDEO_TYPE_CAMERA
;
strcpy
(
v
->
name
,
"Webcam"
);
return
0
;
}
case
VIDIOCSCHAN
:
{
/* The spec says the argument is an integer, but
the bttv driver uses a video_channel arg, which
makes sense becasue it also has the norm flag.
*/
struct
video_channel
*
v
=
arg
;
if
(
v
->
channel
!=
0
)
return
-
EINVAL
;
return
0
;
}
/* Picture functions; contrast etc. */
case
VIDIOCGPICT
:
{
struct
video_picture
*
p
=
arg
;
int
val
;
val
=
pwc_get_brightness
(
pdev
);
if
(
val
>=
0
)
p
->
brightness
=
val
;
else
p
->
brightness
=
0xffff
;
val
=
pwc_get_contrast
(
pdev
);
if
(
val
>=
0
)
p
->
contrast
=
val
;
else
p
->
contrast
=
0xffff
;
/* Gamma, Whiteness, what's the difference? :) */
val
=
pwc_get_gamma
(
pdev
);
if
(
val
>=
0
)
p
->
whiteness
=
val
;
else
p
->
whiteness
=
0xffff
;
val
=
pwc_get_saturation
(
pdev
);
if
(
val
>=
0
)
p
->
colour
=
val
;
else
p
->
colour
=
0xffff
;
p
->
depth
=
24
;
p
->
palette
=
pdev
->
vpalette
;
p
->
hue
=
0xFFFF
;
/* N/A */
break
;
}
case
VIDIOCSPICT
:
{
struct
video_picture
*
p
=
arg
;
/*
* FIXME: Suppose we are mid read
ANSWER: No problem: the firmware of the camera
can handle brightness/contrast/etc
changes at _any_ time, and the palette
is used exactly once in the uncompress
routine.
*/
pwc_set_brightness
(
pdev
,
p
->
brightness
);
pwc_set_contrast
(
pdev
,
p
->
contrast
);
pwc_set_gamma
(
pdev
,
p
->
whiteness
);
pwc_set_saturation
(
pdev
,
p
->
colour
);
if
(
p
->
palette
&&
p
->
palette
!=
pdev
->
vpalette
)
{
switch
(
p
->
palette
)
{
case
VIDEO_PALETTE_YUV420P
:
case
VIDEO_PALETTE_RAW
:
pdev
->
vpalette
=
p
->
palette
;
return
pwc_try_video_mode
(
pdev
,
pdev
->
image
.
x
,
pdev
->
image
.
y
,
pdev
->
vframes
,
pdev
->
vcompression
,
pdev
->
vsnapshot
);
break
;
default:
return
-
EINVAL
;
break
;
}
}
break
;
}
/* Window/size parameters */
case
VIDIOCGWIN
:
{
struct
video_window
*
vw
=
arg
;
vw
->
x
=
0
;
vw
->
y
=
0
;
vw
->
width
=
pdev
->
view
.
x
;
vw
->
height
=
pdev
->
view
.
y
;
vw
->
chromakey
=
0
;
vw
->
flags
=
(
pdev
->
vframes
<<
PWC_FPS_SHIFT
)
|
(
pdev
->
vsnapshot
?
PWC_FPS_SNAPSHOT
:
0
);
break
;
}
case
VIDIOCSWIN
:
{
struct
video_window
*
vw
=
arg
;
int
fps
,
snapshot
,
ret
;
fps
=
(
vw
->
flags
&
PWC_FPS_FRMASK
)
>>
PWC_FPS_SHIFT
;
snapshot
=
vw
->
flags
&
PWC_FPS_SNAPSHOT
;
if
(
fps
==
0
)
fps
=
pdev
->
vframes
;
if
(
pdev
->
view
.
x
==
vw
->
width
&&
pdev
->
view
.
y
&&
fps
==
pdev
->
vframes
&&
snapshot
==
pdev
->
vsnapshot
)
return
0
;
ret
=
pwc_try_video_mode
(
pdev
,
vw
->
width
,
vw
->
height
,
fps
,
pdev
->
vcompression
,
snapshot
);
if
(
ret
)
return
ret
;
break
;
}
/* We don't have overlay support (yet) */
case
VIDIOCGFBUF
:
{
struct
video_buffer
*
vb
=
arg
;
memset
(
vb
,
0
,
sizeof
(
*
vb
));
break
;
}
/* mmap() functions */
case
VIDIOCGMBUF
:
{
/* Tell the user program how much memory is needed for a mmap() */
struct
video_mbuf
*
vm
=
arg
;
int
i
;
memset
(
vm
,
0
,
sizeof
(
*
vm
));
vm
->
size
=
default_mbufs
*
pdev
->
len_per_image
;
vm
->
frames
=
default_mbufs
;
/* double buffering should be enough for most applications */
for
(
i
=
0
;
i
<
default_mbufs
;
i
++
)
vm
->
offsets
[
i
]
=
i
*
pdev
->
len_per_image
;
break
;
}
case
VIDIOCMCAPTURE
:
{
/* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
struct
video_mmap
*
vm
=
arg
;
Trace
(
TRACE_READ
,
"VIDIOCMCAPTURE: %dx%d, frame %d, format %d
\n
"
,
vm
->
width
,
vm
->
height
,
vm
->
frame
,
vm
->
format
);
if
(
vm
->
frame
<
0
||
vm
->
frame
>=
default_mbufs
)
return
-
EINVAL
;
/* xawtv is nasty. It probes the available palettes
by setting a very small image size and trying
various palettes... The driver doesn't support
such small images, so I'm working around it.
*/
if
(
vm
->
format
)
{
switch
(
vm
->
format
)
{
case
VIDEO_PALETTE_YUV420P
:
case
VIDEO_PALETTE_RAW
:
break
;
default:
return
-
EINVAL
;
break
;
}
}
if
((
vm
->
width
!=
pdev
->
view
.
x
||
vm
->
height
!=
pdev
->
view
.
y
)
&&
(
vm
->
width
>=
pdev
->
view_min
.
x
&&
vm
->
height
>=
pdev
->
view_min
.
y
))
{
int
ret
;
Trace
(
TRACE_OPEN
,
"VIDIOCMCAPTURE: changing size to please xawtv :-(.
\n
"
);
ret
=
pwc_try_video_mode
(
pdev
,
vm
->
width
,
vm
->
height
,
pdev
->
vframes
,
pdev
->
vcompression
,
pdev
->
vsnapshot
);
if
(
ret
)
return
ret
;
}
/* ... size mismatch */
/* FIXME: should we lock here? */
if
(
pdev
->
image_used
[
vm
->
frame
])
return
-
EBUSY
;
/* buffer wasn't available. Bummer */
pdev
->
image_used
[
vm
->
frame
]
=
1
;
/* Okay, we're done here. In the SYNC call we wait until a
frame comes available, then expand image into the given
buffer.
In contrast to the CPiA cam the Philips cams deliver a
constant stream, almost like a grabber card. Also,
we have separate buffers for the rawdata and the image,
meaning we can nearly always expand into the requested buffer.
*/
Trace
(
TRACE_READ
,
"VIDIOCMCAPTURE done.
\n
"
);
break
;
}
case
VIDIOCSYNC
:
{
/* The doc says: "Whenever a buffer is used it should
call VIDIOCSYNC to free this frame up and continue."
The only odd thing about this whole procedure is
that MCAPTURE flags the buffer as "in use", and
SYNC immediately unmarks it, while it isn't
after SYNC that you know that the buffer actually
got filled! So you better not start a CAPTURE in
the same frame immediately (use double buffering).
This is not a problem for this cam, since it has
extra intermediate buffers, but a hardware
grabber card will then overwrite the buffer
you're working on.
*/
int
*
mbuf
=
arg
;
int
ret
;
Trace
(
TRACE_READ
,
"VIDIOCSYNC called (%d).
\n
"
,
*
mbuf
);
/* bounds check */
if
(
*
mbuf
<
0
||
*
mbuf
>=
default_mbufs
)
return
-
EINVAL
;
/* check if this buffer was requested anyway */
if
(
pdev
->
image_used
[
*
mbuf
]
==
0
)
return
-
EINVAL
;
/* Add ourselves to the frame wait-queue.
FIXME: needs auditing for safety.
QUESTION: In what respect? I think that using the
frameq is safe now.
*/
add_wait_queue
(
&
pdev
->
frameq
,
&
wait
);
while
(
pdev
->
full_frames
==
NULL
)
{
if
(
pdev
->
error_status
)
{
remove_wait_queue
(
&
pdev
->
frameq
,
&
wait
);
set_current_state
(
TASK_RUNNING
);
return
-
pdev
->
error_status
;
}
if
(
signal_pending
(
current
))
{
remove_wait_queue
(
&
pdev
->
frameq
,
&
wait
);
set_current_state
(
TASK_RUNNING
);
return
-
ERESTARTSYS
;
}
schedule
();
set_current_state
(
TASK_INTERRUPTIBLE
);
}
remove_wait_queue
(
&
pdev
->
frameq
,
&
wait
);
set_current_state
(
TASK_RUNNING
);
/* The frame is ready. Expand in the image buffer
requested by the user. I don't care if you
mmap() 5 buffers and request data in this order:
buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
Grabber hardware may not be so forgiving.
*/
Trace
(
TRACE_READ
,
"VIDIOCSYNC: frame ready.
\n
"
);
pdev
->
fill_image
=
*
mbuf
;
/* tell in which buffer we want the image to be expanded */
/* Decompress, etc */
ret
=
pwc_handle_frame
(
pdev
);
pdev
->
image_used
[
*
mbuf
]
=
0
;
if
(
ret
)
return
-
EFAULT
;
break
;
}
case
VIDIOCGAUDIO
:
{
struct
video_audio
*
v
=
arg
;
strcpy
(
v
->
name
,
"Microphone"
);
v
->
audio
=
-
1
;
/* unknown audio minor */
v
->
flags
=
0
;
v
->
mode
=
VIDEO_SOUND_MONO
;
v
->
volume
=
0
;
v
->
bass
=
0
;
v
->
treble
=
0
;
v
->
balance
=
0x8000
;
v
->
step
=
1
;
break
;
}
case
VIDIOCSAUDIO
:
{
/* Dummy: nothing can be set */
break
;
}
case
VIDIOCGUNIT
:
{
struct
video_unit
*
vu
=
arg
;
vu
->
video
=
pdev
->
vdev
->
minor
&
0x3F
;
vu
->
audio
=
-
1
;
/* not known yet */
vu
->
vbi
=
-
1
;
vu
->
radio
=
-
1
;
vu
->
teletext
=
-
1
;
break
;
}
default:
return
pwc_ioctl
(
pdev
,
cmd
,
arg
);
}
/* ..switch */
return
0
;
}
static
int
pwc_video_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
return
video_usercopy
(
inode
,
file
,
cmd
,
arg
,
pwc_video_do_ioctl
);
}
static
int
pwc_video_mmap
(
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
{
struct
video_device
*
vdev
=
file
->
private_data
;
struct
pwc_device
*
pdev
;
unsigned
long
start
=
vma
->
vm_start
;
unsigned
long
size
=
vma
->
vm_end
-
vma
->
vm_start
;
unsigned
long
page
,
pos
;
Trace
(
TRACE_MEMORY
,
"mmap(0x%p, 0x%lx, %lu) called.
\n
"
,
vdev
,
start
,
size
);
pdev
=
vdev
->
priv
;
pos
=
(
unsigned
long
)
pdev
->
image_data
;
while
(
size
>
0
)
{
page
=
kvirt_to_pa
(
pos
);
if
(
remap_page_range
(
vma
,
start
,
page
,
PAGE_SIZE
,
PAGE_SHARED
))
return
-
EAGAIN
;
start
+=
PAGE_SIZE
;
pos
+=
PAGE_SIZE
;
if
(
size
>
PAGE_SIZE
)
size
-=
PAGE_SIZE
;
else
size
=
0
;
}
return
0
;
}
/***************************************************************************/
/* USB functions */
/* This function gets called when a new device is plugged in or the usb core
* is loaded.
*/
static
int
usb_pwc_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
udev
=
interface_to_usbdev
(
intf
);
struct
pwc_device
*
pdev
=
NULL
;
int
vendor_id
,
product_id
,
type_id
;
int
i
,
hint
;
int
features
=
0
;
int
video_nr
=
-
1
;
/* default: use next available device */
char
serial_number
[
30
],
*
name
;
/* 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
);
/* the interfaces are probed one by one. We are only interested in the
video interface (0) now.
Interface 1 is the Audio Control, and interface 2 Audio itself.
*/
if
(
intf
->
altsetting
->
desc
.
bInterfaceNumber
>
0
)
return
-
ENODEV
;
vendor_id
=
udev
->
descriptor
.
idVendor
;
product_id
=
udev
->
descriptor
.
idProduct
;
if
(
vendor_id
==
0x0471
)
{
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)/PCVC830 (ToUCam II) USB webcam detected.
\n
"
);
name
=
"Philips 730 webcam"
;
type_id
=
730
;
break
;
case
0x0311
:
Info
(
"Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) 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
;
case
0x0313
:
Info
(
"Philips PCVC720K/40 (ToUCam XS) USB webcam detected.
\n
"
);
name
=
"Philips 720K/40 webcam"
;
type_id
=
720
;
break
;
default:
return
-
ENODEV
;
break
;
}
}
else
if
(
vendor_id
==
0x069A
)
{
switch
(
product_id
)
{
case
0x0001
:
Info
(
"Askey VC010 type 1 USB webcam detected.
\n
"
);
name
=
"Askey VC010 webcam"
;
type_id
=
645
;
break
;
default:
return
-
ENODEV
;
break
;
}
}
else
if
(
vendor_id
==
0x046d
)
{
switch
(
product_id
)
{
case
0x08b0
:
Info
(
"Logitech QuickCam Pro 3000 USB webcam detected.
\n
"
);
name
=
"Logitech QuickCam Pro 3000"
;
type_id
=
740
;
/* CCD sensor */
break
;
case
0x08b1
:
Info
(
"Logitech QuickCam Notebook Pro USB webcam detected.
\n
"
);
name
=
"Logitech QuickCam Notebook Pro"
;
type_id
=
740
;
/* CCD 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
;
/* CCD sensor */
break
;
case
0x08B4
:
Info
(
"Logitech QuickCam Zoom (new model) USB webcam detected.
\n
"
);
name
=
"Logitech QuickCam Zoom"
;
type_id
=
740
;
/* CCD sensor */
break
;
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
0x08b7
:
case
0x08b8
:
Info
(
"Logitech QuickCam detected (reserved ID).
\n
"
);
name
=
"Logitech QuickCam (res.)"
;
type_id
=
730
;
/* Assuming CMOS */
break
;
default:
return
-
ENODEV
;
break
;
}
}
else
if
(
vendor_id
==
0x055d
)
{
/* I don't know the difference between the C10 and the C30;
I suppose the difference is the sensor, but both cameras
work equally well with a type_id of 675
*/
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:
return
-
ENODEV
;
break
;
}
}
else
if
(
vendor_id
==
0x041e
)
{
switch
(
product_id
)
{
case
0x400c
:
Info
(
"Creative Labs Webcam 5 detected.
\n
"
);
name
=
"Creative Labs Webcam 5"
;
type_id
=
730
;
break
;
case
0x4011
:
Info
(
"Creative Labs Webcam Pro Ex detected.
\n
"
);
name
=
"Creative Labs Webcam Pro Ex"
;
type_id
=
740
;
break
;
default:
return
-
ENODEV
;
break
;
}
}
else
if
(
vendor_id
==
0x04cc
)
{
switch
(
product_id
)
{
case
0x8116
:
Info
(
"Sotec Afina Eye USB webcam detected.
\n
"
);
name
=
"Sotec Afina Eye"
;
type_id
=
730
;
break
;
default:
return
-
ENODEV
;
break
;
}
}
else
if
(
vendor_id
==
0x06be
)
{
switch
(
product_id
)
{
case
0x8116
:
/* Basicly the same as the Sotec Afina Eye */
Info
(
"AME CU-001 USB webcam detected.
\n
"
);
name
=
"AME CU-001"
;
type_id
=
730
;
break
;
default:
return
-
ENODEV
;
break
;
}
}
else
if
(
vendor_id
==
0x06be
)
{
switch
(
product_id
)
{
case
0x8116
:
/* This is essentially the same cam as the Sotec Afina Eye */
Info
(
"AME Co. Afina Eye USB webcam detected.
\n
"
);
name
=
"AME Co. Afina Eye"
;
type_id
=
750
;
break
;
default:
return
-
ENODEV
;
break
;
}
}
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
);
Trace
(
TRACE_PROBE
,
"Device serial number is %s
\n
"
,
serial_number
);
if
(
udev
->
descriptor
.
bNumConfigurations
>
1
)
Info
(
"Warning: more than 1 configuration available.
\n
"
);
/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
pdev
=
kmalloc
(
sizeof
(
struct
pwc_device
),
GFP_KERNEL
);
if
(
pdev
==
NULL
)
{
Err
(
"Oops, could not allocate memory for pwc_device.
\n
"
);
return
-
ENOMEM
;
}
memset
(
pdev
,
0
,
sizeof
(
struct
pwc_device
));
pdev
->
type
=
type_id
;
pdev
->
vsize
=
default_size
;
pdev
->
vframes
=
default_fps
;
strcpy
(
pdev
->
serial
,
serial_number
);
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
;
}
init_MUTEX
(
&
pdev
->
modlock
);
pdev
->
ptrlock
=
SPIN_LOCK_UNLOCKED
;
pdev
->
udev
=
udev
;
init_waitqueue_head
(
&
pdev
->
frameq
);
pdev
->
vcompression
=
pwc_preferred_compression
;
/* Allocate video_device structure */
pdev
->
vdev
=
video_device_alloc
();
if
(
pdev
->
vdev
==
0
)
{
Err
(
"Err, cannot allocate video_device struture. Failing probe."
);
kfree
(
pdev
);
return
-
ENOMEM
;
}
memcpy
(
pdev
->
vdev
,
&
pwc_template
,
sizeof
(
pwc_template
));
strcpy
(
pdev
->
vdev
->
name
,
name
);
pdev
->
vdev
->
owner
=
THIS_MODULE
;
video_set_drvdata
(
pdev
->
vdev
,
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
))
&&
(
device_hint
[
hint
].
pdev
==
NULL
))
{
/* so far, so good... try serial number */
if
((
device_hint
[
hint
].
serial_number
[
0
]
==
'*'
)
||
!
strcmp
(
device_hint
[
hint
].
serial_number
,
serial_number
))
{
/* match! */
video_nr
=
device_hint
[
hint
].
device_node
;
Trace
(
TRACE_PROBE
,
"Found hint, will try to register as /dev/video%d
\n
"
,
video_nr
);
break
;
}
}
}
pdev
->
vdev
->
release
=
video_device_release
;
i
=
video_register_device
(
pdev
->
vdev
,
VFL_TYPE_GRABBER
,
video_nr
);
if
(
i
<
0
)
{
Err
(
"Failed to register as video device (%d).
\n
"
,
i
);
video_device_release
(
pdev
->
vdev
);
/* Drip... drip... drip... */
kfree
(
pdev
);
/* Oops, no memory leaks please */
return
-
EIO
;
}
else
{
Info
(
"Registered as /dev/video%d.
\n
"
,
pdev
->
vdev
->
minor
&
0x3F
);
}
/* occupy slot */
if
(
hint
<
MAX_DEV_HINTS
)
device_hint
[
hint
].
pdev
=
pdev
;
Trace
(
TRACE_PROBE
,
"probe() function returning struct at 0x%p.
\n
"
,
pdev
);
usb_set_intfdata
(
intf
,
pdev
);
return
0
;
}
/* The user janked out the cable... */
static
void
usb_pwc_disconnect
(
struct
usb_interface
*
intf
)
{
struct
pwc_device
*
pdev
;
int
hint
;
lock_kernel
();
pdev
=
usb_get_intfdata
(
intf
);
usb_set_intfdata
(
intf
,
NULL
);
if
(
pdev
==
NULL
)
{
Err
(
"pwc_disconnect() Called without private pointer.
\n
"
);
goto
disconnect_out
;
}
if
(
pdev
->
udev
==
NULL
)
{
Err
(
"pwc_disconnect() already called for %p
\n
"
,
pdev
);
goto
disconnect_out
;
}
if
(
pdev
->
udev
!=
interface_to_usbdev
(
intf
))
{
Err
(
"pwc_disconnect() Woops: pointer mismatch udev/pdev.
\n
"
);
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
disconnect_out
;
}
#endif
/* We got unplugged; this is signalled by an EPIPE error code */
if
(
pdev
->
vopen
)
{
Info
(
"Disconnected while webcam is in use!
\n
"
);
pdev
->
error_status
=
EPIPE
;
}
/* Alert waiting processes */
wake_up_interruptible
(
&
pdev
->
frameq
);
/* Wait until device is closed */
while
(
pdev
->
vopen
)
schedule
();
/* Device is now closed, so we can safely unregister it */
Trace
(
TRACE_PROBE
,
"Unregistering video device in disconnect().
\n
"
);
video_unregister_device
(
pdev
->
vdev
);
/* Free memory (don't set pdev to 0 just yet) */
kfree
(
pdev
);
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
;
unlock_kernel
();
}
/* *grunt* We have to do atoi ourselves :-( */
static
int
pwc_atoi
(
const
char
*
s
)
{
int
k
=
0
;
k
=
0
;
while
(
*
s
!=
'\0'
&&
*
s
>=
'0'
&&
*
s
<=
'9'
)
{
k
=
10
*
k
+
(
*
s
-
'0'
);
s
++
;
}
return
k
;
}
/*
* Initialization code & module stuff
*/
static
char
size
[
PSZ_MAX
];
static
int
fps
=
0
;
static
int
fbufs
=
0
;
static
int
mbufs
=
0
;
static
int
trace
=
-
1
;
static
int
compression
=
-
1
;
static
char
*
dev_hint
[
MAX_DEV_HINTS
]
=
{
};
module_param_string
(
size
,
size
,
PSZ_MAX
,
0
);
MODULE_PARM_DESC
(
size
,
"Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"
);
module_param
(
fps
,
int
,
0
);
MODULE_PARM_DESC
(
fps
,
"Initial frames per second. Varies with model, useful range 5-30"
);
module_param
(
fbufs
,
int
,
0
);
MODULE_PARM_DESC
(
fbufs
,
"Number of internal frame buffers to reserve"
);
module_param
(
mbufs
,
int
,
0
);
MODULE_PARM_DESC
(
mbufs
,
"Number of external (mmap()ed) image buffers"
);
module_param
(
trace
,
int
,
0
);
MODULE_PARM_DESC
(
trace
,
"For debugging purposes"
);
module_param
(
power_save
,
int
,
0
);
MODULE_PARM_DESC
(
power_save
,
"Turn power save feature in camera on or off"
);
module_param
(
compression
,
int
,
0
);
MODULE_PARM_DESC
(
compression
,
"Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"
);
module_param
(
led_on
,
int
,
0
);
MODULE_PARM_DESC
(
led_on
,
"LED on time in milliseconds"
);
module_param
(
led_off
,
int
,
0
);
MODULE_PARM_DESC
(
led_off
,
"LED off time in milliseconds"
);
/* Commented out, as you should be using udev instead of crud like this... */
/* MODULE_PARM(dev_hint, "0-20s"); */
/* MODULE_PARM_DESC(dev_hint, "Device node hints"); */
MODULE_DESCRIPTION
(
"Philips & OEM USB webcam driver"
);
MODULE_AUTHOR
(
"Nemosoft Unv. <webcam@smcc.demon.nl>"
);
MODULE_LICENSE
(
"GPL"
);
static
int
__init
usb_pwc_init
(
void
)
{
int
i
,
sz
;
char
*
sizenames
[
PSZ_MAX
]
=
{
"sqcif"
,
"qsif"
,
"qcif"
,
"sif"
,
"cif"
,
"vga"
};
Info
(
"Philips webcam module version "
PWC_VERSION
" loaded.
\n
"
);
Info
(
"Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.
\n
"
);
Info
(
"Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,
\n
"
);
Info
(
"the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.
\n
"
);
if
(
fps
)
{
if
(
fps
<
4
||
fps
>
30
)
{
Err
(
"Framerate out of bounds (4-30).
\n
"
);
return
-
EINVAL
;
}
default_fps
=
fps
;
Info
(
"Default framerate set to %d.
\n
"
,
default_fps
);
}
if
(
strlen
(
size
))
{
/* string; try matching with array */
for
(
sz
=
0
;
sz
<
PSZ_MAX
;
sz
++
)
{
if
(
!
strcmp
(
sizenames
[
sz
],
size
))
{
/* Found! */
default_size
=
sz
;
break
;
}
}
if
(
sz
==
PSZ_MAX
)
{
Err
(
"Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].
\n
"
);
return
-
EINVAL
;
}
Info
(
"Default image size set to %s [%dx%d].
\n
"
,
sizenames
[
default_size
],
pwc_image_sizes
[
default_size
].
x
,
pwc_image_sizes
[
default_size
].
y
);
}
if
(
mbufs
)
{
if
(
mbufs
<
1
||
mbufs
>
MAX_IMAGES
)
{
Err
(
"Illegal number of mmap() buffers; use a number between 1 and %d.
\n
"
,
MAX_IMAGES
);
return
-
EINVAL
;
}
default_mbufs
=
mbufs
;
Info
(
"Number of image buffers set to %d.
\n
"
,
default_mbufs
);
}
if
(
fbufs
)
{
if
(
fbufs
<
2
||
fbufs
>
MAX_FRAMES
)
{
Err
(
"Illegal number of frame buffers; use a number between 2 and %d.
\n
"
,
MAX_FRAMES
);
return
-
EINVAL
;
}
default_fbufs
=
fbufs
;
Info
(
"Number of frame buffers set to %d.
\n
"
,
default_fbufs
);
}
if
(
trace
>=
0
)
{
Info
(
"Trace options: 0x%04x
\n
"
,
trace
);
pwc_trace
=
trace
;
}
if
(
compression
>=
0
)
{
if
(
compression
>
3
)
{
Err
(
"Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).
\n
"
);
return
-
EINVAL
;
}
pwc_preferred_compression
=
compression
;
Info
(
"Preferred compression set to %d.
\n
"
,
pwc_preferred_compression
);
}
if
(
power_save
)
Info
(
"Enabling power save on open/close.
\n
"
);
/* Big device node whoopla. Basicly, it allows you to assign a
device node (/dev/videoX) to a camera, based on its type
& serial number. The format is [type[.serialnumber]:]node.
Any camera that isn't matched by these rules gets the next
available free device node.
*/
for
(
i
=
0
;
i
<
MAX_DEV_HINTS
;
i
++
)
{
char
*
s
,
*
colon
,
*
dot
;
/* This loop also initializes the array */
device_hint
[
i
].
pdev
=
NULL
;
s
=
dev_hint
[
i
];
if
(
s
!=
NULL
&&
*
s
!=
'\0'
)
{
device_hint
[
i
].
type
=
-
1
;
/* wildcard */
strcpy
(
device_hint
[
i
].
serial_number
,
"*"
);
/* parse string: chop at ':' & '/' */
colon
=
dot
=
s
;
while
(
*
colon
!=
'\0'
&&
*
colon
!=
':'
)
colon
++
;
while
(
*
dot
!=
'\0'
&&
*
dot
!=
'.'
)
dot
++
;
/* Few sanity checks */
if
(
*
dot
!=
'\0'
&&
dot
>
colon
)
{
Err
(
"Malformed camera hint: the colon must be after the dot.
\n
"
);
return
-
EINVAL
;
}
if
(
*
colon
==
'\0'
)
{
/* No colon */
if
(
*
dot
!=
'\0'
)
{
Err
(
"Malformed camera hint: no colon + device node given.
\n
"
);
return
-
EINVAL
;
}
else
{
/* No type or serial number specified, just a number. */
device_hint
[
i
].
device_node
=
pwc_atoi
(
s
);
}
}
else
{
/* There's a colon, so we have at least a type and a device node */
device_hint
[
i
].
type
=
pwc_atoi
(
s
);
device_hint
[
i
].
device_node
=
pwc_atoi
(
colon
+
1
);
if
(
*
dot
!=
'\0'
)
{
/* There's a serial number as well */
int
k
;
dot
++
;
k
=
0
;
while
(
*
dot
!=
':'
&&
k
<
29
)
{
device_hint
[
i
].
serial_number
[
k
++
]
=
*
dot
;
dot
++
;
}
device_hint
[
i
].
serial_number
[
k
]
=
'\0'
;
}
}
#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
);
Debug
(
" node : %d
\n
"
,
device_hint
[
i
].
device_node
);
#endif
}
else
device_hint
[
i
].
type
=
0
;
/* not filled */
}
/* ..for MAX_DEV_HINTS */
Trace
(
TRACE_PROBE
,
"Registering driver at address 0x%p.
\n
"
,
&
pwc_driver
);
return
usb_register
(
&
pwc_driver
);
}
static
void
__exit
usb_pwc_exit
(
void
)
{
Trace
(
TRACE_MODULE
,
"Deregistering driver.
\n
"
);
usb_deregister
(
&
pwc_driver
);
Info
(
"Philips webcam module removed.
\n
"
);
}
module_init
(
usb_pwc_init
);
module_exit
(
usb_pwc_exit
);
drivers/usb/media/pwc-ioctl.h
deleted
100644 → 0
View file @
0335cce0
#ifndef PWC_IOCTL_H
#define PWC_IOCTL_H
/* (C) 2001-2004 Nemosoft Unv. webcam@smcc.demon.nl
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This is pwc-ioctl.h belonging to PWC 8.12.1
It contains structures and defines to communicate from user space
directly to the driver.
*/
/*
Changes
2001/08/03 Alvarado Added ioctl constants to access methods for
changing white balance and red/blue gains
2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE
2003/12/13 Nemosft Unv. Some modifications to make interfacing to
PWCX easier
*/
/* These are private ioctl() commands, specific for the Philips webcams.
They contain functions not found in other webcams, and settings not
specified in the Video4Linux API.
The #define names are built up like follows:
VIDIOC VIDeo IOCtl prefix
PWC Philps WebCam
G optional: Get
S optional: Set
... the function
*/
/* Enumeration of image sizes */
#define PSZ_SQCIF 0x00
#define PSZ_QSIF 0x01
#define PSZ_QCIF 0x02
#define PSZ_SIF 0x03
#define PSZ_CIF 0x04
#define PSZ_VGA 0x05
#define PSZ_MAX 6
/* The frame rate is encoded in the video_window.flags parameter using
the upper 16 bits, since some flags are defined nowadays. The following
defines provide a mask and shift to filter out this value.
In 'Snapshot' mode the camera freezes its automatic exposure and colour
balance controls.
*/
#define PWC_FPS_SHIFT 16
#define PWC_FPS_MASK 0x00FF0000
#define PWC_FPS_FRMASK 0x003F0000
#define PWC_FPS_SNAPSHOT 0x00400000
/* structure for transfering x & y coordinates */
struct
pwc_coord
{
int
x
,
y
;
/* guess what */
int
size
;
/* size, or offset */
};
/* Used with VIDIOCPWCPROBE */
struct
pwc_probe
{
char
name
[
32
];
int
type
;
};
struct
pwc_serial
{
char
serial
[
30
];
/* String with serial number. Contains terminating 0 */
};
/* pwc_whitebalance.mode values */
#define PWC_WB_INDOOR 0
#define PWC_WB_OUTDOOR 1
#define PWC_WB_FL 2
#define PWC_WB_MANUAL 3
#define PWC_WB_AUTO 4
/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
Set mode to one of the PWC_WB_* values above.
*red and *blue are the respective gains of these colour components inside
the camera; range 0..65535
When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read;
otherwise undefined.
'read_red' and 'read_blue' are read-only.
*/
struct
pwc_whitebalance
{
int
mode
;
int
manual_red
,
manual_blue
;
/* R/W */
int
read_red
,
read_blue
;
/* R/O */
};
/*
'control_speed' and 'control_delay' are used in automatic whitebalance mode,
and tell the camera how fast it should react to changes in lighting, and
with how much delay. Valid values are 0..65535.
*/
struct
pwc_wb_speed
{
int
control_speed
;
int
control_delay
;
};
/* Used with VIDIOCPWC[SG]LED */
struct
pwc_leds
{
int
led_on
;
/* Led on-time; range = 0..25000 */
int
led_off
;
/* Led off-time; range = 0..25000 */
};
/* Image size (used with GREALSIZE) */
struct
pwc_imagesize
{
int
width
;
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 != 0, 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 */
};
/* Range of angles of the camera, both horizontally and vertically.
*/
struct
pwc_mpt_range
{
int
pan_min
,
pan_max
;
/* degrees * 100 */
int
tilt_min
,
tilt_max
;
};
struct
pwc_mpt_status
{
int
status
;
int
time_pan
;
int
time_tilt
;
};
/* This is used for out-of-kernel decompression. With it, you can get
all the necessary information to initialize and use the decompressor
routines in standalone applications.
*/
struct
pwc_video_command
{
int
type
;
/* camera type (645, 675, 730, etc.) */
int
release
;
/* release number */
int
size
;
/* one of PSZ_* */
int
alternate
;
int
command_len
;
/* length of USB video command */
unsigned
char
command_buf
[
13
];
/* Actual USB video command */
int
bandlength
;
/* >0 = compressed */
int
frame_size
;
/* Size of one (un)compressed frame */
};
/* Flags for PWCX subroutines. Not all modules honour all flags. */
#define PWCX_FLAG_PLANAR 0x0001
#define PWCX_FLAG_BAYER 0x0008
/* IOCTL definitions */
/* Restore user settings */
#define VIDIOCPWCRUSER _IO('v', 192)
/* Save user settings */
#define VIDIOCPWCSUSER _IO('v', 193)
/* Restore factory settings */
#define VIDIOCPWCFACTORY _IO('v', 194)
/* You can manipulate the compression factor. A compression preference of 0
means use uncompressed modes when available; 1 is low compression, 2 is
medium and 3 is high compression preferred. Of course, the higher the
compression, the lower the bandwidth used but more chance of artefacts
in the image. The driver automatically chooses a higher compression when
the preferred mode is not available.
*/
/* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
#define VIDIOCPWCSCQUAL _IOW('v', 195, int)
/* Get preferred compression quality */
#define VIDIOCPWCGCQUAL _IOR('v', 195, int)
/* Retrieve serial number of camera */
#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial)
/* This is a probe function; since so many devices are supported, it
becomes difficult to include all the names in programs that want to
check for the enhanced Philips stuff. So in stead, try this PROBE;
it returns a structure with the original name, and the corresponding
Philips type.
To use, fill the structure with zeroes, call PROBE and if that succeeds,
compare the name with that returned from VIDIOCGCAP; they should be the
same. If so, you can be assured it is a Philips (OEM) cam and the type
is valid.
*/
#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe)
/* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
#define VIDIOCPWCSAGC _IOW('v', 200, int)
/* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
#define VIDIOCPWCGAGC _IOR('v', 200, int)
/* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
#define VIDIOCPWCSSHUTTER _IOW('v', 201, int)
/* Color compensation (Auto White Balance) */
#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance)
#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance)
/* Auto WB speed */
#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed)
#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed)
/* LEDs on/off/blink; int range 0..65535 */
#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds)
#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds)
/* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
#define VIDIOCPWCSCONTOUR _IOW('v', 206, int)
#define VIDIOCPWCGCONTOUR _IOR('v', 206, int)
/* Backlight compensation; 0 = off, otherwise on */
#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int)
#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int)
/* Flickerless mode; = 0 off, otherwise on */
#define VIDIOCPWCSFLICKER _IOW('v', 208, int)
#define VIDIOCPWCGFLICKER _IOR('v', 208, int)
/* Dynamic noise reduction; 0 off, 3 = high noise reduction */
#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int)
#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int)
/* 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)
/* 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)
/* Get the USB set-video command; needed for initializing libpwcx */
#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command)
#endif
drivers/usb/media/pwc-misc.c
deleted
100644 → 0
View file @
0335cce0
/* Linux driver for Philips webcam
Various miscellaneous functions and tables.
(C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl)
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/slab.h>
#include "pwc.h"
struct
pwc_coord
pwc_image_sizes
[
PSZ_MAX
]
=
{
{
128
,
96
,
0
},
{
160
,
120
,
0
},
{
176
,
144
,
0
},
{
320
,
240
,
0
},
{
352
,
288
,
0
},
{
640
,
480
,
0
},
};
/* x,y -> PSZ_ */
int
pwc_decode_size
(
struct
pwc_device
*
pdev
,
int
width
,
int
height
)
{
int
i
,
find
;
/* Make sure we don't go beyond our max size.
NB: we have different limits for RAW and normal modes. In case
you don't have the decompressor loaded or use RAW mode,
the maximum viewable size is smaller.
*/
if
(
pdev
->
vpalette
==
VIDEO_PALETTE_RAW
)
{
if
(
width
>
pdev
->
abs_max
.
x
||
height
>
pdev
->
abs_max
.
y
)
{
Debug
(
"VIDEO_PALETTE_RAW: going beyond abs_max.
\n
"
);
return
-
1
;
}
}
else
{
if
(
width
>
pdev
->
view_max
.
x
||
height
>
pdev
->
view_max
.
y
)
{
Debug
(
"VIDEO_PALETTE_ not RAW: going beyond view_max.
\n
"
);
return
-
1
;
}
}
/* Find the largest size supported by the camera that fits into the
requested size.
*/
find
=
-
1
;
for
(
i
=
0
;
i
<
PSZ_MAX
;
i
++
)
{
if
(
pdev
->
image_mask
&
(
1
<<
i
))
{
if
(
pwc_image_sizes
[
i
].
x
<=
width
&&
pwc_image_sizes
[
i
].
y
<=
height
)
find
=
i
;
}
}
return
find
;
}
/* initialize variables depending on type and decompressor*/
void
pwc_construct
(
struct
pwc_device
*
pdev
)
{
switch
(
pdev
->
type
)
{
case
645
:
case
646
:
pdev
->
view_min
.
x
=
128
;
pdev
->
view_min
.
y
=
96
;
pdev
->
view_max
.
x
=
352
;
pdev
->
view_max
.
y
=
288
;
pdev
->
abs_max
.
x
=
352
;
pdev
->
abs_max
.
y
=
288
;
pdev
->
image_mask
=
1
<<
PSZ_SQCIF
|
1
<<
PSZ_QCIF
|
1
<<
PSZ_CIF
;
pdev
->
vcinterface
=
2
;
pdev
->
vendpoint
=
4
;
pdev
->
frame_header_size
=
0
;
pdev
->
frame_trailer_size
=
0
;
break
;
case
675
:
case
680
:
case
690
:
pdev
->
view_min
.
x
=
128
;
pdev
->
view_min
.
y
=
96
;
/* Anthill bug #38: PWC always reports max size, even without PWCX */
if
(
pdev
->
decompressor
!=
NULL
)
{
pdev
->
view_max
.
x
=
640
;
pdev
->
view_max
.
y
=
480
;
}
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
|
1
<<
PSZ_VGA
;
pdev
->
abs_max
.
x
=
640
;
pdev
->
abs_max
.
y
=
480
;
pdev
->
vcinterface
=
3
;
pdev
->
vendpoint
=
4
;
pdev
->
frame_header_size
=
0
;
pdev
->
frame_trailer_size
=
0
;
break
;
case
720
:
case
730
:
case
740
:
case
750
:
pdev
->
view_min
.
x
=
160
;
pdev
->
view_min
.
y
=
120
;
/* Anthill bug #38: PWC always reports max size, even without PWCX */
if
(
pdev
->
decompressor
!=
NULL
)
{
pdev
->
view_max
.
x
=
640
;
pdev
->
view_max
.
y
=
480
;
}
else
{
/* We use CIF, not SIF since some tools really need CIF. So we cheat a bit. */
pdev
->
view_max
.
x
=
352
;
pdev
->
view_max
.
y
=
288
;
}
pdev
->
image_mask
=
1
<<
PSZ_QSIF
|
1
<<
PSZ_SIF
|
1
<<
PSZ_VGA
;
pdev
->
abs_max
.
x
=
640
;
pdev
->
abs_max
.
y
=
480
;
pdev
->
vcinterface
=
3
;
pdev
->
vendpoint
=
5
;
pdev
->
frame_header_size
=
TOUCAM_HEADER_SIZE
;
pdev
->
frame_trailer_size
=
TOUCAM_TRAILER_SIZE
;
break
;
}
pdev
->
vpalette
=
VIDEO_PALETTE_YUV420P
;
/* default */
pdev
->
view_min
.
size
=
pdev
->
view_min
.
x
*
pdev
->
view_min
.
y
;
pdev
->
view_max
.
size
=
pdev
->
view_max
.
x
*
pdev
->
view_max
.
y
;
/* length of image, in YUV format; always allocate enough memory. */
pdev
->
len_per_image
=
(
pdev
->
abs_max
.
x
*
pdev
->
abs_max
.
y
*
3
)
/
2
;
}
drivers/usb/media/pwc.h
deleted
100644 → 0
View file @
0335cce0
/* (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl)
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PWC_H
#define PWC_H
#include <linux/version.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/spinlock.h>
#include <linux/videodev.h>
#include <linux/wait.h>
#include <linux/smp_lock.h>
#include <asm/semaphore.h>
#include <asm/errno.h>
#include "pwc-ioctl.h"
/* Defines and structures for the Philips webcam */
/* Used for checking memory corruption/pointer validation */
#define PWC_MAGIC 0x89DC10ABUL
#undef PWC_MAGIC
/* Turn some debugging options on/off */
#define PWC_DEBUG 0
/* Trace certain actions in the driver */
#define TRACE_MODULE 0x0001
#define TRACE_PROBE 0x0002
#define TRACE_OPEN 0x0004
#define TRACE_READ 0x0008
#define TRACE_MEMORY 0x0010
#define TRACE_FLOW 0x0020
#define TRACE_SIZE 0x0040
#define TRACE_PWCX 0x0080
#define TRACE_SEQUENCE 0x1000
#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
#define Info(A...) printk(KERN_INFO PWC_NAME " " A)
#define Err(A...) printk(KERN_ERR PWC_NAME " " A)
/* Defines for ToUCam cameras */
#define TOUCAM_HEADER_SIZE 8
#define TOUCAM_TRAILER_SIZE 4
#define FEATURE_MOTOR_PANTILT 0x0001
/* Version block */
#define PWC_MAJOR 9
#define PWC_MINOR 0
#define PWC_VERSION "9.0.1"
#define PWC_NAME "pwc"
/* Turn certain features on/off */
#define PWC_INT_PIPE 0
/* Ignore errors in the first N frames, to allow for startup delays */
#define FRAME_LOWMARK 5
/* Size and number of buffers for the ISO pipe. */
#define MAX_ISO_BUFS 2
#define ISO_FRAMES_PER_DESC 10
#define ISO_MAX_FRAME_SIZE 960
#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
/* Frame buffers: contains compressed or uncompressed video data. */
#define MAX_FRAMES 5
/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */
#define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE)
/* Absolute maximum number of buffers available for mmap() */
#define MAX_IMAGES 10
/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
struct
pwc_iso_buf
{
void
*
data
;
int
length
;
int
read
;
struct
urb
*
urb
;
};
/* intermediate buffers with raw data from the USB cam */
struct
pwc_frame_buf
{
void
*
data
;
volatile
int
filled
;
/* number of bytes filled */
struct
pwc_frame_buf
*
next
;
/* list */
#if PWC_DEBUG
int
sequence
;
/* Sequence number */
#endif
};
struct
pwc_device
{
struct
video_device
*
vdev
;
#ifdef PWC_MAGIC
int
magic
;
#endif
/* Pointer to our usb_device */
struct
usb_device
*
udev
;
int
type
;
/* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
int
release
;
/* release number */
int
features
;
/* feature bits */
char
serial
[
30
];
/* serial number (string) */
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 */
/*** Video data ***/
int
vopen
;
/* flag */
int
vendpoint
;
/* video isoc endpoint */
int
vcinterface
;
/* video control interface */
int
valternate
;
/* alternate interface needed */
int
vframes
,
vsize
;
/* frames-per-second & size (see PSZ_*) */
int
vpalette
;
/* palette: 420P, RAW or RGBBAYER */
int
vframe_count
;
/* received frames */
int
vframes_dumped
;
/* counter for dumped frames */
int
vframes_error
;
/* frames received in error */
int
vmax_packet_size
;
/* USB maxpacket size */
int
vlast_packet_size
;
/* for frame synchronisation */
int
visoc_errors
;
/* number of contiguous ISOC errors */
int
vcompression
;
/* desired compression factor */
int
vbandlength
;
/* compressed band length; 0 is uncompressed */
char
vsnapshot
;
/* snapshot mode */
char
vsync
;
/* used by isoc handler */
char
vmirror
;
/* for ToUCaM series */
int
cmd_len
;
unsigned
char
cmd_buf
[
13
];
/* The image acquisition requires 3 to 4 steps:
1. data is gathered in short packets from the USB controller
2. data is synchronized and packed into a frame buffer
3a. in case data is compressed, decompress it directly into image buffer
3b. in case data is uncompressed, copy into image buffer with viewport
4. data is transferred to the user process
Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES....
We have in effect a back-to-back-double-buffer system.
*/
/* 1: isoc */
struct
pwc_iso_buf
sbuf
[
MAX_ISO_BUFS
];
char
iso_init
;
/* 2: frame */
struct
pwc_frame_buf
*
fbuf
;
/* all frames */
struct
pwc_frame_buf
*
empty_frames
,
*
empty_frames_tail
;
/* all empty frames */
struct
pwc_frame_buf
*
full_frames
,
*
full_frames_tail
;
/* all filled frames */
struct
pwc_frame_buf
*
fill_frame
;
/* frame currently being filled */
struct
pwc_frame_buf
*
read_frame
;
/* frame currently read by user process */
int
frame_header_size
,
frame_trailer_size
;
int
frame_size
;
int
frame_total_size
;
/* including header & trailer */
int
drop_frames
;
#if PWC_DEBUG
int
sequence
;
/* Debugging aid */
#endif
/* 3: decompression */
struct
pwc_decompressor
*
decompressor
;
/* function block with decompression routines */
void
*
decompress_data
;
/* private data for decompression engine */
/* 4: image */
/* We have an 'image' and a 'view', where 'image' is the fixed-size image
as delivered by the camera, and 'view' is the size requested by the
program. The camera image is centered in this viewport, laced with
a gray or black border. view_min <= image <= view <= view_max;
*/
int
image_mask
;
/* bitmask of supported sizes */
struct
pwc_coord
view_min
,
view_max
;
/* minimum and maximum viewable sizes */
struct
pwc_coord
abs_max
;
/* maximum supported size with compression */
struct
pwc_coord
image
,
view
;
/* image and viewport size */
struct
pwc_coord
offset
;
/* offset within the viewport */
void
*
image_data
;
/* total buffer, which is subdivided into ... */
void
*
image_ptr
[
MAX_IMAGES
];
/* ...several images... */
int
fill_image
;
/* ...which are rotated. */
int
len_per_image
;
/* length per image */
int
image_read_pos
;
/* In case we read data in pieces, keep track of were we are in the imagebuffer */
int
image_used
[
MAX_IMAGES
];
/* For MCAPTURE and SYNC */
struct
semaphore
modlock
;
/* to prevent races in video_open(), etc */
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 ***/
wait_queue_head_t
frameq
;
/* When waiting for a frame to finish... */
#if PWC_INT_PIPE
void
*
usb_int_handler
;
/* for the interrupt endpoint */
#endif
};
#ifdef __cplusplus
extern
"C"
{
#endif
/* Global variables */
extern
int
pwc_trace
;
extern
int
pwc_preferred_compression
;
/** functions in pwc-if.c */
int
pwc_try_video_mode
(
struct
pwc_device
*
pdev
,
int
width
,
int
height
,
int
new_fps
,
int
new_compression
,
int
new_snapshot
);
/** Functions in pwc-misc.c */
/* sizes in pixels */
extern
struct
pwc_coord
pwc_image_sizes
[
PSZ_MAX
];
int
pwc_decode_size
(
struct
pwc_device
*
pdev
,
int
width
,
int
height
);
void
pwc_construct
(
struct
pwc_device
*
pdev
);
/** Functions in pwc-ctrl.c */
/* Request a certain video mode. Returns < 0 if not possible */
extern
int
pwc_set_video_mode
(
struct
pwc_device
*
pdev
,
int
width
,
int
height
,
int
frames
,
int
compression
,
int
snapshot
);
/* Calculate the number of bytes per image (not frame) */
extern
void
pwc_set_image_buffer_size
(
struct
pwc_device
*
pdev
);
/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
extern
int
pwc_get_brightness
(
struct
pwc_device
*
pdev
);
extern
int
pwc_set_brightness
(
struct
pwc_device
*
pdev
,
int
value
);
extern
int
pwc_get_contrast
(
struct
pwc_device
*
pdev
);
extern
int
pwc_set_contrast
(
struct
pwc_device
*
pdev
,
int
value
);
extern
int
pwc_get_gamma
(
struct
pwc_device
*
pdev
);
extern
int
pwc_set_gamma
(
struct
pwc_device
*
pdev
,
int
value
);
extern
int
pwc_get_saturation
(
struct
pwc_device
*
pdev
);
extern
int
pwc_set_saturation
(
struct
pwc_device
*
pdev
,
int
value
);
extern
int
pwc_set_leds
(
struct
pwc_device
*
pdev
,
int
on_value
,
int
off_value
);
extern
int
pwc_get_leds
(
struct
pwc_device
*
pdev
,
int
*
on_value
,
int
*
off_value
);
extern
int
pwc_get_cmos_sensor
(
struct
pwc_device
*
pdev
,
int
*
sensor
);
/* Power down or up the camera; not supported by all models */
extern
int
pwc_camera_power
(
struct
pwc_device
*
pdev
,
int
power
);
/* Private ioctl()s; see pwc-ioctl.h */
extern
int
pwc_ioctl
(
struct
pwc_device
*
pdev
,
unsigned
int
cmd
,
void
*
arg
);
#ifdef __cplusplus
}
#endif
#endif
drivers/usb/media/pwc_kiara.h
deleted
100644 → 0
View file @
0335cce0
/* SQCIF */
{
/* 5 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 10 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 15 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 20 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 25 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 30 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
},
/* QSIF */
{
/* 5 fps */
{
{
1
,
146
,
0
,
{
0x1D
,
0xF4
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x92
,
0x00
,
0x80
}},
{
1
,
146
,
0
,
{
0x1D
,
0xF4
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x92
,
0x00
,
0x80
}},
{
1
,
146
,
0
,
{
0x1D
,
0xF4
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x92
,
0x00
,
0x80
}},
{
1
,
146
,
0
,
{
0x1D
,
0xF4
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x92
,
0x00
,
0x80
}},
},
/* 10 fps */
{
{
2
,
291
,
0
,
{
0x1C
,
0xF4
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x23
,
0x01
,
0x80
}},
{
1
,
192
,
630
,
{
0x14
,
0xF4
,
0x30
,
0x13
,
0xA9
,
0x12
,
0xE1
,
0x17
,
0x08
,
0xC0
,
0x00
,
0x80
}},
{
1
,
192
,
630
,
{
0x14
,
0xF4
,
0x30
,
0x13
,
0xA9
,
0x12
,
0xE1
,
0x17
,
0x08
,
0xC0
,
0x00
,
0x80
}},
{
1
,
192
,
630
,
{
0x14
,
0xF4
,
0x30
,
0x13
,
0xA9
,
0x12
,
0xE1
,
0x17
,
0x08
,
0xC0
,
0x00
,
0x80
}},
},
/* 15 fps */
{
{
3
,
437
,
0
,
{
0x1B
,
0xF4
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0xB5
,
0x01
,
0x80
}},
{
2
,
292
,
640
,
{
0x13
,
0xF4
,
0x30
,
0x13
,
0xF7
,
0x13
,
0x2F
,
0x13
,
0x20
,
0x24
,
0x01
,
0x80
}},
{
2
,
292
,
640
,
{
0x13
,
0xF4
,
0x30
,
0x13
,
0xF7
,
0x13
,
0x2F
,
0x13
,
0x20
,
0x24
,
0x01
,
0x80
}},
{
1
,
192
,
420
,
{
0x13
,
0xF4
,
0x30
,
0x0D
,
0x1B
,
0x0C
,
0x53
,
0x1E
,
0x18
,
0xC0
,
0x00
,
0x80
}},
},
/* 20 fps */
{
{
4
,
589
,
0
,
{
0x1A
,
0xF4
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x4D
,
0x02
,
0x80
}},
{
3
,
448
,
730
,
{
0x12
,
0xF4
,
0x30
,
0x16
,
0xC9
,
0x16
,
0x01
,
0x0E
,
0x18
,
0xC0
,
0x01
,
0x80
}},
{
2
,
292
,
476
,
{
0x12
,
0xF4
,
0x30
,
0x0E
,
0xD8
,
0x0E
,
0x10
,
0x19
,
0x18
,
0x24
,
0x01
,
0x80
}},
{
1
,
192
,
312
,
{
0x12
,
0xF4
,
0x50
,
0x09
,
0xB3
,
0x08
,
0xEB
,
0x1E
,
0x18
,
0xC0
,
0x00
,
0x80
}},
},
/* 25 fps */
{
{
5
,
703
,
0
,
{
0x19
,
0xF4
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0xBF
,
0x02
,
0x80
}},
{
3
,
447
,
610
,
{
0x11
,
0xF4
,
0x30
,
0x13
,
0x0B
,
0x12
,
0x43
,
0x14
,
0x28
,
0xBF
,
0x01
,
0x80
}},
{
2
,
292
,
398
,
{
0x11
,
0xF4
,
0x50
,
0x0C
,
0x6C
,
0x0B
,
0xA4
,
0x1E
,
0x28
,
0x24
,
0x01
,
0x80
}},
{
1
,
193
,
262
,
{
0x11
,
0xF4
,
0x50
,
0x08
,
0x23
,
0x07
,
0x5B
,
0x1E
,
0x28
,
0xC1
,
0x00
,
0x80
}},
},
/* 30 fps */
{
{
8
,
874
,
0
,
{
0x18
,
0xF4
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x6A
,
0x03
,
0x80
}},
{
5
,
704
,
730
,
{
0x10
,
0xF4
,
0x30
,
0x16
,
0xC9
,
0x16
,
0x01
,
0x0E
,
0x28
,
0xC0
,
0x02
,
0x80
}},
{
3
,
448
,
492
,
{
0x10
,
0xF4
,
0x30
,
0x0F
,
0x5D
,
0x0E
,
0x95
,
0x15
,
0x28
,
0xC0
,
0x01
,
0x80
}},
{
2
,
292
,
320
,
{
0x10
,
0xF4
,
0x50
,
0x09
,
0xFB
,
0x09
,
0x33
,
0x1E
,
0x28
,
0x24
,
0x01
,
0x80
}},
},
},
/* QCIF */
{
/* 5 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 10 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 15 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 20 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 25 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 30 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
},
/* SIF */
{
/* 5 fps */
{
{
4
,
582
,
0
,
{
0x0D
,
0xF4
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x04
,
0x00
,
0x46
,
0x02
,
0x80
}},
{
3
,
387
,
1276
,
{
0x05
,
0xF4
,
0x30
,
0x27
,
0xD8
,
0x26
,
0x48
,
0x03
,
0x10
,
0x83
,
0x01
,
0x80
}},
{
2
,
291
,
960
,
{
0x05
,
0xF4
,
0x30
,
0x1D
,
0xF2
,
0x1C
,
0x62
,
0x04
,
0x10
,
0x23
,
0x01
,
0x80
}},
{
1
,
191
,
630
,
{
0x05
,
0xF4
,
0x50
,
0x13
,
0xA9
,
0x12
,
0x19
,
0x05
,
0x18
,
0xBF
,
0x00
,
0x80
}},
},
/* 10 fps */
{
{
0
,
},
{
6
,
775
,
1278
,
{
0x04
,
0xF4
,
0x30
,
0x27
,
0xE8
,
0x26
,
0x58
,
0x05
,
0x30
,
0x07
,
0x03
,
0x80
}},
{
3
,
447
,
736
,
{
0x04
,
0xF4
,
0x30
,
0x16
,
0xFB
,
0x15
,
0x6B
,
0x05
,
0x28
,
0xBF
,
0x01
,
0x80
}},
{
2
,
292
,
480
,
{
0x04
,
0xF4
,
0x70
,
0x0E
,
0xF9
,
0x0D
,
0x69
,
0x09
,
0x28
,
0x24
,
0x01
,
0x80
}},
},
/* 15 fps */
{
{
0
,
},
{
9
,
955
,
1050
,
{
0x03
,
0xF4
,
0x30
,
0x20
,
0xCF
,
0x1F
,
0x3F
,
0x06
,
0x48
,
0xBB
,
0x03
,
0x80
}},
{
4
,
592
,
650
,
{
0x03
,
0xF4
,
0x30
,
0x14
,
0x44
,
0x12
,
0xB4
,
0x08
,
0x30
,
0x50
,
0x02
,
0x80
}},
{
3
,
448
,
492
,
{
0x03
,
0xF4
,
0x50
,
0x0F
,
0x52
,
0x0D
,
0xC2
,
0x09
,
0x38
,
0xC0
,
0x01
,
0x80
}},
},
/* 20 fps */
{
{
0
,
},
{
9
,
958
,
782
,
{
0x02
,
0xF4
,
0x30
,
0x18
,
0x6A
,
0x16
,
0xDA
,
0x0B
,
0x58
,
0xBE
,
0x03
,
0x80
}},
{
5
,
703
,
574
,
{
0x02
,
0xF4
,
0x50
,
0x11
,
0xE7
,
0x10
,
0x57
,
0x0B
,
0x40
,
0xBF
,
0x02
,
0x80
}},
{
3
,
446
,
364
,
{
0x02
,
0xF4
,
0x90
,
0x0B
,
0x5C
,
0x09
,
0xCC
,
0x0E
,
0x38
,
0xBE
,
0x01
,
0x80
}},
},
/* 25 fps */
{
{
0
,
},
{
9
,
958
,
654
,
{
0x01
,
0xF4
,
0x30
,
0x14
,
0x66
,
0x12
,
0xD6
,
0x0B
,
0x50
,
0xBE
,
0x03
,
0x80
}},
{
6
,
776
,
530
,
{
0x01
,
0xF4
,
0x50
,
0x10
,
0x8C
,
0x0E
,
0xFC
,
0x0C
,
0x48
,
0x08
,
0x03
,
0x80
}},
{
4
,
592
,
404
,
{
0x01
,
0xF4
,
0x70
,
0x0C
,
0x96
,
0x0B
,
0x06
,
0x0B
,
0x48
,
0x50
,
0x02
,
0x80
}},
},
/* 30 fps */
{
{
0
,
},
{
9
,
957
,
526
,
{
0x00
,
0xF4
,
0x50
,
0x10
,
0x68
,
0x0E
,
0xD8
,
0x0D
,
0x58
,
0xBD
,
0x03
,
0x80
}},
{
6
,
775
,
426
,
{
0x00
,
0xF4
,
0x70
,
0x0D
,
0x48
,
0x0B
,
0xB8
,
0x0F
,
0x50
,
0x07
,
0x03
,
0x80
}},
{
4
,
590
,
324
,
{
0x00
,
0x7A
,
0x88
,
0x0A
,
0x1C
,
0x08
,
0xB4
,
0x0E
,
0x50
,
0x4E
,
0x02
,
0x80
}},
},
},
/* CIF */
{
/* 5 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 10 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 15 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 20 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 25 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 30 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
},
/* VGA */
{
/* 5 fps */
{
{
0
,
},
{
6
,
773
,
1272
,
{
0x25
,
0xF4
,
0x30
,
0x27
,
0xB6
,
0x24
,
0x96
,
0x02
,
0x30
,
0x05
,
0x03
,
0x80
}},
{
4
,
592
,
976
,
{
0x25
,
0xF4
,
0x50
,
0x1E
,
0x78
,
0x1B
,
0x58
,
0x03
,
0x30
,
0x50
,
0x02
,
0x80
}},
{
3
,
448
,
738
,
{
0x25
,
0xF4
,
0x90
,
0x17
,
0x0C
,
0x13
,
0xEC
,
0x04
,
0x30
,
0xC0
,
0x01
,
0x80
}},
},
/* 10 fps */
{
{
0
,
},
{
9
,
956
,
788
,
{
0x24
,
0xF4
,
0x70
,
0x18
,
0x9C
,
0x15
,
0x7C
,
0x03
,
0x48
,
0xBC
,
0x03
,
0x80
}},
{
6
,
776
,
640
,
{
0x24
,
0xF4
,
0xB0
,
0x13
,
0xFC
,
0x11
,
0x2C
,
0x04
,
0x48
,
0x08
,
0x03
,
0x80
}},
{
4
,
592
,
488
,
{
0x24
,
0x7A
,
0xE8
,
0x0F
,
0x3C
,
0x0C
,
0x6C
,
0x06
,
0x48
,
0x50
,
0x02
,
0x80
}},
},
/* 15 fps */
{
{
0
,
},
{
9
,
957
,
526
,
{
0x23
,
0x7A
,
0xE8
,
0x10
,
0x68
,
0x0D
,
0x98
,
0x06
,
0x58
,
0xBD
,
0x03
,
0x80
}},
{
9
,
957
,
526
,
{
0x23
,
0x7A
,
0xE8
,
0x10
,
0x68
,
0x0D
,
0x98
,
0x06
,
0x58
,
0xBD
,
0x03
,
0x80
}},
{
8
,
895
,
492
,
{
0x23
,
0x7A
,
0xE8
,
0x0F
,
0x5D
,
0x0C
,
0x8D
,
0x06
,
0x58
,
0x7F
,
0x03
,
0x80
}},
},
/* 20 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 25 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 30 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
},
drivers/usb/media/pwc_nala.h
deleted
100644 → 0
View file @
0335cce0
/* SQCIF */
{
{
0
,
0
,
{
0x04
,
0x01
,
0x03
}},
{
8
,
0
,
{
0x05
,
0x01
,
0x03
}},
{
7
,
0
,
{
0x08
,
0x01
,
0x03
}},
{
7
,
0
,
{
0x0A
,
0x01
,
0x03
}},
{
6
,
0
,
{
0x0C
,
0x01
,
0x03
}},
{
5
,
0
,
{
0x0F
,
0x01
,
0x03
}},
{
4
,
0
,
{
0x14
,
0x01
,
0x03
}},
{
3
,
0
,
{
0x18
,
0x01
,
0x03
}},
},
/* QSIF */
{
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
},
/* QCIF */
{
{
0
,
0
,
{
0x04
,
0x01
,
0x02
}},
{
8
,
0
,
{
0x05
,
0x01
,
0x02
}},
{
7
,
0
,
{
0x08
,
0x01
,
0x02
}},
{
6
,
0
,
{
0x0A
,
0x01
,
0x02
}},
{
5
,
0
,
{
0x0C
,
0x01
,
0x02
}},
{
4
,
0
,
{
0x0F
,
0x01
,
0x02
}},
{
1
,
0
,
{
0x14
,
0x01
,
0x02
}},
{
1
,
0
,
{
0x18
,
0x01
,
0x02
}},
},
/* SIF */
{
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
},
/* CIF */
{
{
4
,
0
,
{
0x04
,
0x01
,
0x01
}},
{
7
,
1
,
{
0x05
,
0x03
,
0x01
}},
{
6
,
1
,
{
0x08
,
0x03
,
0x01
}},
{
4
,
1
,
{
0x0A
,
0x03
,
0x01
}},
{
3
,
1
,
{
0x0C
,
0x03
,
0x01
}},
{
2
,
1
,
{
0x0F
,
0x03
,
0x01
}},
{
0
},
{
0
},
},
/* VGA */
{
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
{
0
},
},
drivers/usb/media/pwc_timon.h
deleted
100644 → 0
View file @
0335cce0
/* SQCIF */
{
/* 5 fps */
{
{
1
,
140
,
0
,
{
0x05
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x8C
,
0xFC
,
0x80
,
0x02
}},
{
1
,
140
,
0
,
{
0x05
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x8C
,
0xFC
,
0x80
,
0x02
}},
{
1
,
140
,
0
,
{
0x05
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x8C
,
0xFC
,
0x80
,
0x02
}},
{
1
,
140
,
0
,
{
0x05
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x8C
,
0xFC
,
0x80
,
0x02
}},
},
/* 10 fps */
{
{
2
,
280
,
0
,
{
0x04
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x18
,
0xA9
,
0x80
,
0x02
}},
{
2
,
280
,
0
,
{
0x04
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x18
,
0xA9
,
0x80
,
0x02
}},
{
2
,
280
,
0
,
{
0x04
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x18
,
0xA9
,
0x80
,
0x02
}},
{
2
,
280
,
0
,
{
0x04
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x18
,
0xA9
,
0x80
,
0x02
}},
},
/* 15 fps */
{
{
3
,
410
,
0
,
{
0x03
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x9A
,
0x71
,
0x80
,
0x02
}},
{
3
,
410
,
0
,
{
0x03
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x9A
,
0x71
,
0x80
,
0x02
}},
{
3
,
410
,
0
,
{
0x03
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x9A
,
0x71
,
0x80
,
0x02
}},
{
3
,
410
,
0
,
{
0x03
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x9A
,
0x71
,
0x80
,
0x02
}},
},
/* 20 fps */
{
{
4
,
559
,
0
,
{
0x02
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x2F
,
0x56
,
0x80
,
0x02
}},
{
4
,
559
,
0
,
{
0x02
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x2F
,
0x56
,
0x80
,
0x02
}},
{
4
,
559
,
0
,
{
0x02
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x2F
,
0x56
,
0x80
,
0x02
}},
{
4
,
559
,
0
,
{
0x02
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x2F
,
0x56
,
0x80
,
0x02
}},
},
/* 25 fps */
{
{
5
,
659
,
0
,
{
0x01
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x93
,
0x46
,
0x80
,
0x02
}},
{
5
,
659
,
0
,
{
0x01
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x93
,
0x46
,
0x80
,
0x02
}},
{
5
,
659
,
0
,
{
0x01
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x93
,
0x46
,
0x80
,
0x02
}},
{
5
,
659
,
0
,
{
0x01
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x93
,
0x46
,
0x80
,
0x02
}},
},
/* 30 fps */
{
{
7
,
838
,
0
,
{
0x00
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x46
,
0x3B
,
0x80
,
0x02
}},
{
7
,
838
,
0
,
{
0x00
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x46
,
0x3B
,
0x80
,
0x02
}},
{
7
,
838
,
0
,
{
0x00
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x46
,
0x3B
,
0x80
,
0x02
}},
{
7
,
838
,
0
,
{
0x00
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x13
,
0x00
,
0x46
,
0x3B
,
0x80
,
0x02
}},
},
},
/* QSIF */
{
/* 5 fps */
{
{
1
,
146
,
0
,
{
0x2D
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x92
,
0xFC
,
0xC0
,
0x02
}},
{
1
,
146
,
0
,
{
0x2D
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x92
,
0xFC
,
0xC0
,
0x02
}},
{
1
,
146
,
0
,
{
0x2D
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x92
,
0xFC
,
0xC0
,
0x02
}},
{
1
,
146
,
0
,
{
0x2D
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x92
,
0xFC
,
0xC0
,
0x02
}},
},
/* 10 fps */
{
{
2
,
291
,
0
,
{
0x2C
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x23
,
0xA1
,
0xC0
,
0x02
}},
{
1
,
191
,
630
,
{
0x2C
,
0xF4
,
0x05
,
0x13
,
0xA9
,
0x12
,
0xE1
,
0x17
,
0x08
,
0xBF
,
0xF4
,
0xC0
,
0x02
}},
{
1
,
191
,
630
,
{
0x2C
,
0xF4
,
0x05
,
0x13
,
0xA9
,
0x12
,
0xE1
,
0x17
,
0x08
,
0xBF
,
0xF4
,
0xC0
,
0x02
}},
{
1
,
191
,
630
,
{
0x2C
,
0xF4
,
0x05
,
0x13
,
0xA9
,
0x12
,
0xE1
,
0x17
,
0x08
,
0xBF
,
0xF4
,
0xC0
,
0x02
}},
},
/* 15 fps */
{
{
3
,
437
,
0
,
{
0x2B
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0xB5
,
0x6D
,
0xC0
,
0x02
}},
{
2
,
291
,
640
,
{
0x2B
,
0xF4
,
0x05
,
0x13
,
0xF7
,
0x13
,
0x2F
,
0x13
,
0x08
,
0x23
,
0xA1
,
0xC0
,
0x02
}},
{
2
,
291
,
640
,
{
0x2B
,
0xF4
,
0x05
,
0x13
,
0xF7
,
0x13
,
0x2F
,
0x13
,
0x08
,
0x23
,
0xA1
,
0xC0
,
0x02
}},
{
1
,
191
,
420
,
{
0x2B
,
0xF4
,
0x0D
,
0x0D
,
0x1B
,
0x0C
,
0x53
,
0x1E
,
0x08
,
0xBF
,
0xF4
,
0xC0
,
0x02
}},
},
/* 20 fps */
{
{
4
,
588
,
0
,
{
0x2A
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x4C
,
0x52
,
0xC0
,
0x02
}},
{
3
,
447
,
730
,
{
0x2A
,
0xF4
,
0x05
,
0x16
,
0xC9
,
0x16
,
0x01
,
0x0E
,
0x18
,
0xBF
,
0x69
,
0xC0
,
0x02
}},
{
2
,
292
,
476
,
{
0x2A
,
0xF4
,
0x0D
,
0x0E
,
0xD8
,
0x0E
,
0x10
,
0x19
,
0x18
,
0x24
,
0xA1
,
0xC0
,
0x02
}},
{
1
,
192
,
312
,
{
0x2A
,
0xF4
,
0x1D
,
0x09
,
0xB3
,
0x08
,
0xEB
,
0x1E
,
0x18
,
0xC0
,
0xF4
,
0xC0
,
0x02
}},
},
/* 25 fps */
{
{
5
,
703
,
0
,
{
0x29
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0xBF
,
0x42
,
0xC0
,
0x02
}},
{
3
,
447
,
610
,
{
0x29
,
0xF4
,
0x05
,
0x13
,
0x0B
,
0x12
,
0x43
,
0x14
,
0x18
,
0xBF
,
0x69
,
0xC0
,
0x02
}},
{
2
,
292
,
398
,
{
0x29
,
0xF4
,
0x0D
,
0x0C
,
0x6C
,
0x0B
,
0xA4
,
0x1E
,
0x18
,
0x24
,
0xA1
,
0xC0
,
0x02
}},
{
1
,
192
,
262
,
{
0x29
,
0xF4
,
0x25
,
0x08
,
0x23
,
0x07
,
0x5B
,
0x1E
,
0x18
,
0xC0
,
0xF4
,
0xC0
,
0x02
}},
},
/* 30 fps */
{
{
8
,
873
,
0
,
{
0x28
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x18
,
0x00
,
0x69
,
0x37
,
0xC0
,
0x02
}},
{
5
,
704
,
774
,
{
0x28
,
0xF4
,
0x05
,
0x18
,
0x21
,
0x17
,
0x59
,
0x0F
,
0x18
,
0xC0
,
0x42
,
0xC0
,
0x02
}},
{
3
,
448
,
492
,
{
0x28
,
0xF4
,
0x05
,
0x0F
,
0x5D
,
0x0E
,
0x95
,
0x15
,
0x18
,
0xC0
,
0x69
,
0xC0
,
0x02
}},
{
2
,
291
,
320
,
{
0x28
,
0xF4
,
0x1D
,
0x09
,
0xFB
,
0x09
,
0x33
,
0x1E
,
0x18
,
0x23
,
0xA1
,
0xC0
,
0x02
}},
},
},
/* QCIF */
{
/* 5 fps */
{
{
1
,
193
,
0
,
{
0x0D
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x12
,
0x00
,
0xC1
,
0xF4
,
0xC0
,
0x02
}},
{
1
,
193
,
0
,
{
0x0D
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x12
,
0x00
,
0xC1
,
0xF4
,
0xC0
,
0x02
}},
{
1
,
193
,
0
,
{
0x0D
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x12
,
0x00
,
0xC1
,
0xF4
,
0xC0
,
0x02
}},
{
1
,
193
,
0
,
{
0x0D
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x12
,
0x00
,
0xC1
,
0xF4
,
0xC0
,
0x02
}},
},
/* 10 fps */
{
{
3
,
385
,
0
,
{
0x0C
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x12
,
0x00
,
0x81
,
0x79
,
0xC0
,
0x02
}},
{
2
,
291
,
800
,
{
0x0C
,
0xF4
,
0x05
,
0x18
,
0xF4
,
0x18
,
0x18
,
0x11
,
0x08
,
0x23
,
0xA1
,
0xC0
,
0x02
}},
{
2
,
291
,
800
,
{
0x0C
,
0xF4
,
0x05
,
0x18
,
0xF4
,
0x18
,
0x18
,
0x11
,
0x08
,
0x23
,
0xA1
,
0xC0
,
0x02
}},
{
1
,
194
,
532
,
{
0x0C
,
0xF4
,
0x05
,
0x10
,
0x9A
,
0x0F
,
0xBE
,
0x1B
,
0x08
,
0xC2
,
0xF0
,
0xC0
,
0x02
}},
},
/* 15 fps */
{
{
4
,
577
,
0
,
{
0x0B
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x12
,
0x00
,
0x41
,
0x52
,
0xC0
,
0x02
}},
{
3
,
447
,
818
,
{
0x0B
,
0xF4
,
0x05
,
0x19
,
0x89
,
0x18
,
0xAD
,
0x0F
,
0x10
,
0xBF
,
0x69
,
0xC0
,
0x02
}},
{
2
,
292
,
534
,
{
0x0B
,
0xF4
,
0x05
,
0x10
,
0xA3
,
0x0F
,
0xC7
,
0x19
,
0x10
,
0x24
,
0xA1
,
0xC0
,
0x02
}},
{
1
,
195
,
356
,
{
0x0B
,
0xF4
,
0x15
,
0x0B
,
0x11
,
0x0A
,
0x35
,
0x1E
,
0x10
,
0xC3
,
0xF0
,
0xC0
,
0x02
}},
},
/* 20 fps */
{
{
6
,
776
,
0
,
{
0x0A
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x12
,
0x00
,
0x08
,
0x3F
,
0xC0
,
0x02
}},
{
4
,
591
,
804
,
{
0x0A
,
0xF4
,
0x05
,
0x19
,
0x1E
,
0x18
,
0x42
,
0x0F
,
0x18
,
0x4F
,
0x4E
,
0xC0
,
0x02
}},
{
3
,
447
,
608
,
{
0x0A
,
0xF4
,
0x05
,
0x12
,
0xFD
,
0x12
,
0x21
,
0x15
,
0x18
,
0xBF
,
0x69
,
0xC0
,
0x02
}},
{
2
,
291
,
396
,
{
0x0A
,
0xF4
,
0x15
,
0x0C
,
0x5E
,
0x0B
,
0x82
,
0x1E
,
0x18
,
0x23
,
0xA1
,
0xC0
,
0x02
}},
},
/* 25 fps */
{
{
9
,
928
,
0
,
{
0x09
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x12
,
0x00
,
0xA0
,
0x33
,
0xC0
,
0x02
}},
{
5
,
703
,
800
,
{
0x09
,
0xF4
,
0x05
,
0x18
,
0xF4
,
0x18
,
0x18
,
0x10
,
0x18
,
0xBF
,
0x42
,
0xC0
,
0x02
}},
{
3
,
447
,
508
,
{
0x09
,
0xF4
,
0x0D
,
0x0F
,
0xD2
,
0x0E
,
0xF6
,
0x1B
,
0x18
,
0xBF
,
0x69
,
0xC0
,
0x02
}},
{
2
,
292
,
332
,
{
0x09
,
0xF4
,
0x1D
,
0x0A
,
0x5A
,
0x09
,
0x7E
,
0x1E
,
0x18
,
0x24
,
0xA1
,
0xC0
,
0x02
}},
},
/* 30 fps */
{
{
0
,
},
{
9
,
956
,
876
,
{
0x08
,
0xF4
,
0x05
,
0x1B
,
0x58
,
0x1A
,
0x7C
,
0x0E
,
0x20
,
0xBC
,
0x33
,
0x10
,
0x02
}},
{
4
,
592
,
542
,
{
0x08
,
0xF4
,
0x05
,
0x10
,
0xE4
,
0x10
,
0x08
,
0x17
,
0x20
,
0x50
,
0x4E
,
0x10
,
0x02
}},
{
2
,
291
,
266
,
{
0x08
,
0xF4
,
0x25
,
0x08
,
0x48
,
0x07
,
0x6C
,
0x1E
,
0x20
,
0x23
,
0xA1
,
0x10
,
0x02
}},
},
},
/* SIF */
{
/* 5 fps */
{
{
4
,
582
,
0
,
{
0x35
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x04
,
0x00
,
0x46
,
0x52
,
0x60
,
0x02
}},
{
3
,
387
,
1276
,
{
0x35
,
0xF4
,
0x05
,
0x27
,
0xD8
,
0x26
,
0x48
,
0x03
,
0x10
,
0x83
,
0x79
,
0x60
,
0x02
}},
{
2
,
291
,
960
,
{
0x35
,
0xF4
,
0x0D
,
0x1D
,
0xF2
,
0x1C
,
0x62
,
0x04
,
0x10
,
0x23
,
0xA1
,
0x60
,
0x02
}},
{
1
,
191
,
630
,
{
0x35
,
0xF4
,
0x1D
,
0x13
,
0xA9
,
0x12
,
0x19
,
0x05
,
0x08
,
0xBF
,
0xF4
,
0x60
,
0x02
}},
},
/* 10 fps */
{
{
0
,
},
{
6
,
775
,
1278
,
{
0x34
,
0xF4
,
0x05
,
0x27
,
0xE8
,
0x26
,
0x58
,
0x05
,
0x30
,
0x07
,
0x3F
,
0x10
,
0x02
}},
{
3
,
447
,
736
,
{
0x34
,
0xF4
,
0x15
,
0x16
,
0xFB
,
0x15
,
0x6B
,
0x05
,
0x18
,
0xBF
,
0x69
,
0x10
,
0x02
}},
{
2
,
291
,
480
,
{
0x34
,
0xF4
,
0x2D
,
0x0E
,
0xF9
,
0x0D
,
0x69
,
0x09
,
0x18
,
0x23
,
0xA1
,
0x10
,
0x02
}},
},
/* 15 fps */
{
{
0
,
},
{
9
,
955
,
1050
,
{
0x33
,
0xF4
,
0x05
,
0x20
,
0xCF
,
0x1F
,
0x3F
,
0x06
,
0x48
,
0xBB
,
0x33
,
0x10
,
0x02
}},
{
4
,
591
,
650
,
{
0x33
,
0xF4
,
0x15
,
0x14
,
0x44
,
0x12
,
0xB4
,
0x08
,
0x30
,
0x4F
,
0x4E
,
0x10
,
0x02
}},
{
3
,
448
,
492
,
{
0x33
,
0xF4
,
0x25
,
0x0F
,
0x52
,
0x0D
,
0xC2
,
0x09
,
0x28
,
0xC0
,
0x69
,
0x10
,
0x02
}},
},
/* 20 fps */
{
{
0
,
},
{
9
,
958
,
782
,
{
0x32
,
0xF4
,
0x0D
,
0x18
,
0x6A
,
0x16
,
0xDA
,
0x0B
,
0x58
,
0xBE
,
0x33
,
0xD0
,
0x02
}},
{
5
,
703
,
574
,
{
0x32
,
0xF4
,
0x1D
,
0x11
,
0xE7
,
0x10
,
0x57
,
0x0B
,
0x40
,
0xBF
,
0x42
,
0xD0
,
0x02
}},
{
3
,
446
,
364
,
{
0x32
,
0xF4
,
0x3D
,
0x0B
,
0x5C
,
0x09
,
0xCC
,
0x0E
,
0x30
,
0xBE
,
0x69
,
0xD0
,
0x02
}},
},
/* 25 fps */
{
{
0
,
},
{
9
,
958
,
654
,
{
0x31
,
0xF4
,
0x15
,
0x14
,
0x66
,
0x12
,
0xD6
,
0x0B
,
0x50
,
0xBE
,
0x33
,
0x90
,
0x02
}},
{
6
,
776
,
530
,
{
0x31
,
0xF4
,
0x25
,
0x10
,
0x8C
,
0x0E
,
0xFC
,
0x0C
,
0x48
,
0x08
,
0x3F
,
0x90
,
0x02
}},
{
4
,
592
,
404
,
{
0x31
,
0xF4
,
0x35
,
0x0C
,
0x96
,
0x0B
,
0x06
,
0x0B
,
0x38
,
0x50
,
0x4E
,
0x90
,
0x02
}},
},
/* 30 fps */
{
{
0
,
},
{
9
,
957
,
526
,
{
0x30
,
0xF4
,
0x25
,
0x10
,
0x68
,
0x0E
,
0xD8
,
0x0D
,
0x58
,
0xBD
,
0x33
,
0x60
,
0x02
}},
{
6
,
775
,
426
,
{
0x30
,
0xF4
,
0x35
,
0x0D
,
0x48
,
0x0B
,
0xB8
,
0x0F
,
0x50
,
0x07
,
0x3F
,
0x60
,
0x02
}},
{
4
,
590
,
324
,
{
0x30
,
0x7A
,
0x4B
,
0x0A
,
0x1C
,
0x08
,
0xB4
,
0x0E
,
0x40
,
0x4E
,
0x52
,
0x60
,
0x02
}},
},
},
/* CIF */
{
/* 5 fps */
{
{
6
,
771
,
0
,
{
0x15
,
0xF4
,
0x04
,
0x00
,
0x00
,
0x00
,
0x00
,
0x03
,
0x00
,
0x03
,
0x3F
,
0x80
,
0x02
}},
{
4
,
465
,
1278
,
{
0x15
,
0xF4
,
0x05
,
0x27
,
0xEE
,
0x26
,
0x36
,
0x03
,
0x18
,
0xD1
,
0x65
,
0x80
,
0x02
}},
{
2
,
291
,
800
,
{
0x15
,
0xF4
,
0x15
,
0x18
,
0xF4
,
0x17
,
0x3C
,
0x05
,
0x18
,
0x23
,
0xA1
,
0x80
,
0x02
}},
{
1
,
193
,
528
,
{
0x15
,
0xF4
,
0x2D
,
0x10
,
0x7E
,
0x0E
,
0xC6
,
0x0A
,
0x18
,
0xC1
,
0xF4
,
0x80
,
0x02
}},
},
/* 10 fps */
{
{
0
,
},
{
9
,
932
,
1278
,
{
0x14
,
0xF4
,
0x05
,
0x27
,
0xEE
,
0x26
,
0x36
,
0x04
,
0x30
,
0xA4
,
0x33
,
0x10
,
0x02
}},
{
4
,
591
,
812
,
{
0x14
,
0xF4
,
0x15
,
0x19
,
0x56
,
0x17
,
0x9E
,
0x06
,
0x28
,
0x4F
,
0x4E
,
0x10
,
0x02
}},
{
2
,
291
,
400
,
{
0x14
,
0xF4
,
0x3D
,
0x0C
,
0x7A
,
0x0A
,
0xC2
,
0x0E
,
0x28
,
0x23
,
0xA1
,
0x10
,
0x02
}},
},
/* 15 fps */
{
{
0
,
},
{
9
,
956
,
876
,
{
0x13
,
0xF4
,
0x0D
,
0x1B
,
0x58
,
0x19
,
0xA0
,
0x05
,
0x38
,
0xBC
,
0x33
,
0x60
,
0x02
}},
{
5
,
703
,
644
,
{
0x13
,
0xF4
,
0x1D
,
0x14
,
0x1C
,
0x12
,
0x64
,
0x08
,
0x38
,
0xBF
,
0x42
,
0x60
,
0x02
}},
{
3
,
448
,
410
,
{
0x13
,
0xF4
,
0x3D
,
0x0C
,
0xC4
,
0x0B
,
0x0C
,
0x0E
,
0x38
,
0xC0
,
0x69
,
0x60
,
0x02
}},
},
/* 20 fps */
{
{
0
,
},
{
9
,
956
,
650
,
{
0x12
,
0xF4
,
0x1D
,
0x14
,
0x4A
,
0x12
,
0x92
,
0x09
,
0x48
,
0xBC
,
0x33
,
0x10
,
0x03
}},
{
6
,
776
,
528
,
{
0x12
,
0xF4
,
0x2D
,
0x10
,
0x7E
,
0x0E
,
0xC6
,
0x0A
,
0x40
,
0x08
,
0x3F
,
0x10
,
0x03
}},
{
4
,
591
,
402
,
{
0x12
,
0xF4
,
0x3D
,
0x0C
,
0x8F
,
0x0A
,
0xD7
,
0x0E
,
0x40
,
0x4F
,
0x4E
,
0x10
,
0x03
}},
},
/* 25 fps */
{
{
0
,
},
{
9
,
956
,
544
,
{
0x11
,
0xF4
,
0x25
,
0x10
,
0xF4
,
0x0F
,
0x3C
,
0x0A
,
0x48
,
0xBC
,
0x33
,
0xC0
,
0x02
}},
{
7
,
840
,
478
,
{
0x11
,
0xF4
,
0x2D
,
0x0E
,
0xEB
,
0x0D
,
0x33
,
0x0B
,
0x48
,
0x48
,
0x3B
,
0xC0
,
0x02
}},
{
5
,
703
,
400
,
{
0x11
,
0xF4
,
0x3D
,
0x0C
,
0x7A
,
0x0A
,
0xC2
,
0x0E
,
0x48
,
0xBF
,
0x42
,
0xC0
,
0x02
}},
},
/* 30 fps */
{
{
0
,
},
{
9
,
956
,
438
,
{
0x10
,
0xF4
,
0x35
,
0x0D
,
0xAC
,
0x0B
,
0xF4
,
0x0D
,
0x50
,
0xBC
,
0x33
,
0x10
,
0x02
}},
{
7
,
838
,
384
,
{
0x10
,
0xF4
,
0x45
,
0x0B
,
0xFD
,
0x0A
,
0x45
,
0x0F
,
0x50
,
0x46
,
0x3B
,
0x10
,
0x02
}},
{
6
,
773
,
354
,
{
0x10
,
0x7A
,
0x4B
,
0x0B
,
0x0C
,
0x09
,
0x80
,
0x10
,
0x50
,
0x05
,
0x3F
,
0x10
,
0x02
}},
},
},
/* VGA */
{
/* 5 fps */
{
{
0
,
},
{
6
,
773
,
1272
,
{
0x1D
,
0xF4
,
0x15
,
0x27
,
0xB6
,
0x24
,
0x96
,
0x02
,
0x30
,
0x05
,
0x3F
,
0x10
,
0x02
}},
{
4
,
592
,
976
,
{
0x1D
,
0xF4
,
0x25
,
0x1E
,
0x78
,
0x1B
,
0x58
,
0x03
,
0x30
,
0x50
,
0x4E
,
0x10
,
0x02
}},
{
3
,
448
,
738
,
{
0x1D
,
0xF4
,
0x3D
,
0x17
,
0x0C
,
0x13
,
0xEC
,
0x04
,
0x30
,
0xC0
,
0x69
,
0x10
,
0x02
}},
},
/* 10 fps */
{
{
0
,
},
{
9
,
956
,
788
,
{
0x1C
,
0xF4
,
0x35
,
0x18
,
0x9C
,
0x15
,
0x7C
,
0x03
,
0x48
,
0xBC
,
0x33
,
0x10
,
0x02
}},
{
6
,
776
,
640
,
{
0x1C
,
0x7A
,
0x53
,
0x13
,
0xFC
,
0x11
,
0x2C
,
0x04
,
0x48
,
0x08
,
0x3F
,
0x10
,
0x02
}},
{
4
,
592
,
488
,
{
0x1C
,
0x7A
,
0x6B
,
0x0F
,
0x3C
,
0x0C
,
0x6C
,
0x06
,
0x48
,
0x50
,
0x4E
,
0x10
,
0x02
}},
},
/* 15 fps */
{
{
0
,
},
{
9
,
957
,
526
,
{
0x1B
,
0x7A
,
0x63
,
0x10
,
0x68
,
0x0D
,
0x98
,
0x06
,
0x58
,
0xBD
,
0x33
,
0x80
,
0x02
}},
{
9
,
957
,
526
,
{
0x1B
,
0x7A
,
0x63
,
0x10
,
0x68
,
0x0D
,
0x98
,
0x06
,
0x58
,
0xBD
,
0x33
,
0x80
,
0x02
}},
{
8
,
895
,
492
,
{
0x1B
,
0x7A
,
0x6B
,
0x0F
,
0x5D
,
0x0C
,
0x8D
,
0x06
,
0x58
,
0x7F
,
0x37
,
0x80
,
0x02
}},
},
/* 20 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 25 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
/* 30 fps */
{
{
0
,
},
{
0
,
},
{
0
,
},
{
0
,
},
},
},
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment