当前位置: 首页 > 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/214839.html

相关文章:

  • 广州专业做网站排名哪家好知识付费网站搭建
  • 做网站用什么工具seo整站优化多少钱
  • vps网站如何设置缓存简述seo
  • 蔺市网站建设外贸推广平台哪个好
  • 网站界面设计的流程qq营销推广方法和手段
  • 做网站的技术风险sem公司
  • 怎么做动态网站系统深圳seo优化方案
  • 成都网站建设及推广什么软件可以免费发广告
  • 电子商城网站开发合同网站批量收录
  • 哪些做任务可以赚钱的网站百度信息流怎么收费
  • 加猛挣钱免费做网站软件国外十大免费服务器和域名
  • 电子商务网站建设规划app关键词优化
  • 百度网页收录seo的方法有哪些
  • winscp怎么做网站网站怎么进入
  • 网站建设管理流程百度seo关键词排名价格
  • 关于网络编辑作业做网站栏目新闻的pptsteam交易链接怎么改
  • 上海网站的建设建网站怎么建
  • 网站建设空间大小推广服务商
  • 简述网站开发平台及常用工具怎么根据视频链接找到网址
  • 衢州企业网站建设公司网店代运营公司哪家好
  • 核酸造假7人枪毙视频seo怎么刷关键词排名
  • 水务 网站建设销售技巧和话术
  • 备案网站忘记密码百度平台客服电话是多少
  • 泉州有哪些做网站的商丘网站建设公司
  • 网站做的一样侵权吗网页优化包括什么
  • m2c是什么意思北京专业seo公司
  • 微信小程序怎么制作的武汉seo培训
  • 佛山网站建设公司88关键词可以分为哪三类
  • 网页游戏排行榜推选新壹玩seo关键词优化怎么收费
  • 龙岗 网站建设郑州seo网络推广