[media] pwc: Remove software emulation of arbritary resolutions
The pwc driver claims to support any resolution between 160x120 and 640x480, but emulates this by simply drawing a black border around the image. Userspace can draw its own black border if it really wants one. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
a08d2c7271
commit
795e6eb326
8 changed files with 93 additions and 223 deletions
|
@ -460,16 +460,6 @@ Who: Jean Delvare <khali@linux-fr.org>
|
||||||
|
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
What: Software emulation of arbritary resolutions in the pwc driver
|
|
||||||
When: 3.3
|
|
||||||
Why: The pwc driver claims to support any resolution between 160x120
|
|
||||||
and 640x480, but emulates this by simply drawing a black border
|
|
||||||
around the image. Userspace can draw its own black border if it
|
|
||||||
really wants one.
|
|
||||||
Who: Hans de Goede <hdegoede@redhat.com>
|
|
||||||
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
What: For VIDIOC_S_FREQUENCY the type field must match the device node's type.
|
What: For VIDIOC_S_FREQUENCY the type field must match the device node's type.
|
||||||
If not, return -EINVAL.
|
If not, return -EINVAL.
|
||||||
When: 3.2
|
When: 3.2
|
||||||
|
|
|
@ -102,8 +102,6 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
|
||||||
#include "pwc-nala.h"
|
#include "pwc-nala.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pwc_set_image_buffer_size(struct pwc_device *pdev);
|
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
static int _send_control_msg(struct pwc_device *pdev,
|
static int _send_control_msg(struct pwc_device *pdev,
|
||||||
|
@ -221,8 +219,9 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
|
||||||
/* Set various parameters */
|
/* Set various parameters */
|
||||||
pdev->vframes = frames;
|
pdev->vframes = frames;
|
||||||
pdev->valternate = pEntry->alternate;
|
pdev->valternate = pEntry->alternate;
|
||||||
pdev->image = pwc_image_sizes[size];
|
pdev->width = pwc_image_sizes[size][0];
|
||||||
pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
|
pdev->height = pwc_image_sizes[size][1];
|
||||||
|
pdev->frame_size = (pdev->width * pdev->height * 3) / 2;
|
||||||
if (pEntry->compressed) {
|
if (pEntry->compressed) {
|
||||||
if (pdev->release < 5) { /* 4 fold compression */
|
if (pdev->release < 5) { /* 4 fold compression */
|
||||||
pdev->vbandlength = 528;
|
pdev->vbandlength = 528;
|
||||||
|
@ -282,12 +281,13 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames,
|
||||||
/* Set various parameters */
|
/* Set various parameters */
|
||||||
pdev->vframes = frames;
|
pdev->vframes = frames;
|
||||||
pdev->valternate = pChoose->alternate;
|
pdev->valternate = pChoose->alternate;
|
||||||
pdev->image = pwc_image_sizes[size];
|
pdev->width = pwc_image_sizes[size][0];
|
||||||
|
pdev->height = pwc_image_sizes[size][1];
|
||||||
pdev->vbandlength = pChoose->bandlength;
|
pdev->vbandlength = pChoose->bandlength;
|
||||||
if (pChoose->bandlength > 0)
|
if (pChoose->bandlength > 0)
|
||||||
pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
|
pdev->frame_size = (pChoose->bandlength * pdev->height) / 4;
|
||||||
else
|
else
|
||||||
pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
|
pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,37 +339,25 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames,
|
||||||
/* All set and go */
|
/* All set and go */
|
||||||
pdev->vframes = frames;
|
pdev->vframes = frames;
|
||||||
pdev->valternate = pChoose->alternate;
|
pdev->valternate = pChoose->alternate;
|
||||||
pdev->image = pwc_image_sizes[size];
|
pdev->width = pwc_image_sizes[size][0];
|
||||||
|
pdev->height = pwc_image_sizes[size][1];
|
||||||
pdev->vbandlength = pChoose->bandlength;
|
pdev->vbandlength = pChoose->bandlength;
|
||||||
if (pdev->vbandlength > 0)
|
if (pdev->vbandlength > 0)
|
||||||
pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
|
pdev->frame_size = (pdev->vbandlength * pdev->height) / 4;
|
||||||
else
|
else
|
||||||
pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
|
pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
|
||||||
PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
|
PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
|
||||||
pdev->frame_size, pdev->vframes, size, pdev->vbandlength);
|
pdev->frame_size, pdev->vframes, size, pdev->vbandlength);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
@pdev: device structure
|
|
||||||
@width: viewport width
|
|
||||||
@height: viewport height
|
|
||||||
@frame: framerate, in fps
|
|
||||||
@compression: preferred compression ratio
|
|
||||||
*/
|
|
||||||
int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
|
int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
|
||||||
int frames, int compression)
|
int frames, int compression)
|
||||||
{
|
{
|
||||||
int ret, size;
|
int ret, size;
|
||||||
|
|
||||||
PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt);
|
PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt);
|
||||||
size = pwc_decode_size(pdev, width, height);
|
size = pwc_get_size(pdev, width, height);
|
||||||
if (size < 0) {
|
|
||||||
PWC_DEBUG_MODULE("Could not find suitable size.\n");
|
|
||||||
return -ERANGE;
|
|
||||||
}
|
|
||||||
PWC_TRACE("decode_size = %d.\n", size);
|
PWC_TRACE("decode_size = %d.\n", size);
|
||||||
|
|
||||||
if (DEVICE_USE_CODEC1(pdev->type)) {
|
if (DEVICE_USE_CODEC1(pdev->type)) {
|
||||||
|
@ -385,12 +373,9 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
|
||||||
PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
|
PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
pdev->view.x = width;
|
|
||||||
pdev->view.y = height;
|
|
||||||
pdev->vcompression = compression;
|
pdev->vcompression = compression;
|
||||||
pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
|
pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
|
||||||
pwc_set_image_buffer_size(pdev);
|
PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height);
|
||||||
PWC_DEBUG_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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,34 +432,6 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pwc_set_image_buffer_size(struct pwc_device *pdev)
|
|
||||||
{
|
|
||||||
int factor = 0;
|
|
||||||
|
|
||||||
/* for V4L2_PIX_FMT_YUV420 */
|
|
||||||
switch (pdev->pixfmt) {
|
|
||||||
case V4L2_PIX_FMT_YUV420:
|
|
||||||
factor = 6;
|
|
||||||
break;
|
|
||||||
case V4L2_PIX_FMT_PWC1:
|
|
||||||
case V4L2_PIX_FMT_PWC2:
|
|
||||||
factor = 6; /* can be uncompressed YUV420P */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
|
int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
|
@ -656,10 +656,6 @@ static void DecompressBand23(struct pwc_dec23_private *pdec,
|
||||||
*
|
*
|
||||||
* Uncompress a pwc23 buffer.
|
* Uncompress a pwc23 buffer.
|
||||||
*
|
*
|
||||||
* pwc.view: size of the image wanted
|
|
||||||
* pwc.image: size of the image returned by the camera
|
|
||||||
* pwc.offset: (x,y) to displayer image in the view
|
|
||||||
*
|
|
||||||
* src: raw data
|
* src: raw data
|
||||||
* dst: image output
|
* dst: image output
|
||||||
*/
|
*/
|
||||||
|
@ -667,7 +663,7 @@ void pwc_dec23_decompress(const struct pwc_device *pwc,
|
||||||
const void *src,
|
const void *src,
|
||||||
void *dst)
|
void *dst)
|
||||||
{
|
{
|
||||||
int bandlines_left, stride, bytes_per_block;
|
int bandlines_left, bytes_per_block;
|
||||||
struct pwc_dec23_private *pdec = pwc->decompress_data;
|
struct pwc_dec23_private *pdec = pwc->decompress_data;
|
||||||
|
|
||||||
/* YUV420P image format */
|
/* YUV420P image format */
|
||||||
|
@ -678,28 +674,23 @@ void pwc_dec23_decompress(const struct pwc_device *pwc,
|
||||||
|
|
||||||
mutex_lock(&pdec->lock);
|
mutex_lock(&pdec->lock);
|
||||||
|
|
||||||
bandlines_left = pwc->image.y / 4;
|
bandlines_left = pwc->height / 4;
|
||||||
bytes_per_block = pwc->view.x * 4;
|
bytes_per_block = pwc->width * 4;
|
||||||
plane_size = pwc->view.x * pwc->view.y;
|
plane_size = pwc->height * pwc->width;
|
||||||
|
|
||||||
/* offset in Y plane */
|
pout_planar_y = dst;
|
||||||
stride = pwc->view.x * pwc->offset.y;
|
pout_planar_u = dst + plane_size;
|
||||||
pout_planar_y = dst + stride + pwc->offset.x;
|
pout_planar_v = dst + plane_size + plane_size / 4;
|
||||||
|
|
||||||
/* offsets in U/V planes */
|
|
||||||
stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2;
|
|
||||||
pout_planar_u = dst + plane_size + stride;
|
|
||||||
pout_planar_v = dst + plane_size + plane_size / 4 + stride;
|
|
||||||
|
|
||||||
while (bandlines_left--) {
|
while (bandlines_left--) {
|
||||||
DecompressBand23(pwc->decompress_data,
|
DecompressBand23(pwc->decompress_data,
|
||||||
src,
|
src,
|
||||||
pout_planar_y, pout_planar_u, pout_planar_v,
|
pout_planar_y, pout_planar_u, pout_planar_v,
|
||||||
pwc->image.x, pwc->view.x);
|
pwc->width, pwc->width);
|
||||||
src += pwc->vbandlength;
|
src += pwc->vbandlength;
|
||||||
pout_planar_y += bytes_per_block;
|
pout_planar_y += bytes_per_block;
|
||||||
pout_planar_u += pwc->view.x;
|
pout_planar_u += pwc->width;
|
||||||
pout_planar_v += pwc->view.x;
|
pout_planar_v += pwc->width;
|
||||||
}
|
}
|
||||||
mutex_unlock(&pdec->lock);
|
mutex_unlock(&pdec->lock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -656,6 +656,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
|
||||||
unsigned int sizes[], void *alloc_ctxs[])
|
unsigned int sizes[], void *alloc_ctxs[])
|
||||||
{
|
{
|
||||||
struct pwc_device *pdev = vb2_get_drv_priv(vq);
|
struct pwc_device *pdev = vb2_get_drv_priv(vq);
|
||||||
|
int size;
|
||||||
|
|
||||||
if (*nbuffers < MIN_FRAMES)
|
if (*nbuffers < MIN_FRAMES)
|
||||||
*nbuffers = MIN_FRAMES;
|
*nbuffers = MIN_FRAMES;
|
||||||
|
@ -664,7 +665,9 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
|
||||||
|
|
||||||
*nplanes = 1;
|
*nplanes = 1;
|
||||||
|
|
||||||
sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
|
size = pwc_get_size(pdev, MAX_WIDTH, MAX_HEIGHT);
|
||||||
|
sizes[0] = PAGE_ALIGN(pwc_image_sizes[size][0] *
|
||||||
|
pwc_image_sizes[size][1] * 3 / 2);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -742,7 +745,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
|
||||||
pwc_camera_power(pdev, 1);
|
pwc_camera_power(pdev, 1);
|
||||||
if (pdev->power_save) {
|
if (pdev->power_save) {
|
||||||
/* Restore video mode */
|
/* Restore video mode */
|
||||||
pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y,
|
pwc_set_video_mode(pdev, pdev->width, pdev->height,
|
||||||
pdev->vframes, pdev->vcompression);
|
pdev->vframes, pdev->vcompression);
|
||||||
}
|
}
|
||||||
pwc_set_leds(pdev, led_on, led_off);
|
pwc_set_leds(pdev, led_on, led_off);
|
||||||
|
@ -1056,7 +1059,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
|
||||||
}
|
}
|
||||||
pdev->type = type_id;
|
pdev->type = type_id;
|
||||||
pdev->vframes = default_fps;
|
pdev->vframes = default_fps;
|
||||||
strcpy(pdev->serial, serial_number);
|
|
||||||
pdev->features = features;
|
pdev->features = features;
|
||||||
pwc_construct(pdev); /* set min/max sizes correct */
|
pwc_construct(pdev); /* set min/max sizes correct */
|
||||||
|
|
||||||
|
@ -1119,7 +1121,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
|
||||||
pwc_set_leds(pdev, 0, 0);
|
pwc_set_leds(pdev, 0, 0);
|
||||||
|
|
||||||
/* Setup intial videomode */
|
/* Setup intial videomode */
|
||||||
rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y,
|
rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT,
|
||||||
pdev->vframes, pdev->vcompression);
|
pdev->vframes, pdev->vcompression);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_free_mem;
|
goto err_free_mem;
|
||||||
|
|
|
@ -27,67 +27,47 @@
|
||||||
|
|
||||||
#include "pwc.h"
|
#include "pwc.h"
|
||||||
|
|
||||||
const struct pwc_coord pwc_image_sizes[PSZ_MAX] =
|
const int pwc_image_sizes[PSZ_MAX][2] =
|
||||||
{
|
{
|
||||||
{ 128, 96, 0 }, /* sqcif */
|
{ 128, 96 }, /* sqcif */
|
||||||
{ 160, 120, 0 }, /* qsif */
|
{ 160, 120 }, /* qsif */
|
||||||
{ 176, 144, 0 }, /* qcif */
|
{ 176, 144 }, /* qcif */
|
||||||
{ 320, 240, 0 }, /* sif */
|
{ 320, 240 }, /* sif */
|
||||||
{ 352, 288, 0 }, /* cif */
|
{ 352, 288 }, /* cif */
|
||||||
{ 640, 480, 0 }, /* vga */
|
{ 640, 480 }, /* vga */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* x,y -> PSZ_ */
|
/* x,y -> PSZ_ */
|
||||||
int pwc_decode_size(struct pwc_device *pdev, int width, int height)
|
int pwc_get_size(struct pwc_device *pdev, int width, int height)
|
||||||
{
|
{
|
||||||
int i, find;
|
int i;
|
||||||
|
|
||||||
/* 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->pixfmt != V4L2_PIX_FMT_YUV420)
|
|
||||||
{
|
|
||||||
if (width > pdev->abs_max.x || height > pdev->abs_max.y)
|
|
||||||
{
|
|
||||||
PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (width > pdev->view_max.x || height > pdev->view_max.y)
|
|
||||||
{
|
|
||||||
PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the largest size supported by the camera that fits into the
|
/* Find the largest size supported by the camera that fits into the
|
||||||
requested size.
|
requested size. */
|
||||||
*/
|
for (i = PSZ_MAX - 1; i >= 0; i--) {
|
||||||
find = -1;
|
if (!(pdev->image_mask & (1 << i)))
|
||||||
for (i = 0; i < PSZ_MAX; i++) {
|
continue;
|
||||||
if (pdev->image_mask & (1 << i)) {
|
|
||||||
if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height)
|
if (pwc_image_sizes[i][0] <= width &&
|
||||||
find = i;
|
pwc_image_sizes[i][1] <= height)
|
||||||
}
|
return i;
|
||||||
}
|
}
|
||||||
return find;
|
|
||||||
|
/* No mode found, return the smallest mode we have */
|
||||||
|
for (i = 0; i < PSZ_MAX; i++) {
|
||||||
|
if (pdev->image_mask & (1 << i))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Never reached there always is atleast one supported mode */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize variables depending on type and decompressor*/
|
/* initialize variables depending on type and decompressor */
|
||||||
void pwc_construct(struct pwc_device *pdev)
|
void pwc_construct(struct pwc_device *pdev)
|
||||||
{
|
{
|
||||||
if (DEVICE_USE_CODEC1(pdev->type)) {
|
if (DEVICE_USE_CODEC1(pdev->type)) {
|
||||||
|
|
||||||
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->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF;
|
||||||
pdev->vcinterface = 2;
|
pdev->vcinterface = 2;
|
||||||
pdev->vendpoint = 4;
|
pdev->vendpoint = 4;
|
||||||
|
@ -96,13 +76,7 @@ void pwc_construct(struct pwc_device *pdev)
|
||||||
|
|
||||||
} else if (DEVICE_USE_CODEC3(pdev->type)) {
|
} else if (DEVICE_USE_CODEC3(pdev->type)) {
|
||||||
|
|
||||||
pdev->view_min.x = 160;
|
|
||||||
pdev->view_min.y = 120;
|
|
||||||
pdev->view_max.x = 640;
|
|
||||||
pdev->view_max.y = 480;
|
|
||||||
pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
|
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->vcinterface = 3;
|
||||||
pdev->vendpoint = 5;
|
pdev->vendpoint = 5;
|
||||||
pdev->frame_header_size = TOUCAM_HEADER_SIZE;
|
pdev->frame_header_size = TOUCAM_HEADER_SIZE;
|
||||||
|
@ -110,20 +84,11 @@ void pwc_construct(struct pwc_device *pdev)
|
||||||
|
|
||||||
} else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
|
} else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
|
||||||
|
|
||||||
pdev->view_min.x = 128;
|
|
||||||
pdev->view_min.y = 96;
|
|
||||||
/* Anthill bug #38: PWC always reports max size, even without PWCX */
|
|
||||||
pdev->view_max.x = 640;
|
|
||||||
pdev->view_max.y = 480;
|
|
||||||
pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
|
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->vcinterface = 3;
|
||||||
pdev->vendpoint = 4;
|
pdev->vendpoint = 4;
|
||||||
pdev->frame_header_size = 0;
|
pdev->frame_header_size = 0;
|
||||||
pdev->frame_trailer_size = 0;
|
pdev->frame_trailer_size = 0;
|
||||||
}
|
}
|
||||||
pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */
|
pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* 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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
|
int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
|
||||||
{
|
{
|
||||||
int n, line, col, stride;
|
int n, line, col;
|
||||||
void *yuv, *image;
|
void *yuv, *image;
|
||||||
u16 *src;
|
u16 *src;
|
||||||
u16 *dsty, *dstu, *dstv;
|
u16 *dsty, *dstu, *dstv;
|
||||||
|
@ -60,35 +60,23 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vb2_set_plane_payload(&fbuf->vb, 0, pdev->view.size);
|
vb2_set_plane_payload(&fbuf->vb, 0,
|
||||||
|
pdev->width * pdev->height * 3 / 2);
|
||||||
|
|
||||||
if (pdev->vbandlength == 0) {
|
if (pdev->vbandlength == 0) {
|
||||||
/* Uncompressed mode.
|
/* Uncompressed mode.
|
||||||
* We copy the data into the output buffer, using the viewport
|
|
||||||
* size (which may be larger than the image size).
|
|
||||||
* Unfortunately we have to do a bit of byte stuffing to get
|
|
||||||
* the desired output format/size.
|
|
||||||
*
|
*
|
||||||
* We do some byte shuffling here to go from the
|
* We do some byte shuffling here to go from the
|
||||||
* native format to YUV420P.
|
* native format to YUV420P.
|
||||||
*/
|
*/
|
||||||
src = (u16 *)yuv;
|
src = (u16 *)yuv;
|
||||||
n = pdev->view.x * pdev->view.y;
|
n = pdev->width * pdev->height;
|
||||||
|
dsty = (u16 *)(image);
|
||||||
|
dstu = (u16 *)(image + n);
|
||||||
|
dstv = (u16 *)(image + n + n / 4);
|
||||||
|
|
||||||
/* offset in Y plane */
|
for (line = 0; line < pdev->height; line++) {
|
||||||
stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
|
for (col = 0; col < pdev->width; col += 4) {
|
||||||
dsty = (u16 *)(image + stride);
|
|
||||||
|
|
||||||
/* offsets in U/V planes */
|
|
||||||
stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
|
|
||||||
dstu = (u16 *)(image + n + stride);
|
|
||||||
dstv = (u16 *)(image + n + n / 4 + stride);
|
|
||||||
|
|
||||||
/* increment after each line */
|
|
||||||
stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
|
|
||||||
|
|
||||||
for (line = 0; line < pdev->image.y; line++) {
|
|
||||||
for (col = 0; col < pdev->image.x; col += 4) {
|
|
||||||
*dsty++ = *src++;
|
*dsty++ = *src++;
|
||||||
*dsty++ = *src++;
|
*dsty++ = *src++;
|
||||||
if (line & 1)
|
if (line & 1)
|
||||||
|
@ -96,11 +84,6 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
|
||||||
else
|
else
|
||||||
*dstu++ = *src++;
|
*dstu++ = *src++;
|
||||||
}
|
}
|
||||||
dsty += stride;
|
|
||||||
if (line & 1)
|
|
||||||
dstv += (stride >> 1);
|
|
||||||
else
|
|
||||||
dstu += (stride >> 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -122,6 +105,3 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
|
|
||||||
|
|
|
@ -398,8 +398,8 @@ int pwc_init_controls(struct pwc_device *pdev)
|
||||||
static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
|
static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
|
||||||
{
|
{
|
||||||
memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
|
memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
|
||||||
f->fmt.pix.width = pdev->view.x;
|
f->fmt.pix.width = pdev->width;
|
||||||
f->fmt.pix.height = pdev->view.y;
|
f->fmt.pix.height = pdev->height;
|
||||||
f->fmt.pix.field = V4L2_FIELD_NONE;
|
f->fmt.pix.field = V4L2_FIELD_NONE;
|
||||||
if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
|
if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
|
||||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
|
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
|
||||||
|
@ -429,6 +429,8 @@ static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_forma
|
||||||
/* ioctl(VIDIOC_TRY_FMT) */
|
/* ioctl(VIDIOC_TRY_FMT) */
|
||||||
static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
|
static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
|
||||||
{
|
{
|
||||||
|
int size;
|
||||||
|
|
||||||
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
||||||
PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
|
PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -455,15 +457,9 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->fmt.pix.width > pdev->view_max.x)
|
size = pwc_get_size(pdev, f->fmt.pix.width, f->fmt.pix.height);
|
||||||
f->fmt.pix.width = pdev->view_max.x;
|
f->fmt.pix.width = pwc_image_sizes[size][0];
|
||||||
else if (f->fmt.pix.width < pdev->view_min.x)
|
f->fmt.pix.height = pwc_image_sizes[size][1];
|
||||||
f->fmt.pix.width = pdev->view_min.x;
|
|
||||||
|
|
||||||
if (f->fmt.pix.height > pdev->view_max.y)
|
|
||||||
f->fmt.pix.height = pdev->view_max.y;
|
|
||||||
else if (f->fmt.pix.height < pdev->view_min.y)
|
|
||||||
f->fmt.pix.height = pdev->view_min.y;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -972,7 +968,7 @@ static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
|
||||||
|
|
||||||
mutex_lock(&pdev->udevlock); /* To avoid race with s_fmt */
|
mutex_lock(&pdev->udevlock); /* To avoid race with s_fmt */
|
||||||
PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
|
PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
|
||||||
pdev->image.x, pdev->image.y);
|
pdev->width, pdev->height);
|
||||||
pwc_vidioc_fill_fmt(pdev, f);
|
pwc_vidioc_fill_fmt(pdev, f);
|
||||||
mutex_unlock(&pdev->udevlock);
|
mutex_unlock(&pdev->udevlock);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1061,25 +1057,21 @@ static int pwc_enum_framesizes(struct file *file, void *fh,
|
||||||
struct pwc_device *pdev = video_drvdata(file);
|
struct pwc_device *pdev = video_drvdata(file);
|
||||||
unsigned int i = 0, index = fsize->index;
|
unsigned int i = 0, index = fsize->index;
|
||||||
|
|
||||||
if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
|
if (fsize->pixel_format == V4L2_PIX_FMT_YUV420 ||
|
||||||
|
(fsize->pixel_format == V4L2_PIX_FMT_PWC1 &&
|
||||||
|
DEVICE_USE_CODEC1(pdev->type)) ||
|
||||||
|
(fsize->pixel_format == V4L2_PIX_FMT_PWC2 &&
|
||||||
|
DEVICE_USE_CODEC23(pdev->type))) {
|
||||||
for (i = 0; i < PSZ_MAX; i++) {
|
for (i = 0; i < PSZ_MAX; i++) {
|
||||||
if (pdev->image_mask & (1UL << i)) {
|
if (!(pdev->image_mask & (1UL << i)))
|
||||||
if (!index--) {
|
continue;
|
||||||
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
if (!index--) {
|
||||||
fsize->discrete.width = pwc_image_sizes[i].x;
|
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
||||||
fsize->discrete.height = pwc_image_sizes[i].y;
|
fsize->discrete.width = pwc_image_sizes[i][0];
|
||||||
return 0;
|
fsize->discrete.height = pwc_image_sizes[i][1];
|
||||||
}
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (fsize->index == 0 &&
|
|
||||||
((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
|
|
||||||
(fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
|
|
||||||
|
|
||||||
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
|
||||||
fsize->discrete.width = pdev->abs_max.x;
|
|
||||||
fsize->discrete.height = pdev->abs_max.y;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1092,8 +1084,8 @@ static int pwc_enum_frameintervals(struct file *file, void *fh,
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < PSZ_MAX; i++) {
|
for (i = 0; i < PSZ_MAX; i++) {
|
||||||
if (pwc_image_sizes[i].x == fival->width &&
|
if (pwc_image_sizes[i][0] == fival->width &&
|
||||||
pwc_image_sizes[i].y == fival->height) {
|
pwc_image_sizes[i][1] == fival->height) {
|
||||||
size = i;
|
size = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,9 @@
|
||||||
#define FEATURE_CODEC1 0x0002
|
#define FEATURE_CODEC1 0x0002
|
||||||
#define FEATURE_CODEC2 0x0004
|
#define FEATURE_CODEC2 0x0004
|
||||||
|
|
||||||
|
#define MAX_WIDTH 640
|
||||||
|
#define MAX_HEIGHT 480
|
||||||
|
|
||||||
/* Ignore errors in the first N frames, to allow for startup delays */
|
/* Ignore errors in the first N frames, to allow for startup delays */
|
||||||
#define FRAME_LOWMARK 5
|
#define FRAME_LOWMARK 5
|
||||||
|
|
||||||
|
@ -205,12 +208,6 @@ struct pwc_raw_frame {
|
||||||
__u8 rawframe[0]; /* frame_size = H / 4 * vbandlength */
|
__u8 rawframe[0]; /* frame_size = H / 4 * vbandlength */
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
/* structure for transferring x & y coordinates */
|
|
||||||
struct pwc_coord {
|
|
||||||
int x, y; /* guess what */
|
|
||||||
int size; /* size, or offset */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* intermediate buffers with raw data from the USB cam */
|
/* intermediate buffers with raw data from the USB cam */
|
||||||
struct pwc_frame_buf
|
struct pwc_frame_buf
|
||||||
{
|
{
|
||||||
|
@ -233,7 +230,6 @@ struct pwc_device
|
||||||
int type;
|
int type;
|
||||||
int release; /* release number */
|
int release; /* release number */
|
||||||
int features; /* feature bits */
|
int features; /* feature bits */
|
||||||
char serial[30]; /* serial number (string) */
|
|
||||||
|
|
||||||
/*** Video data ***/
|
/*** Video data ***/
|
||||||
struct file *capt_file; /* file doing video capture */
|
struct file *capt_file; /* file doing video capture */
|
||||||
|
@ -286,10 +282,7 @@ struct pwc_device
|
||||||
* a gray or black border. view_min <= image <= view <= view_max;
|
* a gray or black border. view_min <= image <= view <= view_max;
|
||||||
*/
|
*/
|
||||||
int image_mask; /* supported sizes */
|
int image_mask; /* supported sizes */
|
||||||
struct pwc_coord view_min, view_max; /* minimum and maximum view */
|
int width, height; /* current resolution */
|
||||||
struct pwc_coord abs_max; /* maximum supported size */
|
|
||||||
struct pwc_coord image, view; /* image and viewport size */
|
|
||||||
struct pwc_coord offset; /* offset of the viewport */
|
|
||||||
|
|
||||||
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
|
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
|
||||||
struct input_dev *button_dev; /* webcam snapshot button input */
|
struct input_dev *button_dev; /* webcam snapshot button input */
|
||||||
|
@ -364,9 +357,9 @@ int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file);
|
||||||
|
|
||||||
/** Functions in pwc-misc.c */
|
/** Functions in pwc-misc.c */
|
||||||
/* sizes in pixels */
|
/* sizes in pixels */
|
||||||
extern const struct pwc_coord pwc_image_sizes[PSZ_MAX];
|
extern const int pwc_image_sizes[PSZ_MAX][2];
|
||||||
|
|
||||||
int pwc_decode_size(struct pwc_device *pdev, int width, int height);
|
int pwc_get_size(struct pwc_device *pdev, int width, int height);
|
||||||
void pwc_construct(struct pwc_device *pdev);
|
void pwc_construct(struct pwc_device *pdev);
|
||||||
|
|
||||||
/** Functions in pwc-ctrl.c */
|
/** Functions in pwc-ctrl.c */
|
||||||
|
|
Loading…
Add table
Reference in a new issue