diff options
| author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2009-08-25 10:46:43 -0400 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-18 23:18:49 -0400 |
| commit | fa48984e36ee73e964eeb994a45de6525114e871 (patch) | |
| tree | 733f9fd78a536209456fbc02ceac2792a2b71755 | |
| parent | 0d205b6a09177cd14c109321fb40873418a11f7e (diff) | |
V4L/DVB (12519): soc-camera: put pixel format initialisation back in probe, add .put_formats()
The move of format translation initialisation into soc_camera_open() was
temporary for the soc-camera as platform driver intermediate step, put it back
into soc_camera_probe(). Also add a .put_formats() method to
soc_camera_host_ops to free any resources host driver might have allocated in
.get_formats().
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
| -rw-r--r-- | drivers/media/video/soc_camera.c | 50 | ||||
| -rw-r--r-- | include/media/soc_camera.h | 7 |
2 files changed, 42 insertions, 15 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 5028023b72aa..aa6614b60d6f 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
| @@ -211,7 +211,7 @@ static int soc_camera_dqbuf(struct file *file, void *priv, | |||
| 211 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) | 211 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) |
| 212 | { | 212 | { |
| 213 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 213 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
| 214 | int i, fmts = 0; | 214 | int i, fmts = 0, ret; |
| 215 | 215 | ||
| 216 | if (!ici->ops->get_formats) | 216 | if (!ici->ops->get_formats) |
| 217 | /* | 217 | /* |
| @@ -224,8 +224,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
| 224 | * First pass - only count formats this host-sensor | 224 | * First pass - only count formats this host-sensor |
| 225 | * configuration can provide | 225 | * configuration can provide |
| 226 | */ | 226 | */ |
| 227 | for (i = 0; i < icd->num_formats; i++) | 227 | for (i = 0; i < icd->num_formats; i++) { |
| 228 | fmts += ici->ops->get_formats(icd, i, NULL); | 228 | ret = ici->ops->get_formats(icd, i, NULL); |
| 229 | if (ret < 0) | ||
| 230 | return ret; | ||
| 231 | fmts += ret; | ||
| 232 | } | ||
| 229 | 233 | ||
| 230 | if (!fmts) | 234 | if (!fmts) |
| 231 | return -ENXIO; | 235 | return -ENXIO; |
| @@ -247,19 +251,32 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
| 247 | icd->user_formats[i].cam_fmt = icd->formats + i; | 251 | icd->user_formats[i].cam_fmt = icd->formats + i; |
| 248 | icd->user_formats[i].buswidth = icd->formats[i].depth; | 252 | icd->user_formats[i].buswidth = icd->formats[i].depth; |
| 249 | } else { | 253 | } else { |
| 250 | fmts += ici->ops->get_formats(icd, i, | 254 | ret = ici->ops->get_formats(icd, i, |
| 251 | &icd->user_formats[fmts]); | 255 | &icd->user_formats[fmts]); |
| 256 | if (ret < 0) | ||
| 257 | goto egfmt; | ||
| 258 | fmts += ret; | ||
| 252 | } | 259 | } |
| 253 | 260 | ||
| 254 | icd->current_fmt = icd->user_formats[0].host_fmt; | 261 | icd->current_fmt = icd->user_formats[0].host_fmt; |
| 255 | 262 | ||
| 256 | return 0; | 263 | return 0; |
| 264 | |||
| 265 | egfmt: | ||
| 266 | icd->num_user_formats = 0; | ||
| 267 | vfree(icd->user_formats); | ||
| 268 | return ret; | ||
| 257 | } | 269 | } |
| 258 | 270 | ||
| 259 | /* Always entered with .video_lock held */ | 271 | /* Always entered with .video_lock held */ |
| 260 | static void soc_camera_free_user_formats(struct soc_camera_device *icd) | 272 | static void soc_camera_free_user_formats(struct soc_camera_device *icd) |
| 261 | { | 273 | { |
| 274 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
| 275 | |||
| 276 | if (ici->ops->put_formats) | ||
| 277 | ici->ops->put_formats(icd); | ||
| 262 | icd->current_fmt = NULL; | 278 | icd->current_fmt = NULL; |
| 279 | icd->num_user_formats = 0; | ||
| 263 | vfree(icd->user_formats); | 280 | vfree(icd->user_formats); |
| 264 | icd->user_formats = NULL; | 281 | icd->user_formats = NULL; |
| 265 | } | 282 | } |
| @@ -344,16 +361,11 @@ static int soc_camera_open(struct file *file) | |||
| 344 | .width = icd->rect_current.width, | 361 | .width = icd->rect_current.width, |
| 345 | .height = icd->rect_current.height, | 362 | .height = icd->rect_current.height, |
| 346 | .field = icd->field, | 363 | .field = icd->field, |
| 364 | .pixelformat = icd->current_fmt->fourcc, | ||
| 365 | .colorspace = icd->current_fmt->colorspace, | ||
| 347 | }, | 366 | }, |
| 348 | }; | 367 | }; |
| 349 | 368 | ||
| 350 | ret = soc_camera_init_user_formats(icd); | ||
| 351 | if (ret < 0) | ||
| 352 | goto eiufmt; | ||
| 353 | |||
| 354 | f.fmt.pix.pixelformat = icd->current_fmt->fourcc; | ||
| 355 | f.fmt.pix.colorspace = icd->current_fmt->colorspace; | ||
| 356 | |||
| 357 | if (icl->power) { | 369 | if (icl->power) { |
| 358 | ret = icl->power(icd->pdev, 1); | 370 | ret = icl->power(icd->pdev, 1); |
| 359 | if (ret < 0) | 371 | if (ret < 0) |
| @@ -404,8 +416,6 @@ eiciadd: | |||
| 404 | if (icl->power) | 416 | if (icl->power) |
| 405 | icl->power(icd->pdev, 0); | 417 | icl->power(icd->pdev, 0); |
| 406 | epower: | 418 | epower: |
| 407 | soc_camera_free_user_formats(icd); | ||
| 408 | eiufmt: | ||
| 409 | icd->use_count--; | 419 | icd->use_count--; |
| 410 | mutex_unlock(&icd->video_lock); | 420 | mutex_unlock(&icd->video_lock); |
| 411 | module_put(ici->ops->owner); | 421 | module_put(ici->ops->owner); |
| @@ -431,7 +441,6 @@ static int soc_camera_close(struct file *file) | |||
| 431 | ici->ops->remove(icd); | 441 | ici->ops->remove(icd); |
| 432 | if (icl->power) | 442 | if (icl->power) |
| 433 | icl->power(icd->pdev, 0); | 443 | icl->power(icd->pdev, 0); |
| 434 | soc_camera_free_user_formats(icd); | ||
| 435 | } | 444 | } |
| 436 | 445 | ||
| 437 | mutex_unlock(&icd->video_lock); | 446 | mutex_unlock(&icd->video_lock); |
| @@ -954,6 +963,14 @@ static int soc_camera_probe(struct device *dev) | |||
| 954 | } | 963 | } |
| 955 | } | 964 | } |
| 956 | 965 | ||
| 966 | /* At this point client .probe() should have run already */ | ||
| 967 | ret = soc_camera_init_user_formats(icd); | ||
| 968 | if (ret < 0) | ||
| 969 | goto eiufmt; | ||
| 970 | |||
| 971 | icd->rect_current = icd->rect_max; | ||
| 972 | icd->field = V4L2_FIELD_ANY; | ||
| 973 | |||
| 957 | /* ..._video_start() will create a device node, so we have to protect */ | 974 | /* ..._video_start() will create a device node, so we have to protect */ |
| 958 | mutex_lock(&icd->video_lock); | 975 | mutex_lock(&icd->video_lock); |
| 959 | 976 | ||
| @@ -978,6 +995,8 @@ static int soc_camera_probe(struct device *dev) | |||
| 978 | 995 | ||
| 979 | evidstart: | 996 | evidstart: |
| 980 | mutex_unlock(&icd->video_lock); | 997 | mutex_unlock(&icd->video_lock); |
| 998 | soc_camera_free_user_formats(icd); | ||
| 999 | eiufmt: | ||
| 981 | if (icl->board_info) { | 1000 | if (icl->board_info) { |
| 982 | soc_camera_free_i2c(icd); | 1001 | soc_camera_free_i2c(icd); |
| 983 | } else { | 1002 | } else { |
| @@ -1023,6 +1042,7 @@ static int soc_camera_remove(struct device *dev) | |||
| 1023 | module_put(drv->owner); | 1042 | module_put(drv->owner); |
| 1024 | } | 1043 | } |
| 1025 | } | 1044 | } |
| 1045 | soc_camera_free_user_formats(icd); | ||
| 1026 | 1046 | ||
| 1027 | return 0; | 1047 | return 0; |
| 1028 | } | 1048 | } |
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index f623c010a539..2b7a8c663605 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h | |||
| @@ -67,8 +67,15 @@ struct soc_camera_host_ops { | |||
| 67 | void (*remove)(struct soc_camera_device *); | 67 | void (*remove)(struct soc_camera_device *); |
| 68 | int (*suspend)(struct soc_camera_device *, pm_message_t); | 68 | int (*suspend)(struct soc_camera_device *, pm_message_t); |
| 69 | int (*resume)(struct soc_camera_device *); | 69 | int (*resume)(struct soc_camera_device *); |
| 70 | /* | ||
| 71 | * .get_formats() is called for each client device format, but | ||
| 72 | * .put_formats() is only called once. Further, if any of the calls to | ||
| 73 | * .get_formats() fail, .put_formats() will not be called at all, the | ||
| 74 | * failing .get_formats() must then clean up internally. | ||
| 75 | */ | ||
| 70 | int (*get_formats)(struct soc_camera_device *, int, | 76 | int (*get_formats)(struct soc_camera_device *, int, |
| 71 | struct soc_camera_format_xlate *); | 77 | struct soc_camera_format_xlate *); |
| 78 | void (*put_formats)(struct soc_camera_device *); | ||
| 72 | int (*set_crop)(struct soc_camera_device *, struct v4l2_rect *); | 79 | int (*set_crop)(struct soc_camera_device *, struct v4l2_rect *); |
| 73 | int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *); | 80 | int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *); |
| 74 | int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *); | 81 | int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *); |
