diff options
Diffstat (limited to 'drivers/media/video/soc_camera.c')
-rw-r--r-- | drivers/media/video/soc_camera.c | 78 |
1 files changed, 43 insertions, 35 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 5fdedc766401..6b3fbcca7747 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <media/v4l2-ioctl.h> | 31 | #include <media/v4l2-ioctl.h> |
32 | #include <media/v4l2-dev.h> | 32 | #include <media/v4l2-dev.h> |
33 | #include <media/videobuf-core.h> | 33 | #include <media/videobuf-core.h> |
34 | #include <media/soc_mediabus.h> | ||
34 | 35 | ||
35 | /* Default to VGA resolution */ | 36 | /* Default to VGA resolution */ |
36 | #define DEFAULT_WIDTH 640 | 37 | #define DEFAULT_WIDTH 640 |
@@ -40,18 +41,6 @@ static LIST_HEAD(hosts); | |||
40 | static LIST_HEAD(devices); | 41 | static LIST_HEAD(devices); |
41 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ | 42 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ |
42 | 43 | ||
43 | const struct soc_camera_data_format *soc_camera_format_by_fourcc( | ||
44 | struct soc_camera_device *icd, unsigned int fourcc) | ||
45 | { | ||
46 | unsigned int i; | ||
47 | |||
48 | for (i = 0; i < icd->num_formats; i++) | ||
49 | if (icd->formats[i].fourcc == fourcc) | ||
50 | return icd->formats + i; | ||
51 | return NULL; | ||
52 | } | ||
53 | EXPORT_SYMBOL(soc_camera_format_by_fourcc); | ||
54 | |||
55 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | 44 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( |
56 | struct soc_camera_device *icd, unsigned int fourcc) | 45 | struct soc_camera_device *icd, unsigned int fourcc) |
57 | { | 46 | { |
@@ -207,21 +196,26 @@ static int soc_camera_dqbuf(struct file *file, void *priv, | |||
207 | /* Always entered with .video_lock held */ | 196 | /* Always entered with .video_lock held */ |
208 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) | 197 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) |
209 | { | 198 | { |
199 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
210 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 200 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
211 | int i, fmts = 0, ret; | 201 | int i, fmts = 0, raw_fmts = 0, ret; |
202 | enum v4l2_mbus_pixelcode code; | ||
203 | |||
204 | while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code)) | ||
205 | raw_fmts++; | ||
212 | 206 | ||
213 | if (!ici->ops->get_formats) | 207 | if (!ici->ops->get_formats) |
214 | /* | 208 | /* |
215 | * Fallback mode - the host will have to serve all | 209 | * Fallback mode - the host will have to serve all |
216 | * sensor-provided formats one-to-one to the user | 210 | * sensor-provided formats one-to-one to the user |
217 | */ | 211 | */ |
218 | fmts = icd->num_formats; | 212 | fmts = raw_fmts; |
219 | else | 213 | else |
220 | /* | 214 | /* |
221 | * First pass - only count formats this host-sensor | 215 | * First pass - only count formats this host-sensor |
222 | * configuration can provide | 216 | * configuration can provide |
223 | */ | 217 | */ |
224 | for (i = 0; i < icd->num_formats; i++) { | 218 | for (i = 0; i < raw_fmts; i++) { |
225 | ret = ici->ops->get_formats(icd, i, NULL); | 219 | ret = ici->ops->get_formats(icd, i, NULL); |
226 | if (ret < 0) | 220 | if (ret < 0) |
227 | return ret; | 221 | return ret; |
@@ -242,11 +236,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
242 | 236 | ||
243 | /* Second pass - actually fill data formats */ | 237 | /* Second pass - actually fill data formats */ |
244 | fmts = 0; | 238 | fmts = 0; |
245 | for (i = 0; i < icd->num_formats; i++) | 239 | for (i = 0; i < raw_fmts; i++) |
246 | if (!ici->ops->get_formats) { | 240 | if (!ici->ops->get_formats) { |
247 | icd->user_formats[i].host_fmt = icd->formats + i; | 241 | v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code); |
248 | icd->user_formats[i].cam_fmt = icd->formats + i; | 242 | icd->user_formats[i].host_fmt = |
249 | icd->user_formats[i].buswidth = icd->formats[i].depth; | 243 | soc_mbus_get_fmtdesc(code); |
244 | icd->user_formats[i].code = code; | ||
250 | } else { | 245 | } else { |
251 | ret = ici->ops->get_formats(icd, i, | 246 | ret = ici->ops->get_formats(icd, i, |
252 | &icd->user_formats[fmts]); | 247 | &icd->user_formats[fmts]); |
@@ -255,7 +250,7 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
255 | fmts += ret; | 250 | fmts += ret; |
256 | } | 251 | } |
257 | 252 | ||
258 | icd->current_fmt = icd->user_formats[0].host_fmt; | 253 | icd->current_fmt = &icd->user_formats[0]; |
259 | 254 | ||
260 | return 0; | 255 | return 0; |
261 | 256 | ||
@@ -281,7 +276,7 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd) | |||
281 | #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ | 276 | #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ |
282 | ((x) >> 24) & 0xff | 277 | ((x) >> 24) & 0xff |
283 | 278 | ||
284 | /* Called with .vb_lock held */ | 279 | /* Called with .vb_lock held, or from the first open(2), see comment there */ |
285 | static int soc_camera_set_fmt(struct soc_camera_file *icf, | 280 | static int soc_camera_set_fmt(struct soc_camera_file *icf, |
286 | struct v4l2_format *f) | 281 | struct v4l2_format *f) |
287 | { | 282 | { |
@@ -302,7 +297,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, | |||
302 | if (ret < 0) { | 297 | if (ret < 0) { |
303 | return ret; | 298 | return ret; |
304 | } else if (!icd->current_fmt || | 299 | } else if (!icd->current_fmt || |
305 | icd->current_fmt->fourcc != pix->pixelformat) { | 300 | icd->current_fmt->host_fmt->fourcc != pix->pixelformat) { |
306 | dev_err(&icd->dev, | 301 | dev_err(&icd->dev, |
307 | "Host driver hasn't set up current format correctly!\n"); | 302 | "Host driver hasn't set up current format correctly!\n"); |
308 | return -EINVAL; | 303 | return -EINVAL; |
@@ -310,6 +305,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, | |||
310 | 305 | ||
311 | icd->user_width = pix->width; | 306 | icd->user_width = pix->width; |
312 | icd->user_height = pix->height; | 307 | icd->user_height = pix->height; |
308 | icd->colorspace = pix->colorspace; | ||
313 | icf->vb_vidq.field = | 309 | icf->vb_vidq.field = |
314 | icd->field = pix->field; | 310 | icd->field = pix->field; |
315 | 311 | ||
@@ -369,8 +365,9 @@ static int soc_camera_open(struct file *file) | |||
369 | .width = icd->user_width, | 365 | .width = icd->user_width, |
370 | .height = icd->user_height, | 366 | .height = icd->user_height, |
371 | .field = icd->field, | 367 | .field = icd->field, |
372 | .pixelformat = icd->current_fmt->fourcc, | 368 | .colorspace = icd->colorspace, |
373 | .colorspace = icd->current_fmt->colorspace, | 369 | .pixelformat = |
370 | icd->current_fmt->host_fmt->fourcc, | ||
374 | }, | 371 | }, |
375 | }; | 372 | }; |
376 | 373 | ||
@@ -390,7 +387,12 @@ static int soc_camera_open(struct file *file) | |||
390 | goto eiciadd; | 387 | goto eiciadd; |
391 | } | 388 | } |
392 | 389 | ||
393 | /* Try to configure with default parameters */ | 390 | /* |
391 | * Try to configure with default parameters. Notice: this is the | ||
392 | * very first open, so, we cannot race against other calls, | ||
393 | * apart from someone else calling open() simultaneously, but | ||
394 | * .video_lock is protecting us against it. | ||
395 | */ | ||
394 | ret = soc_camera_set_fmt(icf, &f); | 396 | ret = soc_camera_set_fmt(icf, &f); |
395 | if (ret < 0) | 397 | if (ret < 0) |
396 | goto esfmt; | 398 | goto esfmt; |
@@ -534,7 +536,7 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, | |||
534 | { | 536 | { |
535 | struct soc_camera_file *icf = file->private_data; | 537 | struct soc_camera_file *icf = file->private_data; |
536 | struct soc_camera_device *icd = icf->icd; | 538 | struct soc_camera_device *icd = icf->icd; |
537 | const struct soc_camera_data_format *format; | 539 | const struct soc_mbus_pixelfmt *format; |
538 | 540 | ||
539 | WARN_ON(priv != file->private_data); | 541 | WARN_ON(priv != file->private_data); |
540 | 542 | ||
@@ -543,7 +545,8 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, | |||
543 | 545 | ||
544 | format = icd->user_formats[f->index].host_fmt; | 546 | format = icd->user_formats[f->index].host_fmt; |
545 | 547 | ||
546 | strlcpy(f->description, format->name, sizeof(f->description)); | 548 | if (format->name) |
549 | strlcpy(f->description, format->name, sizeof(f->description)); | ||
547 | f->pixelformat = format->fourcc; | 550 | f->pixelformat = format->fourcc; |
548 | return 0; | 551 | return 0; |
549 | } | 552 | } |
@@ -560,12 +563,15 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, | |||
560 | pix->width = icd->user_width; | 563 | pix->width = icd->user_width; |
561 | pix->height = icd->user_height; | 564 | pix->height = icd->user_height; |
562 | pix->field = icf->vb_vidq.field; | 565 | pix->field = icf->vb_vidq.field; |
563 | pix->pixelformat = icd->current_fmt->fourcc; | 566 | pix->pixelformat = icd->current_fmt->host_fmt->fourcc; |
564 | pix->bytesperline = pix->width * | 567 | pix->bytesperline = soc_mbus_bytes_per_line(pix->width, |
565 | DIV_ROUND_UP(icd->current_fmt->depth, 8); | 568 | icd->current_fmt->host_fmt); |
569 | pix->colorspace = icd->colorspace; | ||
570 | if (pix->bytesperline < 0) | ||
571 | return pix->bytesperline; | ||
566 | pix->sizeimage = pix->height * pix->bytesperline; | 572 | pix->sizeimage = pix->height * pix->bytesperline; |
567 | dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", | 573 | dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", |
568 | icd->current_fmt->fourcc); | 574 | icd->current_fmt->host_fmt->fourcc); |
569 | return 0; | 575 | return 0; |
570 | } | 576 | } |
571 | 577 | ||
@@ -894,7 +900,7 @@ static int soc_camera_probe(struct device *dev) | |||
894 | struct soc_camera_link *icl = to_soc_camera_link(icd); | 900 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
895 | struct device *control = NULL; | 901 | struct device *control = NULL; |
896 | struct v4l2_subdev *sd; | 902 | struct v4l2_subdev *sd; |
897 | struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE}; | 903 | struct v4l2_mbus_framefmt mf; |
898 | int ret; | 904 | int ret; |
899 | 905 | ||
900 | dev_info(dev, "Probing %s\n", dev_name(dev)); | 906 | dev_info(dev, "Probing %s\n", dev_name(dev)); |
@@ -965,9 +971,11 @@ static int soc_camera_probe(struct device *dev) | |||
965 | 971 | ||
966 | /* Try to improve our guess of a reasonable window format */ | 972 | /* Try to improve our guess of a reasonable window format */ |
967 | sd = soc_camera_to_subdev(icd); | 973 | sd = soc_camera_to_subdev(icd); |
968 | if (!v4l2_subdev_call(sd, video, g_fmt, &f)) { | 974 | if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { |
969 | icd->user_width = f.fmt.pix.width; | 975 | icd->user_width = mf.width; |
970 | icd->user_height = f.fmt.pix.height; | 976 | icd->user_height = mf.height; |
977 | icd->colorspace = mf.colorspace; | ||
978 | icd->field = mf.field; | ||
971 | } | 979 | } |
972 | 980 | ||
973 | /* Do we have to sysfs_remove_link() before device_unregister()? */ | 981 | /* Do we have to sysfs_remove_link() before device_unregister()? */ |