#include #include #include #include "error.h" #include "media_ctrl.h" static void usage(const char *prog) { fprintf(stderr, "Usage: %s [args]\n" "\n" "Commands:\n" " list List all /dev/media* devices\n" " info Show device information\n" " topology Show full pipeline topology\n" " set-link : : <0|1>\n" " Enable (1) or disable (0) a link\n" "\n" "Examples:\n" " %s list\n" " %s info /dev/media0\n" " %s topology /dev/media0\n" " %s set-link /dev/media0 1:0 2:0 1\n", prog, prog, prog, prog, prog); } /* --- list --- */ static void on_device_found(const char *path, void *userdata) { (void)userdata; printf(" %s\n", path); } static int cmd_list(void) { printf("Media devices:\n"); struct App_Error err = media_ctrl_find_devices(on_device_found, NULL); if (!APP_IS_OK(err)) { app_error_print(&err); return 1; } return 0; } /* --- info --- */ static int cmd_info(const char *device) { struct Media_Ctrl *ctrl = NULL; struct App_Error err = media_ctrl_open(device, &ctrl); if (!APP_IS_OK(err)) { app_error_print(&err); return 1; } struct Media_Device_Info info; err = media_ctrl_get_info(ctrl, &info); if (!APP_IS_OK(err)) { app_error_print(&err); media_ctrl_close(ctrl); return 1; } printf("Device: %s\n", device); printf("Driver: %s\n", info.driver); printf("Model: %s\n", info.model); printf("Serial: %s\n", info.serial); printf("Bus info: %s\n", info.bus_info); printf("Media version: %u.%u.%u\n", (info.media_version >> 16) & 0xff, (info.media_version >> 8) & 0xff, info.media_version & 0xff); printf("Hardware rev: 0x%08x\n", info.hw_revision); printf("Driver version: %u.%u.%u\n", (info.driver_version >> 16) & 0xff, (info.driver_version >> 8) & 0xff, info.driver_version & 0xff); media_ctrl_close(ctrl); return 0; } /* --- topology --- */ struct Topology_State { struct Media_Ctrl *ctrl; }; static void on_pad(const struct Media_Pad *pad, void *userdata) { (void)userdata; printf(" pad %u: %s\n", pad->index, media_pad_flag_name(pad->flags)); } static void on_link(const struct Media_Link *link, void *userdata) { (void)userdata; const char *enabled = (link->flags & MEDIA_LNK_FL_ENABLED) ? "enabled" : "disabled"; const char *mutable = (link->flags & MEDIA_LNK_FL_IMMUTABLE) ? ", immutable" : ""; printf(" link: entity %u pad %u -> entity %u pad %u [%s%s]\n", link->source.entity_id, link->source.index, link->sink.entity_id, link->sink.index, enabled, mutable); } static void on_entity(const struct Media_Entity *entity, void *userdata) { struct Topology_State *state = userdata; printf(" Entity %u: %s\n", entity->id, entity->name); printf(" type: %s (0x%08x)\n", media_entity_type_name(entity->type), entity->type); printf(" flags: 0x%08x\n", entity->flags); printf(" pads: %u links: %u\n", entity->pad_count, entity->link_count); if (entity->dev_major != 0 || entity->dev_minor != 0) { printf(" device: %u:%u\n", entity->dev_major, entity->dev_minor); } struct App_Error err = media_ctrl_enum_entity_pads_and_links( state->ctrl, entity, on_pad, on_link, NULL); if (!APP_IS_OK(err)) { fprintf(stderr, " (error enumerating pads/links: "); app_error_print(&err); fprintf(stderr, ")\n"); } } static int cmd_topology(const char *device) { struct Media_Ctrl *ctrl = NULL; struct App_Error err = media_ctrl_open(device, &ctrl); if (!APP_IS_OK(err)) { app_error_print(&err); return 1; } struct Media_Device_Info info; err = media_ctrl_get_info(ctrl, &info); if (!APP_IS_OK(err)) { app_error_print(&err); media_ctrl_close(ctrl); return 1; } printf("Device: %s (%s)\n\n", info.model, device); struct Topology_State state = { .ctrl = ctrl }; err = media_ctrl_enum_entities(ctrl, on_entity, &state); if (!APP_IS_OK(err)) { app_error_print(&err); media_ctrl_close(ctrl); return 1; } media_ctrl_close(ctrl); return 0; } /* --- set-link --- */ static int parse_entity_pad(const char *s, uint32_t *entity_out, uint16_t *pad_out) { unsigned int entity, pad; if (sscanf(s, "%u:%u", &entity, &pad) != 2) { return -1; } *entity_out = (uint32_t)entity; *pad_out = (uint16_t)pad; return 0; } static int cmd_set_link( const char *device, const char *src_arg, const char *sink_arg, const char *enabled_arg) { uint32_t src_entity, sink_entity; uint16_t src_pad, sink_pad; if (parse_entity_pad(src_arg, &src_entity, &src_pad) < 0) { fprintf(stderr, "Invalid source: '%s' (expected entity:pad)\n", src_arg); return 1; } if (parse_entity_pad(sink_arg, &sink_entity, &sink_pad) < 0) { fprintf(stderr, "Invalid sink: '%s' (expected entity:pad)\n", sink_arg); return 1; } int enabled = atoi(enabled_arg); struct Media_Ctrl *ctrl = NULL; struct App_Error err = media_ctrl_open(device, &ctrl); if (!APP_IS_OK(err)) { app_error_print(&err); return 1; } err = media_ctrl_set_link(ctrl, src_entity, src_pad, sink_entity, sink_pad, enabled); if (!APP_IS_OK(err)) { app_error_print(&err); media_ctrl_close(ctrl); return 1; } printf("Link %u:%u -> %u:%u %s\n", src_entity, src_pad, sink_entity, sink_pad, enabled ? "enabled" : "disabled"); media_ctrl_close(ctrl); return 0; } /* --- main --- */ int main(int argc, char **argv) { if (argc < 2) { usage(argv[0]); return 1; } const char *cmd = argv[1]; if (strcmp(cmd, "list") == 0) { return cmd_list(); } if (strcmp(cmd, "info") == 0) { if (argc < 3) { fprintf(stderr, "info requires a device argument\n"); return 1; } return cmd_info(argv[2]); } if (strcmp(cmd, "topology") == 0) { if (argc < 3) { fprintf(stderr, "topology requires a device argument\n"); return 1; } return cmd_topology(argv[2]); } if (strcmp(cmd, "set-link") == 0) { if (argc < 6) { fprintf(stderr, "set-link requires: : : <0|1>\n"); return 1; } return cmd_set_link(argv[2], argv[3], argv[4], argv[5]); } fprintf(stderr, "Unknown command: %s\n\n", cmd); usage(argv[0]); return 1; }