1 /*
2 * Media controller interface library
3 *
4 * Copyright (C) 2010-2014 Ideas on board SPRL
5 *
6 * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
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 Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <sys/ioctl.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <sys/sysmacros.h>
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 #include <linux/media.h>
37 #include <linux/videodev2.h>
38
39 #include "mediactl.h"
40 #include "mediactl-priv.h"
41 #include "tools.h"
42
43 /* -----------------------------------------------------------------------------
44 * Graph access
45 */
46
media_entity_remote_source(struct media_pad * pad)47 struct media_pad *media_entity_remote_source(struct media_pad *pad)
48 {
49 unsigned int i;
50
51 if (!(pad->flags & MEDIA_PAD_FL_SINK))
52 return NULL;
53
54 for (i = 0; i < pad->entity->num_links; ++i) {
55 struct media_link *link = &pad->entity->links[i];
56
57 if (!(link->flags & MEDIA_LNK_FL_ENABLED))
58 continue;
59
60 if (link->sink == pad)
61 return link->source;
62 }
63
64 return NULL;
65 }
66
media_get_entity_by_name(struct media_device * media,const char * name)67 struct media_entity *media_get_entity_by_name(struct media_device *media,
68 const char *name)
69 {
70 unsigned int i;
71
72 for (i = 0; i < media->entities_count; ++i) {
73 struct media_entity *entity = &media->entities[i];
74
75 if (strcmp(entity->info.name, name) == 0)
76 return entity;
77 }
78
79 return NULL;
80 }
81
media_get_entity_by_id(struct media_device * media,__u32 id)82 struct media_entity *media_get_entity_by_id(struct media_device *media,
83 __u32 id)
84 {
85 bool next = id & MEDIA_ENT_ID_FLAG_NEXT;
86 unsigned int i;
87
88 id &= ~MEDIA_ENT_ID_FLAG_NEXT;
89
90 for (i = 0; i < media->entities_count; ++i) {
91 struct media_entity *entity = &media->entities[i];
92
93 if ((entity->info.id == id && !next) ||
94 (entity->info.id > id && next))
95 return entity;
96 }
97
98 return NULL;
99 }
100
media_get_entities_count(struct media_device * media)101 unsigned int media_get_entities_count(struct media_device *media)
102 {
103 return media->entities_count;
104 }
105
media_get_entity(struct media_device * media,unsigned int index)106 struct media_entity *media_get_entity(struct media_device *media, unsigned int index)
107 {
108 if (index >= media->entities_count)
109 return NULL;
110
111 return &media->entities[index];
112 }
113
media_entity_get_pad(struct media_entity * entity,unsigned int index)114 const struct media_pad *media_entity_get_pad(struct media_entity *entity, unsigned int index)
115 {
116 if (index >= entity->info.pads)
117 return NULL;
118
119 return &entity->pads[index];
120 }
121
media_entity_get_links_count(struct media_entity * entity)122 unsigned int media_entity_get_links_count(struct media_entity *entity)
123 {
124 return entity->num_links;
125 }
126
media_entity_get_link(struct media_entity * entity,unsigned int index)127 const struct media_link *media_entity_get_link(struct media_entity *entity, unsigned int index)
128 {
129 if (index >= entity->num_links)
130 return NULL;
131
132 return &entity->links[index];
133 }
134
media_entity_get_devname(struct media_entity * entity)135 const char *media_entity_get_devname(struct media_entity *entity)
136 {
137 return entity->devname[0] ? entity->devname : NULL;
138 }
139
media_get_default_entity(struct media_device * media,unsigned int type)140 struct media_entity *media_get_default_entity(struct media_device *media,
141 unsigned int type)
142 {
143 switch (type) {
144 case MEDIA_ENT_T_DEVNODE_V4L:
145 return media->def.v4l;
146 case MEDIA_ENT_T_DEVNODE_FB:
147 return media->def.fb;
148 case MEDIA_ENT_T_DEVNODE_ALSA:
149 return media->def.alsa;
150 case MEDIA_ENT_T_DEVNODE_DVB:
151 return media->def.dvb;
152 }
153
154 return NULL;
155 }
156
media_get_info(struct media_device * media)157 const struct media_device_info *media_get_info(struct media_device *media)
158 {
159 return &media->info;
160 }
161
media_get_devnode(struct media_device * media)162 const char *media_get_devnode(struct media_device *media)
163 {
164 return media->devnode;
165 }
166
media_entity_get_info(struct media_entity * entity)167 const struct media_entity_desc *media_entity_get_info(struct media_entity *entity)
168 {
169 return &entity->info;
170 }
171
172 /* -----------------------------------------------------------------------------
173 * Open/close
174 */
175
media_device_open(struct media_device * media)176 static int media_device_open(struct media_device *media)
177 {
178 int ret;
179
180 if (media->fd != -1)
181 return 0;
182
183 media_dbg(media, "Opening media device %s\n", media->devnode);
184
185 media->fd = open(media->devnode, O_RDWR);
186 if (media->fd < 0) {
187 ret = -errno;
188 media_dbg(media, "%s: Can't open media device %s\n",
189 __func__, media->devnode);
190 return ret;
191 }
192
193 return 0;
194 }
195
media_device_close(struct media_device * media)196 static void media_device_close(struct media_device *media)
197 {
198 if (media->fd != -1) {
199 close(media->fd);
200 media->fd = -1;
201 }
202 }
203
204 /* -----------------------------------------------------------------------------
205 * Link setup
206 */
207
media_setup_link(struct media_device * media,struct media_pad * source,struct media_pad * sink,__u32 flags)208 int media_setup_link(struct media_device *media,
209 struct media_pad *source,
210 struct media_pad *sink,
211 __u32 flags)
212 {
213 struct media_link_desc ulink = { { 0 } };
214 struct media_link *link;
215 unsigned int i;
216 int ret;
217
218 ret = media_device_open(media);
219 if (ret < 0)
220 goto done;
221
222 for (i = 0; i < source->entity->num_links; i++) {
223 link = &source->entity->links[i];
224
225 if (link->source->entity == source->entity &&
226 link->source->index == source->index &&
227 link->sink->entity == sink->entity &&
228 link->sink->index == sink->index)
229 break;
230 }
231
232 if (i == source->entity->num_links) {
233 media_dbg(media, "%s: Link not found\n", __func__);
234 ret = -ENOENT;
235 goto done;
236 }
237
238 /* source pad */
239 ulink.source.entity = source->entity->info.id;
240 ulink.source.index = source->index;
241 ulink.source.flags = MEDIA_PAD_FL_SOURCE;
242
243 /* sink pad */
244 ulink.sink.entity = sink->entity->info.id;
245 ulink.sink.index = sink->index;
246 ulink.sink.flags = MEDIA_PAD_FL_SINK;
247
248 ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
249
250 ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
251 if (ret == -1) {
252 ret = -errno;
253 media_dbg(media, "%s: Unable to setup link (%s)\n",
254 __func__, strerror(errno));
255 goto done;
256 }
257
258 link->flags = ulink.flags;
259 link->twin->flags = ulink.flags;
260
261 ret = 0;
262
263 done:
264 media_device_close(media);
265 return ret;
266 }
267
media_reset_links(struct media_device * media)268 int media_reset_links(struct media_device *media)
269 {
270 unsigned int i, j;
271 int ret;
272
273 for (i = 0; i < media->entities_count; ++i) {
274 struct media_entity *entity = &media->entities[i];
275
276 for (j = 0; j < entity->num_links; j++) {
277 struct media_link *link = &entity->links[j];
278
279 if (link->flags & MEDIA_LNK_FL_IMMUTABLE ||
280 link->source->entity != entity)
281 continue;
282
283 ret = media_setup_link(media, link->source, link->sink,
284 link->flags & ~MEDIA_LNK_FL_ENABLED);
285 if (ret < 0)
286 return ret;
287 }
288 }
289
290 return 0;
291 }
292
293 /* -----------------------------------------------------------------------------
294 * Entities, pads and links enumeration
295 */
296
media_entity_add_link(struct media_entity * entity)297 static struct media_link *media_entity_add_link(struct media_entity *entity)
298 {
299 if (entity->num_links >= entity->max_links) {
300 struct media_link *links = entity->links;
301 unsigned int max_links = entity->max_links * 2;
302 unsigned int i;
303
304 links = realloc(links, max_links * sizeof *links);
305 if (links == NULL)
306 return NULL;
307
308 for (i = 0; i < entity->num_links; ++i)
309 links[i].twin->twin = &links[i];
310
311 entity->max_links = max_links;
312 entity->links = links;
313 }
314
315 return &entity->links[entity->num_links++];
316 }
317
media_enum_links(struct media_device * media)318 static int media_enum_links(struct media_device *media)
319 {
320 __u32 id;
321 int ret = 0;
322
323 for (id = 1; id <= media->entities_count; id++) {
324 struct media_entity *entity = &media->entities[id - 1];
325 struct media_links_enum links = { 0 };
326 unsigned int i;
327
328 links.entity = entity->info.id;
329 links.pads = calloc(entity->info.pads, sizeof(struct media_pad_desc));
330 links.links = calloc(entity->info.links, sizeof(struct media_link_desc));
331
332 if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
333 ret = -errno;
334 media_dbg(media,
335 "%s: Unable to enumerate pads and links (%s).\n",
336 __func__, strerror(errno));
337 free(links.pads);
338 free(links.links);
339 return ret;
340 }
341
342 for (i = 0; i < entity->info.pads; ++i) {
343 entity->pads[i].entity = entity;
344 entity->pads[i].index = links.pads[i].index;
345 entity->pads[i].flags = links.pads[i].flags;
346 }
347
348 for (i = 0; i < entity->info.links; ++i) {
349 struct media_link_desc *link = &links.links[i];
350 struct media_link *fwdlink;
351 struct media_link *backlink;
352 struct media_entity *source;
353 struct media_entity *sink;
354
355 source = media_get_entity_by_id(media, link->source.entity);
356 sink = media_get_entity_by_id(media, link->sink.entity);
357
358 if (source == NULL || sink == NULL) {
359 media_dbg(media,
360 "WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
361 id, i, link->source.entity,
362 link->source.index,
363 link->sink.entity,
364 link->sink.index);
365 ret = -EINVAL;
366 } else {
367 fwdlink = media_entity_add_link(source);
368 fwdlink->source = &source->pads[link->source.index];
369 fwdlink->sink = &sink->pads[link->sink.index];
370 fwdlink->flags = link->flags;
371
372 backlink = media_entity_add_link(sink);
373 backlink->source = &source->pads[link->source.index];
374 backlink->sink = &sink->pads[link->sink.index];
375 backlink->flags = link->flags;
376
377 fwdlink->twin = backlink;
378 backlink->twin = fwdlink;
379 }
380 }
381
382 free(links.pads);
383 free(links.links);
384 }
385
386 return ret;
387 }
388
389 #ifdef HAVE_LIBUDEV
390
391 #include <libudev.h>
392
media_udev_open(struct udev ** udev)393 static inline int media_udev_open(struct udev **udev)
394 {
395 *udev = udev_new();
396 if (*udev == NULL)
397 return -ENOMEM;
398 return 0;
399 }
400
media_udev_close(struct udev * udev)401 static inline void media_udev_close(struct udev *udev)
402 {
403 if (udev != NULL)
404 udev_unref(udev);
405 }
406
media_get_devname_udev(struct udev * udev,struct media_entity * entity)407 static int media_get_devname_udev(struct udev *udev,
408 struct media_entity *entity)
409 {
410 struct udev_device *device;
411 dev_t devnum;
412 const char *p;
413 int ret = -ENODEV;
414
415 if (udev == NULL)
416 return -EINVAL;
417
418 devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
419 media_dbg(entity->media, "looking up device: %u:%u\n",
420 major(devnum), minor(devnum));
421 device = udev_device_new_from_devnum(udev, 'c', devnum);
422 if (device) {
423 p = udev_device_get_devnode(device);
424 if (p) {
425 strncpy(entity->devname, p, sizeof(entity->devname));
426 entity->devname[sizeof(entity->devname) - 1] = '\0';
427 }
428 ret = 0;
429 }
430
431 udev_device_unref(device);
432
433 return ret;
434 }
435
436 #else /* HAVE_LIBUDEV */
437
438 struct udev;
439
media_udev_open(struct udev ** udev)440 static inline int media_udev_open(struct udev **udev) { return 0; }
441
media_udev_close(struct udev * udev)442 static inline void media_udev_close(struct udev *udev) { }
443
media_get_devname_udev(struct udev * udev,struct media_entity * entity)444 static inline int media_get_devname_udev(struct udev *udev,
445 struct media_entity *entity)
446 {
447 return -ENOTSUP;
448 }
449
450 #endif /* HAVE_LIBUDEV */
451
media_get_devname_sysfs(struct media_entity * entity)452 static int media_get_devname_sysfs(struct media_entity *entity)
453 {
454 struct stat devstat;
455 char devname[32];
456 char sysname[32];
457 char target[1024];
458 char *p;
459 int ret;
460
461 sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major,
462 entity->info.v4l.minor);
463 ret = readlink(sysname, target, sizeof(target) - 1);
464 if (ret < 0)
465 return -errno;
466
467 target[ret] = '\0';
468 p = strrchr(target, '/');
469 if (p == NULL)
470 return -EINVAL;
471
472 sprintf(devname, "/dev/%s", p + 1);
473 if (strstr(p + 1, "dvb")) {
474 char *s = p + 1;
475
476 if (strncmp(s, "dvb", 3))
477 return -EINVAL;
478 s += 3;
479 p = strchr(s, '.');
480 if (!p)
481 return -EINVAL;
482 *p = '/';
483 sprintf(devname, "/dev/dvb/adapter%s", s);
484 } else {
485 sprintf(devname, "/dev/%s", p + 1);
486 }
487 ret = stat(devname, &devstat);
488 if (ret < 0)
489 return -errno;
490
491 /* Sanity check: udev might have reordered the device nodes.
492 * Make sure the major/minor match. We should really use
493 * libudev.
494 */
495 if (major(devstat.st_rdev) == entity->info.v4l.major &&
496 minor(devstat.st_rdev) == entity->info.v4l.minor)
497 strcpy(entity->devname, devname);
498
499 return 0;
500 }
501
media_enum_entities(struct media_device * media)502 static int media_enum_entities(struct media_device *media)
503 {
504 struct media_entity *entity;
505 struct udev *udev;
506 unsigned int size;
507 __u32 id;
508 int ret;
509
510 ret = media_udev_open(&udev);
511 if (ret < 0)
512 media_dbg(media, "Can't get udev context\n");
513
514 for (id = 0, ret = 0; ; id = entity->info.id) {
515 size = (media->entities_count + 1) * sizeof(*media->entities);
516 media->entities = realloc(media->entities, size);
517
518 entity = &media->entities[media->entities_count];
519 memset(entity, 0, sizeof(*entity));
520 entity->fd = -1;
521 entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
522 entity->media = media;
523
524 ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
525 if (ret < 0) {
526 ret = errno != EINVAL ? -errno : 0;
527 break;
528 }
529
530 /* Number of links (for outbound links) plus number of pads (for
531 * inbound links) is a good safe initial estimate of the total
532 * number of links.
533 */
534 entity->max_links = entity->info.pads + entity->info.links;
535
536 entity->pads = malloc(entity->info.pads * sizeof(*entity->pads));
537 entity->links = malloc(entity->max_links * sizeof(*entity->links));
538 if (entity->pads == NULL || entity->links == NULL) {
539 ret = -ENOMEM;
540 break;
541 }
542
543 media->entities_count++;
544
545 if (entity->info.flags & MEDIA_ENT_FL_DEFAULT) {
546 switch (entity->info.type) {
547 case MEDIA_ENT_T_DEVNODE_V4L:
548 media->def.v4l = entity;
549 break;
550 case MEDIA_ENT_T_DEVNODE_FB:
551 media->def.fb = entity;
552 break;
553 case MEDIA_ENT_T_DEVNODE_ALSA:
554 media->def.alsa = entity;
555 break;
556 case MEDIA_ENT_T_DEVNODE_DVB:
557 media->def.dvb = entity;
558 break;
559 }
560 }
561
562 /* Find the corresponding device name. */
563 if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE &&
564 media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
565 continue;
566
567 /* Don't try to parse empty major,minor */
568 if (!entity->info.dev.major && !entity->info.dev.minor)
569 continue;
570
571 /* Try to get the device name via udev */
572 if (!media_get_devname_udev(udev, entity))
573 continue;
574
575 /* Fall back to get the device name via sysfs */
576 media_get_devname_sysfs(entity);
577 }
578
579 media_udev_close(udev);
580 return ret;
581 }
582
media_device_enumerate(struct media_device * media)583 int media_device_enumerate(struct media_device *media)
584 {
585 int ret;
586
587 if (media->entities)
588 return 0;
589
590 ret = media_device_open(media);
591 if (ret < 0)
592 return ret;
593
594 memset(&media->info, 0, sizeof(media->info));
595
596 ret = ioctl(media->fd, MEDIA_IOC_DEVICE_INFO, &media->info);
597 if (ret < 0) {
598 ret = -errno;
599 media_dbg(media, "%s: Unable to retrieve media device "
600 "information for device %s (%s)\n", __func__,
601 media->devnode, strerror(errno));
602 goto done;
603 }
604
605 media_dbg(media, "Enumerating entities\n");
606
607 ret = media_enum_entities(media);
608 if (ret < 0) {
609 media_dbg(media,
610 "%s: Unable to enumerate entities for device %s (%s)\n",
611 __func__, media->devnode, strerror(-ret));
612 goto done;
613 }
614
615 media_dbg(media, "Found %u entities\n", media->entities_count);
616 media_dbg(media, "Enumerating pads and links\n");
617
618 ret = media_enum_links(media);
619 if (ret < 0) {
620 media_dbg(media,
621 "%s: Unable to enumerate pads and linksfor device %s\n",
622 __func__, media->devnode);
623 goto done;
624 }
625
626 ret = 0;
627
628 done:
629 media_device_close(media);
630 return ret;
631 }
632
633 /* -----------------------------------------------------------------------------
634 * Create/destroy
635 */
636
media_debug_default(void * ptr,...)637 static void media_debug_default(void *ptr, ...)
638 {
639 }
640
media_debug_set_handler(struct media_device * media,void (* debug_handler)(void *,...),void * debug_priv)641 void media_debug_set_handler(struct media_device *media,
642 void (*debug_handler)(void *, ...),
643 void *debug_priv)
644 {
645 if (debug_handler) {
646 media->debug_handler = debug_handler;
647 media->debug_priv = debug_priv;
648 } else {
649 media->debug_handler = media_debug_default;
650 media->debug_priv = NULL;
651 }
652 }
653
__media_device_new(void)654 static struct media_device *__media_device_new(void)
655 {
656 struct media_device *media;
657
658 media = calloc(1, sizeof(*media));
659 if (media == NULL)
660 return NULL;
661
662 media->fd = -1;
663 media->refcount = 1;
664
665 media_debug_set_handler(media, NULL, NULL);
666
667 return media;
668 }
669
media_device_new(const char * devnode)670 struct media_device *media_device_new(const char *devnode)
671 {
672 struct media_device *media;
673
674 media = __media_device_new();
675 if (media == NULL)
676 return NULL;
677
678 media->devnode = strdup(devnode);
679 if (media->devnode == NULL) {
680 media_device_unref(media);
681 return NULL;
682 }
683
684 return media;
685 }
686
media_device_new_emulated(struct media_device_info * info)687 struct media_device *media_device_new_emulated(struct media_device_info *info)
688 {
689 struct media_device *media;
690
691 media = __media_device_new();
692 if (media == NULL)
693 return NULL;
694
695 media->info = *info;
696
697 return media;
698 }
699
media_device_ref(struct media_device * media)700 struct media_device *media_device_ref(struct media_device *media)
701 {
702 media->refcount++;
703 return media;
704 }
705
media_device_unref(struct media_device * media)706 void media_device_unref(struct media_device *media)
707 {
708 unsigned int i;
709
710 media->refcount--;
711 if (media->refcount > 0)
712 return;
713
714 for (i = 0; i < media->entities_count; ++i) {
715 struct media_entity *entity = &media->entities[i];
716
717 free(entity->pads);
718 free(entity->links);
719 if (entity->fd != -1)
720 close(entity->fd);
721 }
722
723 free(media->entities);
724 free(media->devnode);
725 free(media);
726 }
727
media_device_add_entity(struct media_device * media,const struct media_entity_desc * desc,const char * devnode)728 int media_device_add_entity(struct media_device *media,
729 const struct media_entity_desc *desc,
730 const char *devnode)
731 {
732 struct media_entity **defent = NULL;
733 struct media_entity *entity;
734 unsigned int size;
735
736 size = (media->entities_count + 1) * sizeof(*media->entities);
737 entity = realloc(media->entities, size);
738 if (entity == NULL)
739 return -ENOMEM;
740
741 media->entities = entity;
742 media->entities_count++;
743
744 entity = &media->entities[media->entities_count - 1];
745 memset(entity, 0, sizeof *entity);
746
747 entity->fd = -1;
748 entity->media = media;
749 strncpy(entity->devname, devnode, sizeof entity->devname);
750 entity->devname[sizeof entity->devname - 1] = '\0';
751
752 entity->info.id = 0;
753 entity->info.type = desc->type;
754 entity->info.flags = 0;
755 memcpy(entity->info.name, desc->name, sizeof entity->info.name);
756
757 switch (entity->info.type) {
758 case MEDIA_ENT_T_DEVNODE_V4L:
759 defent = &media->def.v4l;
760 entity->info.v4l = desc->v4l;
761 break;
762 case MEDIA_ENT_T_DEVNODE_FB:
763 defent = &media->def.fb;
764 entity->info.fb = desc->fb;
765 break;
766 case MEDIA_ENT_T_DEVNODE_ALSA:
767 defent = &media->def.alsa;
768 entity->info.alsa = desc->alsa;
769 break;
770 case MEDIA_ENT_T_DEVNODE_DVB:
771 defent = &media->def.dvb;
772 entity->info.dvb = desc->dvb;
773 break;
774 }
775
776 if (desc->flags & MEDIA_ENT_FL_DEFAULT) {
777 entity->info.flags |= MEDIA_ENT_FL_DEFAULT;
778 if (defent)
779 *defent = entity;
780 }
781
782 return 0;
783 }
784
media_parse_entity(struct media_device * media,const char * p,char ** endp)785 struct media_entity *media_parse_entity(struct media_device *media,
786 const char *p, char **endp)
787 {
788 unsigned int entity_id;
789 struct media_entity *entity;
790 char *end;
791
792 /* endp can be NULL. To avoid spreading NULL checks across the function,
793 * set endp to &end in that case.
794 */
795 if (endp == NULL)
796 endp = &end;
797
798 for (; isspace(*p); ++p);
799
800 if (*p == '"' || *p == '\'') {
801 char *name;
802
803 for (end = (char *)p + 1; *end && *end != '"' && *end != '\''; ++end);
804 if (*end != '"' && *end != '\'') {
805 media_dbg(media, "missing matching '\"'\n");
806 *endp = end;
807 return NULL;
808 }
809
810 name = strndup(p + 1, end - p - 1);
811 if (!name)
812 return NULL;
813 entity = media_get_entity_by_name(media, name);
814 free(name);
815 if (entity == NULL) {
816 media_dbg(media, "no such entity \"%.*s\"\n", end - p - 1, p + 1);
817 *endp = (char *)p + 1;
818 return NULL;
819 }
820
821 ++end;
822 } else {
823 entity_id = strtoul(p, &end, 10);
824 entity = media_get_entity_by_id(media, entity_id);
825 if (entity == NULL) {
826 media_dbg(media, "no such entity %d\n", entity_id);
827 *endp = (char *)p;
828 return NULL;
829 }
830 }
831 for (p = end; isspace(*p); ++p);
832
833 *endp = (char *)p;
834
835 return entity;
836 }
837
media_parse_pad(struct media_device * media,const char * p,char ** endp)838 struct media_pad *media_parse_pad(struct media_device *media,
839 const char *p, char **endp)
840 {
841 unsigned int pad;
842 struct media_entity *entity;
843 char *end;
844
845 if (endp == NULL)
846 endp = &end;
847
848 entity = media_parse_entity(media, p, &end);
849 if (!entity) {
850 *endp = end;
851 return NULL;
852 }
853
854 if (*end != ':') {
855 media_dbg(media, "Expected ':'\n", *end);
856 *endp = end;
857 return NULL;
858 }
859
860 for (p = end + 1; isspace(*p); ++p);
861
862 pad = strtoul(p, &end, 10);
863
864 if (pad >= entity->info.pads) {
865 media_dbg(media, "No pad '%d' on entity \"%s\". Maximum pad number is %d\n",
866 pad, entity->info.name, entity->info.pads - 1);
867 *endp = (char *)p;
868 return NULL;
869 }
870
871 for (p = end; isspace(*p); ++p);
872 *endp = (char *)p;
873
874 return &entity->pads[pad];
875 }
876
media_parse_pad_stream(struct media_device * media,const char * p,unsigned int * stream,char ** endp)877 struct media_pad *media_parse_pad_stream(struct media_device *media,
878 const char *p, unsigned int *stream,
879 char **endp)
880 {
881 struct media_pad *pad;
882 const char *orig_p = p;
883 char *ep;
884
885 pad = media_parse_pad(media, p, &ep);
886 if (pad == NULL)
887 return NULL;
888
889 p = ep;
890
891 if (*p == '/') {
892 unsigned int s;
893
894 p++;
895
896 s = strtoul(p, &ep, 10);
897
898 if (ep == p) {
899 media_dbg(media, "Unable to parse stream: '%s'\n", orig_p);
900 if (endp)
901 *endp = (char*)p;
902 return NULL;
903 }
904
905 *stream = s;
906
907 p++;
908 } else {
909 *stream = 0;
910 }
911
912 for (; isspace(*p); ++p);
913
914 if (endp)
915 *endp = (char*)p;
916
917 return pad;
918 }
919
media_parse_link(struct media_device * media,const char * p,char ** endp)920 struct media_link *media_parse_link(struct media_device *media,
921 const char *p, char **endp)
922 {
923 struct media_link *link;
924 struct media_pad *source;
925 struct media_pad *sink;
926 unsigned int i;
927 char *end;
928
929 source = media_parse_pad(media, p, &end);
930 if (source == NULL) {
931 *endp = end;
932 return NULL;
933 }
934
935 if (end[0] != '-' || end[1] != '>') {
936 *endp = end;
937 media_dbg(media, "Expected '->'\n");
938 return NULL;
939 }
940
941 p = end + 2;
942
943 sink = media_parse_pad(media, p, &end);
944 if (sink == NULL) {
945 *endp = end;
946 return NULL;
947 }
948
949 *endp = end;
950
951 for (i = 0; i < source->entity->num_links; i++) {
952 link = &source->entity->links[i];
953
954 if (link->source == source && link->sink == sink)
955 return link;
956 }
957
958 media_dbg(media, "No link between \"%s\":%d and \"%s\":%d\n",
959 source->entity->info.name, source->index,
960 sink->entity->info.name, sink->index);
961 return NULL;
962 }
963
media_parse_setup_link(struct media_device * media,const char * p,char ** endp)964 int media_parse_setup_link(struct media_device *media,
965 const char *p, char **endp)
966 {
967 struct media_link *link;
968 __u32 flags;
969 char *end;
970
971 link = media_parse_link(media, p, &end);
972 if (link == NULL) {
973 media_dbg(media,
974 "%s: Unable to parse link\n", __func__);
975 *endp = end;
976 return -EINVAL;
977 }
978
979 p = end;
980 if (*p++ != '[') {
981 media_dbg(media, "Unable to parse link flags: expected '['.\n");
982 *endp = (char *)p - 1;
983 return -EINVAL;
984 }
985
986 flags = strtoul(p, &end, 10);
987 for (p = end; isspace(*p); p++);
988 if (*p++ != ']') {
989 media_dbg(media, "Unable to parse link flags: expected ']'.\n");
990 *endp = (char *)p - 1;
991 return -EINVAL;
992 }
993
994 for (; isspace(*p); p++);
995 *endp = (char *)p;
996
997 media_dbg(media,
998 "Setting up link %u:%u -> %u:%u [%u]\n",
999 link->source->entity->info.id, link->source->index,
1000 link->sink->entity->info.id, link->sink->index,
1001 flags);
1002
1003 return media_setup_link(media, link->source, link->sink, flags);
1004 }
1005
media_print_streampos(struct media_device * media,const char * p,const char * end)1006 void media_print_streampos(struct media_device *media, const char *p,
1007 const char *end)
1008 {
1009 int pos;
1010
1011 pos = end - p + 1;
1012
1013 if (pos < 0)
1014 pos = 0;
1015 if (pos > strlen(p))
1016 pos = strlen(p);
1017
1018 media_dbg(media, "\n");
1019 media_dbg(media, " %s\n", p);
1020 media_dbg(media, " %*s\n", pos, "^");
1021 }
1022
media_parse_setup_links(struct media_device * media,const char * p)1023 int media_parse_setup_links(struct media_device *media, const char *p)
1024 {
1025 char *end;
1026 int ret;
1027
1028 do {
1029 ret = media_parse_setup_link(media, p, &end);
1030 if (ret < 0) {
1031 media_print_streampos(media, p, end);
1032 return ret;
1033 }
1034
1035 p = end + 1;
1036 } while (*end == ',');
1037
1038 return *end ? -EINVAL : 0;
1039 }
1040