aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pwc
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-01-04 14:58:44 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-01-06 07:46:46 -0500
commit795e6eb3262d3b7247ce450835eea6df6571d103 (patch)
tree558c161d69a04a172f54c1edd38c44b2553bf10e /drivers/media/video/pwc
parenta08d2c727153dc6cea1d5d54a43fd7d69c1467c3 (diff)
[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>
Diffstat (limited to 'drivers/media/video/pwc')
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c69
-rw-r--r--drivers/media/video/pwc/pwc-dec23.c29
-rw-r--r--drivers/media/video/pwc/pwc-if.c10
-rw-r--r--drivers/media/video/pwc/pwc-misc.c87
-rw-r--r--drivers/media/video/pwc/pwc-uncompress.c38
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c52
-rw-r--r--drivers/media/video/pwc/pwc.h19
7 files changed, 92 insertions, 212 deletions
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 684b7c50eea..6b9c97fff27 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -102,8 +102,6 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
102#include "pwc-nala.h" 102#include "pwc-nala.h"
103}; 103};
104 104
105static void pwc_set_image_buffer_size(struct pwc_device *pdev);
106
107/****************************************************************************/ 105/****************************************************************************/
108 106
109static int _send_control_msg(struct pwc_device *pdev, 107static 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)
221 /* Set various parameters */ 219 /* Set various parameters */
222 pdev->vframes = frames; 220 pdev->vframes = frames;
223 pdev->valternate = pEntry->alternate; 221 pdev->valternate = pEntry->alternate;
224 pdev->image = pwc_image_sizes[size]; 222 pdev->width = pwc_image_sizes[size][0];
225 pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; 223 pdev->height = pwc_image_sizes[size][1];
224 pdev->frame_size = (pdev->width * pdev->height * 3) / 2;
226 if (pEntry->compressed) { 225 if (pEntry->compressed) {
227 if (pdev->release < 5) { /* 4 fold compression */ 226 if (pdev->release < 5) { /* 4 fold compression */
228 pdev->vbandlength = 528; 227 pdev->vbandlength = 528;
@@ -282,12 +281,13 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames,
282 /* Set various parameters */ 281 /* Set various parameters */
283 pdev->vframes = frames; 282 pdev->vframes = frames;
284 pdev->valternate = pChoose->alternate; 283 pdev->valternate = pChoose->alternate;
285 pdev->image = pwc_image_sizes[size]; 284 pdev->width = pwc_image_sizes[size][0];
285 pdev->height = pwc_image_sizes[size][1];
286 pdev->vbandlength = pChoose->bandlength; 286 pdev->vbandlength = pChoose->bandlength;
287 if (pChoose->bandlength > 0) 287 if (pChoose->bandlength > 0)
288 pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; 288 pdev->frame_size = (pChoose->bandlength * pdev->height) / 4;
289 else 289 else
290 pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; 290 pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
291 return 0; 291 return 0;
292} 292}
293 293
@@ -339,37 +339,25 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames,
339 /* All set and go */ 339 /* All set and go */
340 pdev->vframes = frames; 340 pdev->vframes = frames;
341 pdev->valternate = pChoose->alternate; 341 pdev->valternate = pChoose->alternate;
342 pdev->image = pwc_image_sizes[size]; 342 pdev->width = pwc_image_sizes[size][0];
343 pdev->height = pwc_image_sizes[size][1];
343 pdev->vbandlength = pChoose->bandlength; 344 pdev->vbandlength = pChoose->bandlength;
344 if (pdev->vbandlength > 0) 345 if (pdev->vbandlength > 0)
345 pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; 346 pdev->frame_size = (pdev->vbandlength * pdev->height) / 4;
346 else 347 else
347 pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; 348 pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
348 PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n", 349 PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
349 pdev->frame_size, pdev->vframes, size, pdev->vbandlength); 350 pdev->frame_size, pdev->vframes, size, pdev->vbandlength);
350 return 0; 351 return 0;
351} 352}
352 353
353
354
355/**
356 @pdev: device structure
357 @width: viewport width
358 @height: viewport height
359 @frame: framerate, in fps
360 @compression: preferred compression ratio
361 */
362int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, 354int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
363 int frames, int compression) 355 int frames, int compression)
364{ 356{
365 int ret, size; 357 int ret, size;
366 358
367 PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt); 359 PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt);
368 size = pwc_decode_size(pdev, width, height); 360 size = pwc_get_size(pdev, width, height);
369 if (size < 0) {
370 PWC_DEBUG_MODULE("Could not find suitable size.\n");
371 return -ERANGE;
372 }
373 PWC_TRACE("decode_size = %d.\n", size); 361 PWC_TRACE("decode_size = %d.\n", size);
374 362
375 if (DEVICE_USE_CODEC1(pdev->type)) { 363 if (DEVICE_USE_CODEC1(pdev->type)) {
@@ -385,12 +373,9 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
385 PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); 373 PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
386 return ret; 374 return ret;
387 } 375 }
388 pdev->view.x = width;
389 pdev->view.y = height;
390 pdev->vcompression = compression; 376 pdev->vcompression = compression;
391 pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; 377 pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
392 pwc_set_image_buffer_size(pdev); 378 PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height);
393 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);
394 return 0; 379 return 0;
395} 380}
396 381
@@ -447,34 +432,6 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i
447 return ret; 432 return ret;
448} 433}
449 434
450static void pwc_set_image_buffer_size(struct pwc_device *pdev)
451{
452 int factor = 0;
453
454 /* for V4L2_PIX_FMT_YUV420 */
455 switch (pdev->pixfmt) {
456 case V4L2_PIX_FMT_YUV420:
457 factor = 6;
458 break;
459 case V4L2_PIX_FMT_PWC1:
460 case V4L2_PIX_FMT_PWC2:
461 factor = 6; /* can be uncompressed YUV420P */
462 break;
463 }
464
465 /* Set sizes in bytes */
466 pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
467 pdev->view.size = pdev->view.x * pdev->view.y * factor / 4;
468
469 /* Align offset, or you'll get some very weird results in
470 YUV420 mode... x must be multiple of 4 (to get the Y's in
471 place), and y even (or you'll mixup U & V). This is less of a
472 problem for YUV420P.
473 */
474 pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
475 pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
476}
477
478int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) 435int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
479{ 436{
480 int ret; 437 int ret;
diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c
index e531f85460c..2c6709112b2 100644
--- a/drivers/media/video/pwc/pwc-dec23.c
+++ b/drivers/media/video/pwc/pwc-dec23.c
@@ -656,10 +656,6 @@ static void DecompressBand23(struct pwc_dec23_private *pdec,
656 * 656 *
657 * Uncompress a pwc23 buffer. 657 * Uncompress a pwc23 buffer.
658 * 658 *
659 * pwc.view: size of the image wanted
660 * pwc.image: size of the image returned by the camera
661 * pwc.offset: (x,y) to displayer image in the view
662 *
663 * src: raw data 659 * src: raw data
664 * dst: image output 660 * dst: image output
665 */ 661 */
@@ -667,7 +663,7 @@ void pwc_dec23_decompress(const struct pwc_device *pwc,
667 const void *src, 663 const void *src,
668 void *dst) 664 void *dst)
669{ 665{
670 int bandlines_left, stride, bytes_per_block; 666 int bandlines_left, bytes_per_block;
671 struct pwc_dec23_private *pdec = pwc->decompress_data; 667 struct pwc_dec23_private *pdec = pwc->decompress_data;
672 668
673 /* YUV420P image format */ 669 /* YUV420P image format */
@@ -678,28 +674,23 @@ void pwc_dec23_decompress(const struct pwc_device *pwc,
678 674
679 mutex_lock(&pdec->lock); 675 mutex_lock(&pdec->lock);
680 676
681 bandlines_left = pwc->image.y / 4; 677 bandlines_left = pwc->height / 4;
682 bytes_per_block = pwc->view.x * 4; 678 bytes_per_block = pwc->width * 4;
683 plane_size = pwc->view.x * pwc->view.y; 679 plane_size = pwc->height * pwc->width;
684
685 /* offset in Y plane */
686 stride = pwc->view.x * pwc->offset.y;
687 pout_planar_y = dst + stride + pwc->offset.x;
688 680
689 /* offsets in U/V planes */ 681 pout_planar_y = dst;
690 stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2; 682 pout_planar_u = dst + plane_size;
691 pout_planar_u = dst + plane_size + stride; 683 pout_planar_v = dst + plane_size + plane_size / 4;
692 pout_planar_v = dst + plane_size + plane_size / 4 + stride;
693 684
694 while (bandlines_left--) { 685 while (bandlines_left--) {
695 DecompressBand23(pwc->decompress_data, 686 DecompressBand23(pwc->decompress_data,
696 src, 687 src,
697 pout_planar_y, pout_planar_u, pout_planar_v, 688 pout_planar_y, pout_planar_u, pout_planar_v,
698 pwc->image.x, pwc->view.x); 689 pwc->width, pwc->width);
699 src += pwc->vbandlength; 690 src += pwc->vbandlength;
700 pout_planar_y += bytes_per_block; 691 pout_planar_y += bytes_per_block;
701 pout_planar_u += pwc->view.x; 692 pout_planar_u += pwc->width;
702 pout_planar_v += pwc->view.x; 693 pout_planar_v += pwc->width;
703 } 694 }
704 mutex_unlock(&pdec->lock); 695 mutex_unlock(&pdec->lock);
705} 696}
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 963b4a55ec7..be4406a7c80 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -656,6 +656,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
656 unsigned int sizes[], void *alloc_ctxs[]) 656 unsigned int sizes[], void *alloc_ctxs[])
657{ 657{
658 struct pwc_device *pdev = vb2_get_drv_priv(vq); 658 struct pwc_device *pdev = vb2_get_drv_priv(vq);
659 int size;
659 660
660 if (*nbuffers < MIN_FRAMES) 661 if (*nbuffers < MIN_FRAMES)
661 *nbuffers = MIN_FRAMES; 662 *nbuffers = MIN_FRAMES;
@@ -664,7 +665,9 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
664 665
665 *nplanes = 1; 666 *nplanes = 1;
666 667
667 sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2); 668 size = pwc_get_size(pdev, MAX_WIDTH, MAX_HEIGHT);
669 sizes[0] = PAGE_ALIGN(pwc_image_sizes[size][0] *
670 pwc_image_sizes[size][1] * 3 / 2);
668 671
669 return 0; 672 return 0;
670} 673}
@@ -742,7 +745,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
742 pwc_camera_power(pdev, 1); 745 pwc_camera_power(pdev, 1);
743 if (pdev->power_save) { 746 if (pdev->power_save) {
744 /* Restore video mode */ 747 /* Restore video mode */
745 pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, 748 pwc_set_video_mode(pdev, pdev->width, pdev->height,
746 pdev->vframes, pdev->vcompression); 749 pdev->vframes, pdev->vcompression);
747 } 750 }
748 pwc_set_leds(pdev, led_on, led_off); 751 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
1056 } 1059 }
1057 pdev->type = type_id; 1060 pdev->type = type_id;
1058 pdev->vframes = default_fps; 1061 pdev->vframes = default_fps;
1059 strcpy(pdev->serial, serial_number);
1060 pdev->features = features; 1062 pdev->features = features;
1061 pwc_construct(pdev); /* set min/max sizes correct */ 1063 pwc_construct(pdev); /* set min/max sizes correct */
1062 1064
@@ -1119,7 +1121,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
1119 pwc_set_leds(pdev, 0, 0); 1121 pwc_set_leds(pdev, 0, 0);
1120 1122
1121 /* Setup intial videomode */ 1123 /* Setup intial videomode */
1122 rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y, 1124 rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT,
1123 pdev->vframes, pdev->vcompression); 1125 pdev->vframes, pdev->vcompression);
1124 if (rc) 1126 if (rc)
1125 goto err_free_mem; 1127 goto err_free_mem;
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c
index 0b031336eab..23a55b5814f 100644
--- a/drivers/media/video/pwc/pwc-misc.c
+++ b/drivers/media/video/pwc/pwc-misc.c
@@ -27,67 +27,47 @@
27 27
28#include "pwc.h" 28#include "pwc.h"
29 29
30const struct pwc_coord pwc_image_sizes[PSZ_MAX] = 30const int pwc_image_sizes[PSZ_MAX][2] =
31{ 31{
32 { 128, 96, 0 }, /* sqcif */ 32 { 128, 96 }, /* sqcif */
33 { 160, 120, 0 }, /* qsif */ 33 { 160, 120 }, /* qsif */
34 { 176, 144, 0 }, /* qcif */ 34 { 176, 144 }, /* qcif */
35 { 320, 240, 0 }, /* sif */ 35 { 320, 240 }, /* sif */
36 { 352, 288, 0 }, /* cif */ 36 { 352, 288 }, /* cif */
37 { 640, 480, 0 }, /* vga */ 37 { 640, 480 }, /* vga */
38}; 38};
39 39
40/* x,y -> PSZ_ */ 40/* x,y -> PSZ_ */
41int pwc_decode_size(struct pwc_device *pdev, int width, int height) 41int pwc_get_size(struct pwc_device *pdev, int width, int height)
42{ 42{
43 int i, find; 43 int i;
44
45 /* Make sure we don't go beyond our max size.
46 NB: we have different limits for RAW and normal modes. In case
47 you don't have the decompressor loaded or use RAW mode,
48 the maximum viewable size is smaller.
49 */
50 if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
51 {
52 if (width > pdev->abs_max.x || height > pdev->abs_max.y)
53 {
54 PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
55 return -1;
56 }
57 }
58 else
59 {
60 if (width > pdev->view_max.x || height > pdev->view_max.y)
61 {
62 PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
63 return -1;
64 }
65 }
66 44
67 /* Find the largest size supported by the camera that fits into the 45 /* Find the largest size supported by the camera that fits into the
68 requested size. 46 requested size. */
69 */ 47 for (i = PSZ_MAX - 1; i >= 0; i--) {
70 find = -1; 48 if (!(pdev->image_mask & (1 << i)))
49 continue;
50
51 if (pwc_image_sizes[i][0] <= width &&
52 pwc_image_sizes[i][1] <= height)
53 return i;
54 }
55
56 /* No mode found, return the smallest mode we have */
71 for (i = 0; i < PSZ_MAX; i++) { 57 for (i = 0; i < PSZ_MAX; i++) {
72 if (pdev->image_mask & (1 << i)) { 58 if (pdev->image_mask & (1 << i))
73 if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) 59 return i;
74 find = i;
75 }
76 } 60 }
77 return find; 61
62 /* Never reached there always is atleast one supported mode */
63 return 0;
78} 64}
79 65
80/* initialize variables depending on type and decompressor*/ 66/* initialize variables depending on type and decompressor */
81void pwc_construct(struct pwc_device *pdev) 67void pwc_construct(struct pwc_device *pdev)
82{ 68{
83 if (DEVICE_USE_CODEC1(pdev->type)) { 69 if (DEVICE_USE_CODEC1(pdev->type)) {
84 70
85 pdev->view_min.x = 128;
86 pdev->view_min.y = 96;
87 pdev->view_max.x = 352;
88 pdev->view_max.y = 288;
89 pdev->abs_max.x = 352;
90 pdev->abs_max.y = 288;
91 pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; 71 pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF;
92 pdev->vcinterface = 2; 72 pdev->vcinterface = 2;
93 pdev->vendpoint = 4; 73 pdev->vendpoint = 4;
@@ -96,13 +76,7 @@ void pwc_construct(struct pwc_device *pdev)
96 76
97 } else if (DEVICE_USE_CODEC3(pdev->type)) { 77 } else if (DEVICE_USE_CODEC3(pdev->type)) {
98 78
99 pdev->view_min.x = 160;
100 pdev->view_min.y = 120;
101 pdev->view_max.x = 640;
102 pdev->view_max.y = 480;
103 pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; 79 pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
104 pdev->abs_max.x = 640;
105 pdev->abs_max.y = 480;
106 pdev->vcinterface = 3; 80 pdev->vcinterface = 3;
107 pdev->vendpoint = 5; 81 pdev->vendpoint = 5;
108 pdev->frame_header_size = TOUCAM_HEADER_SIZE; 82 pdev->frame_header_size = TOUCAM_HEADER_SIZE;
@@ -110,20 +84,11 @@ void pwc_construct(struct pwc_device *pdev)
110 84
111 } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ { 85 } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
112 86
113 pdev->view_min.x = 128;
114 pdev->view_min.y = 96;
115 /* Anthill bug #38: PWC always reports max size, even without PWCX */
116 pdev->view_max.x = 640;
117 pdev->view_max.y = 480;
118 pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; 87 pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
119 pdev->abs_max.x = 640;
120 pdev->abs_max.y = 480;
121 pdev->vcinterface = 3; 88 pdev->vcinterface = 3;
122 pdev->vendpoint = 4; 89 pdev->vendpoint = 4;
123 pdev->frame_header_size = 0; 90 pdev->frame_header_size = 0;
124 pdev->frame_trailer_size = 0; 91 pdev->frame_trailer_size = 0;
125 } 92 }
126 pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */ 93 pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */
127 pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
128 pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
129} 94}
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c
index e55b568cbf3..b65903fbcf0 100644
--- a/drivers/media/video/pwc/pwc-uncompress.c
+++ b/drivers/media/video/pwc/pwc-uncompress.c
@@ -35,7 +35,7 @@
35 35
36int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) 36int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
37{ 37{
38 int n, line, col, stride; 38 int n, line, col;
39 void *yuv, *image; 39 void *yuv, *image;
40 u16 *src; 40 u16 *src;
41 u16 *dsty, *dstu, *dstv; 41 u16 *dsty, *dstu, *dstv;
@@ -60,35 +60,23 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
60 return 0; 60 return 0;
61 } 61 }
62 62
63 vb2_set_plane_payload(&fbuf->vb, 0, pdev->view.size); 63 vb2_set_plane_payload(&fbuf->vb, 0,
64 pdev->width * pdev->height * 3 / 2);
64 65
65 if (pdev->vbandlength == 0) { 66 if (pdev->vbandlength == 0) {
66 /* Uncompressed mode. 67 /* Uncompressed mode.
67 * We copy the data into the output buffer, using the viewport
68 * size (which may be larger than the image size).
69 * Unfortunately we have to do a bit of byte stuffing to get
70 * the desired output format/size.
71 * 68 *
72 * We do some byte shuffling here to go from the 69 * We do some byte shuffling here to go from the
73 * native format to YUV420P. 70 * native format to YUV420P.
74 */ 71 */
75 src = (u16 *)yuv; 72 src = (u16 *)yuv;
76 n = pdev->view.x * pdev->view.y; 73 n = pdev->width * pdev->height;
74 dsty = (u16 *)(image);
75 dstu = (u16 *)(image + n);
76 dstv = (u16 *)(image + n + n / 4);
77 77
78 /* offset in Y plane */ 78 for (line = 0; line < pdev->height; line++) {
79 stride = pdev->view.x * pdev->offset.y + pdev->offset.x; 79 for (col = 0; col < pdev->width; col += 4) {
80 dsty = (u16 *)(image + stride);
81
82 /* offsets in U/V planes */
83 stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
84 dstu = (u16 *)(image + n + stride);
85 dstv = (u16 *)(image + n + n / 4 + stride);
86
87 /* increment after each line */
88 stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
89
90 for (line = 0; line < pdev->image.y; line++) {
91 for (col = 0; col < pdev->image.x; col += 4) {
92 *dsty++ = *src++; 80 *dsty++ = *src++;
93 *dsty++ = *src++; 81 *dsty++ = *src++;
94 if (line & 1) 82 if (line & 1)
@@ -96,11 +84,6 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
96 else 84 else
97 *dstu++ = *src++; 85 *dstu++ = *src++;
98 } 86 }
99 dsty += stride;
100 if (line & 1)
101 dstv += (stride >> 1);
102 else
103 dstu += (stride >> 1);
104 } 87 }
105 88
106 return 0; 89 return 0;
@@ -122,6 +105,3 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
122 } 105 }
123 return 0; 106 return 0;
124} 107}
125
126
127/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index 87457b53f49..097ec582ee6 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -398,8 +398,8 @@ int pwc_init_controls(struct pwc_device *pdev)
398static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f) 398static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
399{ 399{
400 memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); 400 memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
401 f->fmt.pix.width = pdev->view.x; 401 f->fmt.pix.width = pdev->width;
402 f->fmt.pix.height = pdev->view.y; 402 f->fmt.pix.height = pdev->height;
403 f->fmt.pix.field = V4L2_FIELD_NONE; 403 f->fmt.pix.field = V4L2_FIELD_NONE;
404 if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) { 404 if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
405 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; 405 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
429/* ioctl(VIDIOC_TRY_FMT) */ 429/* ioctl(VIDIOC_TRY_FMT) */
430static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) 430static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
431{ 431{
432 int size;
433
432 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { 434 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
433 PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); 435 PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
434 return -EINVAL; 436 return -EINVAL;
@@ -455,15 +457,9 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
455 457
456 } 458 }
457 459
458 if (f->fmt.pix.width > pdev->view_max.x) 460 size = pwc_get_size(pdev, f->fmt.pix.width, f->fmt.pix.height);
459 f->fmt.pix.width = pdev->view_max.x; 461 f->fmt.pix.width = pwc_image_sizes[size][0];
460 else if (f->fmt.pix.width < pdev->view_min.x) 462 f->fmt.pix.height = pwc_image_sizes[size][1];
461 f->fmt.pix.width = pdev->view_min.x;
462
463 if (f->fmt.pix.height > pdev->view_max.y)
464 f->fmt.pix.height = pdev->view_max.y;
465 else if (f->fmt.pix.height < pdev->view_min.y)
466 f->fmt.pix.height = pdev->view_min.y;
467 463
468 return 0; 464 return 0;
469} 465}
@@ -972,7 +968,7 @@ static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
972 968
973 mutex_lock(&pdev->udevlock); /* To avoid race with s_fmt */ 969 mutex_lock(&pdev->udevlock); /* To avoid race with s_fmt */
974 PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n", 970 PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
975 pdev->image.x, pdev->image.y); 971 pdev->width, pdev->height);
976 pwc_vidioc_fill_fmt(pdev, f); 972 pwc_vidioc_fill_fmt(pdev, f);
977 mutex_unlock(&pdev->udevlock); 973 mutex_unlock(&pdev->udevlock);
978 return 0; 974 return 0;
@@ -1061,25 +1057,21 @@ static int pwc_enum_framesizes(struct file *file, void *fh,
1061 struct pwc_device *pdev = video_drvdata(file); 1057 struct pwc_device *pdev = video_drvdata(file);
1062 unsigned int i = 0, index = fsize->index; 1058 unsigned int i = 0, index = fsize->index;
1063 1059
1064 if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { 1060 if (fsize->pixel_format == V4L2_PIX_FMT_YUV420 ||
1061 (fsize->pixel_format == V4L2_PIX_FMT_PWC1 &&
1062 DEVICE_USE_CODEC1(pdev->type)) ||
1063 (fsize->pixel_format == V4L2_PIX_FMT_PWC2 &&
1064 DEVICE_USE_CODEC23(pdev->type))) {
1065 for (i = 0; i < PSZ_MAX; i++) { 1065 for (i = 0; i < PSZ_MAX; i++) {
1066 if (pdev->image_mask & (1UL << i)) { 1066 if (!(pdev->image_mask & (1UL << i)))
1067 if (!index--) { 1067 continue;
1068 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; 1068 if (!index--) {
1069 fsize->discrete.width = pwc_image_sizes[i].x; 1069 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1070 fsize->discrete.height = pwc_image_sizes[i].y; 1070 fsize->discrete.width = pwc_image_sizes[i][0];
1071 return 0; 1071 fsize->discrete.height = pwc_image_sizes[i][1];
1072 } 1072 return 0;
1073 } 1073 }
1074 } 1074 }
1075 } else if (fsize->index == 0 &&
1076 ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
1077 (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
1078
1079 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1080 fsize->discrete.width = pdev->abs_max.x;
1081 fsize->discrete.height = pdev->abs_max.y;
1082 return 0;
1083 } 1075 }
1084 return -EINVAL; 1076 return -EINVAL;
1085} 1077}
@@ -1092,8 +1084,8 @@ static int pwc_enum_frameintervals(struct file *file, void *fh,
1092 unsigned int i; 1084 unsigned int i;
1093 1085
1094 for (i = 0; i < PSZ_MAX; i++) { 1086 for (i = 0; i < PSZ_MAX; i++) {
1095 if (pwc_image_sizes[i].x == fival->width && 1087 if (pwc_image_sizes[i][0] == fival->width &&
1096 pwc_image_sizes[i].y == fival->height) { 1088 pwc_image_sizes[i][1] == fival->height) {
1097 size = i; 1089 size = i;
1098 break; 1090 break;
1099 } 1091 }
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 19c692c186f..5d013851ed2 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -107,6 +107,9 @@
107#define FEATURE_CODEC1 0x0002 107#define FEATURE_CODEC1 0x0002
108#define FEATURE_CODEC2 0x0004 108#define FEATURE_CODEC2 0x0004
109 109
110#define MAX_WIDTH 640
111#define MAX_HEIGHT 480
112
110/* Ignore errors in the first N frames, to allow for startup delays */ 113/* Ignore errors in the first N frames, to allow for startup delays */
111#define FRAME_LOWMARK 5 114#define FRAME_LOWMARK 5
112 115
@@ -205,12 +208,6 @@ struct pwc_raw_frame {
205 __u8 rawframe[0]; /* frame_size = H / 4 * vbandlength */ 208 __u8 rawframe[0]; /* frame_size = H / 4 * vbandlength */
206} __packed; 209} __packed;
207 210
208/* structure for transferring x & y coordinates */
209struct pwc_coord {
210 int x, y; /* guess what */
211 int size; /* size, or offset */
212};
213
214/* intermediate buffers with raw data from the USB cam */ 211/* intermediate buffers with raw data from the USB cam */
215struct pwc_frame_buf 212struct pwc_frame_buf
216{ 213{
@@ -233,7 +230,6 @@ struct pwc_device
233 int type; 230 int type;
234 int release; /* release number */ 231 int release; /* release number */
235 int features; /* feature bits */ 232 int features; /* feature bits */
236 char serial[30]; /* serial number (string) */
237 233
238 /*** Video data ***/ 234 /*** Video data ***/
239 struct file *capt_file; /* file doing video capture */ 235 struct file *capt_file; /* file doing video capture */
@@ -286,10 +282,7 @@ struct pwc_device
286 * a gray or black border. view_min <= image <= view <= view_max; 282 * a gray or black border. view_min <= image <= view <= view_max;
287 */ 283 */
288 int image_mask; /* supported sizes */ 284 int image_mask; /* supported sizes */
289 struct pwc_coord view_min, view_max; /* minimum and maximum view */ 285 int width, height; /* current resolution */
290 struct pwc_coord abs_max; /* maximum supported size */
291 struct pwc_coord image, view; /* image and viewport size */
292 struct pwc_coord offset; /* offset of the viewport */
293 286
294#ifdef CONFIG_USB_PWC_INPUT_EVDEV 287#ifdef CONFIG_USB_PWC_INPUT_EVDEV
295 struct input_dev *button_dev; /* webcam snapshot button input */ 288 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);
364 357
365/** Functions in pwc-misc.c */ 358/** Functions in pwc-misc.c */
366/* sizes in pixels */ 359/* sizes in pixels */
367extern const struct pwc_coord pwc_image_sizes[PSZ_MAX]; 360extern const int pwc_image_sizes[PSZ_MAX][2];
368 361
369int pwc_decode_size(struct pwc_device *pdev, int width, int height); 362int pwc_get_size(struct pwc_device *pdev, int width, int height);
370void pwc_construct(struct pwc_device *pdev); 363void pwc_construct(struct pwc_device *pdev);
371 364
372/** Functions in pwc-ctrl.c */ 365/** Functions in pwc-ctrl.c */