mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-04-30 06:46:49 -04:00
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:
parent
deeea620f6
commit
a16f3d704e
8 changed files with 217 additions and 108 deletions
|
|
@ -797,6 +797,7 @@ if build_module_avb
|
|||
'module-avb/aecp.c',
|
||||
'module-avb/aecp-aem.c',
|
||||
'module-avb/aecp-vendor-unique-milan-v12.c',
|
||||
'module-avb/aecp-vendor-unique-milan-v12-cmds-resps/cmd-get-milan-info.c',
|
||||
'module-avb/aecp-aem-cmds-resps/cmd-available.c',
|
||||
'module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c',
|
||||
'module-avb/aecp-aem-cmds-resps/cmd-get-set-name.c',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki <alexandre.malki@kebag-logic.com> */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <spa/utils/defs.h>
|
||||
|
||||
#include "../aecp.h"
|
||||
#include "../aecp-vendor-unique-milan-v12.h"
|
||||
#include "../internal.h"
|
||||
|
||||
#include "cmd-get-milan-info.h"
|
||||
#include "cmd-resp-helpers.h"
|
||||
|
||||
/* Milan v1.2 Section 5.4.4.1 GET_MILAN_INFO Response payload. */
|
||||
struct avb_packet_aecp_mvu_get_milan_info_rsp {
|
||||
uint32_t protocol_version;
|
||||
uint32_t features_flags;
|
||||
uint32_t certification_version;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* Milan v1.2 Section 5.4.4.1: protocol_version is 1 across every Milan release. */
|
||||
#define MILAN_MVU_PROTOCOL_VERSION 0x00000001u
|
||||
|
||||
/* Milan v1.2 Section 5.4.4.1 Table 5.20: features_flags bit 0 = REDUNDANCY (not
|
||||
* implemented), upper bits reserved. */
|
||||
#define MILAN_MVU_FEATURES_FLAGS 0x00000000u
|
||||
|
||||
/* Milan v1.2 Section 5.4.4.1: certification_version byte-encoded
|
||||
* major.minor.revision.build. Milan v1.2 = 0x01020000. */
|
||||
#define MILAN_MVU_CERTIFICATION_VERSION 0x01020000u
|
||||
|
||||
int handle_cmd_mvu_get_milan_info_milan_v12(struct aecp *aecp, int64_t now,
|
||||
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));
|
||||
int wire = total < 60 ? 60 : total;
|
||||
|
||||
(void)now;
|
||||
|
||||
if (wire > (int)sizeof(buf))
|
||||
return -EMSGSIZE;
|
||||
|
||||
memcpy(buf, m, len);
|
||||
if (len < wire)
|
||||
memset(buf + len, 0, wire - 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);
|
||||
|
||||
/* IEEE 1722-2011 Section 5.3 / IEEE 1722.1-2021 Section 9.2.1.1.7: CDL excludes
|
||||
* the 12-octet AVTPDU common header. */
|
||||
AVB_PACKET_SET_LENGTH(&aecp_hdr->hdr,
|
||||
(uint16_t)(total - sizeof(struct avb_ethernet_header) -
|
||||
sizeof(struct avb_packet_header) -
|
||||
sizeof(uint64_t)));
|
||||
|
||||
((uint8_t *)&vu_reply->command_type)[0] &= 0x7f;
|
||||
vu_reply->reserved = 0;
|
||||
|
||||
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);
|
||||
|
||||
return avb_server_send_packet(server, h_reply->src, AVB_TSN_ETH,
|
||||
buf, wire);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki <alexandre.malki@kebag-logic.com> */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef __AVB_AECP_MVU_CMD_GET_MILAN_INFO_H__
|
||||
#define __AVB_AECP_MVU_CMD_GET_MILAN_INFO_H__
|
||||
|
||||
#include "../aecp-vendor-unique-milan-v12.h"
|
||||
|
||||
int handle_cmd_mvu_get_milan_info_milan_v12(struct aecp *aecp, int64_t now,
|
||||
const void *m, int len);
|
||||
|
||||
#endif /* __AVB_AECP_MVU_CMD_GET_MILAN_INFO_H__ */
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki <alexandre.malki@kebag-logic.com> */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef __AVB_AECP_MVU_HELPERS_H__
|
||||
#define __AVB_AECP_MVU_HELPERS_H__
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <pipewire/log.h>
|
||||
|
||||
#include "../aecp.h"
|
||||
#include "../aecp-vendor-unique-milan-v12.h"
|
||||
#include "../internal.h"
|
||||
|
||||
/* Milan v1.2 Section 5.4.3.2.2: r bit is reserved (must be 0) in commands and
|
||||
* responses. Command vs response is signalled by AECP message_type. */
|
||||
static inline int reply_mvu_status(struct aecp *aecp, int status,
|
||||
const void *m, int len)
|
||||
{
|
||||
uint8_t buf[2048];
|
||||
struct server *server = aecp->server;
|
||||
struct avb_ethernet_header *h = (void *)buf;
|
||||
struct avb_packet_aecp_header *reply = SPA_PTROFF(h, sizeof(*h), void);
|
||||
struct avb_packet_aecp_vendor_unique *vu_reply;
|
||||
int wire = len < 60 ? 60 : len;
|
||||
|
||||
if (len < 0 || (size_t)wire > sizeof(buf)) {
|
||||
pw_log_warn("reply_mvu_status: invalid len %d", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(buf, m, len);
|
||||
if (wire > len)
|
||||
memset(buf + len, 0, wire - len);
|
||||
AVB_PACKET_AECP_SET_MESSAGE_TYPE(reply,
|
||||
AVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_RESPONSE);
|
||||
AVB_PACKET_AECP_SET_STATUS(reply, status);
|
||||
|
||||
if ((size_t)wire >= sizeof(*h) + sizeof(*vu_reply)) {
|
||||
vu_reply = SPA_PTROFF(h, sizeof(*h), void);
|
||||
((uint8_t *)&vu_reply->command_type)[0] &= 0x7f;
|
||||
}
|
||||
|
||||
return avb_server_send_packet(server, h->src, AVB_TSN_ETH, buf, wire);
|
||||
}
|
||||
|
||||
static inline int reply_mvu_not_implemented(struct aecp *aecp,
|
||||
const void *m, int len)
|
||||
{
|
||||
return reply_mvu_status(aecp, AVB_AECP_STATUS_NOT_IMPLEMENTED, m, len);
|
||||
}
|
||||
|
||||
static inline int direct_reply_mvu_not_implemented(struct aecp *aecp,
|
||||
int64_t now, const void *m, int len)
|
||||
{
|
||||
(void)now;
|
||||
return reply_mvu_not_implemented(aecp, m, len);
|
||||
}
|
||||
|
||||
static inline int reply_mvu_success(struct aecp *aecp,
|
||||
const void *m, int len)
|
||||
{
|
||||
return reply_mvu_status(aecp, AVB_AECP_STATUS_SUCCESS, m, len);
|
||||
}
|
||||
|
||||
#endif /* __AVB_AECP_MVU_HELPERS_H__ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,17 +8,8 @@
|
|||
|
||||
#include "aecp.h"
|
||||
|
||||
/* Milan v1.2 Section 5.4.4 — Milan Vendor Unique (MVU) protocol carried inside an
|
||||
* IEEE 1722.1 AECP VENDOR_UNIQUE_COMMAND/RESPONSE (message_type 6/7).
|
||||
*
|
||||
* Wire layout after the standard AECP common header:
|
||||
* protocol_id (6) | command_type (2) | command-specific data
|
||||
*
|
||||
* Milan v1.2 Section 5.4.3.2.1: protocol_id is the Avnu OUI-36 00-1B-C5-0A-C
|
||||
* appended with the 12-bit MVU protocol id 0x100, giving the 6-byte
|
||||
* marker 00-1B-C5-0A-C1-00. command_type is a 1-bit U flag (MSB) +
|
||||
* 15-bit command code. */
|
||||
|
||||
/* Milan v1.2 Section 5.4.3.2.1 protocol_id: Avnu OUI-36 00-1B-C5-0A-C +
|
||||
* 12-bit MVU id 0x100 = 00-1B-C5-0A-C1-00. */
|
||||
#define AVB_AECP_MVU_PROTOCOL_ID_0 0x00
|
||||
#define AVB_AECP_MVU_PROTOCOL_ID_1 0x1B
|
||||
#define AVB_AECP_MVU_PROTOCOL_ID_2 0xC5
|
||||
|
|
@ -26,25 +17,22 @@
|
|||
#define AVB_AECP_MVU_PROTOCOL_ID_4 0xC1
|
||||
#define AVB_AECP_MVU_PROTOCOL_ID_5 0x00
|
||||
|
||||
/* Milan MVU command codes (Milan v1.2 Section 5.4.4). */
|
||||
/* Milan v1.2 Section 5.4.3.2.3 Table 5.18 MVU command codes. */
|
||||
#define AVB_AECP_MVU_CMD_GET_MILAN_INFO 0x0000
|
||||
|
||||
#define AVB_AECP_MVU_CMD_TYPE_U_FLAG_MASK 0x8000
|
||||
/* Milan v1.2 Section 5.4.3.2.2: r is reserved (must be 0). */
|
||||
#define AVB_AECP_MVU_CMD_TYPE_R_FLAG_MASK 0x8000
|
||||
#define AVB_AECP_MVU_CMD_TYPE_CMD_MASK 0x7FFF
|
||||
|
||||
/* Milan v1.2 Section 5.4.3.2 Figure 5.2 MVU payload format. */
|
||||
struct avb_packet_aecp_vendor_unique {
|
||||
struct avb_packet_aecp_header hdr;
|
||||
uint8_t protocol_id[6];
|
||||
uint16_t command_type;
|
||||
uint16_t reserved;
|
||||
uint8_t payload[0];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct avb_packet_aecp_mvu_get_milan_info_rsp {
|
||||
uint32_t protocol_version;
|
||||
uint32_t features_flags;
|
||||
uint32_t certification_version;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
int aecp_vendor_unique_milan_v12_handle_command(struct aecp *aecp,
|
||||
const void *m, int len);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue