aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/soc_camera.c93
-rw-r--r--include/media/soc_camera.h25
2 files changed, 105 insertions, 13 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 9db66a4fd1a3..5e48c2cc1a44 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -47,6 +47,18 @@ const struct soc_camera_data_format *soc_camera_format_by_fourcc(
47} 47}
48EXPORT_SYMBOL(soc_camera_format_by_fourcc); 48EXPORT_SYMBOL(soc_camera_format_by_fourcc);
49 49
50const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
51 struct soc_camera_device *icd, unsigned int fourcc)
52{
53 unsigned int i;
54
55 for (i = 0; i < icd->num_user_formats; i++)
56 if (icd->user_formats[i].host_fmt->fourcc == fourcc)
57 return icd->user_formats + i;
58 return NULL;
59}
60EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
61
50static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, 62static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
51 struct v4l2_format *f) 63 struct v4l2_format *f)
52{ 64{
@@ -161,6 +173,59 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
161 return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK); 173 return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
162} 174}
163 175
176static int soc_camera_init_user_formats(struct soc_camera_device *icd)
177{
178 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
179 int i, fmts = 0;
180
181 if (!ici->ops->get_formats)
182 /*
183 * Fallback mode - the host will have to serve all
184 * sensor-provided formats one-to-one to the user
185 */
186 fmts = icd->num_formats;
187 else
188 /*
189 * First pass - only count formats this host-sensor
190 * configuration can provide
191 */
192 for (i = 0; i < icd->num_formats; i++)
193 fmts += ici->ops->get_formats(icd, i, NULL);
194
195 if (!fmts)
196 return -ENXIO;
197
198 icd->user_formats =
199 vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
200 if (!icd->user_formats)
201 return -ENOMEM;
202
203 icd->num_user_formats = fmts;
204 fmts = 0;
205
206 dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
207
208 /* Second pass - actually fill data formats */
209 for (i = 0; i < icd->num_formats; i++)
210 if (!ici->ops->get_formats) {
211 icd->user_formats[i].host_fmt = icd->formats + i;
212 icd->user_formats[i].cam_fmt = icd->formats + i;
213 icd->user_formats[i].buswidth = icd->formats[i].depth;
214 } else {
215 fmts += ici->ops->get_formats(icd, i,
216 &icd->user_formats[fmts]);
217 }
218
219 icd->current_fmt = icd->user_formats[0].host_fmt;
220
221 return 0;
222}
223
224static void soc_camera_free_user_formats(struct soc_camera_device *icd)
225{
226 vfree(icd->user_formats);
227}
228
164static int soc_camera_open(struct inode *inode, struct file *file) 229static int soc_camera_open(struct inode *inode, struct file *file)
165{ 230{
166 struct video_device *vdev; 231 struct video_device *vdev;
@@ -197,10 +262,12 @@ static int soc_camera_open(struct inode *inode, struct file *file)
197 262
198 /* Now we really have to activate the camera */ 263 /* Now we really have to activate the camera */
199 if (icd->use_count == 1) { 264 if (icd->use_count == 1) {
265 ret = soc_camera_init_user_formats(icd);
266 if (ret < 0)
267 goto eiufmt;
200 ret = ici->ops->add(icd); 268 ret = ici->ops->add(icd);
201 if (ret < 0) { 269 if (ret < 0) {
202 dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); 270 dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
203 icd->use_count--;
204 goto eiciadd; 271 goto eiciadd;
205 } 272 }
206 } 273 }
@@ -216,6 +283,9 @@ static int soc_camera_open(struct inode *inode, struct file *file)
216 283
217 /* All errors are entered with the video_lock held */ 284 /* All errors are entered with the video_lock held */
218eiciadd: 285eiciadd:
286 soc_camera_free_user_formats(icd);
287eiufmt:
288 icd->use_count--;
219 module_put(ici->ops->owner); 289 module_put(ici->ops->owner);
220emgi: 290emgi:
221 module_put(icd->ops->owner); 291 module_put(icd->ops->owner);
@@ -234,8 +304,10 @@ static int soc_camera_close(struct inode *inode, struct file *file)
234 304
235 mutex_lock(&video_lock); 305 mutex_lock(&video_lock);
236 icd->use_count--; 306 icd->use_count--;
237 if (!icd->use_count) 307 if (!icd->use_count) {
238 ici->ops->remove(icd); 308 ici->ops->remove(icd);
309 soc_camera_free_user_formats(icd);
310 }
239 module_put(icd->ops->owner); 311 module_put(icd->ops->owner);
240 module_put(ici->ops->owner); 312 module_put(ici->ops->owner);
241 mutex_unlock(&video_lock); 313 mutex_unlock(&video_lock);
@@ -311,6 +383,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
311 struct soc_camera_device *icd = icf->icd; 383 struct soc_camera_device *icd = icf->icd;
312 struct soc_camera_host *ici = 384 struct soc_camera_host *ici =
313 to_soc_camera_host(icd->dev.parent); 385 to_soc_camera_host(icd->dev.parent);
386 __u32 pixfmt = f->fmt.pix.pixelformat;
314 int ret; 387 int ret;
315 struct v4l2_rect rect; 388 struct v4l2_rect rect;
316 389
@@ -328,14 +401,12 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
328 if (ret < 0) { 401 if (ret < 0) {
329 return ret; 402 return ret;
330 } else if (!icd->current_fmt || 403 } else if (!icd->current_fmt ||
331 icd->current_fmt->fourcc != f->fmt.pix.pixelformat) { 404 icd->current_fmt->fourcc != pixfmt) {
332 dev_err(&ici->dev, "Host driver hasn't set up current " 405 dev_err(&ici->dev,
333 "format correctly!\n"); 406 "Host driver hasn't set up current format correctly!\n");
334 return -EINVAL; 407 return -EINVAL;
335 } 408 }
336 409
337 /* buswidth may be further adjusted by the ici */
338 icd->buswidth = icd->current_fmt->depth;
339 icd->width = rect.width; 410 icd->width = rect.width;
340 icd->height = rect.height; 411 icd->height = rect.height;
341 icf->vb_vidq.field = f->fmt.pix.field; 412 icf->vb_vidq.field = f->fmt.pix.field;
@@ -347,7 +418,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
347 icd->width, icd->height); 418 icd->width, icd->height);
348 419
349 /* set physical bus parameters */ 420 /* set physical bus parameters */
350 return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat); 421 return ici->ops->set_bus_param(icd, pixfmt);
351} 422}
352 423
353static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, 424static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
@@ -359,10 +430,10 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
359 430
360 WARN_ON(priv != file->private_data); 431 WARN_ON(priv != file->private_data);
361 432
362 if (f->index >= icd->num_formats) 433 if (f->index >= icd->num_user_formats)
363 return -EINVAL; 434 return -EINVAL;
364 435
365 format = &icd->formats[f->index]; 436 format = icd->user_formats[f->index].host_fmt;
366 437
367 strlcpy(f->description, format->name, sizeof(f->description)); 438 strlcpy(f->description, format->name, sizeof(f->description));
368 f->pixelformat = format->fourcc; 439 f->pixelformat = format->fourcc;
@@ -919,8 +990,6 @@ int soc_camera_video_start(struct soc_camera_device *icd)
919 vdev->minor = -1; 990 vdev->minor = -1;
920 vdev->tvnorms = V4L2_STD_UNKNOWN, 991 vdev->tvnorms = V4L2_STD_UNKNOWN,
921 992
922 icd->current_fmt = &icd->formats[0];
923
924 err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor); 993 err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
925 if (err < 0) { 994 if (err < 0) {
926 dev_err(vdev->parent, "video_register_device failed\n"); 995 dev_err(vdev->parent, "video_register_device failed\n");
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index dddaf45c9583..da57ffdaec4d 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -41,6 +41,8 @@ struct soc_camera_device {
41 const struct soc_camera_data_format *current_fmt; 41 const struct soc_camera_data_format *current_fmt;
42 const struct soc_camera_data_format *formats; 42 const struct soc_camera_data_format *formats;
43 int num_formats; 43 int num_formats;
44 struct soc_camera_format_xlate *user_formats;
45 int num_user_formats;
44 struct module *owner; 46 struct module *owner;
45 void *host_priv; /* per-device host private data */ 47 void *host_priv; /* per-device host private data */
46 /* soc_camera.c private count. Only accessed with video_lock held */ 48 /* soc_camera.c private count. Only accessed with video_lock held */
@@ -65,8 +67,10 @@ struct soc_camera_host_ops {
65 struct module *owner; 67 struct module *owner;
66 int (*add)(struct soc_camera_device *); 68 int (*add)(struct soc_camera_device *);
67 void (*remove)(struct soc_camera_device *); 69 void (*remove)(struct soc_camera_device *);
68 int (*suspend)(struct soc_camera_device *, pm_message_t state); 70 int (*suspend)(struct soc_camera_device *, pm_message_t);
69 int (*resume)(struct soc_camera_device *); 71 int (*resume)(struct soc_camera_device *);
72 int (*get_formats)(struct soc_camera_device *, int,
73 struct soc_camera_format_xlate *);
70 int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *); 74 int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *);
71 int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *); 75 int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
72 void (*init_videobuf)(struct videobuf_queue *, 76 void (*init_videobuf)(struct videobuf_queue *,
@@ -107,6 +111,8 @@ extern void soc_camera_video_stop(struct soc_camera_device *icd);
107 111
108extern const struct soc_camera_data_format *soc_camera_format_by_fourcc( 112extern const struct soc_camera_data_format *soc_camera_format_by_fourcc(
109 struct soc_camera_device *icd, unsigned int fourcc); 113 struct soc_camera_device *icd, unsigned int fourcc);
114extern const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
115 struct soc_camera_device *icd, unsigned int fourcc);
110 116
111struct soc_camera_data_format { 117struct soc_camera_data_format {
112 const char *name; 118 const char *name;
@@ -115,6 +121,23 @@ struct soc_camera_data_format {
115 enum v4l2_colorspace colorspace; 121 enum v4l2_colorspace colorspace;
116}; 122};
117 123
124/**
125 * struct soc_camera_format_xlate - match between host and sensor formats
126 * @cam_fmt: sensor format provided by the sensor
127 * @host_fmt: host format after host translation from cam_fmt
128 * @buswidth: bus width for this format
129 *
130 * Host and sensor translation structure. Used in table of host and sensor
131 * formats matchings in soc_camera_device. A host can override the generic list
132 * generation by implementing get_formats(), and use it for format checks and
133 * format setup.
134 */
135struct soc_camera_format_xlate {
136 const struct soc_camera_data_format *cam_fmt;
137 const struct soc_camera_data_format *host_fmt;
138 unsigned char buswidth;
139};
140
118struct soc_camera_ops { 141struct soc_camera_ops {
119 struct module *owner; 142 struct module *owner;
120 int (*probe)(struct soc_camera_device *); 143 int (*probe)(struct soc_camera_device *);