当前位置: 首页 > wzjs >正文

廊坊哪家公司做网站企业官方网站推广

廊坊哪家公司做网站,企业官方网站推广,怒江州城乡建设局网站,武汉设计工程学院宿舍Linux SPI核心驱动 spidev.c 深度解析 spidev.c 是Linux内核中SPI设备的通用用户空间接口驱动,它允许用户空间程序通过 /dev/spidevX.Y 文件直接访问SPI设备。以下是其核心工作流程的详细解析: 一、驱动注册与初始化流程 1. 模块初始化与注册 static…

Linux SPI核心驱动 spidev.c 深度解析

spidev.c 是Linux内核中SPI设备的通用用户空间接口驱动,它允许用户空间程序通过 /dev/spidevX.Y 文件直接访问SPI设备。以下是其核心工作流程的详细解析:

一、驱动注册与初始化流程

1. 模块初始化与注册
static LIST_HEAD(spidev_list);        /* 全局SPI设备链表头 */
static DEFINE_SPINLOCK(spidev_lock);  /* 保护spidev_list的锁 */static int __init spidev_init(void)
{int status;/* 分配并初始化字符设备区域 */status = alloc_chrdev_region(&spidev_major, 0,SPI_MAX_DEVICES, "spidev");if (status < 0)return status;/* 创建SPI设备类 */spidev_class = class_create(THIS_MODULE, "spidev");if (IS_ERR(spidev_class)) {status = PTR_ERR(spidev_class);goto fail_class;}/* 注册SPI驱动 */status = spi_register_driver(&spidev_spi_driver);if (status < 0)goto fail_driver;return 0;fail_driver:class_destroy(spidev_class);
fail_class:unregister_chrdev_region(spidev_major, SPI_MAX_DEVICES);return status;
}

关键数据结构:

  • spidev_list:全局双向链表,用于存储所有注册的SPI设备
  • spidev_lock:自旋锁,保护对链表的并发访问

二、设备发现与结构体分配流程

1. 设备树触发匹配
  1. 内核解析设备树中的SPI设备节点(如 /spi@12340000/sensor@0
  2. 创建 spi_device 结构体并注册到SPI总线
  3. SPI总线调用 spidev_spi_driverprobe 函数进行匹配
2. spidev_probe 函数执行流程
static int spidev_probe(struct spi_device *spi)
{struct spidev_data *spidev;int status;/* 分配并初始化spidev_data结构体 */spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);if (!spidev)return -ENOMEM;/* 初始化设备信息 */spidev->spi = spi;INIT_LIST_HEAD(&spidev->list);  /* 初始化链表节点 */get_device(&spi->dev);/* 分配次设备号并加入全局链表 */spin_lock(&spidev_lock);status = -EBUSY;for (i = 0; i < SPI_MAX_DEVICES; i++) {if (!spidev_table[i])break;}if (i < SPI_MAX_DEVICES) {spidev->devt = MKDEV(MAJOR(spidev_major), i);spidev_table[i] = spidev;  /* 加入全局表 */list_add_tail(&spidev->list, &spidev_list);  /* 加入设备链表 */status = 0;}spin_unlock(&spidev_lock);if (status < 0)goto err;/* 创建设备文件 (/dev/spidevX.Y) */spidev->device = device_create(spidev_class, &spi->dev,spidev->devt, spidev,"spidev%d.%d", spi->master->bus_num,spi->chip_select);if (IS_ERR(spidev->device)) {status = PTR_ERR(spidev->device);goto err;}return 0;err:/* 错误处理和资源释放 */spin_lock(&spidev_lock);if (spidev->devt)spidev_table[MINOR(spidev->devt)] = NULL;list_del(&spidev->list);  /* 从链表中移除 */spin_unlock(&spidev_lock);kfree(spidev);return status;
}

