IOCTL and Control Plane¶
1. What is ioctl?¶
ioctl (input/output control) is a system call used to send control commands
from user space to kernel drivers.
Unlike read() / write() which handle data transfer, ioctl() is used for:
- Configuration
- Status query
- Device-specific control operations
2. IOCTL Design Philosophy¶
Command-based (NOT message-based)¶
Linux ioctl follows a command-per-struct model:
- Each command has its own data structure
- No global message container
- No embedded "cmd" field inside struct
Correct design:
#define MYGPIO_IOC_SET_DEBOUNCE _IOW(MYGPIO_IOC_MAGIC, 1, struct mygpio_ioc_debounce)
#define MYGPIO_IOC_GET_STATUS _IOR(MYGPIO_IOC_MAGIC, 2, struct mygpio_ioc_status)
#define MYGPIO_IOC_CLR_EVENTS _IO(MYGPIO_IOC_MAGIC, 3)
Avoid:
- giant union-based container
- message-style multiplexing
3. IOCTL Command Encoding¶
Linux provides macros:
| Macro | Direction | Description |
|---|---|---|
_IO |
none | no data |
_IOR |
read | kernel → user |
_IOW |
write | user → kernel |
_IOWR |
both | bidirectional |
Example:
#define MYGPIO_IOC_MAGIC 'M'
struct mygpio_ioc_debounce {
__u32 debounce_ms;
};
#define MYGPIO_IOC_SET_DEBOUNCE \
_IOW(MYGPIO_IOC_MAGIC, 1, struct mygpio_ioc_debounce)
4. User ↔ Kernel Memory Handling¶
User pointer must NEVER be dereferenced directly.
Use:
Example:
5. ABI (Application Binary Interface)¶
IOCTL interface is a stable ABI:
- Structure layout must not change arbitrarily
- Use fixed-size types (
__u32, etc.) - Consider versioning
Example:
6. Control Plane vs Data Plane¶
Data Plane¶
Handles continuous data flow:
read()poll()- event queue
Control Plane¶
Handles configuration and queries:
ioctl()
7. Locking Strategy¶
Different data requires different locks:
| Data Type | Lock |
|---|---|
| Event queue | spinlock |
| Runtime config | mutex |
| ISR path | spinlock only |
Example:
mutex_lock(&mydev->ctrl_lock);
mydev->debounce_ms = cfg.debounce_ms;
mutex_unlock(&mydev->ctrl_lock);
8. Snapshot Design¶
GET_STATUS returns a snapshot:
- Not fully atomic across all fields
- Acceptable trade-off
Example:
mutex_lock(&ctrl_lock);
copy runtime state
mutex_unlock();
spin_lock();
copy queue state
spin_unlock();
9. Error Handling¶
Common return values:
| Error | Meaning |
|---|---|
-ENOTTY |
unknown ioctl |
-EFAULT |
invalid user pointer |
-EINVAL |
invalid argument |
10. Debug Logging¶
Use:
dev_dbg()→ frequent operationsdev_info()→ important state change
Example:
Summary¶
Key principles:
- ioctl is command-based
- ABI must be stable
- separate control plane from data plane
- proper locking is critical
- snapshot is acceptable design trade-off