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>
28 #include <linux/slab.h>
30 #include <media/media-device.h>
31 #include <media/media-devnode.h>
32 #include <media/media-entity.h>
34 #ifdef CONFIG_MEDIA_CONTROLLER
36 /* -----------------------------------------------------------------------------
40 static int media_device_open(struct file
*filp
)
45 static int media_device_close(struct file
*filp
)
50 static int media_device_get_info(struct media_device
*dev
,
51 struct media_device_info __user
*__info
)
53 struct media_device_info info
;
55 memset(&info
, 0, sizeof(info
));
57 strlcpy(info
.driver
, dev
->dev
->driver
->name
, sizeof(info
.driver
));
58 strlcpy(info
.model
, dev
->model
, sizeof(info
.model
));
59 strlcpy(info
.serial
, dev
->serial
, sizeof(info
.serial
));
60 strlcpy(info
.bus_info
, dev
->bus_info
, sizeof(info
.bus_info
));
62 info
.media_version
= MEDIA_API_VERSION
;
63 info
.hw_revision
= dev
->hw_revision
;
64 info
.driver_version
= dev
->driver_version
;
66 if (copy_to_user(__info
, &info
, sizeof(*__info
)))
71 static struct media_entity
*find_entity(struct media_device
*mdev
, u32 id
)
73 struct media_entity
*entity
;
74 int next
= id
& MEDIA_ENT_ID_FLAG_NEXT
;
76 id
&= ~MEDIA_ENT_ID_FLAG_NEXT
;
78 spin_lock(&mdev
->lock
);
80 media_device_for_each_entity(entity
, mdev
) {
81 if (((media_entity_id(entity
) == id
) && !next
) ||
82 ((media_entity_id(entity
) > id
) && next
)) {
83 spin_unlock(&mdev
->lock
);
88 spin_unlock(&mdev
->lock
);
93 static long media_device_enum_entities(struct media_device
*mdev
,
94 struct media_entity_desc __user
*uent
)
96 struct media_entity
*ent
;
97 struct media_entity_desc u_ent
;
99 memset(&u_ent
, 0, sizeof(u_ent
));
100 if (copy_from_user(&u_ent
.id
, &uent
->id
, sizeof(u_ent
.id
)))
103 ent
= find_entity(mdev
, u_ent
.id
);
108 u_ent
.id
= media_entity_id(ent
);
110 strlcpy(u_ent
.name
, ent
->name
, sizeof(u_ent
.name
));
111 u_ent
.type
= ent
->function
;
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
= media_entity_id(kpad
->entity
);
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
*ent_link
;
155 struct media_link_desc __user
*ulink
= links
->links
;
157 list_for_each_entry(ent_link
, &entity
->links
, list
) {
158 struct media_link_desc link
;
160 /* Ignore backlinks. */
161 if (ent_link
->source
->entity
!= entity
)
163 memset(&link
, 0, sizeof(link
));
164 media_device_kpad_to_upad(ent_link
->source
,
166 media_device_kpad_to_upad(ent_link
->sink
,
168 link
.flags
= ent_link
->flags
;
169 if (copy_to_user(ulink
, &link
, sizeof(*ulink
)))
178 static long media_device_enum_links(struct media_device
*mdev
,
179 struct media_links_enum __user
*ulinks
)
181 struct media_links_enum links
;
184 if (copy_from_user(&links
, ulinks
, sizeof(links
)))
187 rval
= __media_device_enum_links(mdev
, &links
);
191 if (copy_to_user(ulinks
, &links
, sizeof(*ulinks
)))
197 static long media_device_setup_link(struct media_device
*mdev
,
198 struct media_link_desc __user
*_ulink
)
200 struct media_link
*link
= NULL
;
201 struct media_link_desc ulink
;
202 struct media_entity
*source
;
203 struct media_entity
*sink
;
206 if (copy_from_user(&ulink
, _ulink
, sizeof(ulink
)))
209 /* Find the source and sink entities and link.
211 source
= find_entity(mdev
, ulink
.source
.entity
);
212 sink
= find_entity(mdev
, ulink
.sink
.entity
);
214 if (source
== NULL
|| sink
== NULL
)
217 if (ulink
.source
.index
>= source
->num_pads
||
218 ulink
.sink
.index
>= sink
->num_pads
)
221 link
= media_entity_find_link(&source
->pads
[ulink
.source
.index
],
222 &sink
->pads
[ulink
.sink
.index
]);
226 /* Setup the link on both entities. */
227 ret
= __media_entity_setup_link(link
, ulink
.flags
);
229 if (copy_to_user(_ulink
, &ulink
, sizeof(ulink
)))
235 static long __media_device_get_topology(struct media_device
*mdev
,
236 struct media_v2_topology
*topo
)
238 struct media_entity
*entity
;
239 struct media_interface
*intf
;
240 struct media_pad
*pad
;
241 struct media_link
*link
;
242 struct media_v2_entity uentity
;
243 struct media_v2_interface uintf
;
244 struct media_v2_pad upad
;
245 struct media_v2_link ulink
;
248 topo
->topology_version
= mdev
->topology_version
;
250 /* Get entities and number of entities */
252 media_device_for_each_entity(entity
, mdev
) {
255 if (ret
|| !topo
->entities
)
258 if (i
> topo
->num_entities
) {
263 /* Copy fields to userspace struct if not error */
264 memset(&uentity
, 0, sizeof(uentity
));
265 uentity
.id
= entity
->graph_obj
.id
;
266 uentity
.function
= entity
->function
;
267 strncpy(uentity
.name
, entity
->name
,
268 sizeof(uentity
.name
));
270 if (copy_to_user(&topo
->entities
[i
- 1], &uentity
, sizeof(uentity
)))
273 topo
->num_entities
= i
;
275 /* Get interfaces and number of interfaces */
277 media_device_for_each_intf(intf
, mdev
) {
280 if (ret
|| !topo
->interfaces
)
283 if (i
> topo
->num_interfaces
) {
288 memset(&uintf
, 0, sizeof(uintf
));
290 /* Copy intf fields to userspace struct */
291 uintf
.id
= intf
->graph_obj
.id
;
292 uintf
.intf_type
= intf
->type
;
293 uintf
.flags
= intf
->flags
;
295 if (media_type(&intf
->graph_obj
) == MEDIA_GRAPH_INTF_DEVNODE
) {
296 struct media_intf_devnode
*devnode
;
298 devnode
= intf_to_devnode(intf
);
300 uintf
.devnode
.major
= devnode
->major
;
301 uintf
.devnode
.minor
= devnode
->minor
;
304 if (copy_to_user(&topo
->interfaces
[i
- 1], &uintf
, sizeof(uintf
)))
307 topo
->num_interfaces
= i
;
309 /* Get pads and number of pads */
311 media_device_for_each_pad(pad
, mdev
) {
314 if (ret
|| !topo
->pads
)
317 if (i
> topo
->num_pads
) {
322 memset(&upad
, 0, sizeof(upad
));
324 /* Copy pad fields to userspace struct */
325 upad
.id
= pad
->graph_obj
.id
;
326 upad
.entity_id
= pad
->entity
->graph_obj
.id
;
327 upad
.flags
= pad
->flags
;
329 if (copy_to_user(&topo
->pads
[i
- 1], &upad
, sizeof(upad
)))
334 /* Get links and number of links */
336 media_device_for_each_link(link
, mdev
) {
337 if (link
->is_backlink
)
342 if (ret
|| !topo
->links
)
345 if (i
> topo
->num_links
) {
350 memset(&ulink
, 0, sizeof(ulink
));
352 /* Copy link fields to userspace struct */
353 ulink
.id
= link
->graph_obj
.id
;
354 ulink
.source_id
= link
->gobj0
->id
;
355 ulink
.sink_id
= link
->gobj1
->id
;
356 ulink
.flags
= link
->flags
;
358 if (media_type(link
->gobj0
) != MEDIA_GRAPH_PAD
)
359 ulink
.flags
|= MEDIA_LNK_FL_INTERFACE_LINK
;
361 if (copy_to_user(&topo
->links
[i
- 1], &ulink
, sizeof(ulink
)))
369 static long media_device_get_topology(struct media_device
*mdev
,
370 struct media_v2_topology __user
*utopo
)
372 struct media_v2_topology ktopo
;
375 ret
= copy_from_user(&ktopo
, utopo
, sizeof(ktopo
));
380 ret
= __media_device_get_topology(mdev
, &ktopo
);
384 ret
= copy_to_user(utopo
, &ktopo
, sizeof(*utopo
));
389 static long media_device_ioctl(struct file
*filp
, unsigned int cmd
,
392 struct media_devnode
*devnode
= media_devnode_data(filp
);
393 struct media_device
*dev
= to_media_device(devnode
);
397 case MEDIA_IOC_DEVICE_INFO
:
398 ret
= media_device_get_info(dev
,
399 (struct media_device_info __user
*)arg
);
402 case MEDIA_IOC_ENUM_ENTITIES
:
403 ret
= media_device_enum_entities(dev
,
404 (struct media_entity_desc __user
*)arg
);
407 case MEDIA_IOC_ENUM_LINKS
:
408 mutex_lock(&dev
->graph_mutex
);
409 ret
= media_device_enum_links(dev
,
410 (struct media_links_enum __user
*)arg
);
411 mutex_unlock(&dev
->graph_mutex
);
414 case MEDIA_IOC_SETUP_LINK
:
415 mutex_lock(&dev
->graph_mutex
);
416 ret
= media_device_setup_link(dev
,
417 (struct media_link_desc __user
*)arg
);
418 mutex_unlock(&dev
->graph_mutex
);
421 case MEDIA_IOC_G_TOPOLOGY
:
422 mutex_lock(&dev
->graph_mutex
);
423 ret
= media_device_get_topology(dev
,
424 (struct media_v2_topology __user
*)arg
);
425 mutex_unlock(&dev
->graph_mutex
);
437 struct media_links_enum32
{
439 compat_uptr_t pads
; /* struct media_pad_desc * */
440 compat_uptr_t links
; /* struct media_link_desc * */
444 static long media_device_enum_links32(struct media_device
*mdev
,
445 struct media_links_enum32 __user
*ulinks
)
447 struct media_links_enum links
;
448 compat_uptr_t pads_ptr
, links_ptr
;
450 memset(&links
, 0, sizeof(links
));
452 if (get_user(links
.entity
, &ulinks
->entity
)
453 || get_user(pads_ptr
, &ulinks
->pads
)
454 || get_user(links_ptr
, &ulinks
->links
))
457 links
.pads
= compat_ptr(pads_ptr
);
458 links
.links
= compat_ptr(links_ptr
);
460 return __media_device_enum_links(mdev
, &links
);
463 #define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32)
465 static long media_device_compat_ioctl(struct file
*filp
, unsigned int cmd
,
468 struct media_devnode
*devnode
= media_devnode_data(filp
);
469 struct media_device
*dev
= to_media_device(devnode
);
473 case MEDIA_IOC_DEVICE_INFO
:
474 case MEDIA_IOC_ENUM_ENTITIES
:
475 case MEDIA_IOC_SETUP_LINK
:
476 case MEDIA_IOC_G_TOPOLOGY
:
477 return media_device_ioctl(filp
, cmd
, arg
);
479 case MEDIA_IOC_ENUM_LINKS32
:
480 mutex_lock(&dev
->graph_mutex
);
481 ret
= media_device_enum_links32(dev
,
482 (struct media_links_enum32 __user
*)arg
);
483 mutex_unlock(&dev
->graph_mutex
);
492 #endif /* CONFIG_COMPAT */
494 static const struct media_file_operations media_device_fops
= {
495 .owner
= THIS_MODULE
,
496 .open
= media_device_open
,
497 .ioctl
= media_device_ioctl
,
499 .compat_ioctl
= media_device_compat_ioctl
,
500 #endif /* CONFIG_COMPAT */
501 .release
= media_device_close
,
504 /* -----------------------------------------------------------------------------
508 static ssize_t
show_model(struct device
*cd
,
509 struct device_attribute
*attr
, char *buf
)
511 struct media_device
*mdev
= to_media_device(to_media_devnode(cd
));
513 return sprintf(buf
, "%.*s\n", (int)sizeof(mdev
->model
), mdev
->model
);
516 static DEVICE_ATTR(model
, S_IRUGO
, show_model
, NULL
);
518 /* -----------------------------------------------------------------------------
519 * Registration/unregistration
522 static void media_device_release(struct media_devnode
*mdev
)
524 dev_dbg(mdev
->parent
, "Media device released\n");
528 * media_device_register - register a media device
529 * @mdev: The media device
531 * The caller is responsible for initializing the media device before
532 * registration. The following fields must be set:
534 * - dev must point to the parent device
535 * - model must be filled with the device model name
537 int __must_check
__media_device_register(struct media_device
*mdev
,
538 struct module
*owner
)
542 if (WARN_ON(mdev
->dev
== NULL
|| mdev
->model
[0] == 0))
545 INIT_LIST_HEAD(&mdev
->entities
);
546 INIT_LIST_HEAD(&mdev
->interfaces
);
547 INIT_LIST_HEAD(&mdev
->pads
);
548 INIT_LIST_HEAD(&mdev
->links
);
549 spin_lock_init(&mdev
->lock
);
550 mutex_init(&mdev
->graph_mutex
);
552 /* Register the device node. */
553 mdev
->devnode
.fops
= &media_device_fops
;
554 mdev
->devnode
.parent
= mdev
->dev
;
555 mdev
->devnode
.release
= media_device_release
;
556 ret
= media_devnode_register(&mdev
->devnode
, owner
);
560 ret
= device_create_file(&mdev
->devnode
.dev
, &dev_attr_model
);
562 media_devnode_unregister(&mdev
->devnode
);
566 dev_dbg(mdev
->dev
, "Media device registered\n");
570 EXPORT_SYMBOL_GPL(__media_device_register
);
573 * media_device_unregister - unregister a media device
574 * @mdev: The media device
577 void media_device_unregister(struct media_device
*mdev
)
579 struct media_entity
*entity
;
580 struct media_entity
*next
;
581 struct media_interface
*intf
, *tmp_intf
;
583 /* Remove all entities from the media device */
584 list_for_each_entry_safe(entity
, next
, &mdev
->entities
, graph_obj
.list
)
585 media_device_unregister_entity(entity
);
587 /* Remove all interfaces from the media device */
588 spin_lock(&mdev
->lock
);
589 list_for_each_entry_safe(intf
, tmp_intf
, &mdev
->interfaces
,
591 __media_remove_intf_links(intf
);
592 media_gobj_remove(&intf
->graph_obj
);
595 spin_unlock(&mdev
->lock
);
597 device_remove_file(&mdev
->devnode
.dev
, &dev_attr_model
);
598 media_devnode_unregister(&mdev
->devnode
);
600 dev_dbg(mdev
->dev
, "Media device unregistered\n");
602 EXPORT_SYMBOL_GPL(media_device_unregister
);
605 * media_device_register_entity - Register an entity with a media device
606 * @mdev: The media device
607 * @entity: The entity
609 int __must_check
media_device_register_entity(struct media_device
*mdev
,
610 struct media_entity
*entity
)
614 if (entity
->function
== MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN
||
615 entity
->function
== MEDIA_ENT_T_UNKNOWN
)
617 "Entity type for entity %s was not initialized!\n",
620 /* Warn if we apparently re-register an entity */
621 WARN_ON(entity
->graph_obj
.mdev
!= NULL
);
622 entity
->graph_obj
.mdev
= mdev
;
623 INIT_LIST_HEAD(&entity
->links
);
625 spin_lock(&mdev
->lock
);
626 /* Initialize media_gobj embedded at the entity */
627 media_gobj_init(mdev
, MEDIA_GRAPH_ENTITY
, &entity
->graph_obj
);
629 /* Initialize objects at the pads */
630 for (i
= 0; i
< entity
->num_pads
; i
++)
631 media_gobj_init(mdev
, MEDIA_GRAPH_PAD
,
632 &entity
->pads
[i
].graph_obj
);
634 spin_unlock(&mdev
->lock
);
638 EXPORT_SYMBOL_GPL(media_device_register_entity
);
641 * media_device_unregister_entity - Unregister an entity
642 * @entity: The entity
644 * If the entity has never been registered this function will return
647 void media_device_unregister_entity(struct media_entity
*entity
)
650 struct media_device
*mdev
= entity
->graph_obj
.mdev
;
651 struct media_link
*link
, *tmp
;
652 struct media_interface
*intf
;
657 spin_lock(&mdev
->lock
);
659 /* Remove all interface links pointing to this entity */
660 list_for_each_entry(intf
, &mdev
->interfaces
, graph_obj
.list
) {
661 list_for_each_entry_safe(link
, tmp
, &intf
->links
, list
) {
662 if (link
->entity
== entity
)
663 __media_remove_intf_link(link
);
667 /* Remove all data links that belong to this entity */
668 __media_entity_remove_links(entity
);
670 /* Remove all pads that belong to this entity */
671 for (i
= 0; i
< entity
->num_pads
; i
++)
672 media_gobj_remove(&entity
->pads
[i
].graph_obj
);
674 /* Remove the entity */
675 media_gobj_remove(&entity
->graph_obj
);
677 spin_unlock(&mdev
->lock
);
678 entity
->graph_obj
.mdev
= NULL
;
680 EXPORT_SYMBOL_GPL(media_device_unregister_entity
);
682 static void media_device_release_devres(struct device
*dev
, void *res
)
687 * media_device_get_devres() - get media device as device resource
688 * creates if one doesn't exist
690 struct media_device
*media_device_get_devres(struct device
*dev
)
692 struct media_device
*mdev
;
694 mdev
= devres_find(dev
, media_device_release_devres
, NULL
, NULL
);
698 mdev
= devres_alloc(media_device_release_devres
,
699 sizeof(struct media_device
), GFP_KERNEL
);
702 return devres_get(dev
, mdev
, NULL
, NULL
);
704 EXPORT_SYMBOL_GPL(media_device_get_devres
);
707 * media_device_find_devres() - find media device as device resource
709 struct media_device
*media_device_find_devres(struct device
*dev
)
711 return devres_find(dev
, media_device_release_devres
, NULL
, NULL
);
713 EXPORT_SYMBOL_GPL(media_device_find_devres
);
715 #endif /* CONFIG_MEDIA_CONTROLLER */