关键步骤:

  1. 分配私有数据:创建 spidev_data 结构体存储设备信息
  2. 初始化链表节点:通过 INIT_LIST_HEAD 初始化 spidev->list
  3. 加入全局链表:使用 list_add_tail 将设备添加到 spidev_list 尾部
  4. 加入全局数组:同时将设备存入 spidev_table 数组(双重索引)

三、核心数据结构

1. 设备私有数据结构
struct spidev_data {struct spi_device   *spi;       /* 关联的SPI设备 */dev_t               devt;       /* 设备号 */struct device       *device;    /* 设备实例 */spinlock_t          spi_lock;   /* 保护传输参数的锁 */u32                 max_speed_hz; /* 最大传输速率 */u8                  mode;       /* SPI模式 */u8                  bits_per_word; /* 位宽 */struct mutex        buf_lock;   /* 保护缓冲区的锁 */unsigned            use_count;  /* 引用计数 */struct list_head    list;       /* 链表节点,用于加入spidev_list */
};
2. 全局状态
static LIST_HEAD(spidev_list);        /* 全局SPI设备链表 */
static struct spidev_data *spidev_table[SPI_MAX_DEVICES]; /* 全局设备数组 */
static dev_t spidev_major;            /* 主设备号 */
static struct class *spidev_class;    /* 设备类 */
  • 双重索引机制
    • spidev_list:双向链表,便于遍历所有设备
    • spidev_table:数组,通过次设备号快速查找设备

四、打开SPI设备的执行流程

1. 用户空间调用 open("/dev/spidevX.Y")

触发内核调用 spidev_fops 中的 open 函数:

static int spidev_open(struct inode *inode, struct file *filp)
{struct spidev_data *spidev;int minor = iminor(inode);int status = -ENODEV;/* 从全局表中查找设备 */spin_lock(&spidev_lock);spidev = spidev_table[minor];if (!spidev)goto out;/* 获取设备引用计数 */get_device(&spidev->spi->dev);filp->private_data = spidev;/* 初始化传输设置(默认值) */spin_lock(&spidev->spi_lock);spidev->mode = spidev->spi->mode;spidev->bits_per_word = spidev->spi->bits_per_word;spidev->max_speed_hz = spidev->spi->max_speed_hz;spin_unlock(&spidev->spi_lock);status = 0;
out:spin_unlock(&spidev_lock);return status;
}

关键步骤:

  1. 获取次设备号:从 inode 中提取次设备号
  2. 查找设备数据:通过 spidev_table 数组快速定位设备
  3. 设置私有数据:将 spidev_data 存入 file->private_data
  4. 初始化传输参数:从 spi_device 复制默认传输参数

五、设备移除流程

当SPI设备被移除时(如热插拔或驱动卸载),执行以下流程:

static void spidev_remove(struct spi_device *spi)
{struct spidev_data *spidev;int minor;/* 查找对应的spidev_data */spin_lock(&spidev_lock);list_for_each_entry(spidev, &spidev_list, list) {if (spidev->spi == spi)break;}if (list_entry_is_head(&spidev->list, &spidev_list, list)) {spin_unlock(&spidev_lock);return;}minor = MINOR(spidev->devt);/* 从链表和数组中移除 */list_del(&spidev->list);spidev_table[minor] = NULL;spin_unlock(&spidev_lock);/* 销毁设备文件 */device_destroy(spidev_class, spidev->devt);/* 释放资源 */put_device(&spi->dev);kfree(spidev);
}

关键步骤:

  1. 遍历链表查找设备:使用 list_for_each_entry 遍历 spidev_list
  2. 从链表移除:使用 list_del 将设备从链表中删除
  3. 从数组清除:将 spidev_table 对应位置置为NULL
  4. 销毁设备文件:调用 device_destroy 删除 /dev/spidevX.Y

六、总结:数据流与调用链

