milan-avb: aecp-vendor-unique-milan-v12: dispatch via per-cmd table per Milan v1.2 Section 5.4.4

This commit is contained in:
hackerman-kl 2026-04-26 21:04:21 +02:00 committed by Wim Taymans
parent deeea620f6
commit a16f3d704e
8 changed files with 217 additions and 108 deletions

View file

@ -1,8 +1,10 @@
/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki */
/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki <alexandre.malki@kebag-logic.com> */
/* SPDX-License-Identifier: MIT */
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <pipewire/pipewire.h>
@ -12,15 +14,27 @@
#include "aecp-vendor-unique-milan-v12.h"
#include "internal.h"
/* Milan v1.2: protocol version this implementation supports. The high 16
* bits encode the MVU protocol major version; bits 15..0 the minor. v1.0
* of MVU = 0x00010000. Most controllers (Hive, etc.) accept anything
* 0x00010000 and don't gate features on this value. */
#define MILAN_MVU_PROTOCOL_VERSION 0x00010000u
#include "aecp-vendor-unique-milan-v12-cmds-resps/cmd-resp-helpers.h"
#include "aecp-vendor-unique-milan-v12-cmds-resps/cmd-get-milan-info.h"
#define MILAN_MVU_FEATURES_FLAGS 0x00000000u
struct mvu_cmd_info {
int (*handle_command) (struct aecp *aecp, int64_t now,
const void *m, int len);
};
#define MILAN_MVU_CERTIFICATION_VERSION 0x00000000u
#define MVU_HANDLE_CMD(cmd, handle_exec) \
[cmd] = { \
.handle_command = handle_exec, \
}
static const char * const mvu_cmd_names[] = {
[AVB_AECP_MVU_CMD_GET_MILAN_INFO] = "get-milan-info",
};
static const struct mvu_cmd_info mvu_cmd_info_milan_v12[] = {
MVU_HANDLE_CMD(AVB_AECP_MVU_CMD_GET_MILAN_INFO,
handle_cmd_mvu_get_milan_info_milan_v12),
};
static const uint8_t mvu_protocol_id[6] = {
AVB_AECP_MVU_PROTOCOL_ID_0,
@ -31,83 +45,15 @@ static const uint8_t mvu_protocol_id[6] = {
AVB_AECP_MVU_PROTOCOL_ID_5,
};
static int reply_mvu_status(struct aecp *aecp, uint8_t status,
const void *m, int len)
{
struct server *server = aecp->server;
uint8_t buf[2048];
struct avb_ethernet_header *h = (void *)buf;
struct avb_packet_aecp_header *aecp_hdr;
if (len > (int)sizeof(buf))
return -EMSGSIZE;
memcpy(buf, m, len);
aecp_hdr = SPA_PTROFF(h, sizeof(*h), void);
AVB_PACKET_AECP_SET_MESSAGE_TYPE(aecp_hdr,
AVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_RESPONSE);
AVB_PACKET_AECP_SET_STATUS(aecp_hdr, status);
return avb_server_send_packet(server, h->src, AVB_TSN_ETH, buf, len);
}
static int handle_get_milan_info(struct aecp *aecp, const void *m, int len)
{
struct server *server = aecp->server;
uint8_t buf[2048];
struct avb_ethernet_header *h_reply;
struct avb_packet_aecp_header *aecp_hdr;
struct avb_packet_aecp_vendor_unique *vu_reply;
struct avb_packet_aecp_mvu_get_milan_info_rsp *body;
int total = (int)(sizeof(struct avb_ethernet_header) +
sizeof(struct avb_packet_aecp_vendor_unique) +
sizeof(struct avb_packet_aecp_mvu_get_milan_info_rsp));
if (total > (int)sizeof(buf))
return -EMSGSIZE;
memcpy(buf, m, len);
if (len < total)
memset(buf + len, 0, total - len);
h_reply = (struct avb_ethernet_header *)buf;
aecp_hdr = SPA_PTROFF(h_reply, sizeof(*h_reply), void);
vu_reply = (struct avb_packet_aecp_vendor_unique *)aecp_hdr;
AVB_PACKET_AECP_SET_MESSAGE_TYPE(aecp_hdr,
AVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_RESPONSE);
AVB_PACKET_AECP_SET_STATUS(aecp_hdr, AVB_AECP_STATUS_SUCCESS);
AVB_PACKET_SET_LENGTH(&aecp_hdr->hdr,
(uint16_t)(total - sizeof(struct avb_ethernet_header) -
sizeof(struct avb_packet_header)));
/* protocol_id and command_type are echoed from the command — the U
* flag is preserved but reset for the response per Section 5.4.4.2. */
vu_reply->command_type = htons(ntohs(vu_reply->command_type) &
AVB_AECP_MVU_CMD_TYPE_CMD_MASK);
body = (struct avb_packet_aecp_mvu_get_milan_info_rsp *)vu_reply->payload;
body->protocol_version = htonl(MILAN_MVU_PROTOCOL_VERSION);
body->features_flags = htonl(MILAN_MVU_FEATURES_FLAGS);
body->certification_version = htonl(MILAN_MVU_CERTIFICATION_VERSION);
pw_log_info("MVU GET_MILAN_INFO reply proto=0x%08x features=0x%08x "
"cert=0x%08x", MILAN_MVU_PROTOCOL_VERSION,
MILAN_MVU_FEATURES_FLAGS, MILAN_MVU_CERTIFICATION_VERSION);
return avb_server_send_packet(server, h_reply->src, AVB_TSN_ETH,
buf, total);
}
int aecp_vendor_unique_milan_v12_handle_command(struct aecp *aecp,
const void *m, int len)
{
const struct avb_ethernet_header *h = m;
const struct avb_packet_aecp_vendor_unique *vu;
uint16_t command_type;
uint16_t cmd;
const struct mvu_cmd_info *info;
uint16_t command_type, cmd;
struct timespec ts_now = {0};
int64_t now;
if (len < (int)(sizeof(*h) + sizeof(*vu)))
return 0;
@ -121,16 +67,23 @@ int aecp_vendor_unique_milan_v12_handle_command(struct aecp *aecp,
command_type = ntohs(vu->command_type);
cmd = command_type & AVB_AECP_MVU_CMD_TYPE_CMD_MASK;
pw_log_debug("MVU command 0x%04x (U=%d)", cmd,
(command_type & AVB_AECP_MVU_CMD_TYPE_U_FLAG_MASK) ? 1 : 0);
pw_log_info("mvu command %s (r=%d)",
cmd < SPA_N_ELEMENTS(mvu_cmd_names) && mvu_cmd_names[cmd]
? mvu_cmd_names[cmd] : "unknown",
(command_type & AVB_AECP_MVU_CMD_TYPE_R_FLAG_MASK) ? 1 : 0);
switch (cmd) {
case AVB_AECP_MVU_CMD_GET_MILAN_INFO:
(void)handle_get_milan_info(aecp, m, len);
return 1;
default:
(void)reply_mvu_status(aecp, AVB_AECP_STATUS_NOT_IMPLEMENTED,
m, len);
if (cmd >= SPA_N_ELEMENTS(mvu_cmd_info_milan_v12) ||
mvu_cmd_info_milan_v12[cmd].handle_command == NULL) {
(void)reply_mvu_not_implemented(aecp, m, len);
return 1;
}
info = &mvu_cmd_info_milan_v12[cmd];
if (clock_gettime(CLOCK_TAI, &ts_now))
pw_log_warn("clock_gettime(CLOCK_TAI): %m");
now = SPA_TIMESPEC_TO_NSEC(&ts_now);
(void)info->handle_command(aecp, now, m, len);
return 1;
}