diff options
-rw-r--r-- | drivers/media/video/soc_camera.c | 100 |
1 files changed, 68 insertions, 32 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 9939b045cb4c..fcd6b2ce9c19 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -30,6 +30,10 @@ | |||
30 | #include <media/videobuf-core.h> | 30 | #include <media/videobuf-core.h> |
31 | #include <media/soc_camera.h> | 31 | #include <media/soc_camera.h> |
32 | 32 | ||
33 | /* Default to VGA resolution */ | ||
34 | #define DEFAULT_WIDTH 640 | ||
35 | #define DEFAULT_HEIGHT 480 | ||
36 | |||
33 | static LIST_HEAD(hosts); | 37 | static LIST_HEAD(hosts); |
34 | static LIST_HEAD(devices); | 38 | static LIST_HEAD(devices); |
35 | static DEFINE_MUTEX(list_lock); | 39 | static DEFINE_MUTEX(list_lock); |
@@ -256,6 +260,44 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd) | |||
256 | vfree(icd->user_formats); | 260 | vfree(icd->user_formats); |
257 | } | 261 | } |
258 | 262 | ||
263 | /* Called with .vb_lock held */ | ||
264 | static int soc_camera_set_fmt(struct soc_camera_file *icf, | ||
265 | struct v4l2_format *f) | ||
266 | { | ||
267 | struct soc_camera_device *icd = icf->icd; | ||
268 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
269 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
270 | int ret; | ||
271 | |||
272 | /* We always call try_fmt() before set_fmt() or set_crop() */ | ||
273 | ret = ici->ops->try_fmt(icd, f); | ||
274 | if (ret < 0) | ||
275 | return ret; | ||
276 | |||
277 | ret = ici->ops->set_fmt(icd, f); | ||
278 | if (ret < 0) { | ||
279 | return ret; | ||
280 | } else if (!icd->current_fmt || | ||
281 | icd->current_fmt->fourcc != pix->pixelformat) { | ||
282 | dev_err(&ici->dev, | ||
283 | "Host driver hasn't set up current format correctly!\n"); | ||
284 | return -EINVAL; | ||
285 | } | ||
286 | |||
287 | icd->width = pix->width; | ||
288 | icd->height = pix->height; | ||
289 | icf->vb_vidq.field = pix->field; | ||
290 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
291 | dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", | ||
292 | f->type); | ||
293 | |||
294 | dev_dbg(&icd->dev, "set width: %d height: %d\n", | ||
295 | icd->width, icd->height); | ||
296 | |||
297 | /* set physical bus parameters */ | ||
298 | return ici->ops->set_bus_param(icd, pix->pixelformat); | ||
299 | } | ||
300 | |||
259 | static int soc_camera_open(struct file *file) | 301 | static int soc_camera_open(struct file *file) |
260 | { | 302 | { |
261 | struct video_device *vdev; | 303 | struct video_device *vdev; |
@@ -297,6 +339,15 @@ static int soc_camera_open(struct file *file) | |||
297 | 339 | ||
298 | /* Now we really have to activate the camera */ | 340 | /* Now we really have to activate the camera */ |
299 | if (icd->use_count == 1) { | 341 | if (icd->use_count == 1) { |
342 | struct v4l2_format f = { | ||
343 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
344 | .fmt.pix = { | ||
345 | .width = DEFAULT_WIDTH, | ||
346 | .height = DEFAULT_HEIGHT, | ||
347 | .field = V4L2_FIELD_ANY, | ||
348 | }, | ||
349 | }; | ||
350 | |||
300 | ret = soc_camera_init_user_formats(icd); | 351 | ret = soc_camera_init_user_formats(icd); |
301 | if (ret < 0) | 352 | if (ret < 0) |
302 | goto eiufmt; | 353 | goto eiufmt; |
@@ -305,6 +356,14 @@ static int soc_camera_open(struct file *file) | |||
305 | dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); | 356 | dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); |
306 | goto eiciadd; | 357 | goto eiciadd; |
307 | } | 358 | } |
359 | |||
360 | f.fmt.pix.pixelformat = icd->current_fmt->fourcc; | ||
361 | f.fmt.pix.colorspace = icd->current_fmt->colorspace; | ||
362 | |||
363 | /* Try to configure with default parameters */ | ||
364 | ret = soc_camera_set_fmt(icf, &f); | ||
365 | if (ret < 0) | ||
366 | goto esfmt; | ||
308 | } | 367 | } |
309 | 368 | ||
310 | mutex_unlock(&icd->video_lock); | 369 | mutex_unlock(&icd->video_lock); |
@@ -316,7 +375,12 @@ static int soc_camera_open(struct file *file) | |||
316 | 375 | ||
317 | return 0; | 376 | return 0; |
318 | 377 | ||
319 | /* First two errors are entered with the .video_lock held */ | 378 | /* |
379 | * First three errors are entered with the .video_lock held | ||
380 | * and use_count == 1 | ||
381 | */ | ||
382 | esfmt: | ||
383 | ici->ops->remove(icd); | ||
320 | eiciadd: | 384 | eiciadd: |
321 | soc_camera_free_user_formats(icd); | 385 | soc_camera_free_user_formats(icd); |
322 | eiufmt: | 386 | eiufmt: |
@@ -415,16 +479,10 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | |||
415 | { | 479 | { |
416 | struct soc_camera_file *icf = file->private_data; | 480 | struct soc_camera_file *icf = file->private_data; |
417 | struct soc_camera_device *icd = icf->icd; | 481 | struct soc_camera_device *icd = icf->icd; |
418 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
419 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
420 | int ret; | 482 | int ret; |
421 | 483 | ||
422 | WARN_ON(priv != file->private_data); | 484 | WARN_ON(priv != file->private_data); |
423 | 485 | ||
424 | ret = soc_camera_try_fmt_vid_cap(file, priv, f); | ||
425 | if (ret < 0) | ||
426 | return ret; | ||
427 | |||
428 | mutex_lock(&icf->vb_vidq.vb_lock); | 486 | mutex_lock(&icf->vb_vidq.vb_lock); |
429 | 487 | ||
430 | if (videobuf_queue_is_busy(&icf->vb_vidq)) { | 488 | if (videobuf_queue_is_busy(&icf->vb_vidq)) { |
@@ -433,29 +491,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | |||
433 | goto unlock; | 491 | goto unlock; |
434 | } | 492 | } |
435 | 493 | ||
436 | ret = ici->ops->set_fmt(icd, f); | 494 | ret = soc_camera_set_fmt(icf, f); |
437 | if (ret < 0) { | ||
438 | goto unlock; | ||
439 | } else if (!icd->current_fmt || | ||
440 | icd->current_fmt->fourcc != pix->pixelformat) { | ||
441 | dev_err(&ici->dev, | ||
442 | "Host driver hasn't set up current format correctly!\n"); | ||
443 | ret = -EINVAL; | ||
444 | goto unlock; | ||
445 | } | ||
446 | |||
447 | icd->width = f->fmt.pix.width; | ||
448 | icd->height = f->fmt.pix.height; | ||
449 | icf->vb_vidq.field = pix->field; | ||
450 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
451 | dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", | ||
452 | f->type); | ||
453 | |||
454 | dev_dbg(&icd->dev, "set width: %d height: %d\n", | ||
455 | icd->width, icd->height); | ||
456 | |||
457 | /* set physical bus parameters */ | ||
458 | ret = ici->ops->set_bus_param(icd, pix->pixelformat); | ||
459 | 495 | ||
460 | unlock: | 496 | unlock: |
461 | mutex_unlock(&icf->vb_vidq.vb_lock); | 497 | mutex_unlock(&icf->vb_vidq.vb_lock); |
@@ -642,8 +678,8 @@ static int soc_camera_cropcap(struct file *file, void *fh, | |||
642 | a->bounds.height = icd->height_max; | 678 | a->bounds.height = icd->height_max; |
643 | a->defrect.left = icd->x_min; | 679 | a->defrect.left = icd->x_min; |
644 | a->defrect.top = icd->y_min; | 680 | a->defrect.top = icd->y_min; |
645 | a->defrect.width = 640; | 681 | a->defrect.width = DEFAULT_WIDTH; |
646 | a->defrect.height = 480; | 682 | a->defrect.height = DEFAULT_HEIGHT; |
647 | a->pixelaspect.numerator = 1; | 683 | a->pixelaspect.numerator = 1; |
648 | a->pixelaspect.denominator = 1; | 684 | a->pixelaspect.denominator = 1; |
649 | 685 | ||