From f25d668816faf7115ab65fad1f61a02532a609b3 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 29 Sep 2026 11:35:02 +0000 Subject: [PATCH] Answer unknown ioctl commands quietly with -ENOTTY dmdevfs now probes every node with the standard DMDRVI_IOCTL_BLOCK_GET_INFO (0x100) and DMDRVI_IOCTL_MONITOR_GET_POLICY (0x200) commands to classify it, so dmdma logged an "invalid ioctl command" error for every probe. Unknown commands are not an error for a driver: return -ENOTTY without logging, as dmdrvi documents. Also move dmdma's private commands to DMDRVI_IOCTL_CUSTOM_BASE (0x1000): they started at 1, colliding with the standard DMDRVI_IOCTL_NET_* range (0x01..), so a generic network probe would have been misread as a dmdma command. Callers using the enum names only need a rebuild. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016sVYVjrMNmMfPjWQkkGJTM --- include/dmdma_types.h | 5 ++++- src/dmdma.c | 15 +++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/dmdma_types.h b/include/dmdma_types.h index b343f2f..7631f03 100644 --- a/include/dmdma_types.h +++ b/include/dmdma_types.h @@ -196,7 +196,10 @@ typedef enum */ typedef enum { - dmdma_ioctl_cmd_start_transfer = 1, /**< arg = const dmdma_transfer_config_t* - configure and start */ + /* Private commands start at DMDRVI_IOCTL_CUSTOM_BASE (0x1000, dmdrvi_ioctl.h) + * so they never collide with the standard DMDRVI_IOCTL_* commands (network, + * block, monitor) that dmdevfs and other generic clients send to any node. */ + dmdma_ioctl_cmd_start_transfer = 0x1000, /**< arg = const dmdma_transfer_config_t* - configure and start */ dmdma_ioctl_cmd_stop_transfer, /**< Abort a transfer in progress; arg = NULL */ dmdma_ioctl_cmd_is_busy, /**< arg = bool* - whether a transfer is currently in flight */ dmdma_ioctl_cmd_get_remaining, /**< arg = size_t* - elements left in the current/last transfer */ diff --git a/src/dmdma.c b/src/dmdma.c index f944a75..6f24364 100644 --- a/src/dmdma.c +++ b/src/dmdma.c @@ -11,6 +11,11 @@ /* "DMDA" packed into a uint32_t - see dmdrvi context magic-field convention */ #define DMDMA_CONTEXT_MAGIC 0x444D4441UL +#ifdef DMDRVI_IOCTL_CUSTOM_BASE +_Static_assert(dmdma_ioctl_cmd_start_transfer == DMDRVI_IOCTL_CUSTOM_BASE, + "dmdma private ioctl commands must start at DMDRVI_IOCTL_CUSTOM_BASE"); +#endif + /* Generous upper bound on physical DMA controllers a board can have - real * hardware (STM32F4/F7) has at most 2. */ #define DMDMA_MAX_CONTROLLERS 4U @@ -655,10 +660,12 @@ dmod_dmdrvi_dif_api_declaration(2.0, dmdma, int, _ioctl, return -EINVAL; } - if (command < 0 || command >= dmdma_ioctl_cmd_max) + /* Not an error: generic clients (e.g. dmdevfs probing every node for the + * block/monitor classes) send standard DMDRVI_IOCTL_* commands a DMA stream + * does not implement - answer -ENOTTY quietly, as dmdrvi expects. */ + if (command < dmdma_ioctl_cmd_start_transfer || command >= dmdma_ioctl_cmd_max) { - DMOD_LOG_ERROR("Invalid ioctl command %d\n", command); - return -EINVAL; + return -ENOTTY; } dmdma_controller_t controller = context->config.controller; @@ -713,7 +720,7 @@ dmod_dmdrvi_dif_api_declaration(2.0, dmdma, int, _ioctl, return 0; default: - return -EINVAL; + return -ENOTTY; } }