linux

Linux驱动案例分析:成功案例分享

小樊
51
2025-06-18 20:45:02
栏目: 智能运维

在Linux驱动开发中,成功案例分享对于理解驱动开发的实践和应用非常有帮助。以下是两个具体的成功案例:

1. I2S驱动案例分析

背景

I2S(Inter-IC Sound)是一种常见的音频接口标准,广泛应用于各种音频设备中。下面是一个基于Linux的I2S驱动案例分析。

案例描述

static const struct of_device_id rockchip_i2s_match[] = {
    { .compatible = "rockchip,rk3066-i2s", },
    { .compatible = "rockchip,rk3188-i2s", },
    { .compatible = "rockchip,rk3288-i2s", },
    { .compatible = "rockchip,rk3399-i2s", .data = &rk3399_i2s_pins },
};
MODULE_DEVICE_TABLE(of, rockchip_i2s_match);

static struct platform_driver rockchip_i2s_driver = {
    .probe = rockchip_i2s_probe,
    .remove = rockchip_i2s_remove,
    .driver = {
        .name = "rockchip_i2s",
        .of_match_table = of_match_ptr(rockchip_i2s_match),
        .pm = &rockchip_i2s_pm_ops,
    },
};
module_platform_driver(rockchip_i2s_driver);
static int rockchip_i2s_probe(struct platform_device *pdev) {
    struct device_node *node = pdev->dev.of_node;
    const struct of_device_id *of_id;
    struct rk_i2s_dev *i2s;
    struct snd_soc_dai_driver *soc_dai;
    struct resource *res;
    void __iomem *regs;
    int ret;
    int val;

    i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
    if (!i2s) {
        ret = -ENOMEM;
        goto err;
    }

    i2s->dev = &pdev->dev;

    ret = clk_prepare_enable(i2s->hclk);
    if (ret) {
        dev_err(&pdev->dev, "Failed to enable hclk: %d\n", ret);
        goto err;
    }

    i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk");
    if (IS_ERR(i2s->mclk)) {
        dev_err(&pdev->dev, "Failed to get mclk: %ld\n", PTR_ERR(i2s->mclk));
        goto err;
    }

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!res) {
        dev_err(&pdev->dev, "Failed to get resource: %d\n", ret);
        ret = -ENOMEM;
        goto err;
    }

    regs = devm_platform_get_and_ioremap_resource(pdev, 0, res);
    if (!regs) {
        dev_err(&pdev->dev, "Failed to map resource: %d\n", ret);
        ret = -ENOMEM;
        goto err;
    }

    i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &rockchip_i2s_regmap_config);
    if (IS_ERR(i2s->regmap)) {
        dev_err(&pdev->dev, "Failed to initialize regmap: %ld\n", PTR_ERR(i2s->regmap));
        ret = -ENOMEM;
        goto err;
    }

    i2s->playback_DMA_data.addr = res->start + I2S_TXDR;
    i2s->playback_DMA_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
    i2s->playback_DMA_data.maxburst = 4;
    i2s->capture_DMA_data.addr = res->start + I2S_RXDR;
    i2s->capture_DMA_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
    i2s->capture_DMA_data.maxburst = 4;

    soc_dai = devm_kmemdup(&pdev->dev, &rockchip_i2s_dai, sizeof(*soc_dai), GFP_KERNEL);
    if (!soc_dai) {
        dev_err(&pdev->dev, "Failed to allocate dai driver: %d\n", ret);
        ret = -ENOMEM;
        goto err;
    }

    ret = snd_soc_register_dai(soc_dai);
    if (ret) {
        dev_err(&pdev->dev, "Failed to register dai: %d\n", ret);
        goto err;
    }

    return 0;

err:
    return ret;
}

案例解析

  1. 设备匹配:通过of_device_id数组匹配具体的设备型号。
  2. 平台驱动结构:定义了驱动的探测和移除函数。
  3. 资源获取:获取I2S的时钟资源和寄存器资源。
  4. DMA配置:配置音频数据的DMA通道。
  5. 注册驱动:通过snd_soc_register_dai注册I2S驱动。

2. WSL2调试CDC设备案例

背景

CDC(Communication Device Class)设备在Windows下正常工作,但在Linux下无法正常工作。通过WSL2(Windows Subsystem for Linux 2)可以在Windows下进行Linux内核调试。

案例描述

  1. 启用调试信息
#undef DEBUG
#undef VERBOSE_DEBUG
#define DEBUG
#define VERBOSE_DEBUG
  1. 重新编译内核
make -j$(nproc) KCONFIG_CONFIG=.config && make modules_install -j$(nproc) && make install -j$(nproc)
  1. 复制内核到WSL
sudo cp vmlinux /mnt/d/

案例解析

  1. 启用调试信息:通过修改内核配置文件启用调试信息。
  2. 重新编译内核:重新编译内核并安装模块。
  3. 复制内核到WSL:将编译后的内核复制到WSL环境中,以便进行调试。

以上两个案例展示了Linux驱动开发在不同场景下的具体应用和解决方案。通过这些案例,可以更好地理解和掌握Linux驱动开发的实践技巧。

0
看了该问题的人还看了