mcpField
D
device-drivers

device-drivers

github.com/mohitmishra786开发269370 次安装18 周前更新
代码仓库

关于 device-drivers

面向开发 Linux 内核设备驱动的 Agent 技能,介绍常见驱动模型与硬件接口。内容涵盖字符设备、中断、DMA、寄存器映射、电源管理和 udev。

主要功能

  1. 01Platform、I2C 和 SPI 驱动模型
  2. 02字符设备生命周期
  3. 03硬中断与线程化 IRQ
  4. 04DMA 映射与同步
  5. 05regmap 与运行时电源管理
  6. 06设备节点的 udev 规则

适用场景

  1. 01为内存映射硬件编写驱动
  2. 02实现字符设备接口
  3. 03处理设备中断或 DMA
  4. 04配置用户空间对设备节点的访问

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill device-drivers

安装后在 Claude Code 中输入/device-drivers确认已加载。

详细介绍

设备驱动

用途

指导 Agent 进行 Linux 内核设备驱动开发:驱动模型(platform_driver、i2c_driver、spi_driver)、字符设备生命周期、中断处理(包括线程化中断)、DMA engine API、用于寄存器抽象的 regmap、运行时电源管理,以及用于用户空间设备节点的 udev 规则。

适用场景

  • 为内存映射硬件编写平台驱动
  • 实现支持 read/write/ioctl 的字符设备
  • 处理中断(硬中断与线程化中断)
  • 设置 DMA 一致性映射或流式映射
  • 使用 regmap 抽象寄存器访问
  • 配置 udev 规则以设置 /dev 节点权限

工作流

1. 驱动模型概述
Device tree / ACPI → bus (platform, i2c, spi, pci)
    → struct device → struct device_driver
        → probe() / remove()
// platform_driver.c — minimal platform driver
#include <linux/module.h>
#include <linux/platform_device.h>

static int my_probe(struct platform_device *pdev)
{
    struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    void __iomem *base = devm_ioremap_resource(&pdev->dev, res);
    if (IS_ERR(base))
        return PTR_ERR(base);
    dev_info(&pdev->dev, "probed at %pa\n", &res->start);
    return 0;
}

static void my_remove(struct platform_device *pdev)
{
    dev_info(&pdev->dev, "removed\n");
}

static struct platform_driver my_driver = {
    .probe  = my_probe,
    .remove = my_remove,
    .driver = { .name = "my-device", .owner = THIS_MODULE },
};

module_platform_driver(my_driver);
MODULE_LICENSE("GPL");
2. 字符设备生命周期
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "mydev"
#define MINOR_BASE  0
#define MINOR_COUNT 1

static dev_t dev_num;
static struct cdev my_cdev;
static struct class *dev_class;

static ssize_t my_read(struct file *filp, char __user *buf,
                       size_t count, loff_t *ppos)
{
    char kbuf[64] = "hello from kernel\n";
    size_t len = strlen(kbuf);
    if (*ppos >= len)
        return 0;
    if (count > len - *ppos)
        count = len - *ppos;
    if (copy_to_user(buf, kbuf + *ppos, count))
        return -EFAULT;
    *ppos += count;
    return count;
}

static const struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .read  = my_read,
};

static int __init mydev_init(void)
{
    int ret;
    ret = alloc_chrdev_region(&dev_num, MINOR_BASE, MINOR_COUNT, DEVICE_NAME);
    if (ret)
        return ret;

    cdev_init(&my_cdev, &my_fops);
    my_cdev.owner = THIS_MODULE;
    ret = cdev_add(&my_cdev, dev_num, MINOR_COUNT);
    if (ret)
        goto err_cdev;

    dev_class = class_create(DEVICE_NAME);
    device_create(dev_class, NULL, dev_num, NULL, DEVICE_NAME);
    return 0;

err_cdev:
    unregister_chrdev_region(dev_num, MINOR_COUNT);
    return ret;
}
# After loading module
ls -l /dev/mydev
cat /dev/mydev
3. 中断处理
#include <linux/interrupt.h>

static irqreturn_t my_hardirq(int irq, void *dev_id)
{
    // Minimal work: acknowledge, schedule bottom half
    return IRQ_WAKE_THREAD;
}

static irqreturn_t my_threaded(int irq, void *dev_id)
{
    // Process data — can sleep
    process_ring_buffer();
    return IRQ_HANDLED;
}

