[media] media: Media device information query
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / media / media-device.c
1 /*
2 * Media device
3 *
4 * Copyright (C) 2010 Nokia Corporation
5 *
6 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
7 * Sakari Ailus <sakari.ailus@iki.fi>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #include <linux/types.h>
24 #include <linux/ioctl.h>
25 #include <linux/media.h>
26
27 #include <media/media-device.h>
28 #include <media/media-devnode.h>
29 #include <media/media-entity.h>
30
31 /* -----------------------------------------------------------------------------
32 * Userspace API
33 */
34
35 static int media_device_open(struct file *filp)
36 {
37 return 0;
38 }
39
40 static int media_device_close(struct file *filp)
41 {
42 return 0;
43 }
44
45 static int media_device_get_info(struct media_device *dev,
46 struct media_device_info __user *__info)
47 {
48 struct media_device_info info;
49
50 memset(&info, 0, sizeof(info));
51
52 strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver));
53 strlcpy(info.model, dev->model, sizeof(info.model));
54 strlcpy(info.serial, dev->serial, sizeof(info.serial));
55 strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info));
56
57 info.media_version = MEDIA_API_VERSION;
58 info.hw_revision = dev->hw_revision;
59 info.driver_version = dev->driver_version;
60
61 return copy_to_user(__info, &info, sizeof(*__info));
62 }
63
64 static long media_device_ioctl(struct file *filp, unsigned int cmd,
65 unsigned long arg)
66 {
67 struct media_devnode *devnode = media_devnode_data(filp);
68 struct media_device *dev = to_media_device(devnode);
69 long ret;
70
71 switch (cmd) {
72 case MEDIA_IOC_DEVICE_INFO:
73 ret = media_device_get_info(dev,
74 (struct media_device_info __user *)arg);
75 break;
76
77 default:
78 ret = -ENOIOCTLCMD;
79 }
80
81 return ret;
82 }
83
84 static const struct media_file_operations media_device_fops = {
85 .owner = THIS_MODULE,
86 .open = media_device_open,
87 .ioctl = media_device_ioctl,
88 .release = media_device_close,
89 };
90
91 /* -----------------------------------------------------------------------------
92 * sysfs
93 */
94
95 static ssize_t show_model(struct device *cd,
96 struct device_attribute *attr, char *buf)
97 {
98 struct media_device *mdev = to_media_device(to_media_devnode(cd));
99
100 return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
101 }
102
103 static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
104
105 /* -----------------------------------------------------------------------------
106 * Registration/unregistration
107 */
108
109 static void media_device_release(struct media_devnode *mdev)
110 {
111 }
112
113 /**
114 * media_device_register - register a media device
115 * @mdev: The media device
116 *
117 * The caller is responsible for initializing the media device before
118 * registration. The following fields must be set:
119 *
120 * - dev must point to the parent device
121 * - model must be filled with the device model name
122 */
123 int __must_check media_device_register(struct media_device *mdev)
124 {
125 int ret;
126
127 if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
128 return -EINVAL;
129
130 mdev->entity_id = 1;
131 INIT_LIST_HEAD(&mdev->entities);
132 spin_lock_init(&mdev->lock);
133 mutex_init(&mdev->graph_mutex);
134
135 /* Register the device node. */
136 mdev->devnode.fops = &media_device_fops;
137 mdev->devnode.parent = mdev->dev;
138 mdev->devnode.release = media_device_release;
139 ret = media_devnode_register(&mdev->devnode);
140 if (ret < 0)
141 return ret;
142
143 ret = device_create_file(&mdev->devnode.dev, &dev_attr_model);
144 if (ret < 0) {
145 media_devnode_unregister(&mdev->devnode);
146 return ret;
147 }
148
149 return 0;
150 }
151 EXPORT_SYMBOL_GPL(media_device_register);
152
153 /**
154 * media_device_unregister - unregister a media device
155 * @mdev: The media device
156 *
157 */
158 void media_device_unregister(struct media_device *mdev)
159 {
160 struct media_entity *entity;
161 struct media_entity *next;
162
163 list_for_each_entry_safe(entity, next, &mdev->entities, list)
164 media_device_unregister_entity(entity);
165
166 device_remove_file(&mdev->devnode.dev, &dev_attr_model);
167 media_devnode_unregister(&mdev->devnode);
168 }
169 EXPORT_SYMBOL_GPL(media_device_unregister);
170
171 /**
172 * media_device_register_entity - Register an entity with a media device
173 * @mdev: The media device
174 * @entity: The entity
175 */
176 int __must_check media_device_register_entity(struct media_device *mdev,
177 struct media_entity *entity)
178 {
179 /* Warn if we apparently re-register an entity */
180 WARN_ON(entity->parent != NULL);
181 entity->parent = mdev;
182
183 spin_lock(&mdev->lock);
184 if (entity->id == 0)
185 entity->id = mdev->entity_id++;
186 else
187 mdev->entity_id = max(entity->id + 1, mdev->entity_id);
188 list_add_tail(&entity->list, &mdev->entities);
189 spin_unlock(&mdev->lock);
190
191 return 0;
192 }
193 EXPORT_SYMBOL_GPL(media_device_register_entity);
194
195 /**
196 * media_device_unregister_entity - Unregister an entity
197 * @entity: The entity
198 *
199 * If the entity has never been registered this function will return
200 * immediately.
201 */
202 void media_device_unregister_entity(struct media_entity *entity)
203 {
204 struct media_device *mdev = entity->parent;
205
206 if (mdev == NULL)
207 return;
208
209 spin_lock(&mdev->lock);
210 list_del(&entity->list);
211 spin_unlock(&mdev->lock);
212 entity->parent = NULL;
213 }
214 EXPORT_SYMBOL_GPL(media_device_unregister_entity);