diff options
-rw-r--r-- | drivers/media/video/soc_camera.c | 93 | ||||
-rw-r--r-- | include/media/soc_camera.h | 25 |
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 | } |
48 | EXPORT_SYMBOL(soc_camera_format_by_fourcc); | 48 | EXPORT_SYMBOL(soc_camera_format_by_fourcc); |
49 | 49 | ||
50 | const 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 | } | ||
60 | EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); | ||
61 | |||
50 | static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, | 62 | static 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 | ||
176 | static 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 | |||
224 | static void soc_camera_free_user_formats(struct soc_camera_device *icd) | ||
225 | { | ||
226 | vfree(icd->user_formats); | ||
227 | } | ||
228 | |||
164 | static int soc_camera_open(struct inode *inode, struct file *file) | 229 | static 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 */ |
218 | eiciadd: | 285 | eiciadd: |
286 | soc_camera_free_user_formats(icd); | ||
287 | eiufmt: | ||
288 | icd->use_count--; | ||
219 | module_put(ici->ops->owner); | 289 | module_put(ici->ops->owner); |
220 | emgi: | 290 | emgi: |
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 | ||
353 | static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, | 424 | static 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 | ||
108 | extern const struct soc_camera_data_format *soc_camera_format_by_fourcc( | 112 | extern 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); |
114 | extern const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | ||
115 | struct soc_camera_device *icd, unsigned int fourcc); | ||
110 | 116 | ||
111 | struct soc_camera_data_format { | 117 | struct 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 | */ | ||
135 | struct 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 | |||
118 | struct soc_camera_ops { | 141 | struct 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 *); |