Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 795e6eb3 authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent a08d2c72
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -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.
	If not, return -EINVAL.
When:	3.2
+13 −56
Original line number Diff line number Diff line
@@ -102,8 +102,6 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
#include "pwc-nala.h"
};

static void pwc_set_image_buffer_size(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 */
	pdev->vframes = frames;
	pdev->valternate = pEntry->alternate;
	pdev->image = pwc_image_sizes[size];
	pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
	pdev->width  = pwc_image_sizes[size][0];
	pdev->height = pwc_image_sizes[size][1];
	pdev->frame_size = (pdev->width * pdev->height * 3) / 2;
	if (pEntry->compressed) {
		if (pdev->release < 5) { /* 4 fold compression */
			pdev->vbandlength = 528;
@@ -282,12 +281,13 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames,
	/* Set various parameters */
	pdev->vframes = frames;
	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;
	if (pChoose->bandlength > 0)
		pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
		pdev->frame_size = (pChoose->bandlength * pdev->height) / 4;
	else
		pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
		pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
	return 0;
}

@@ -339,37 +339,25 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames,
	/* All set and go */
	pdev->vframes = frames;
	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;
	if (pdev->vbandlength > 0)
		pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
		pdev->frame_size = (pdev->vbandlength * pdev->height) / 4;
	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",
	    pdev->frame_size, pdev->vframes, size, pdev->vbandlength);
	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 frames, int compression)
{
	int ret, size;

	PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt);
	size = pwc_decode_size(pdev, width, height);
	if (size < 0) {
		PWC_DEBUG_MODULE("Could not find suitable size.\n");
		return -ERANGE;
	}
	size = pwc_get_size(pdev, width, height);
	PWC_TRACE("decode_size = %d.\n", size);

	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);
		return ret;
	}
	pdev->view.x = width;
	pdev->view.y = height;
	pdev->vcompression = compression;
	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 viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
	PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height);
	return 0;
}

@@ -447,34 +432,6 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i
	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 ret;
+10 −19
Original line number Diff line number Diff line
@@ -656,10 +656,6 @@ static void DecompressBand23(struct pwc_dec23_private *pdec,
 *
 * 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
 * dst: image output
 */
@@ -667,7 +663,7 @@ void pwc_dec23_decompress(const struct pwc_device *pwc,
			  const void *src,
			  void *dst)
{
	int bandlines_left, stride, bytes_per_block;
	int bandlines_left, bytes_per_block;
	struct pwc_dec23_private *pdec = pwc->decompress_data;

	/* YUV420P image format */
@@ -678,28 +674,23 @@ void pwc_dec23_decompress(const struct pwc_device *pwc,

	mutex_lock(&pdec->lock);

	bandlines_left = pwc->image.y / 4;
	bytes_per_block = pwc->view.x * 4;
	plane_size = pwc->view.x * pwc->view.y;

	/* offset in Y plane */
	stride = pwc->view.x * pwc->offset.y;
	pout_planar_y = dst + stride + pwc->offset.x;
	bandlines_left = pwc->height / 4;
	bytes_per_block = pwc->width * 4;
	plane_size = pwc->height * pwc->width;

	/* 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;
	pout_planar_y = dst;
	pout_planar_u = dst + plane_size;
	pout_planar_v = dst + plane_size + plane_size / 4;

	while (bandlines_left--) {
		DecompressBand23(pwc->decompress_data,
				 src,
				 pout_planar_y, pout_planar_u, pout_planar_v,
				 pwc->image.x, pwc->view.x);
				 pwc->width, pwc->width);
		src += pwc->vbandlength;
		pout_planar_y += bytes_per_block;
		pout_planar_u += pwc->view.x;
		pout_planar_v += pwc->view.x;
		pout_planar_u += pwc->width;
		pout_planar_v += pwc->width;
	}
	mutex_unlock(&pdec->lock);
}
+6 −4
Original line number Diff line number Diff line
@@ -656,6 +656,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
				unsigned int sizes[], void *alloc_ctxs[])
{
	struct pwc_device *pdev = vb2_get_drv_priv(vq);
	int size;

	if (*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;

	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;
}
@@ -742,7 +745,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
	pwc_camera_power(pdev, 1);
	if (pdev->power_save) {
		/* 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);
	}
	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->vframes = default_fps;
	strcpy(pdev->serial, serial_number);
	pdev->features = features;
	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);

	/* 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);
	if (rc)
		goto err_free_mem;
+26 −61
Original line number Diff line number Diff line
@@ -27,54 +27,40 @@

#include "pwc.h"

const struct pwc_coord pwc_image_sizes[PSZ_MAX] =
const int pwc_image_sizes[PSZ_MAX][2] =
{
	{ 128,  96, 0 }, /* sqcif */
	{ 160, 120, 0 }, /* qsif */
	{ 176, 144, 0 }, /* qcif */
	{ 320, 240, 0 }, /* sif */
	{ 352, 288, 0 }, /* cif */
	{ 640, 480, 0 }, /* vga */
	{ 128,  96 }, /* sqcif */
	{ 160, 120 }, /* qsif */
	{ 176, 144 }, /* qcif */
	{ 320, 240 }, /* sif */
	{ 352, 288 }, /* cif */
	{ 640, 480 }, /* vga */
};

/* 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
	   requested size. */
	for (i = PSZ_MAX - 1; i >= 0; i--) {
		if (!(pdev->image_mask & (1 << i)))
			continue;

		if (pwc_image_sizes[i][0] <= width &&
		    pwc_image_sizes[i][1] <= height)
			return i;
	}

	/* Find the largest size supported by the camera that fits into the
	   requested size.
	 */
	find = -1;
	/* No mode found, return the smallest mode we have */
	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;
		}
		if (pdev->image_mask & (1 << i))
			return i;
	}
	return find;

	/* Never reached there always is atleast one supported mode */
	return 0;
}

/* initialize variables depending on type and decompressor */
@@ -82,12 +68,6 @@ void pwc_construct(struct pwc_device *pdev)
{
	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->vcinterface = 2;
		pdev->vendpoint = 4;
@@ -96,13 +76,7 @@ void pwc_construct(struct pwc_device *pdev)

	} 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->abs_max.x = 640;
		pdev->abs_max.y = 480;
		pdev->vcinterface = 3;
		pdev->vendpoint = 5;
		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)) */ {

		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->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;
	}
	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;
}
Loading