123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- #include "device.h"
- #include <errno.h>
- #include <fcntl.h>
- #include <glib.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/ioctl.h>
- #include <unistd.h>
- bool
- mp_find_device_path(struct media_v2_intf_devnode devnode, char *path, int length)
- {
- char uevent_path[256];
- snprintf(uevent_path, 256, "/sys/dev/char/%d:%d/uevent", devnode.major,
- devnode.minor);
- FILE *f = fopen(uevent_path, "r");
- if (!f) {
- return false;
- }
- char line[512];
- while (fgets(line, 512, f)) {
- if (strncmp(line, "DEVNAME=", 8) == 0) {
- // Drop newline
- int length = strlen(line);
- if (line[length - 1] == '\n')
- line[length - 1] = '\0';
- snprintf(path, length, "/dev/%s", line + 8);
- return true;
- }
- }
- fclose(f);
- return false;
- }
- struct _MPDevice {
- int fd;
- struct media_device_info info;
- struct media_v2_entity *entities;
- size_t num_entities;
- struct media_v2_interface *interfaces;
- size_t num_interfaces;
- struct media_v2_pad *pads;
- size_t num_pads;
- struct media_v2_link *links;
- size_t num_links;
- };
- static void
- errno_printerr(const char *s)
- {
- g_printerr("MPDevice: %s error %d, %s\n", s, errno, strerror(errno));
- }
- static int
- xioctl(int fd, int request, void *arg)
- {
- int r;
- do {
- r = ioctl(fd, request, arg);
- } while (r == -1 && errno == EINTR);
- return r;
- }
- MPDevice *
- mp_device_find(const char *driver_name)
- {
- MPDeviceList *list = mp_device_list_new();
- MPDevice *found_device = mp_device_list_find_remove(&list, driver_name);
- mp_device_list_free(list);
- return found_device;
- }
- MPDevice *
- mp_device_open(const char *path)
- {
- int fd = open(path, O_RDWR);
- if (fd == -1) {
- errno_printerr("open");
- return NULL;
- }
- return mp_device_new(fd);
- }
- MPDevice *
- mp_device_new(int fd)
- {
- // Get the topology of the media device
- struct media_v2_topology topology = {};
- if (xioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology) == -1 ||
- topology.num_entities == 0) {
- close(fd);
- return NULL;
- }
- // Create the device
- MPDevice *device = calloc(1, sizeof(MPDevice));
- device->fd = fd;
- device->entities =
- calloc(topology.num_entities, sizeof(struct media_v2_entity));
- device->num_entities = topology.num_entities;
- device->interfaces =
- calloc(topology.num_interfaces, sizeof(struct media_v2_interface));
- device->num_interfaces = topology.num_interfaces;
- device->pads = calloc(topology.num_pads, sizeof(struct media_v2_pad));
- device->num_pads = topology.num_pads;
- device->links = calloc(topology.num_links, sizeof(struct media_v2_link));
- device->num_links = topology.num_links;
- // Get the actual devices and interfaces
- topology.ptr_entities = (uint64_t)device->entities;
- topology.ptr_interfaces = (uint64_t)device->interfaces;
- topology.ptr_pads = (uint64_t)device->pads;
- topology.ptr_links = (uint64_t)device->links;
- if (xioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology) == -1) {
- errno_printerr("MEDIA_IOC_G_TOPOLOGY");
- mp_device_close(device);
- return NULL;
- }
- // Get device info
- if (xioctl(fd, MEDIA_IOC_DEVICE_INFO, &device->info) == -1) {
- errno_printerr("MEDIA_IOC_DEVICE_INFO");
- mp_device_close(device);
- return NULL;
- }
- return device;
- }
- void
- mp_device_close(MPDevice *device)
- {
- close(device->fd);
- free(device->entities);
- free(device->interfaces);
- free(device->pads);
- free(device->links);
- free(device);
- }
- bool
- mp_device_setup_link(MPDevice *device, uint32_t source_pad_id, uint32_t sink_pad_id,
- bool enabled)
- {
- const struct media_v2_pad *source_pad =
- mp_device_get_pad(device, source_pad_id);
- g_return_val_if_fail(source_pad, false);
- const struct media_v2_pad *sink_pad = mp_device_get_pad(device, sink_pad_id);
- g_return_val_if_fail(sink_pad, false);
- struct media_link_desc link = {};
- link.flags = enabled ? MEDIA_LNK_FL_ENABLED : 0;
- link.source.entity = source_pad->entity_id;
- link.source.index = 0;
- link.sink.entity = sink_pad->entity_id;
- link.sink.index = 0;
- if (xioctl(device->fd, MEDIA_IOC_SETUP_LINK, &link) == -1) {
- errno_printerr("MEDIA_IOC_SETUP_LINK");
- return false;
- }
- return true;
- }
- const struct media_v2_entity *
- mp_device_find_entity(const MPDevice *device, const char *driver_name)
- {
- int length = strlen(driver_name);
- // Find the entity from the name
- for (uint32_t i = 0; i < device->num_entities; ++i) {
- if (strncmp(device->entities[i].name, driver_name, length) == 0) {
- return &device->entities[i];
- }
- }
- return NULL;
- }
- const struct media_v2_entity *
- mp_device_find_entity_type(const MPDevice *device, const uint32_t type)
- {
- // Find the entity from the entity type
- for (uint32_t i = 0; i < device->num_entities; ++i) {
- if (device->entities[i].function == type) {
- return &device->entities[i];
- }
- }
- return NULL;
- }
- const struct media_device_info *
- mp_device_get_info(const MPDevice *device)
- {
- return &device->info;
- }
- const struct media_v2_entity *
- mp_device_get_entity(const MPDevice *device, uint32_t id)
- {
- for (int i = 0; i < device->num_entities; ++i) {
- if (device->entities[i].id == id) {
- return &device->entities[i];
- }
- }
- return NULL;
- }
- const struct media_v2_entity *
- mp_device_get_entities(const MPDevice *device)
- {
- return device->entities;
- }
- size_t
- mp_device_get_num_entities(const MPDevice *device)
- {
- return device->num_entities;
- }
- const struct media_v2_interface *
- mp_device_find_entity_interface(const MPDevice *device, uint32_t entity_id)
- {
- // Find the interface through the link
- const struct media_v2_link *link = mp_device_find_link_to(device, entity_id);
- if (!link) {
- return NULL;
- }
- return mp_device_get_interface(device, link->source_id);
- }
- const struct media_v2_interface *
- mp_device_get_interface(const MPDevice *device, uint32_t id)
- {
- for (int i = 0; i < device->num_interfaces; ++i) {
- if (device->interfaces[i].id == id) {
- return &device->interfaces[i];
- }
- }
- return NULL;
- }
- const struct media_v2_interface *
- mp_device_get_interfaces(const MPDevice *device)
- {
- return device->interfaces;
- }
- size_t
- mp_device_get_num_interfaces(const MPDevice *device)
- {
- return device->num_interfaces;
- }
- const struct media_v2_pad *
- mp_device_get_pad_from_entity(const MPDevice *device, uint32_t entity_id)
- {
- for (int i = 0; i < device->num_pads; ++i) {
- if (device->pads[i].entity_id == entity_id) {
- return &device->pads[i];
- }
- }
- return NULL;
- }
- const struct media_v2_pad *
- mp_device_get_pad(const MPDevice *device, uint32_t id)
- {
- for (int i = 0; i < device->num_pads; ++i) {
- if (device->pads[i].id == id) {
- return &device->pads[i];
- }
- }
- return NULL;
- }
- const struct media_v2_pad *
- mp_device_get_pads(const MPDevice *device)
- {
- return device->pads;
- }
- size_t
- mp_device_get_num_pads(const MPDevice *device)
- {
- return device->num_pads;
- }
- const struct media_v2_link *
- mp_device_find_entity_link(const MPDevice *device, uint32_t entity_id)
- {
- const struct media_v2_pad *pad =
- mp_device_get_pad_from_entity(device, entity_id);
- const struct media_v2_link *link = mp_device_find_link_to(device, pad->id);
- if (link) {
- return link;
- }
- return mp_device_find_link_from(device, pad->id);
- }
- const struct media_v2_link *
- mp_device_find_link_from(const MPDevice *device, uint32_t source)
- {
- for (int i = 0; i < device->num_links; ++i) {
- if (device->links[i].source_id == source) {
- return &device->links[i];
- }
- }
- return NULL;
- }
- const struct media_v2_link *
- mp_device_find_link_to(const MPDevice *device, uint32_t sink)
- {
- for (int i = 0; i < device->num_links; ++i) {
- if (device->links[i].sink_id == sink) {
- return &device->links[i];
- }
- }
- return NULL;
- }
- const struct media_v2_link *
- mp_device_find_link_between(const MPDevice *device, uint32_t source, uint32_t sink)
- {
- for (int i = 0; i < device->num_links; ++i) {
- if (device->links[i].source_id == source &&
- device->links[i].sink_id == sink) {
- return &device->links[i];
- }
- }
- return NULL;
- }
- const struct media_v2_link *
- mp_device_get_link(const MPDevice *device, uint32_t id)
- {
- for (int i = 0; i < device->num_links; ++i) {
- if (device->links[i].id == id) {
- return &device->links[i];
- }
- }
- return NULL;
- }
- const struct media_v2_link *
- mp_device_get_links(const MPDevice *device)
- {
- return device->links;
- }
- size_t
- mp_device_get_num_links(const MPDevice *device)
- {
- return device->num_links;
- }
- struct _MPDeviceList {
- MPDevice *device;
- MPDeviceList *next;
- };
- MPDeviceList *
- mp_device_list_new()
- {
- MPDeviceList *current = NULL;
- // Enumerate media device files
- struct dirent *dir;
- DIR *d = opendir("/dev");
- while ((dir = readdir(d)) != NULL) {
- if (strncmp(dir->d_name, "media", 5) == 0) {
- char path[261];
- snprintf(path, 261, "/dev/%s", dir->d_name);
- MPDevice *device = mp_device_open(path);
- if (device) {
- MPDeviceList *next = malloc(sizeof(MPDeviceList));
- next->device = device;
- next->next = current;
- current = next;
- }
- }
- }
- closedir(d);
- return current;
- }
- void
- mp_device_list_free(MPDeviceList *device_list)
- {
- while (device_list) {
- MPDeviceList *tmp = device_list;
- device_list = tmp->next;
- mp_device_close(tmp->device);
- free(tmp);
- }
- }
- MPDevice *
- mp_device_list_find_remove(MPDeviceList **list, const char *driver_name)
- {
- MPDevice *found_device = NULL;
- int length = strlen(driver_name);
- while (*list) {
- MPDevice *device = mp_device_list_get(*list);
- const struct media_device_info *info = mp_device_get_info(device);
- if (strncmp(info->driver, driver_name, length) == 0) {
- found_device = mp_device_list_remove(list);
- break;
- }
- list = &(*list)->next;
- }
- return found_device;
- }
- MPDevice *
- mp_device_list_remove(MPDeviceList **device_list)
- {
- MPDevice *device = (*device_list)->device;
- if ((*device_list)->next) {
- MPDeviceList *tmp = (*device_list)->next;
- **device_list = *tmp;
- free(tmp);
- } else {
- free(*device_list);
- *device_list = NULL;
- }
- return device;
- }
- MPDevice *
- mp_device_list_get(const MPDeviceList *device_list)
- {
- return device_list->device;
- }
- MPDeviceList *
- mp_device_list_next(const MPDeviceList *device_list)
- {
- return device_list->next;
- }
|