Files
video-setup/dev/cli/media_ctrl_cli.c
mikael-lovqvists-claude-agent 4ba2a8118d Fix MEDIA_LNK_FL_* and MEDIA_PAD_FL_* visibility in CLI translation unit
The CLI is a separate translation unit that doesn't include <linux/media.h>,
so the kernel flag constants were undefined there. Fix by defining our own
public constants in media_ctrl.h:
- MEDIA_LINK_FL_{ENABLED,IMMUTABLE,DYNAMIC} for link flags
- MEDIA_PAD_FLAG_{SINK,SOURCE} for pad flags (distinct names avoid
  redefinition conflict with kernel's MEDIA_PAD_FL_* in media_ctrl.c)

media_ctrl.c now translates kernel flags to our constants on the way out.
Added fallback #defines for kernel constants that were missing them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 21:51:49 +00:00

249 lines
6.2 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "error.h"
#include "media_ctrl.h"
static void usage(const char *prog) {
fprintf(stderr,
"Usage: %s <command> [args]\n"
"\n"
"Commands:\n"
" list List all /dev/media* devices\n"
" info <device> Show device information\n"
" topology <device> Show full pipeline topology\n"
" set-link <device> <src_entity>:<src_pad> <sink_entity>:<sink_pad> <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_LINK_FL_ENABLED) ? "enabled" : "disabled";
const char *mutable = (link->flags & MEDIA_LINK_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: <device> <src_entity>:<src_pad> <sink_entity>:<sink_pad> <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;
}