static int request_device_irq(struct device *dev, int irq)
{
    return devm_request_threaded_irq(dev, irq, my_hardirq, my_threaded,
                                     IRQF_ONESHOT, "mydev", dev);
}
模式适用场景
仅硬中断微秒级工作,无阻塞操作
线程化中断I2C/SPI 读取、调度、互斥锁
IRQF_ONESHOT电平触发;线程化处理程序返回前屏蔽中断
4. DMA engine API
#include <linux/dma-mapping.h>

// Coherent (consistent) mapping — CPU and device see same memory
void *cpu_addr;
dma_addr_t dma_handle;
cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, GFP_KERNEL);

// Streaming (single) mapping for already-allocated buffers
dma_addr_t dma = dma_map_single(dev, kernel_buf, size, DMA_TO_DEVICE);
dma_sync_single_for_device(dev, dma, size, DMA_TO_DEVICE);
// ... device reads ...
dma_unmap_single(dev, dma, size, DMA_TO_DEVICE);
# Debug DMA mappings
cat /sys/kernel/debug/dma_buf/bufinfo 2>/dev/null
5. regmap 抽象
#include <linux/regmap.h>

static const struct regmap_config my_regmap_config = {
    .reg_bits   = 8,
    .val_bits   = 8,
    .max_register = 0xFF,
};

// I2C regmap (typical for sensors)
static struct regmap *regmap;

regmap_write(regmap, 0x01, 0x80);  // set config register
regmap_read(regmap, 0x02, &val);   // read status
regmap_update_bits(regmap, 0x03, MASK, VALUE);

regmap 负责锁定、缓存和批量访问——新驱动中优先使用它,而不是直接使用 i2c_smbus_*。

6. 电源管理
#include <linux/pm_runtime.h>

static int my_runtime_suspend(struct device *dev)
{
    // Gate clocks, put hardware in low-power state
    return 0;
}

static int my_runtime_resume(struct device *dev)
{
    // Restore registers, enable clocks
    return 0;
}

static const struct dev_pm_ops my_pm_ops = {
    .runtime_suspend = my_runtime_suspend,
    .runtime_resume  = my_runtime_resume,
};

// In probe:
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);  // ensure powered on
7. udev 规则
# /etc/udev/rules.d/99-mydev.rules
KERNEL=="mydev", MODE="0666", GROUP="plugdev"
SUBSYSTEM=="i2c-dev", KERNEL=="i2c-1", GROUP="i2c", MODE="0660"
sudo udevadm control --reload-rules
sudo udevadm trigger
udevadm info -a -n /dev/mydev
8. I2C 和 SPI 驱动桩
// i2c_driver
static const struct i2c_device_id my_i2c_id[] = {
    { "sensor-chip", 0 },
    { }
};
MODULE_DEVICE_TABLE(i2c, my_i2c_id);

static struct i2c_driver my_i2c_driver = {
    .driver = { .name = "sensor-chip" },
    .probe  = my_i2c_probe,
    .remove = my_i2c_remove,
    .id_table = my_i2c_id,
};
module_i2c_driver(my_i2c_driver);

常见问题

症状原因修复方法
probe failed with -EBUSY资源冲突或重复 probe检查设备树 status;确认 devm_* 已清理
中断风暴处理程序中缺少确认操作在硬中断处理中确认中断;使用 IRQF_ONESHOT
DMA 一致性错误同步方向错误在边界处调用 dma_sync_single_for_cpu/device
缺少 /dev/nodeclass_create/device_create 失败检查 dmesg;确认 cdev_add 的返回值
copy_to_user 故障用户空间指针无效使用 access_ok 验证
运行时 PM 挂起缺少 pm_runtime_put平衡 get/put;使用 devm_pm_runtime_enable

相关技能

  • skills/kernel/kernel-internals — 驱动依赖的 VFS、内存分配器
  • skills/low-level-programming/linux-kernel-modules — Kbuild、模块加载、签名
  • skills/kernel/kernel-debugging — 使用 kgdb、ftrace 排查驱动问题
  • skills/embedded/zephyr — 嵌入式 RTOS 驱动模型对比
  • skills/observability/ebpf — 无需修改内核即可跟踪驱动事件
  • skills/kernel/kernel-testing — 驱动逻辑的 KUnit 测试

评论

支持 Markdown