4 * Copyright (C) 2010 Nokia Corporation
6 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
7 * Sakari Ailus <sakari.ailus@iki.fi>
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.
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.
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
23 #include <linux/compat.h>
24 #include <linux/export.h>
25 #include <linux/ioctl.h>
26 #include <linux/media.h>
27 #include <linux/types.h>
29 #include <media/media-device.h>
30 #include <media/media-devnode.h>
31 #include <media/media-entity.h>
33 /* -----------------------------------------------------------------------------
37 static int media_device_open(struct file
*filp
)
42 static int media_device_close(struct file
*filp
)
47 static int media_device_get_info(struct media_device
*dev
,
48 struct media_device_info __user
*__info
)
50 struct media_device_info info
;
52 memset(&info
, 0, sizeof(info
));
54 strlcpy(info
.driver
, dev
->dev
->driver
->name
, sizeof(info
.driver
));
55 strlcpy(info
.model
, dev
->model
, sizeof(info
.model
));
56 strlcpy(info
.serial
, dev
->serial
, sizeof(info
.serial
));
57 strlcpy(info
.bus_info
, dev
->bus_info
, sizeof(info
.bus_info
));
59 info
.media_version
= MEDIA_API_VERSION
;
60 info
.hw_revision
= dev
->hw_revision
;
61 info
.driver_version
= dev
->driver_version
;
63 if (copy_to_user(__info
, &info
, sizeof(*__info
)))
68 static struct media_entity
*find_entity(struct media_device
*mdev
, u32 id
)
70 struct media_entity
*entity
;
71 int next
= id
& MEDIA_ENT_ID_FLAG_NEXT
;
73 id
&= ~MEDIA_ENT_ID_FLAG_NEXT
;
75 spin_lock(&mdev
->lock
);
77 media_device_for_each_entity(entity
, mdev
) {
78 if ((entity
->id
== id
&& !next
) ||
79 (entity
->id
> id
&& next
)) {
80 spin_unlock(&mdev
->lock
);
85 spin_unlock(&mdev
->lock
);
90 static long media_device_enum_entities(struct media_device
*mdev
,
91 struct media_entity_desc __user
*uent
)
93 struct media_entity
*ent
;
94 struct media_entity_desc u_ent
;
96 if (copy_from_user(&u_ent
.id
, &uent
->id
, sizeof(u_ent
.id
)))
99 ent
= find_entity(mdev
, u_ent
.id
);
106 strncpy(u_ent
.name
, ent
->name
, sizeof(u_ent
.name
));
107 u_ent
.name
[sizeof(u_ent
.name
) - 1] = '\0';
109 memset(u_ent
.name
, 0, sizeof(u_ent
.name
));
111 u_ent
.type
= ent
->type
;
112 u_ent
.revision
= ent
->revision
;
113 u_ent
.flags
= ent
->flags
;
114 u_ent
.group_id
= ent
->group_id
;
115 u_ent
.pads
= ent
->num_pads
;
116 u_ent
.links
= ent
->num_links
- ent
->num_backlinks
;
117 memcpy(&u_ent
.raw
, &ent
->info
, sizeof(ent
->info
));
118 if (copy_to_user(uent
, &u_ent
, sizeof(u_ent
)))
123 static void media_device_kpad_to_upad(const struct media_pad
*kpad
,
124 struct media_pad_desc
*upad
)
126 upad
->entity
= kpad
->entity
->id
;
127 upad
->index
= kpad
->index
;
128 upad
->flags
= kpad
->flags
;
131 static long __media_device_enum_links(struct media_device
*mdev
,
132 struct media_links_enum
*links
)
134 struct media_entity
*entity
;
136 entity
= find_entity(mdev
, links
->entity
);
143 for (p
= 0; p
< entity
->num_pads
; p
++) {
144 struct media_pad_desc pad
;
146 memset(&pad
, 0, sizeof(pad
));
147 media_device_kpad_to_upad(&entity
->pads
[p
], &pad
);
148 if (copy_to_user(&links
->pads
[p
], &pad
, sizeof(pad
)))
154 struct media_link_desc __user
*ulink
;
157 for (l
= 0, ulink
= links
->links
; l
< entity
->num_links
; l
++) {
158 struct media_link_desc link
;
160 /* Ignore backlinks. */
161 if (entity
->links
[l
].source
->entity
!= entity
)
164 memset(&link
, 0, sizeof(link
));
165 media_device_kpad_to_upad(entity
->links
[l
].source
,
167 media_device_kpad_to_upad(entity
->links
[l
].sink
,
169 link
.flags
= entity
->links
[l
].flags
;
170 if (copy_to_user(ulink
, &link
, sizeof(*ulink
)))
179 static long media_device_enum_links(struct media_device
*mdev
,
180 struct media_links_enum __user
*ulinks
)
182 struct media_links_enum links
;
185 if (copy_from_user(&links
, ulinks
, sizeof(links
)))
188 rval
= __media_device_enum_links(mdev
, &links
);
192 if (copy_to_user(ulinks
, &links
, sizeof(*ulinks
)))
198 static long media_device_setup_link(struct media_device
*mdev
,
199 struct media_link_desc __user
*_ulink
)
201 struct media_link
*link
= NULL
;
202 struct media_link_desc ulink
;
203 struct media_entity
*source
;
204 struct media_entity
*sink
;
207 if (copy_from_user(&ulink
, _ulink
, sizeof(ulink
)))
210 /* Find the source and sink entities and link.
212 source
= find_entity(mdev
, ulink
.source
.entity
);
213 sink
= find_entity(mdev
, ulink
.sink
.entity
);
215 if (source
== NULL
|| sink
== NULL
)
218 if (ulink
.source
.index
>= source
->num_pads
||
219 ulink
.sink
.index
>= sink
->num_pads
)
222 link
= media_entity_find_link(&source
->pads
[ulink
.source
.index
],
223 &sink
->pads
[ulink
.sink
.index
]);
227 /* Setup the link on both entities. */
228 ret
= __media_entity_setup_link(link
, ulink
.flags
);
230 if (copy_to_user(_ulink
, &ulink
, sizeof(ulink
)))
236 static long media_device_ioctl(struct file
*filp
, unsigned int cmd
,
239 struct media_devnode
*devnode
= media_devnode_data(filp
);
240 struct media_device
*dev
= to_media_device(devnode
);
244 case MEDIA_IOC_DEVICE_INFO
:
245 ret
= media_device_get_info(dev
,
246 (struct media_device_info __user
*)arg
);
249 case MEDIA_IOC_ENUM_ENTITIES
:
250 ret
= media_device_enum_entities(dev
,
251 (struct media_entity_desc __user
*)arg
);
254 case MEDIA_IOC_ENUM_LINKS
:
255 mutex_lock(&dev
->graph_mutex
);
256 ret
= media_device_enum_links(dev
,
257 (struct media_links_enum __user
*)arg
);
258 mutex_unlock(&dev
->graph_mutex
);
261 case MEDIA_IOC_SETUP_LINK
:
262 mutex_lock(&dev
->graph_mutex
);
263 ret
= media_device_setup_link(dev
,
264 (struct media_link_desc __user
*)arg
);
265 mutex_unlock(&dev
->graph_mutex
);
277 struct media_links_enum32
{
279 compat_uptr_t pads
; /* struct media_pad_desc * */
280 compat_uptr_t links
; /* struct media_link_desc * */
284 static long media_device_enum_links32(struct media_device
*mdev
,
285 struct media_links_enum32 __user
*ulinks
)
287 struct media_links_enum links
;
288 compat_uptr_t pads_ptr
, links_ptr
;
290 memset(&links
, 0, sizeof(links
));
292 if (get_user(links
.entity
, &ulinks
->entity
)
293 || get_user(pads_ptr
, &ulinks
->pads
)
294 || get_user(links_ptr
, &ulinks
->links
))
297 links
.pads
= compat_ptr(pads_ptr
);
298 links
.links
= compat_ptr(links_ptr
);
300 return __media_device_enum_links(mdev
, &links
);
303 #define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32)
305 static long media_device_compat_ioctl(struct file
*filp
, unsigned int cmd
,
308 struct media_devnode
*devnode
= media_devnode_data(filp
);
309 struct media_device
*dev
= to_media_device(devnode
);
313 case MEDIA_IOC_DEVICE_INFO
:
314 case MEDIA_IOC_ENUM_ENTITIES
:
315 case MEDIA_IOC_SETUP_LINK
:
316 return media_device_ioctl(filp
, cmd
, arg
);
318 case MEDIA_IOC_ENUM_LINKS32
:
319 mutex_lock(&dev
->graph_mutex
);
320 ret
= media_device_enum_links32(dev
,
321 (struct media_links_enum32 __user
*)arg
);
322 mutex_unlock(&dev
->graph_mutex
);
331 #endif /* CONFIG_COMPAT */
333 static const struct media_file_operations media_device_fops
= {
334 .owner
= THIS_MODULE
,
335 .open
= media_device_open
,
336 .ioctl
= media_device_ioctl
,
338 .compat_ioctl
= media_device_compat_ioctl
,
339 #endif /* CONFIG_COMPAT */
340 .release
= media_device_close
,
343 /* -----------------------------------------------------------------------------
347 static ssize_t
show_model(struct device
*cd
,
348 struct device_attribute
*attr
, char *buf
)
350 struct media_device
*mdev
= to_media_device(to_media_devnode(cd
));
352 return sprintf(buf
, "%.*s\n", (int)sizeof(mdev
->model
), mdev
->model
);
355 static DEVICE_ATTR(model
, S_IRUGO
, show_model
, NULL
);
357 /* -----------------------------------------------------------------------------
358 * Registration/unregistration
361 static void media_device_release(struct media_devnode
*mdev
)
366 * media_device_register - register a media device
367 * @mdev: The media device
369 * The caller is responsible for initializing the media device before
370 * registration. The following fields must be set:
372 * - dev must point to the parent device
373 * - model must be filled with the device model name
375 int __must_check
media_device_register(struct media_device
*mdev
)
379 if (WARN_ON(mdev
->dev
== NULL
|| mdev
->model
[0] == 0))
383 INIT_LIST_HEAD(&mdev
->entities
);
384 spin_lock_init(&mdev
->lock
);
385 mutex_init(&mdev
->graph_mutex
);
387 /* Register the device node. */
388 mdev
->devnode
.fops
= &media_device_fops
;
389 mdev
->devnode
.parent
= mdev
->dev
;
390 mdev
->devnode
.release
= media_device_release
;
391 ret
= media_devnode_register(&mdev
->devnode
);
395 ret
= device_create_file(&mdev
->devnode
.dev
, &dev_attr_model
);
397 media_devnode_unregister(&mdev
->devnode
);
403 EXPORT_SYMBOL_GPL(media_device_register
);
406 * media_device_unregister - unregister a media device
407 * @mdev: The media device
410 void media_device_unregister(struct media_device
*mdev
)
412 struct media_entity
*entity
;
413 struct media_entity
*next
;
415 list_for_each_entry_safe(entity
, next
, &mdev
->entities
, list
)
416 media_device_unregister_entity(entity
);
418 device_remove_file(&mdev
->devnode
.dev
, &dev_attr_model
);
419 media_devnode_unregister(&mdev
->devnode
);
421 EXPORT_SYMBOL_GPL(media_device_unregister
);
424 * media_device_register_entity - Register an entity with a media device
425 * @mdev: The media device
426 * @entity: The entity
428 int __must_check
media_device_register_entity(struct media_device
*mdev
,
429 struct media_entity
*entity
)
431 /* Warn if we apparently re-register an entity */
432 WARN_ON(entity
->parent
!= NULL
);
433 entity
->parent
= mdev
;
435 spin_lock(&mdev
->lock
);
437 entity
->id
= mdev
->entity_id
++;
439 mdev
->entity_id
= max(entity
->id
+ 1, mdev
->entity_id
);
440 list_add_tail(&entity
->list
, &mdev
->entities
);
441 spin_unlock(&mdev
->lock
);
445 EXPORT_SYMBOL_GPL(media_device_register_entity
);
448 * media_device_unregister_entity - Unregister an entity
449 * @entity: The entity
451 * If the entity has never been registered this function will return
454 void media_device_unregister_entity(struct media_entity
*entity
)
456 struct media_device
*mdev
= entity
->parent
;
461 spin_lock(&mdev
->lock
);
462 list_del(&entity
->list
);
463 spin_unlock(&mdev
->lock
);
464 entity
->parent
= NULL
;
466 EXPORT_SYMBOL_GPL(media_device_unregister_entity
);