1. 驱动加载与设备注册
spidev_init()→ alloc_chrdev_region()        // 分配字符设备区域→ class_create()               // 创建设备类→ spi_register_driver()        // 注册SPI驱动→ spidev_probe()             // 设备匹配成功后调用→ kzalloc(spidev_data)     // 分配设备私有数据→ INIT_LIST_HEAD()         // 初始化链表节点→ 从spidev_table分配次设备号→ list_add_tail()          // 加入全局链表spidev_list→ spidev_table[i] = spidev // 加入全局数组→ device_create()          // 创建/dev/spidevX.Y文件
2. 打开设备流程
用户空间: open("/dev/spidevX.Y")→ 内核: spidev_open()→ iminor(inode)              // 获取次设备号→ spidev_table[minor]        // 从全局数组查找设备→ get_device()               // 增加设备引用计数→ filp->private_data = spidev // 设置私有数据→ 复制spi_device参数到spidev_data
3. 设备移除流程
spidev_remove()→ list_for_each_entry()        // 遍历spidev_list查找设备→ list_del()                   // 从链表中移除→ spidev_table[minor] = NULL   // 从数组中清除→ device_destroy()             // 销毁设备文件→ kfree(spidev)                // 释放内存

七、调试与验证方法

  1. 查看设备链表

    // 内核调试代码示例
    static void debug_spidev_list(void)
    {struct spidev_data *spidev;printk(KERN_INFO "SPI设备链表:\n");list_for_each_entry(spidev, &spidev_list, list) {printk(KERN_INFO "  设备: /dev/spidev%d.%d, 模式: 0x%x\n",MAJOR(spidev->devt), MINOR(spidev->devt),spidev->mode);}
    }
    
  2. 使用 lsof 查看打开的设备

    lsof | grep spidev
    
  3. 查看sysfs信息

    ls /sys/bus/spi/drivers/spidev/
    cat /sys/bus/spi/drivers/spidev/*/modalias
    

spidev.c 通过双重索引机制(链表+数组)实现了SPI设备的高效管理:

  • 链表:便于遍历所有设备,适用于批量操作和设备移除
  • 数组:通过次设备号快速定位,适用于文件操作(如open)
  • 自旋锁:保护共享资源,确保并发安全

理解这些数据结构和流程对于开发SPI驱动和应用程序至关重要。

http://www.dtcms.com/wzjs/189685.html

相关文章:

  • 旅游网站国内外研究现状湖南网站设计外包服务
  • 长沙有哪些做的好一点的网站长沙seo步骤
  • 成都网站开发收费app推广拉新平台
  • 网站建设亿码酷专注windows优化大师是什么
  • 江西工厂网站建设免费永久个人域名注册
  • wordpress 动态效果湖南靠谱的关键词优化
  • 建设电子商务网站总体设计阶段亚马逊seo什么意思
  • 网站同步更新到新浪微博seo的优点和缺点
  • 公司网站建设山东谷歌seo软件
  • 阐述电子商务网站的建设要求郑州网站建设价格
  • 常德seo公司排名优化推广
  • 云服务器做淘客网站如何免费制作自己的网站
  • 深圳网站设计制作网络营销与直播电商是干什么的
  • dedecms 营销网站模板杭州百度推广代理商
  • 做网站架构seo全网推广
  • 网站排名优化平台怎么发外链
  • wordpress更换主题影响武汉百度网站优化公司
  • 像淘宝类别网站怎么做厦门网站建设公司
  • 做网站一个月30ip如何注册网站
  • 手机网站开发前台架构游戏推广员是诈骗吗
  • 免费签名设计软件南京百度关键字优化价格
  • 网站定制设计网页价格多少钱app拉新推广平台有哪些
  • 个性手绘个人网站模板下载小红书seo关键词优化多少钱
  • 做京东网站需要哪些手续费免费卖货平台
  • 浮梁网站建设营销推广是什么
  • 门户网站的建设公司长沙网
  • 网站开发整合编辑器娃哈哈软文推广
  • cms优秀网站设计案例seo云优化方法
  • 成都 网站设计新网站怎么做优化
  • 有谁认识做微网站的少儿编程