diff options
Diffstat (limited to 'drivers/media/video/soc_camera.c')
-rw-r--r-- | drivers/media/video/soc_camera.c | 389 |
1 files changed, 274 insertions, 115 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 66ebe5956a87..90077cb4fe66 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -33,10 +33,9 @@ | |||
33 | static LIST_HEAD(hosts); | 33 | static LIST_HEAD(hosts); |
34 | static LIST_HEAD(devices); | 34 | static LIST_HEAD(devices); |
35 | static DEFINE_MUTEX(list_lock); | 35 | static DEFINE_MUTEX(list_lock); |
36 | static DEFINE_MUTEX(video_lock); | ||
37 | 36 | ||
38 | const static struct soc_camera_data_format* | 37 | const struct soc_camera_data_format *soc_camera_format_by_fourcc( |
39 | format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc) | 38 | struct soc_camera_device *icd, unsigned int fourcc) |
40 | { | 39 | { |
41 | unsigned int i; | 40 | unsigned int i; |
42 | 41 | ||
@@ -45,67 +44,87 @@ format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc) | |||
45 | return icd->formats + i; | 44 | return icd->formats + i; |
46 | return NULL; | 45 | return NULL; |
47 | } | 46 | } |
47 | EXPORT_SYMBOL(soc_camera_format_by_fourcc); | ||
48 | 48 | ||
49 | static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, | 49 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( |
50 | struct v4l2_format *f) | 50 | struct soc_camera_device *icd, unsigned int fourcc) |
51 | { | 51 | { |
52 | struct soc_camera_file *icf = file->private_data; | 52 | unsigned int i; |
53 | struct soc_camera_device *icd = icf->icd; | ||
54 | struct soc_camera_host *ici = | ||
55 | to_soc_camera_host(icd->dev.parent); | ||
56 | enum v4l2_field field; | ||
57 | const struct soc_camera_data_format *fmt; | ||
58 | int ret; | ||
59 | 53 | ||
60 | WARN_ON(priv != file->private_data); | 54 | for (i = 0; i < icd->num_user_formats; i++) |
55 | if (icd->user_formats[i].host_fmt->fourcc == fourcc) | ||
56 | return icd->user_formats + i; | ||
57 | return NULL; | ||
58 | } | ||
59 | EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); | ||
61 | 60 | ||
62 | fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat); | 61 | /** |
63 | if (!fmt) { | 62 | * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags |
64 | dev_dbg(&icd->dev, "invalid format 0x%08x\n", | 63 | * @icl: camera platform parameters |
65 | f->fmt.pix.pixelformat); | 64 | * @flags: flags to be inverted according to platform configuration |
66 | return -EINVAL; | 65 | * @return: resulting flags |
67 | } | 66 | */ |
67 | unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, | ||
68 | unsigned long flags) | ||
69 | { | ||
70 | unsigned long f; | ||
68 | 71 | ||
69 | dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc); | 72 | /* If only one of the two polarities is supported, switch to the opposite */ |
73 | if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) { | ||
74 | f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW); | ||
75 | if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW) | ||
76 | flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW; | ||
77 | } | ||
70 | 78 | ||
71 | field = f->fmt.pix.field; | 79 | if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) { |
80 | f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW); | ||
81 | if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW) | ||
82 | flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW; | ||
83 | } | ||
72 | 84 | ||
73 | if (field == V4L2_FIELD_ANY) { | 85 | if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) { |
74 | field = V4L2_FIELD_NONE; | 86 | f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING); |
75 | } else if (V4L2_FIELD_NONE != field) { | 87 | if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING) |
76 | dev_err(&icd->dev, "Field type invalid.\n"); | 88 | flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING; |
77 | return -EINVAL; | ||
78 | } | 89 | } |
79 | 90 | ||
80 | /* test physical bus parameters */ | 91 | return flags; |
81 | ret = ici->ops->try_bus_param(icd, f->fmt.pix.pixelformat); | 92 | } |
82 | if (ret) | 93 | EXPORT_SYMBOL(soc_camera_apply_sensor_flags); |
83 | return ret; | ||
84 | 94 | ||
85 | /* limit format to hardware capabilities */ | 95 | static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, |
86 | ret = ici->ops->try_fmt_cap(icd, f); | 96 | struct v4l2_format *f) |
97 | { | ||
98 | struct soc_camera_file *icf = file->private_data; | ||
99 | struct soc_camera_device *icd = icf->icd; | ||
100 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
87 | 101 | ||
88 | /* calculate missing fields */ | 102 | WARN_ON(priv != file->private_data); |
89 | f->fmt.pix.field = field; | ||
90 | f->fmt.pix.bytesperline = | ||
91 | (f->fmt.pix.width * fmt->depth) >> 3; | ||
92 | f->fmt.pix.sizeimage = | ||
93 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
94 | 103 | ||
95 | return ret; | 104 | /* limit format to hardware capabilities */ |
105 | return ici->ops->try_fmt(icd, f); | ||
96 | } | 106 | } |
97 | 107 | ||
98 | static int soc_camera_enum_input(struct file *file, void *priv, | 108 | static int soc_camera_enum_input(struct file *file, void *priv, |
99 | struct v4l2_input *inp) | 109 | struct v4l2_input *inp) |
100 | { | 110 | { |
111 | struct soc_camera_file *icf = file->private_data; | ||
112 | struct soc_camera_device *icd = icf->icd; | ||
113 | int ret = 0; | ||
114 | |||
101 | if (inp->index != 0) | 115 | if (inp->index != 0) |
102 | return -EINVAL; | 116 | return -EINVAL; |
103 | 117 | ||
104 | inp->type = V4L2_INPUT_TYPE_CAMERA; | 118 | if (icd->ops->enum_input) |
105 | inp->std = V4L2_STD_UNKNOWN; | 119 | ret = icd->ops->enum_input(icd, inp); |
106 | strcpy(inp->name, "Camera"); | 120 | else { |
121 | /* default is camera */ | ||
122 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
123 | inp->std = V4L2_STD_UNKNOWN; | ||
124 | strcpy(inp->name, "Camera"); | ||
125 | } | ||
107 | 126 | ||
108 | return 0; | 127 | return ret; |
109 | } | 128 | } |
110 | 129 | ||
111 | static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i) | 130 | static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i) |
@@ -125,7 +144,14 @@ static int soc_camera_s_input(struct file *file, void *priv, unsigned int i) | |||
125 | 144 | ||
126 | static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) | 145 | static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) |
127 | { | 146 | { |
128 | return 0; | 147 | struct soc_camera_file *icf = file->private_data; |
148 | struct soc_camera_device *icd = icf->icd; | ||
149 | int ret = 0; | ||
150 | |||
151 | if (icd->ops->set_std) | ||
152 | ret = icd->ops->set_std(icd, a); | ||
153 | |||
154 | return ret; | ||
129 | } | 155 | } |
130 | 156 | ||
131 | static int soc_camera_reqbufs(struct file *file, void *priv, | 157 | static int soc_camera_reqbufs(struct file *file, void *priv, |
@@ -134,8 +160,7 @@ static int soc_camera_reqbufs(struct file *file, void *priv, | |||
134 | int ret; | 160 | int ret; |
135 | struct soc_camera_file *icf = file->private_data; | 161 | struct soc_camera_file *icf = file->private_data; |
136 | struct soc_camera_device *icd = icf->icd; | 162 | struct soc_camera_device *icd = icf->icd; |
137 | struct soc_camera_host *ici = | 163 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
138 | to_soc_camera_host(icd->dev.parent); | ||
139 | 164 | ||
140 | WARN_ON(priv != file->private_data); | 165 | WARN_ON(priv != file->private_data); |
141 | 166 | ||
@@ -178,6 +203,59 @@ static int soc_camera_dqbuf(struct file *file, void *priv, | |||
178 | return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK); | 203 | return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK); |
179 | } | 204 | } |
180 | 205 | ||
206 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) | ||
207 | { | ||
208 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
209 | int i, fmts = 0; | ||
210 | |||
211 | if (!ici->ops->get_formats) | ||
212 | /* | ||
213 | * Fallback mode - the host will have to serve all | ||
214 | * sensor-provided formats one-to-one to the user | ||
215 | */ | ||
216 | fmts = icd->num_formats; | ||
217 | else | ||
218 | /* | ||
219 | * First pass - only count formats this host-sensor | ||
220 | * configuration can provide | ||
221 | */ | ||
222 | for (i = 0; i < icd->num_formats; i++) | ||
223 | fmts += ici->ops->get_formats(icd, i, NULL); | ||
224 | |||
225 | if (!fmts) | ||
226 | return -ENXIO; | ||
227 | |||
228 | icd->user_formats = | ||
229 | vmalloc(fmts * sizeof(struct soc_camera_format_xlate)); | ||
230 | if (!icd->user_formats) | ||
231 | return -ENOMEM; | ||
232 | |||
233 | icd->num_user_formats = fmts; | ||
234 | fmts = 0; | ||
235 | |||
236 | dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts); | ||
237 | |||
238 | /* Second pass - actually fill data formats */ | ||
239 | for (i = 0; i < icd->num_formats; i++) | ||
240 | if (!ici->ops->get_formats) { | ||
241 | icd->user_formats[i].host_fmt = icd->formats + i; | ||
242 | icd->user_formats[i].cam_fmt = icd->formats + i; | ||
243 | icd->user_formats[i].buswidth = icd->formats[i].depth; | ||
244 | } else { | ||
245 | fmts += ici->ops->get_formats(icd, i, | ||
246 | &icd->user_formats[fmts]); | ||
247 | } | ||
248 | |||
249 | icd->current_fmt = icd->user_formats[0].host_fmt; | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static void soc_camera_free_user_formats(struct soc_camera_device *icd) | ||
255 | { | ||
256 | vfree(icd->user_formats); | ||
257 | } | ||
258 | |||
181 | static int soc_camera_open(struct inode *inode, struct file *file) | 259 | static int soc_camera_open(struct inode *inode, struct file *file) |
182 | { | 260 | { |
183 | struct video_device *vdev; | 261 | struct video_device *vdev; |
@@ -190,8 +268,10 @@ static int soc_camera_open(struct inode *inode, struct file *file) | |||
190 | if (!icf) | 268 | if (!icf) |
191 | return -ENOMEM; | 269 | return -ENOMEM; |
192 | 270 | ||
193 | /* Protect against icd->remove() until we module_get() both drivers. */ | 271 | /* |
194 | mutex_lock(&video_lock); | 272 | * It is safe to dereference these pointers now as long as a user has |
273 | * the video device open - we are protected by the held cdev reference. | ||
274 | */ | ||
195 | 275 | ||
196 | vdev = video_devdata(file); | 276 | vdev = video_devdata(file); |
197 | icd = container_of(vdev->parent, struct soc_camera_device, dev); | 277 | icd = container_of(vdev->parent, struct soc_camera_device, dev); |
@@ -209,20 +289,25 @@ static int soc_camera_open(struct inode *inode, struct file *file) | |||
209 | goto emgi; | 289 | goto emgi; |
210 | } | 290 | } |
211 | 291 | ||
292 | /* Protect against icd->remove() until we module_get() both drivers. */ | ||
293 | mutex_lock(&icd->video_lock); | ||
294 | |||
212 | icf->icd = icd; | 295 | icf->icd = icd; |
213 | icd->use_count++; | 296 | icd->use_count++; |
214 | 297 | ||
215 | /* Now we really have to activate the camera */ | 298 | /* Now we really have to activate the camera */ |
216 | if (icd->use_count == 1) { | 299 | if (icd->use_count == 1) { |
300 | ret = soc_camera_init_user_formats(icd); | ||
301 | if (ret < 0) | ||
302 | goto eiufmt; | ||
217 | ret = ici->ops->add(icd); | 303 | ret = ici->ops->add(icd); |
218 | if (ret < 0) { | 304 | if (ret < 0) { |
219 | dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); | 305 | dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); |
220 | icd->use_count--; | ||
221 | goto eiciadd; | 306 | goto eiciadd; |
222 | } | 307 | } |
223 | } | 308 | } |
224 | 309 | ||
225 | mutex_unlock(&video_lock); | 310 | mutex_unlock(&icd->video_lock); |
226 | 311 | ||
227 | file->private_data = icf; | 312 | file->private_data = icf; |
228 | dev_dbg(&icd->dev, "camera device open\n"); | 313 | dev_dbg(&icd->dev, "camera device open\n"); |
@@ -231,13 +316,16 @@ static int soc_camera_open(struct inode *inode, struct file *file) | |||
231 | 316 | ||
232 | return 0; | 317 | return 0; |
233 | 318 | ||
234 | /* All errors are entered with the video_lock held */ | 319 | /* First two errors are entered with the .video_lock held */ |
235 | eiciadd: | 320 | eiciadd: |
321 | soc_camera_free_user_formats(icd); | ||
322 | eiufmt: | ||
323 | icd->use_count--; | ||
324 | mutex_unlock(&icd->video_lock); | ||
236 | module_put(ici->ops->owner); | 325 | module_put(ici->ops->owner); |
237 | emgi: | 326 | emgi: |
238 | module_put(icd->ops->owner); | 327 | module_put(icd->ops->owner); |
239 | emgd: | 328 | emgd: |
240 | mutex_unlock(&video_lock); | ||
241 | vfree(icf); | 329 | vfree(icf); |
242 | return ret; | 330 | return ret; |
243 | } | 331 | } |
@@ -249,13 +337,16 @@ static int soc_camera_close(struct inode *inode, struct file *file) | |||
249 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 337 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
250 | struct video_device *vdev = icd->vdev; | 338 | struct video_device *vdev = icd->vdev; |
251 | 339 | ||
252 | mutex_lock(&video_lock); | 340 | mutex_lock(&icd->video_lock); |
253 | icd->use_count--; | 341 | icd->use_count--; |
254 | if (!icd->use_count) | 342 | if (!icd->use_count) { |
255 | ici->ops->remove(icd); | 343 | ici->ops->remove(icd); |
344 | soc_camera_free_user_formats(icd); | ||
345 | } | ||
346 | mutex_unlock(&icd->video_lock); | ||
347 | |||
256 | module_put(icd->ops->owner); | 348 | module_put(icd->ops->owner); |
257 | module_put(ici->ops->owner); | 349 | module_put(ici->ops->owner); |
258 | mutex_unlock(&video_lock); | ||
259 | 350 | ||
260 | vfree(icf); | 351 | vfree(icf); |
261 | 352 | ||
@@ -265,7 +356,7 @@ static int soc_camera_close(struct inode *inode, struct file *file) | |||
265 | } | 356 | } |
266 | 357 | ||
267 | static ssize_t soc_camera_read(struct file *file, char __user *buf, | 358 | static ssize_t soc_camera_read(struct file *file, char __user *buf, |
268 | size_t count, loff_t *ppos) | 359 | size_t count, loff_t *ppos) |
269 | { | 360 | { |
270 | struct soc_camera_file *icf = file->private_data; | 361 | struct soc_camera_file *icf = file->private_data; |
271 | struct soc_camera_device *icd = icf->icd; | 362 | struct soc_camera_device *icd = icf->icd; |
@@ -299,8 +390,7 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt) | |||
299 | { | 390 | { |
300 | struct soc_camera_file *icf = file->private_data; | 391 | struct soc_camera_file *icf = file->private_data; |
301 | struct soc_camera_device *icd = icf->icd; | 392 | struct soc_camera_device *icd = icf->icd; |
302 | struct soc_camera_host *ici = | 393 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
303 | to_soc_camera_host(icd->dev.parent); | ||
304 | 394 | ||
305 | if (list_empty(&icf->vb_vidq.stream)) { | 395 | if (list_empty(&icf->vb_vidq.stream)) { |
306 | dev_err(&icd->dev, "Trying to poll with no queued buffers!\n"); | 396 | dev_err(&icd->dev, "Trying to poll with no queued buffers!\n"); |
@@ -310,7 +400,6 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt) | |||
310 | return ici->ops->poll(file, pt); | 400 | return ici->ops->poll(file, pt); |
311 | } | 401 | } |
312 | 402 | ||
313 | |||
314 | static struct file_operations soc_camera_fops = { | 403 | static struct file_operations soc_camera_fops = { |
315 | .owner = THIS_MODULE, | 404 | .owner = THIS_MODULE, |
316 | .open = soc_camera_open, | 405 | .open = soc_camera_open, |
@@ -322,44 +411,50 @@ static struct file_operations soc_camera_fops = { | |||
322 | .llseek = no_llseek, | 411 | .llseek = no_llseek, |
323 | }; | 412 | }; |
324 | 413 | ||
325 | |||
326 | static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | 414 | static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, |
327 | struct v4l2_format *f) | 415 | struct v4l2_format *f) |
328 | { | 416 | { |
329 | struct soc_camera_file *icf = file->private_data; | 417 | struct soc_camera_file *icf = file->private_data; |
330 | struct soc_camera_device *icd = icf->icd; | 418 | struct soc_camera_device *icd = icf->icd; |
331 | struct soc_camera_host *ici = | 419 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
332 | to_soc_camera_host(icd->dev.parent); | 420 | struct v4l2_pix_format *pix = &f->fmt.pix; |
421 | __u32 pixfmt = pix->pixelformat; | ||
333 | int ret; | 422 | int ret; |
334 | struct v4l2_rect rect; | 423 | struct v4l2_rect rect; |
335 | const static struct soc_camera_data_format *data_fmt; | ||
336 | 424 | ||
337 | WARN_ON(priv != file->private_data); | 425 | WARN_ON(priv != file->private_data); |
338 | 426 | ||
339 | data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat); | 427 | ret = soc_camera_try_fmt_vid_cap(file, priv, f); |
340 | if (!data_fmt) | ||
341 | return -EINVAL; | ||
342 | |||
343 | /* buswidth may be further adjusted by the ici */ | ||
344 | icd->buswidth = data_fmt->depth; | ||
345 | |||
346 | ret = soc_camera_try_fmt_vid_cap(file, icf, f); | ||
347 | if (ret < 0) | 428 | if (ret < 0) |
348 | return ret; | 429 | return ret; |
349 | 430 | ||
431 | mutex_lock(&icf->vb_vidq.vb_lock); | ||
432 | |||
433 | if (videobuf_queue_is_busy(&icf->vb_vidq)) { | ||
434 | dev_err(&icd->dev, "S_FMT denied: queue busy\n"); | ||
435 | ret = -EBUSY; | ||
436 | goto unlock; | ||
437 | } | ||
438 | |||
350 | rect.left = icd->x_current; | 439 | rect.left = icd->x_current; |
351 | rect.top = icd->y_current; | 440 | rect.top = icd->y_current; |
352 | rect.width = f->fmt.pix.width; | 441 | rect.width = pix->width; |
353 | rect.height = f->fmt.pix.height; | 442 | rect.height = pix->height; |
354 | ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect); | 443 | ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect); |
355 | if (ret < 0) | 444 | if (ret < 0) { |
356 | return ret; | 445 | goto unlock; |
446 | } else if (!icd->current_fmt || | ||
447 | icd->current_fmt->fourcc != pixfmt) { | ||
448 | dev_err(&ici->dev, | ||
449 | "Host driver hasn't set up current format correctly!\n"); | ||
450 | ret = -EINVAL; | ||
451 | goto unlock; | ||
452 | } | ||
357 | 453 | ||
358 | icd->current_fmt = data_fmt; | ||
359 | icd->width = rect.width; | 454 | icd->width = rect.width; |
360 | icd->height = rect.height; | 455 | icd->height = rect.height; |
361 | icf->vb_vidq.field = f->fmt.pix.field; | 456 | icf->vb_vidq.field = pix->field; |
362 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type) | 457 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
363 | dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", | 458 | dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", |
364 | f->type); | 459 | f->type); |
365 | 460 | ||
@@ -367,11 +462,16 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | |||
367 | icd->width, icd->height); | 462 | icd->width, icd->height); |
368 | 463 | ||
369 | /* set physical bus parameters */ | 464 | /* set physical bus parameters */ |
370 | return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat); | 465 | ret = ici->ops->set_bus_param(icd, pixfmt); |
466 | |||
467 | unlock: | ||
468 | mutex_unlock(&icf->vb_vidq.vb_lock); | ||
469 | |||
470 | return ret; | ||
371 | } | 471 | } |
372 | 472 | ||
373 | static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, | 473 | static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, |
374 | struct v4l2_fmtdesc *f) | 474 | struct v4l2_fmtdesc *f) |
375 | { | 475 | { |
376 | struct soc_camera_file *icf = file->private_data; | 476 | struct soc_camera_file *icf = file->private_data; |
377 | struct soc_camera_device *icd = icf->icd; | 477 | struct soc_camera_device *icd = icf->icd; |
@@ -379,10 +479,10 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, | |||
379 | 479 | ||
380 | WARN_ON(priv != file->private_data); | 480 | WARN_ON(priv != file->private_data); |
381 | 481 | ||
382 | if (f->index >= icd->num_formats) | 482 | if (f->index >= icd->num_user_formats) |
383 | return -EINVAL; | 483 | return -EINVAL; |
384 | 484 | ||
385 | format = &icd->formats[f->index]; | 485 | format = icd->user_formats[f->index].host_fmt; |
386 | 486 | ||
387 | strlcpy(f->description, format->name, sizeof(f->description)); | 487 | strlcpy(f->description, format->name, sizeof(f->description)); |
388 | f->pixelformat = format->fourcc; | 488 | f->pixelformat = format->fourcc; |
@@ -390,21 +490,21 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, | |||
390 | } | 490 | } |
391 | 491 | ||
392 | static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, | 492 | static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, |
393 | struct v4l2_format *f) | 493 | struct v4l2_format *f) |
394 | { | 494 | { |
395 | struct soc_camera_file *icf = file->private_data; | 495 | struct soc_camera_file *icf = file->private_data; |
396 | struct soc_camera_device *icd = icf->icd; | 496 | struct soc_camera_device *icd = icf->icd; |
497 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
397 | 498 | ||
398 | WARN_ON(priv != file->private_data); | 499 | WARN_ON(priv != file->private_data); |
399 | 500 | ||
400 | f->fmt.pix.width = icd->width; | 501 | pix->width = icd->width; |
401 | f->fmt.pix.height = icd->height; | 502 | pix->height = icd->height; |
402 | f->fmt.pix.field = icf->vb_vidq.field; | 503 | pix->field = icf->vb_vidq.field; |
403 | f->fmt.pix.pixelformat = icd->current_fmt->fourcc; | 504 | pix->pixelformat = icd->current_fmt->fourcc; |
404 | f->fmt.pix.bytesperline = | 505 | pix->bytesperline = pix->width * |
405 | (f->fmt.pix.width * icd->current_fmt->depth) >> 3; | 506 | DIV_ROUND_UP(icd->current_fmt->depth, 8); |
406 | f->fmt.pix.sizeimage = | 507 | pix->sizeimage = pix->height * pix->bytesperline; |
407 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
408 | dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", | 508 | dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", |
409 | icd->current_fmt->fourcc); | 509 | icd->current_fmt->fourcc); |
410 | return 0; | 510 | return 0; |
@@ -415,8 +515,7 @@ static int soc_camera_querycap(struct file *file, void *priv, | |||
415 | { | 515 | { |
416 | struct soc_camera_file *icf = file->private_data; | 516 | struct soc_camera_file *icf = file->private_data; |
417 | struct soc_camera_device *icd = icf->icd; | 517 | struct soc_camera_device *icd = icf->icd; |
418 | struct soc_camera_host *ici = | 518 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
419 | to_soc_camera_host(icd->dev.parent); | ||
420 | 519 | ||
421 | WARN_ON(priv != file->private_data); | 520 | WARN_ON(priv != file->private_data); |
422 | 521 | ||
@@ -429,6 +528,7 @@ static int soc_camera_streamon(struct file *file, void *priv, | |||
429 | { | 528 | { |
430 | struct soc_camera_file *icf = file->private_data; | 529 | struct soc_camera_file *icf = file->private_data; |
431 | struct soc_camera_device *icd = icf->icd; | 530 | struct soc_camera_device *icd = icf->icd; |
531 | int ret; | ||
432 | 532 | ||
433 | WARN_ON(priv != file->private_data); | 533 | WARN_ON(priv != file->private_data); |
434 | 534 | ||
@@ -437,10 +537,16 @@ static int soc_camera_streamon(struct file *file, void *priv, | |||
437 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 537 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
438 | return -EINVAL; | 538 | return -EINVAL; |
439 | 539 | ||
540 | mutex_lock(&icd->video_lock); | ||
541 | |||
440 | icd->ops->start_capture(icd); | 542 | icd->ops->start_capture(icd); |
441 | 543 | ||
442 | /* This calls buf_queue from host driver's videobuf_queue_ops */ | 544 | /* This calls buf_queue from host driver's videobuf_queue_ops */ |
443 | return videobuf_streamon(&icf->vb_vidq); | 545 | ret = videobuf_streamon(&icf->vb_vidq); |
546 | |||
547 | mutex_unlock(&icd->video_lock); | ||
548 | |||
549 | return ret; | ||
444 | } | 550 | } |
445 | 551 | ||
446 | static int soc_camera_streamoff(struct file *file, void *priv, | 552 | static int soc_camera_streamoff(struct file *file, void *priv, |
@@ -456,12 +562,16 @@ static int soc_camera_streamoff(struct file *file, void *priv, | |||
456 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 562 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
457 | return -EINVAL; | 563 | return -EINVAL; |
458 | 564 | ||
565 | mutex_lock(&icd->video_lock); | ||
566 | |||
459 | /* This calls buf_release from host driver's videobuf_queue_ops for all | 567 | /* This calls buf_release from host driver's videobuf_queue_ops for all |
460 | * remaining buffers. When the last buffer is freed, stop capture */ | 568 | * remaining buffers. When the last buffer is freed, stop capture */ |
461 | videobuf_streamoff(&icf->vb_vidq); | 569 | videobuf_streamoff(&icf->vb_vidq); |
462 | 570 | ||
463 | icd->ops->stop_capture(icd); | 571 | icd->ops->stop_capture(icd); |
464 | 572 | ||
573 | mutex_unlock(&icd->video_lock); | ||
574 | |||
465 | return 0; | 575 | return 0; |
466 | } | 576 | } |
467 | 577 | ||
@@ -567,14 +677,16 @@ static int soc_camera_s_crop(struct file *file, void *fh, | |||
567 | { | 677 | { |
568 | struct soc_camera_file *icf = file->private_data; | 678 | struct soc_camera_file *icf = file->private_data; |
569 | struct soc_camera_device *icd = icf->icd; | 679 | struct soc_camera_device *icd = icf->icd; |
570 | struct soc_camera_host *ici = | 680 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
571 | to_soc_camera_host(icd->dev.parent); | ||
572 | int ret; | 681 | int ret; |
573 | 682 | ||
574 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 683 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
575 | return -EINVAL; | 684 | return -EINVAL; |
576 | 685 | ||
577 | ret = ici->ops->set_fmt_cap(icd, 0, &a->c); | 686 | /* Cropping is allowed during a running capture, guard consistency */ |
687 | mutex_lock(&icf->vb_vidq.vb_lock); | ||
688 | |||
689 | ret = ici->ops->set_fmt(icd, 0, &a->c); | ||
578 | if (!ret) { | 690 | if (!ret) { |
579 | icd->width = a->c.width; | 691 | icd->width = a->c.width; |
580 | icd->height = a->c.height; | 692 | icd->height = a->c.height; |
@@ -582,6 +694,8 @@ static int soc_camera_s_crop(struct file *file, void *fh, | |||
582 | icd->y_current = a->c.top; | 694 | icd->y_current = a->c.top; |
583 | } | 695 | } |
584 | 696 | ||
697 | mutex_unlock(&icf->vb_vidq.vb_lock); | ||
698 | |||
585 | return ret; | 699 | return ret; |
586 | } | 700 | } |
587 | 701 | ||
@@ -692,18 +806,35 @@ static int scan_add_device(struct soc_camera_device *icd) | |||
692 | static int soc_camera_probe(struct device *dev) | 806 | static int soc_camera_probe(struct device *dev) |
693 | { | 807 | { |
694 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | 808 | struct soc_camera_device *icd = to_soc_camera_dev(dev); |
695 | struct soc_camera_host *ici = | 809 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
696 | to_soc_camera_host(icd->dev.parent); | ||
697 | int ret; | 810 | int ret; |
698 | 811 | ||
699 | if (!icd->ops->probe) | 812 | /* |
700 | return -ENODEV; | 813 | * Possible race scenario: |
814 | * modprobe <camera-host-driver> triggers __func__ | ||
815 | * at this moment respective <camera-sensor-driver> gets rmmod'ed | ||
816 | * to protect take module references. | ||
817 | */ | ||
818 | |||
819 | if (!try_module_get(icd->ops->owner)) { | ||
820 | dev_err(&icd->dev, "Couldn't lock sensor driver.\n"); | ||
821 | ret = -EINVAL; | ||
822 | goto emgd; | ||
823 | } | ||
824 | |||
825 | if (!try_module_get(ici->ops->owner)) { | ||
826 | dev_err(&icd->dev, "Couldn't lock capture bus driver.\n"); | ||
827 | ret = -EINVAL; | ||
828 | goto emgi; | ||
829 | } | ||
830 | |||
831 | mutex_lock(&icd->video_lock); | ||
701 | 832 | ||
702 | /* We only call ->add() here to activate and probe the camera. | 833 | /* We only call ->add() here to activate and probe the camera. |
703 | * We shall ->remove() and deactivate it immediately afterwards. */ | 834 | * We shall ->remove() and deactivate it immediately afterwards. */ |
704 | ret = ici->ops->add(icd); | 835 | ret = ici->ops->add(icd); |
705 | if (ret < 0) | 836 | if (ret < 0) |
706 | return ret; | 837 | goto eiadd; |
707 | 838 | ||
708 | ret = icd->ops->probe(icd); | 839 | ret = icd->ops->probe(icd); |
709 | if (ret >= 0) { | 840 | if (ret >= 0) { |
@@ -717,6 +848,12 @@ static int soc_camera_probe(struct device *dev) | |||
717 | } | 848 | } |
718 | ici->ops->remove(icd); | 849 | ici->ops->remove(icd); |
719 | 850 | ||
851 | eiadd: | ||
852 | mutex_unlock(&icd->video_lock); | ||
853 | module_put(ici->ops->owner); | ||
854 | emgi: | ||
855 | module_put(icd->ops->owner); | ||
856 | emgd: | ||
720 | return ret; | 857 | return ret; |
721 | } | 858 | } |
722 | 859 | ||
@@ -779,11 +916,20 @@ int soc_camera_host_register(struct soc_camera_host *ici) | |||
779 | int ret; | 916 | int ret; |
780 | struct soc_camera_host *ix; | 917 | struct soc_camera_host *ix; |
781 | 918 | ||
782 | if (!ici->ops->init_videobuf || !ici->ops->add || !ici->ops->remove) | 919 | if (!ici || !ici->ops || |
920 | !ici->ops->try_fmt || | ||
921 | !ici->ops->set_fmt || | ||
922 | !ici->ops->set_bus_param || | ||
923 | !ici->ops->querycap || | ||
924 | !ici->ops->init_videobuf || | ||
925 | !ici->ops->reqbufs || | ||
926 | !ici->ops->add || | ||
927 | !ici->ops->remove || | ||
928 | !ici->ops->poll) | ||
783 | return -EINVAL; | 929 | return -EINVAL; |
784 | 930 | ||
785 | /* Number might be equal to the platform device ID */ | 931 | /* Number might be equal to the platform device ID */ |
786 | sprintf(ici->dev.bus_id, "camera_host%d", ici->nr); | 932 | dev_set_name(&ici->dev, "camera_host%d", ici->nr); |
787 | 933 | ||
788 | mutex_lock(&list_lock); | 934 | mutex_lock(&list_lock); |
789 | list_for_each_entry(ix, &hosts, list) { | 935 | list_for_each_entry(ix, &hosts, list) { |
@@ -847,7 +993,16 @@ int soc_camera_device_register(struct soc_camera_device *icd) | |||
847 | struct soc_camera_device *ix; | 993 | struct soc_camera_device *ix; |
848 | int num = -1, i; | 994 | int num = -1, i; |
849 | 995 | ||
850 | if (!icd) | 996 | if (!icd || !icd->ops || |
997 | !icd->ops->probe || | ||
998 | !icd->ops->init || | ||
999 | !icd->ops->release || | ||
1000 | !icd->ops->start_capture || | ||
1001 | !icd->ops->stop_capture || | ||
1002 | !icd->ops->set_fmt || | ||
1003 | !icd->ops->try_fmt || | ||
1004 | !icd->ops->query_bus_param || | ||
1005 | !icd->ops->set_bus_param) | ||
851 | return -EINVAL; | 1006 | return -EINVAL; |
852 | 1007 | ||
853 | for (i = 0; i < 256 && num < 0; i++) { | 1008 | for (i = 0; i < 256 && num < 0; i++) { |
@@ -867,10 +1022,12 @@ int soc_camera_device_register(struct soc_camera_device *icd) | |||
867 | 1022 | ||
868 | icd->devnum = num; | 1023 | icd->devnum = num; |
869 | icd->dev.bus = &soc_camera_bus_type; | 1024 | icd->dev.bus = &soc_camera_bus_type; |
870 | snprintf(icd->dev.bus_id, sizeof(icd->dev.bus_id), | 1025 | dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum); |
871 | "%u-%u", icd->iface, icd->devnum); | ||
872 | 1026 | ||
873 | icd->dev.release = dummy_release; | 1027 | icd->dev.release = dummy_release; |
1028 | icd->use_count = 0; | ||
1029 | icd->host_priv = NULL; | ||
1030 | mutex_init(&icd->video_lock); | ||
874 | 1031 | ||
875 | return scan_add_device(icd); | 1032 | return scan_add_device(icd); |
876 | } | 1033 | } |
@@ -917,6 +1074,10 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { | |||
917 | #endif | 1074 | #endif |
918 | }; | 1075 | }; |
919 | 1076 | ||
1077 | /* | ||
1078 | * Usually called from the struct soc_camera_ops .probe() method, i.e., from | ||
1079 | * soc_camera_probe() above with .video_lock held | ||
1080 | */ | ||
920 | int soc_camera_video_start(struct soc_camera_device *icd) | 1081 | int soc_camera_video_start(struct soc_camera_device *icd) |
921 | { | 1082 | { |
922 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1083 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
@@ -932,7 +1093,7 @@ int soc_camera_video_start(struct soc_camera_device *icd) | |||
932 | dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev); | 1093 | dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev); |
933 | 1094 | ||
934 | strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); | 1095 | strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); |
935 | /* Maybe better &ici->dev */ | 1096 | |
936 | vdev->parent = &icd->dev; | 1097 | vdev->parent = &icd->dev; |
937 | vdev->current_norm = V4L2_STD_UNKNOWN; | 1098 | vdev->current_norm = V4L2_STD_UNKNOWN; |
938 | vdev->fops = &soc_camera_fops; | 1099 | vdev->fops = &soc_camera_fops; |
@@ -941,8 +1102,6 @@ int soc_camera_video_start(struct soc_camera_device *icd) | |||
941 | vdev->minor = -1; | 1102 | vdev->minor = -1; |
942 | vdev->tvnorms = V4L2_STD_UNKNOWN, | 1103 | vdev->tvnorms = V4L2_STD_UNKNOWN, |
943 | 1104 | ||
944 | icd->current_fmt = &icd->formats[0]; | ||
945 | |||
946 | err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor); | 1105 | err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor); |
947 | if (err < 0) { | 1106 | if (err < 0) { |
948 | dev_err(vdev->parent, "video_register_device failed\n"); | 1107 | dev_err(vdev->parent, "video_register_device failed\n"); |
@@ -968,10 +1127,10 @@ void soc_camera_video_stop(struct soc_camera_device *icd) | |||
968 | if (!icd->dev.parent || !vdev) | 1127 | if (!icd->dev.parent || !vdev) |
969 | return; | 1128 | return; |
970 | 1129 | ||
971 | mutex_lock(&video_lock); | 1130 | mutex_lock(&icd->video_lock); |
972 | video_unregister_device(vdev); | 1131 | video_unregister_device(vdev); |
973 | icd->vdev = NULL; | 1132 | icd->vdev = NULL; |
974 | mutex_unlock(&video_lock); | 1133 | mutex_unlock(&icd->video_lock); |
975 | } | 1134 | } |
976 | EXPORT_SYMBOL(soc_camera_video_stop); | 1135 | EXPORT_SYMBOL(soc_camera_video_stop); |
977 | 1136 | ||