diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2009-08-25 10:28:22 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-18 23:18:27 -0400 |
commit | 40e2e0927003424c25807b575dd40da2b8685857 (patch) | |
tree | 917ca8fd5f7598194d264ec92a08b312d4932b90 /drivers/media/video/soc_camera.c | |
parent | bc1937b41d8253e2b554da385023a92189d38917 (diff) |
V4L/DVB (12506): soc-camera: convert to platform device
Convert soc-camera core and all drivers to platform device API. We already
converted platforms to register a platform device for each soc-camera client,
now we remove the compatibility code and switch completely to the new scheme.
This is a preparatory step for the v4l2-subdev conversion.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/soc_camera.c')
-rw-r--r-- | drivers/media/video/soc_camera.c | 431 |
1 files changed, 212 insertions, 219 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 0340754e5406..20ef5c773fae 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -21,15 +21,15 @@ | |||
21 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/module.h> | ||
25 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/module.h> | ||
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | 28 | ||
29 | #include <media/soc_camera.h> | 29 | #include <media/soc_camera.h> |
30 | #include <media/v4l2-common.h> | 30 | #include <media/v4l2-common.h> |
31 | #include <media/v4l2-dev.h> | ||
32 | #include <media/v4l2-ioctl.h> | 31 | #include <media/v4l2-ioctl.h> |
32 | #include <media/v4l2-dev.h> | ||
33 | #include <media/videobuf-core.h> | 33 | #include <media/videobuf-core.h> |
34 | 34 | ||
35 | /* Default to VGA resolution */ | 35 | /* Default to VGA resolution */ |
@@ -38,7 +38,7 @@ | |||
38 | 38 | ||
39 | static LIST_HEAD(hosts); | 39 | static LIST_HEAD(hosts); |
40 | static LIST_HEAD(devices); | 40 | static LIST_HEAD(devices); |
41 | static DEFINE_MUTEX(list_lock); | 41 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ |
42 | 42 | ||
43 | const struct soc_camera_data_format *soc_camera_format_by_fourcc( | 43 | const struct soc_camera_data_format *soc_camera_format_by_fourcc( |
44 | struct soc_camera_device *icd, unsigned int fourcc) | 44 | struct soc_camera_device *icd, unsigned int fourcc) |
@@ -209,6 +209,7 @@ static int soc_camera_dqbuf(struct file *file, void *priv, | |||
209 | return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK); | 209 | return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK); |
210 | } | 210 | } |
211 | 211 | ||
212 | /* Always entered with .video_lock held */ | ||
212 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) | 213 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) |
213 | { | 214 | { |
214 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 215 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
@@ -257,9 +258,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
257 | return 0; | 258 | return 0; |
258 | } | 259 | } |
259 | 260 | ||
261 | /* Always entered with .video_lock held */ | ||
260 | static void soc_camera_free_user_formats(struct soc_camera_device *icd) | 262 | static void soc_camera_free_user_formats(struct soc_camera_device *icd) |
261 | { | 263 | { |
264 | icd->current_fmt = NULL; | ||
262 | vfree(icd->user_formats); | 265 | vfree(icd->user_formats); |
266 | icd->user_formats = NULL; | ||
263 | } | 267 | } |
264 | 268 | ||
265 | /* Called with .vb_lock held */ | 269 | /* Called with .vb_lock held */ |
@@ -310,10 +314,6 @@ static int soc_camera_open(struct file *file) | |||
310 | struct soc_camera_file *icf; | 314 | struct soc_camera_file *icf; |
311 | int ret; | 315 | int ret; |
312 | 316 | ||
313 | icf = vmalloc(sizeof(*icf)); | ||
314 | if (!icf) | ||
315 | return -ENOMEM; | ||
316 | |||
317 | /* | 317 | /* |
318 | * It is safe to dereference these pointers now as long as a user has | 318 | * It is safe to dereference these pointers now as long as a user has |
319 | * the video device open - we are protected by the held cdev reference. | 319 | * the video device open - we are protected by the held cdev reference. |
@@ -321,8 +321,17 @@ static int soc_camera_open(struct file *file) | |||
321 | 321 | ||
322 | vdev = video_devdata(file); | 322 | vdev = video_devdata(file); |
323 | icd = container_of(vdev->parent, struct soc_camera_device, dev); | 323 | icd = container_of(vdev->parent, struct soc_camera_device, dev); |
324 | |||
325 | if (!icd->ops) | ||
326 | /* No device driver attached */ | ||
327 | return -ENODEV; | ||
328 | |||
324 | ici = to_soc_camera_host(icd->dev.parent); | 329 | ici = to_soc_camera_host(icd->dev.parent); |
325 | 330 | ||
331 | icf = vmalloc(sizeof(*icf)); | ||
332 | if (!icf) | ||
333 | return -ENOMEM; | ||
334 | |||
326 | if (!try_module_get(icd->ops->owner)) { | 335 | if (!try_module_get(icd->ops->owner)) { |
327 | dev_err(&icd->dev, "Couldn't lock sensor driver.\n"); | 336 | dev_err(&icd->dev, "Couldn't lock sensor driver.\n"); |
328 | ret = -EINVAL; | 337 | ret = -EINVAL; |
@@ -335,7 +344,7 @@ static int soc_camera_open(struct file *file) | |||
335 | goto emgi; | 344 | goto emgi; |
336 | } | 345 | } |
337 | 346 | ||
338 | /* Protect against icd->remove() until we module_get() both drivers. */ | 347 | /* Protect against icd->ops->remove() until we module_get() both drivers. */ |
339 | mutex_lock(&icd->video_lock); | 348 | mutex_lock(&icd->video_lock); |
340 | 349 | ||
341 | icf->icd = icd; | 350 | icf->icd = icd; |
@@ -350,11 +359,18 @@ static int soc_camera_open(struct file *file) | |||
350 | .width = icd->width, | 359 | .width = icd->width, |
351 | .height = icd->height, | 360 | .height = icd->height, |
352 | .field = icd->field, | 361 | .field = icd->field, |
353 | .pixelformat = icd->current_fmt->fourcc, | ||
354 | .colorspace = icd->current_fmt->colorspace, | ||
355 | }, | 362 | }, |
356 | }; | 363 | }; |
357 | 364 | ||
365 | ret = soc_camera_init_user_formats(icd); | ||
366 | if (ret < 0) | ||
367 | goto eiufmt; | ||
368 | |||
369 | dev_dbg(&icd->dev, "Using fmt %x\n", icd->current_fmt->fourcc); | ||
370 | |||
371 | f.fmt.pix.pixelformat = icd->current_fmt->fourcc; | ||
372 | f.fmt.pix.colorspace = icd->current_fmt->colorspace; | ||
373 | |||
358 | ret = ici->ops->add(icd); | 374 | ret = ici->ops->add(icd); |
359 | if (ret < 0) { | 375 | if (ret < 0) { |
360 | dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); | 376 | dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); |
@@ -383,6 +399,8 @@ static int soc_camera_open(struct file *file) | |||
383 | esfmt: | 399 | esfmt: |
384 | ici->ops->remove(icd); | 400 | ici->ops->remove(icd); |
385 | eiciadd: | 401 | eiciadd: |
402 | soc_camera_free_user_formats(icd); | ||
403 | eiufmt: | ||
386 | icd->use_count--; | 404 | icd->use_count--; |
387 | mutex_unlock(&icd->video_lock); | 405 | mutex_unlock(&icd->video_lock); |
388 | module_put(ici->ops->owner); | 406 | module_put(ici->ops->owner); |
@@ -402,8 +420,10 @@ static int soc_camera_close(struct file *file) | |||
402 | 420 | ||
403 | mutex_lock(&icd->video_lock); | 421 | mutex_lock(&icd->video_lock); |
404 | icd->use_count--; | 422 | icd->use_count--; |
405 | if (!icd->use_count) | 423 | if (!icd->use_count) { |
406 | ici->ops->remove(icd); | 424 | ici->ops->remove(icd); |
425 | soc_camera_free_user_formats(icd); | ||
426 | } | ||
407 | 427 | ||
408 | mutex_unlock(&icd->video_lock); | 428 | mutex_unlock(&icd->video_lock); |
409 | 429 | ||
@@ -764,29 +784,6 @@ static int soc_camera_s_register(struct file *file, void *fh, | |||
764 | } | 784 | } |
765 | #endif | 785 | #endif |
766 | 786 | ||
767 | static int device_register_link(struct soc_camera_device *icd) | ||
768 | { | ||
769 | int ret = dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum); | ||
770 | |||
771 | if (!ret) | ||
772 | ret = device_register(&icd->dev); | ||
773 | |||
774 | if (ret < 0) { | ||
775 | /* Prevent calling device_unregister() */ | ||
776 | icd->dev.parent = NULL; | ||
777 | dev_err(&icd->dev, "Cannot register device: %d\n", ret); | ||
778 | /* Even if probe() was unsuccessful for all registered drivers, | ||
779 | * device_register() returns 0, and we add the link, just to | ||
780 | * document this camera's control device */ | ||
781 | } else if (icd->control) | ||
782 | /* Have to sysfs_remove_link() before device_unregister()? */ | ||
783 | if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj, | ||
784 | "control")) | ||
785 | dev_warn(&icd->dev, | ||
786 | "Failed creating the control symlink\n"); | ||
787 | return ret; | ||
788 | } | ||
789 | |||
790 | /* So far this function cannot fail */ | 787 | /* So far this function cannot fail */ |
791 | static void scan_add_host(struct soc_camera_host *ici) | 788 | static void scan_add_host(struct soc_camera_host *ici) |
792 | { | 789 | { |
@@ -796,106 +793,124 @@ static void scan_add_host(struct soc_camera_host *ici) | |||
796 | 793 | ||
797 | list_for_each_entry(icd, &devices, list) { | 794 | list_for_each_entry(icd, &devices, list) { |
798 | if (icd->iface == ici->nr) { | 795 | if (icd->iface == ici->nr) { |
796 | int ret; | ||
799 | icd->dev.parent = ici->dev; | 797 | icd->dev.parent = ici->dev; |
800 | device_register_link(icd); | 798 | dev_set_name(&icd->dev, "%u-%u", icd->iface, |
799 | icd->devnum); | ||
800 | ret = device_register(&icd->dev); | ||
801 | if (ret < 0) { | ||
802 | icd->dev.parent = NULL; | ||
803 | dev_err(&icd->dev, | ||
804 | "Cannot register device: %d\n", ret); | ||
805 | } | ||
801 | } | 806 | } |
802 | } | 807 | } |
803 | 808 | ||
804 | mutex_unlock(&list_lock); | 809 | mutex_unlock(&list_lock); |
805 | } | 810 | } |
806 | 811 | ||
807 | /* return: 0 if no match found or a match found and | 812 | #ifdef CONFIG_I2C_BOARDINFO |
808 | * device_register() successful, error code otherwise */ | 813 | static int soc_camera_init_i2c(struct soc_camera_device *icd, |
809 | static int scan_add_device(struct soc_camera_device *icd) | 814 | struct soc_camera_link *icl) |
810 | { | 815 | { |
811 | struct soc_camera_host *ici; | 816 | struct i2c_client *client; |
812 | int ret = 0; | 817 | struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id); |
818 | int ret; | ||
813 | 819 | ||
814 | mutex_lock(&list_lock); | 820 | if (!adap) { |
821 | ret = -ENODEV; | ||
822 | dev_err(&icd->dev, "Cannot get I2C adapter #%d. No driver?\n", | ||
823 | icl->i2c_adapter_id); | ||
824 | goto ei2cga; | ||
825 | } | ||
815 | 826 | ||
816 | list_add_tail(&icd->list, &devices); | 827 | icl->board_info->platform_data = icd; |
817 | 828 | ||
818 | /* Watch out for class_for_each_device / class_find_device API by | 829 | client = i2c_new_device(adap, icl->board_info); |
819 | * Dave Young <hidave.darkstar@gmail.com> */ | 830 | if (!client) { |
820 | list_for_each_entry(ici, &hosts, list) { | 831 | ret = -ENOMEM; |
821 | if (icd->iface == ici->nr) { | 832 | goto ei2cnd; |
822 | ret = 1; | ||
823 | icd->dev.parent = ici->dev; | ||
824 | break; | ||
825 | } | ||
826 | } | 833 | } |
827 | 834 | ||
828 | mutex_unlock(&list_lock); | 835 | /* |
829 | 836 | * We set icd drvdata at two locations - here and in | |
830 | if (ret) | 837 | * soc_camera_video_start(). Depending on the module loading / |
831 | ret = device_register_link(icd); | 838 | * initialisation order one of these locations will be entered first |
839 | */ | ||
840 | /* Use to_i2c_client(dev) to recover the i2c client */ | ||
841 | dev_set_drvdata(&icd->dev, &client->dev); | ||
832 | 842 | ||
843 | return 0; | ||
844 | ei2cnd: | ||
845 | i2c_put_adapter(adap); | ||
846 | ei2cga: | ||
833 | return ret; | 847 | return ret; |
834 | } | 848 | } |
835 | 849 | ||
850 | static void soc_camera_free_i2c(struct soc_camera_device *icd) | ||
851 | { | ||
852 | struct i2c_client *client = | ||
853 | to_i2c_client(to_soc_camera_control(icd)); | ||
854 | dev_set_drvdata(&icd->dev, NULL); | ||
855 | i2c_unregister_device(client); | ||
856 | i2c_put_adapter(client->adapter); | ||
857 | } | ||
858 | #else | ||
859 | #define soc_camera_init_i2c(icd, icl) (-ENODEV) | ||
860 | #define soc_camera_free_i2c(icd) do {} while (0) | ||
861 | #endif | ||
862 | |||
863 | static int video_dev_create(struct soc_camera_device *icd); | ||
864 | /* Called during host-driver probe */ | ||
836 | static int soc_camera_probe(struct device *dev) | 865 | static int soc_camera_probe(struct device *dev) |
837 | { | 866 | { |
838 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | 867 | struct soc_camera_device *icd = to_soc_camera_dev(dev); |
839 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 868 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
840 | int ret; | 869 | int ret; |
841 | 870 | ||
842 | /* | 871 | dev_info(dev, "Probing %s\n", dev_name(dev)); |
843 | * Possible race scenario: | ||
844 | * modprobe <camera-host-driver> triggers __func__ | ||
845 | * at this moment respective <camera-sensor-driver> gets rmmod'ed | ||
846 | * to protect take module references. | ||
847 | */ | ||
848 | 872 | ||
849 | if (!try_module_get(icd->ops->owner)) { | 873 | ret = video_dev_create(icd); |
850 | dev_err(&icd->dev, "Couldn't lock sensor driver.\n"); | 874 | if (ret < 0) |
851 | ret = -EINVAL; | 875 | goto evdc; |
852 | goto emgd; | ||
853 | } | ||
854 | 876 | ||
855 | if (!try_module_get(ici->ops->owner)) { | 877 | /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */ |
856 | dev_err(&icd->dev, "Couldn't lock capture bus driver.\n"); | 878 | if (icl->board_info) { |
879 | ret = soc_camera_init_i2c(icd, icl); | ||
880 | if (ret < 0) | ||
881 | goto eadddev; | ||
882 | } else if (!icl->add_device || !icl->del_device) { | ||
857 | ret = -EINVAL; | 883 | ret = -EINVAL; |
858 | goto emgi; | 884 | goto eadddev; |
885 | } else { | ||
886 | ret = icl->add_device(icl, &icd->dev); | ||
887 | if (ret < 0) | ||
888 | goto eadddev; | ||
859 | } | 889 | } |
860 | 890 | ||
861 | mutex_lock(&icd->video_lock); | 891 | ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, icd->vdev->minor); |
862 | 892 | if (ret < 0) { | |
863 | /* We only call ->add() here to activate and probe the camera. | 893 | dev_err(&icd->dev, "video_register_device failed: %d\n", ret); |
864 | * We shall ->remove() and deactivate it immediately afterwards. */ | 894 | goto evidregd; |
865 | ret = ici->ops->add(icd); | 895 | } |
866 | if (ret < 0) | ||
867 | goto eiadd; | ||
868 | |||
869 | ret = icd->ops->probe(icd); | ||
870 | if (ret >= 0) { | ||
871 | const struct v4l2_queryctrl *qctrl; | ||
872 | 896 | ||
873 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN); | 897 | /* Do we have to sysfs_remove_link() before device_unregister()? */ |
874 | icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0; | 898 | if (to_soc_camera_control(icd) && |
875 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); | 899 | sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj, |
876 | icd->exposure = qctrl ? qctrl->default_value : | 900 | "control")) |
877 | (unsigned short)~0; | 901 | dev_warn(&icd->dev, "Failed creating the control symlink\n"); |
878 | 902 | ||
879 | ret = soc_camera_init_user_formats(icd); | ||
880 | if (ret < 0) { | ||
881 | if (icd->ops->remove) | ||
882 | icd->ops->remove(icd); | ||
883 | goto eiufmt; | ||
884 | } | ||
885 | 903 | ||
886 | icd->height = DEFAULT_HEIGHT; | 904 | return 0; |
887 | icd->width = DEFAULT_WIDTH; | ||
888 | icd->field = V4L2_FIELD_ANY; | ||
889 | } | ||
890 | 905 | ||
891 | eiufmt: | 906 | evidregd: |
892 | ici->ops->remove(icd); | 907 | if (icl->board_info) |
893 | eiadd: | 908 | soc_camera_free_i2c(icd); |
894 | mutex_unlock(&icd->video_lock); | 909 | else |
895 | module_put(ici->ops->owner); | 910 | icl->del_device(icl); |
896 | emgi: | 911 | eadddev: |
897 | module_put(icd->ops->owner); | 912 | video_device_release(icd->vdev); |
898 | emgd: | 913 | evdc: |
899 | return ret; | 914 | return ret; |
900 | } | 915 | } |
901 | 916 | ||
@@ -904,13 +919,22 @@ emgd: | |||
904 | static int soc_camera_remove(struct device *dev) | 919 | static int soc_camera_remove(struct device *dev) |
905 | { | 920 | { |
906 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | 921 | struct soc_camera_device *icd = to_soc_camera_dev(dev); |
922 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
923 | struct video_device *vdev = icd->vdev; | ||
907 | 924 | ||
908 | mutex_lock(&icd->video_lock); | 925 | BUG_ON(!dev->parent); |
909 | if (icd->ops->remove) | ||
910 | icd->ops->remove(icd); | ||
911 | mutex_unlock(&icd->video_lock); | ||
912 | 926 | ||
913 | soc_camera_free_user_formats(icd); | 927 | if (vdev) { |
928 | mutex_lock(&icd->video_lock); | ||
929 | video_unregister_device(vdev); | ||
930 | icd->vdev = NULL; | ||
931 | mutex_unlock(&icd->video_lock); | ||
932 | } | ||
933 | |||
934 | if (icl->board_info) | ||
935 | soc_camera_free_i2c(icd); | ||
936 | else | ||
937 | icl->del_device(icl); | ||
914 | 938 | ||
915 | return 0; | 939 | return 0; |
916 | } | 940 | } |
@@ -1005,10 +1029,14 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) | |||
1005 | 1029 | ||
1006 | list_for_each_entry(icd, &devices, list) { | 1030 | list_for_each_entry(icd, &devices, list) { |
1007 | if (icd->dev.parent == ici->dev) { | 1031 | if (icd->dev.parent == ici->dev) { |
1032 | /* The bus->remove will be called */ | ||
1008 | device_unregister(&icd->dev); | 1033 | device_unregister(&icd->dev); |
1009 | /* Not before device_unregister(), .remove | 1034 | /* Not before device_unregister(), .remove |
1010 | * needs parent to call ici->ops->remove() */ | 1035 | * needs parent to call ici->ops->remove() */ |
1011 | icd->dev.parent = NULL; | 1036 | icd->dev.parent = NULL; |
1037 | |||
1038 | /* If the host module is loaded again, device_register() | ||
1039 | * would complain "already initialised" */ | ||
1012 | memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj)); | 1040 | memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj)); |
1013 | } | 1041 | } |
1014 | } | 1042 | } |
@@ -1020,26 +1048,14 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) | |||
1020 | EXPORT_SYMBOL(soc_camera_host_unregister); | 1048 | EXPORT_SYMBOL(soc_camera_host_unregister); |
1021 | 1049 | ||
1022 | /* Image capture device */ | 1050 | /* Image capture device */ |
1023 | int soc_camera_device_register(struct soc_camera_device *icd) | 1051 | static int soc_camera_device_register(struct soc_camera_device *icd) |
1024 | { | 1052 | { |
1025 | struct soc_camera_device *ix; | 1053 | struct soc_camera_device *ix; |
1026 | int num = -1, i; | 1054 | int num = -1, i; |
1027 | 1055 | ||
1028 | if (!icd || !icd->ops || | ||
1029 | !icd->ops->probe || | ||
1030 | !icd->ops->init || | ||
1031 | !icd->ops->release || | ||
1032 | !icd->ops->start_capture || | ||
1033 | !icd->ops->stop_capture || | ||
1034 | !icd->ops->set_crop || | ||
1035 | !icd->ops->set_fmt || | ||
1036 | !icd->ops->try_fmt || | ||
1037 | !icd->ops->query_bus_param || | ||
1038 | !icd->ops->set_bus_param) | ||
1039 | return -EINVAL; | ||
1040 | |||
1041 | for (i = 0; i < 256 && num < 0; i++) { | 1056 | for (i = 0; i < 256 && num < 0; i++) { |
1042 | num = i; | 1057 | num = i; |
1058 | /* Check if this index is available on this interface */ | ||
1043 | list_for_each_entry(ix, &devices, list) { | 1059 | list_for_each_entry(ix, &devices, list) { |
1044 | if (ix->iface == icd->iface && ix->devnum == i) { | 1060 | if (ix->iface == icd->iface && ix->devnum == i) { |
1045 | num = -1; | 1061 | num = -1; |
@@ -1061,21 +1077,15 @@ int soc_camera_device_register(struct soc_camera_device *icd) | |||
1061 | icd->host_priv = NULL; | 1077 | icd->host_priv = NULL; |
1062 | mutex_init(&icd->video_lock); | 1078 | mutex_init(&icd->video_lock); |
1063 | 1079 | ||
1064 | return scan_add_device(icd); | 1080 | list_add_tail(&icd->list, &devices); |
1081 | |||
1082 | return 0; | ||
1065 | } | 1083 | } |
1066 | EXPORT_SYMBOL(soc_camera_device_register); | ||
1067 | 1084 | ||
1068 | void soc_camera_device_unregister(struct soc_camera_device *icd) | 1085 | static void soc_camera_device_unregister(struct soc_camera_device *icd) |
1069 | { | 1086 | { |
1070 | mutex_lock(&list_lock); | ||
1071 | list_del(&icd->list); | 1087 | list_del(&icd->list); |
1072 | |||
1073 | /* The bus->remove will be eventually called */ | ||
1074 | if (icd->dev.parent) | ||
1075 | device_unregister(&icd->dev); | ||
1076 | mutex_unlock(&list_lock); | ||
1077 | } | 1088 | } |
1078 | EXPORT_SYMBOL(soc_camera_device_unregister); | ||
1079 | 1089 | ||
1080 | static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { | 1090 | static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { |
1081 | .vidioc_querycap = soc_camera_querycap, | 1091 | .vidioc_querycap = soc_camera_querycap, |
@@ -1106,22 +1116,13 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { | |||
1106 | #endif | 1116 | #endif |
1107 | }; | 1117 | }; |
1108 | 1118 | ||
1109 | /* | 1119 | static int video_dev_create(struct soc_camera_device *icd) |
1110 | * Usually called from the struct soc_camera_ops .probe() method, i.e., from | ||
1111 | * soc_camera_probe() above with .video_lock held | ||
1112 | */ | ||
1113 | int soc_camera_video_start(struct soc_camera_device *icd) | ||
1114 | { | 1120 | { |
1115 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1121 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1116 | int err = -ENOMEM; | 1122 | struct video_device *vdev = video_device_alloc(); |
1117 | struct video_device *vdev; | ||
1118 | 1123 | ||
1119 | if (!icd->dev.parent) | ||
1120 | return -ENODEV; | ||
1121 | |||
1122 | vdev = video_device_alloc(); | ||
1123 | if (!vdev) | 1124 | if (!vdev) |
1124 | goto evidallocd; | 1125 | return -ENOMEM; |
1125 | dev_dbg(ici->dev, "Allocated video_device %p\n", vdev); | 1126 | dev_dbg(ici->dev, "Allocated video_device %p\n", vdev); |
1126 | 1127 | ||
1127 | strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); | 1128 | strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); |
@@ -1132,118 +1133,110 @@ int soc_camera_video_start(struct soc_camera_device *icd) | |||
1132 | vdev->ioctl_ops = &soc_camera_ioctl_ops; | 1133 | vdev->ioctl_ops = &soc_camera_ioctl_ops; |
1133 | vdev->release = video_device_release; | 1134 | vdev->release = video_device_release; |
1134 | vdev->minor = -1; | 1135 | vdev->minor = -1; |
1135 | vdev->tvnorms = V4L2_STD_UNKNOWN, | 1136 | vdev->tvnorms = V4L2_STD_UNKNOWN; |
1136 | 1137 | ||
1137 | err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor); | ||
1138 | if (err < 0) { | ||
1139 | dev_err(vdev->parent, "video_register_device failed\n"); | ||
1140 | goto evidregd; | ||
1141 | } | ||
1142 | icd->vdev = vdev; | 1138 | icd->vdev = vdev; |
1143 | 1139 | ||
1144 | return 0; | 1140 | return 0; |
1141 | } | ||
1145 | 1142 | ||
1146 | evidregd: | 1143 | /* |
1147 | video_device_release(vdev); | 1144 | * Usually called from the struct soc_camera_ops .probe() method, i.e., from |
1148 | evidallocd: | 1145 | * soc_camera_probe() above with .video_lock held |
1149 | return err; | 1146 | */ |
1147 | int soc_camera_video_start(struct soc_camera_device *icd, struct device *dev) | ||
1148 | { | ||
1149 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
1150 | const struct v4l2_queryctrl *qctrl; | ||
1151 | |||
1152 | if (!icd->dev.parent) | ||
1153 | return -ENODEV; | ||
1154 | |||
1155 | if (!icd->ops || | ||
1156 | !icd->ops->init || | ||
1157 | !icd->ops->release || | ||
1158 | !icd->ops->start_capture || | ||
1159 | !icd->ops->stop_capture || | ||
1160 | !icd->ops->set_fmt || | ||
1161 | !icd->ops->try_fmt || | ||
1162 | !icd->ops->query_bus_param || | ||
1163 | !icd->ops->set_bus_param) | ||
1164 | return -EINVAL; | ||
1165 | |||
1166 | /* See comment in soc_camera_probe() */ | ||
1167 | dev_set_drvdata(&icd->dev, dev); | ||
1168 | |||
1169 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN); | ||
1170 | icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0; | ||
1171 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); | ||
1172 | icd->exposure = qctrl ? qctrl->default_value : (unsigned short)~0; | ||
1173 | |||
1174 | return ici->ops->add(icd); | ||
1150 | } | 1175 | } |
1151 | EXPORT_SYMBOL(soc_camera_video_start); | 1176 | EXPORT_SYMBOL(soc_camera_video_start); |
1152 | 1177 | ||
1153 | /* Called from client .remove() methods with .video_lock held */ | 1178 | /* Called from client .remove() methods with .video_lock held */ |
1154 | void soc_camera_video_stop(struct soc_camera_device *icd) | 1179 | void soc_camera_video_stop(struct soc_camera_device *icd) |
1155 | { | 1180 | { |
1156 | struct video_device *vdev = icd->vdev; | 1181 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1157 | 1182 | ||
1158 | dev_dbg(&icd->dev, "%s\n", __func__); | 1183 | dev_dbg(&icd->dev, "%s\n", __func__); |
1159 | 1184 | ||
1160 | if (!icd->dev.parent || !vdev) | 1185 | ici->ops->remove(icd); |
1161 | return; | ||
1162 | |||
1163 | video_unregister_device(vdev); | ||
1164 | icd->vdev = NULL; | ||
1165 | } | 1186 | } |
1166 | EXPORT_SYMBOL(soc_camera_video_stop); | 1187 | EXPORT_SYMBOL(soc_camera_video_stop); |
1167 | 1188 | ||
1168 | #ifdef CONFIG_I2C_BOARDINFO | 1189 | static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) |
1169 | static int soc_camera_init_i2c(struct platform_device *pdev, | ||
1170 | struct soc_camera_link *icl) | ||
1171 | { | 1190 | { |
1172 | struct i2c_client *client; | 1191 | struct soc_camera_link *icl = pdev->dev.platform_data; |
1173 | struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id); | 1192 | struct soc_camera_device *icd; |
1174 | int ret; | 1193 | int ret; |
1175 | 1194 | ||
1176 | if (!adap) { | 1195 | if (!icl) |
1177 | ret = -ENODEV; | 1196 | return -EINVAL; |
1178 | dev_err(&pdev->dev, "Cannot get adapter #%d. No driver?\n", | ||
1179 | icl->i2c_adapter_id); | ||
1180 | goto ei2cga; | ||
1181 | } | ||
1182 | 1197 | ||
1183 | icl->board_info->platform_data = icl; | 1198 | icd = kzalloc(sizeof(*icd), GFP_KERNEL); |
1184 | client = i2c_new_device(adap, icl->board_info); | 1199 | if (!icd) |
1185 | if (!client) { | 1200 | return -ENOMEM; |
1186 | ret = -ENOMEM; | ||
1187 | goto ei2cnd; | ||
1188 | } | ||
1189 | 1201 | ||
1190 | platform_set_drvdata(pdev, client); | 1202 | icd->iface = icl->bus_id; |
1203 | platform_set_drvdata(pdev, icd); | ||
1204 | icd->dev.platform_data = icl; | ||
1191 | 1205 | ||
1192 | return 0; | 1206 | ret = soc_camera_device_register(icd); |
1193 | ei2cnd: | 1207 | if (ret < 0) |
1194 | i2c_put_adapter(adap); | 1208 | goto escdevreg; |
1195 | ei2cga: | ||
1196 | return ret; | ||
1197 | } | ||
1198 | 1209 | ||
1199 | static void soc_camera_free_i2c(struct platform_device *pdev) | 1210 | return 0; |
1200 | { | ||
1201 | struct i2c_client *client = platform_get_drvdata(pdev); | ||
1202 | 1211 | ||
1203 | if (!client) | 1212 | escdevreg: |
1204 | return; | 1213 | kfree(icd); |
1205 | 1214 | ||
1206 | i2c_unregister_device(client); | 1215 | return ret; |
1207 | i2c_put_adapter(client->adapter); | ||
1208 | } | 1216 | } |
1209 | #else | ||
1210 | #define soc_camera_init_i2c(d, icl) (-ENODEV) | ||
1211 | #define soc_camera_free_i2c(d) do {} while (0) | ||
1212 | #endif | ||
1213 | 1217 | ||
1214 | static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) | 1218 | /* Only called on rmmod for each platform device, since they are not |
1219 | * hot-pluggable. Now we know, that all our users - hosts and devices have | ||
1220 | * been unloaded already */ | ||
1221 | static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) | ||
1215 | { | 1222 | { |
1216 | struct soc_camera_link *icl = pdev->dev.platform_data; | 1223 | struct soc_camera_device *icd = platform_get_drvdata(pdev); |
1217 | 1224 | ||
1218 | if (!icl) | 1225 | if (!icd) |
1219 | return -EINVAL; | 1226 | return -EINVAL; |
1220 | 1227 | ||
1221 | if (icl->board_info) | 1228 | soc_camera_device_unregister(icd); |
1222 | return soc_camera_init_i2c(pdev, icl); | ||
1223 | else if (!icl->add_device || !icl->del_device) | ||
1224 | return -EINVAL; | ||
1225 | 1229 | ||
1226 | /* &pdev->dev will become &icd->dev */ | 1230 | kfree(icd); |
1227 | return icl->add_device(icl, &pdev->dev); | ||
1228 | } | ||
1229 | 1231 | ||
1230 | static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) | ||
1231 | { | ||
1232 | struct soc_camera_link *icl = pdev->dev.platform_data; | ||
1233 | |||
1234 | if (icl->board_info) | ||
1235 | soc_camera_free_i2c(pdev); | ||
1236 | else | ||
1237 | icl->del_device(icl); | ||
1238 | return 0; | 1232 | return 0; |
1239 | } | 1233 | } |
1240 | 1234 | ||
1241 | static struct platform_driver __refdata soc_camera_pdrv = { | 1235 | static struct platform_driver __refdata soc_camera_pdrv = { |
1242 | .probe = soc_camera_pdrv_probe, | 1236 | .remove = __devexit_p(soc_camera_pdrv_remove), |
1243 | .remove = __devexit_p(soc_camera_pdrv_remove), | 1237 | .driver = { |
1244 | .driver = { | 1238 | .name = "soc-camera-pdrv", |
1245 | .name = "soc-camera-pdrv", | 1239 | .owner = THIS_MODULE, |
1246 | .owner = THIS_MODULE, | ||
1247 | }, | 1240 | }, |
1248 | }; | 1241 | }; |
1249 | 1242 | ||
@@ -1256,7 +1249,7 @@ static int __init soc_camera_init(void) | |||
1256 | if (ret) | 1249 | if (ret) |
1257 | goto edrvr; | 1250 | goto edrvr; |
1258 | 1251 | ||
1259 | ret = platform_driver_register(&soc_camera_pdrv); | 1252 | ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe); |
1260 | if (ret) | 1253 | if (ret) |
1261 | goto epdr; | 1254 | goto epdr; |
1262 | 1255 | ||