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

四川省住房和城乡建设厅官网站网中山网站建设是什么

四川省住房和城乡建设厅官网站网,中山网站建设是什么,wordpress图片怎么居中,沧州网站开发在设备驱动模型中#xff0c;引入总线的概念可以对驱动代码和设备信息进行分离。但是驱动中总线的概念是软件层面的一种抽象#xff0c;与我们SOC中物理总线的概念并不严格相等。 物理总线#xff1a;芯片与各个功能外设之间传送信息的公共通信干线#xff0c;其中又包括数…在设备驱动模型中引入总线的概念可以对驱动代码和设备信息进行分离。但是驱动中总线的概念是软件层面的一种抽象与我们SOC中物理总线的概念并不严格相等。 物理总线芯片与各个功能外设之间传送信息的公共通信干线其中又包括数据总线、地址总线和控制总线以此来传输各种通信时序。驱动总线负责管理设备和驱动。制定设备和驱动的匹配规则一旦总线上注册了新的设备或者是新的驱动总线将尝试为他们进行配对。 一般对于I2C、SPI、USB这些常见类型的物理总线来说Linux内核会自动创建与之相应的驱动总线因此I2C设备、SPI设备、USB设备自然是注册挂载在相应的总线上。但是实际项目开发中还有很多结构简单的设备对他们进行控制并不需要特殊的时序。他们也就没有相应的物理总线比如led、蜂鸣器和按键等Linux内核将不会为他们创建相应的驱动总线。为了使这部分设备的驱动开发也能够遵循设备驱动模型Linux内核引入了一种虚拟的总线–平台总线platform_bus。 平台总线用于管理、挂载那些没有相应物理总线的设备这些设备被称为平台设备对应的设备驱动则被称为平台驱动。平台设备驱动的核心依然是Linux设备驱动模型平台设备使用platform_device结构体来进行表示其继承了设备驱动模型中的device结构体。而平台驱动使用platform_driver结构体来进行表示其则是继承了设备驱动模中的device_driver结构体。 平台设备 platform_device结构体 platform_device结构体(内核源码/include/linux/platform_device.h) struct platform_device {const char *name;int id;struct device dev;u32 num_resources;struct resource *resource;const struct platform_device_id *id_entry;/* 省略部分成员 */};name 设备名称总线进行匹配时会比较设备和驱动的名称是否一致id 指定设备的编号Linux支持同名的设备而同名设备之间则是通过该编号进行区分dev Linux设备模型中的device结构体linux内核大量使用了面向对象思想platform_device通过继承该结构体可复用它的相关代码方便内核管理平台设备num_resources 记录资源的个数当结构体成员resource存放的是数组时需要记录resource数组的个数内核提供了宏定义ARRAY_SIZE用于计算数组的个数resource 平台设备提供给驱动的资源如irqdma内存等等。该结构体会在接下来的内容进行讲解id_entry 平台总线提供的另一种匹配方式原理依然是通过比较字符串这部分内容会在平台总线小节中讲这里的id_entry用于保存匹配的结果 何为设备信息 平台设备的工作是为驱动程序提供设备信息设备信息包括硬件信息和软件信息两部分。 硬件信息驱动程序需要使用到什么寄存器占用哪些中断号、内存资源和IO口等。软件信息以太网卡设备中的MAC地址、I2C设备中的设备地址、SPI设备的片选信号线等等。 对于硬件信息使用结构体struct resource来保存设备所提供的资源比如设备使用的中断编号寄存器物理地址等结构体原型如下 resource结构体(内核源码/include/linux/ioport.h) /* * Resources are tree-like, allowing * nesting etc.. */struct resource {resource_size_t start;resource_size_t end;const char *name;unsigned long flags;/* 省略部分成员 */ };name 指定资源的名字可以设置为NULLstart、end 指定资源的起始地址以及结束地址flags 用于指定该资源的类型在Linux中资源包括I/O、Memory、Register、IRQ、DMA、Bus等多种类型最常见的有以下几种 资源宏定义描述IORESOURCE_IO用于IO地址空间对应于IO端口映射方式IORESOURCE_MEM用于外设的可直接寻址的地址空间IORESOURCE_IRQ用于指定该设备使用某个中断IORESOURCE_DMA用于指定使用的DMA通道 设备驱动程序的主要目的是操作设备的寄存器。不同架构的计算机提供不同的操作接口主要有IO端口映射和IO內存映射两种方式。 对应于IO端口映射方式只能通过专门的接口函数(如inb、outb)才能访问 采用IO内存映射的方式可以像访问内存一样去读写寄存器。在嵌入式中基本上没有IO地址空间所以通常使用IORESOURCE_MEM。 在资源的起始地址和结束地址中对于IORESOURCE_IO或者是IORESOURCE_MEM他们表示要使用的内存的起始位置以及结束位置 若是只用一个中断引脚或者是一个通道则它们的start和end成员值必须是相等的。 而对于软件信息这种特殊信息需要我们以私有数据的形式进行封装保存我们注意到platform_device结构体中 有个device结构体类型的成员dev。在前面章节我们提到过Linux设备模型使用device结构体来抽象物理设备 该结构体的成员platform_data可用于保存设备的私有数据。platform_data是void *类型的万能指针 无论你想要提供的是什么内容只需要把数据的地址赋值给platform_data即可 还是以GPIO引脚号为例示例代码如下 unsigned int pin 10;struct platform_device pdev {.dev {.platform_data pin;} }将保存了GPIO引脚号的变量pin地址赋值给platform_data指针在驱动程序中通过调用平台设备总线中的核心函数可以获取到我们需要的引脚号。 注册/注销平台设备 platform_device_register函数(内核源码/drivers/base/platform.c)int platform_device_register(struct platform_device *pdev)函数参数和返回值如下 参数 pdev: platform_device类型结构体指针 返回值 成功 0失败 负数 platform_device_unregister函数(内核源码/drivers/base/platform.c)void platform_device_unregister(struct platform_device *pdev)函数参数和返回值如下 参数 pdev: platform_device类型结构体指针 返回值 无 平台驱动 platform_driver结构体 platform_driver结构体(内核源码/include/platform_device.h)struct platform_driver {int (*probe)(struct platform_device *);int (*remove)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table;....... };probe 函数指针驱动开发人员需要在驱动程序中初始化该函数指针当总线为设备和驱动匹配上之后会回调执行该函数。我们一般通过该函数对设备进行一系列的初始化。remove 函数指针驱动开发人员需要在驱动程序中初始化该函数指针当我们移除某个平台设备时会回调执行该函数指针该函数实现的操作通常是probe函数实现操作的逆过程。driver Linux设备模型中用于抽象驱动的device_driver结构体platform_driver继承该结构体也就获取了设备模型驱动对象的特性id_table 表示该驱动能够兼容的设备类型。 platform_device_id结构体原型如下所示: id_table结构体(内核源码/include/linux/mod_devicetable.h)struct platform_device_id {char name[PLATFORM_NAME_SIZE];kernel_ulong_t driver_data;};name是数组用于指定驱动的名称总线进行匹配时会依据该结构体的name成员与platform_device中的变量name进行比较匹配driver_data则是用于来保存设备的配置。我们知道在同系列的设备中往往只是某些寄存器的配置不一样为了减少代码的冗余 尽量做到一个驱动可以匹配多个设备的目的 注册/注销平台驱动 platform_driver_register函数int platform_driver_register(struct platform_driver *drv);函数参数和返回值如下 参数 drv: platform_driver类型结构体指针 返回值 成功 0失败 负数 platform_driver_unregister函数(内核源码/drivers/base/platform.c)void platform_driver_unregister(struct platform_driver *drv);参数 drv: platform_driver类型结构体指针 返回值 无 平台驱动获取设备信息 platform_get_resource()函数通常会在驱动的probe函数中执行用于获取平台设备提供的资源结构体最终会返回一个struct resource类型的指针该函数原型如下 struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);参数 dev 指定要获取哪个平台设备的资源type 指定获取资源的类型如IORESOURCE_MEM、IORESOURCE_IO等num 指定要获取的资源编号。每个设备所需要资源的个数是不一定的为此内核对这些资源进行了编号对于不同的资源编号之间是相互独立的。 返回值 成功 struct resource结构体类型指针失败 NULL 假若资源类型为IORESOURCE_IRQ平台设备驱动还提供以下函数接口来获取中断引脚 int platform_get_irq(struct platform_device *pdev, unsigned int num)参数 pdev 指定要获取哪个平台设备的资源num 指定要获取的资源编号。 返回值 成功 可用的中断号失败 负数 对于存放在device结构体中成员platform_data的软件信息我们可以使用dev_get_platdata函数来获取函数原型如下所示 static inline void *dev_get_platdata(const struct device *dev) {return dev-platform_data; }参数 dev struct device结构体类型指针 返回值 device结构体中成员platform_data指针 平台总线 平台总线注册和匹配方式 在Linux的设备驱动模型中总线是最重要的一环。每当有新的设备或者新的驱动加入到总线时总线便会调用platform_match函数对新增的设备或驱动进行配对。内核中使用bus_type来抽象描述系统重的总线平台总线结构体原型如下 platform_bus_type结构体(内核源码/driver/base/platform.c)struct bus_type platform_bus_type {.name platform,.dev_groups platform_dev_groups,.match platform_match,.uevent platform_uevent,.pm platform_dev_pm_ops,};EXPORT_SYMBOL_GPL(platform_bus_type);内核用platform_bus_type来描述平台总线该总线在linux内核启动的时候自动进行注册。这里重点是platform总线的match函数指针该函数指针指向的函数将负责实现平台总线和平台设备的匹配过程。对于每个驱动总线 它都必须实例化该函数指针。 id_table匹配方式 在定义结构体platform_driver时我们需要提供一个id_table的数组该数组说明了当前的驱动能够支持的设备。当加载该驱动时总线的match函数发现id_table非空 则会比较id_table中的name成员和平台设备的name成员若相同则会返回匹配的条目。 示例 编译一个driver.ko和两个device.ko文件两个device都是杂项设备共用主设备号动态分配不同的次设备号共用一个驱动。 haptic_dev0.c/** Date: 2024-10-17 16:10:22* LastEditors: zdk* LastEditTime: 2024-10-18 10:50:21* FilePath: \kernel\drivers\haptics\haptic_dev0.c*/ /** Silicon Integrated Co., Ltd haptic sih688x haptic driver file** Copyright (c) 2021 heater daokuan.zhusi-in.com** This program is free software; you can redistribute it and/or modify it* under the terms of the GNU General Public License version 2 as published by* the Free Software Foundation*/#include linux/init.h //包含宏定义的头文件 #include linux/module.h //包含初始化加载模块的头文件 #include linux/fs.h #include linux/sysfs.h #include linux/platform_device.h//定义的资源 //寄存器地址 和 大小 static struct resource haptic_dev_res[] {[0] DEFINE_RES_MEM(0x01,1),[1] DEFINE_RES_MEM(0x02,1) };//定义私有数据 //整形数据表示状态 0,1,2等可自定义 static int status 0;static void haptic_dev_release(struct device* dev) {printk(%s\n,__func__); }static struct platform_device haptic_dev {.name haptic_dev0,.id 0,.num_resources ARRAY_SIZE(haptic_dev_res),.resource haptic_dev_res,.dev{.platform_data status,.release haptic_dev_release,}, };static int __init haptic_dev_init(void) {int ret 0;//内核层只能使用printk不能使用printfprintk(KERN_EMERG %s\n,__FUNCTION__); ret platform_device_register(haptic_dev);return ret; }static void __exit haptic_dev_exit(void) {platform_device_unregister(haptic_dev);printk(KERN_EMERG %s\n,__FUNCTION__); }module_init(haptic_dev_init);//模块入口 module_exit(haptic_dev_exit);//模块出口MODULE_AUTHOR(daokuan.zhugsi-in.com);//声明作者信息 MODULE_DESCRIPTION(Haptics Device V1.0.0); //对这个模块作一个简单的描述 MODULE_LICENSE(GPL v2);//声明开源许可证// GPL 是指明 这是GNU General Public License的任意版本// “GPL v2” 是指明 这仅声明为GPL的第二版本haptic_dev1.c/** Date: 2024-10-17 16:10:22* LastEditors: zdk* LastEditTime: 2024-10-18 10:50:28* FilePath: \kernel\drivers\haptics\haptic_dev1.c*/ /** Silicon Integrated Co., Ltd haptic sih688x haptic driver file** Copyright (c) 2021 heater daokuan.zhusi-in.com** This program is free software; you can redistribute it and/or modify it* under the terms of the GNU General Public License version 2 as published by* the Free Software Foundation*/#include linux/init.h //包含宏定义的头文件 #include linux/module.h //包含初始化加载模块的头文件 #include linux/fs.h #include linux/sysfs.h #include linux/platform_device.h//定义的资源 //寄存器地址 和 大小 static struct resource haptic_dev_res[] {[0] DEFINE_RES_MEM(0x03,1),[1] DEFINE_RES_MEM(0x04,1) };//定义私有数据 //整形数据表示状态 0,1,2等可自定义 static int status 1;static void haptic_dev_release(struct device* dev) {printk(%s\n,__func__); }static struct platform_device haptic_dev {.name haptic_dev1,.id 1,.num_resources ARRAY_SIZE(haptic_dev_res),.resource haptic_dev_res,.dev{.platform_data status,.release haptic_dev_release,}, };static int __init haptic_dev_init(void) {int ret 0;//内核层只能使用printk不能使用printfprintk(KERN_EMERG %s\n,__FUNCTION__); ret platform_device_register(haptic_dev);return ret; }static void __exit haptic_dev_exit(void) {platform_device_unregister(haptic_dev);printk(KERN_EMERG %s\n,__FUNCTION__); }module_init(haptic_dev_init);//模块入口 module_exit(haptic_dev_exit);//模块出口MODULE_AUTHOR(daokuan.zhugsi-in.com);//声明作者信息 MODULE_DESCRIPTION(Haptics Device V1.0.0); //对这个模块作一个简单的描述 MODULE_LICENSE(GPL v2);//声明开源许可证// GPL 是指明 这是GNU General Public License的任意版本// “GPL v2” 是指明 这仅声明为GPL的第二版本haptic_drv.c/** Date: 2024-10-17 16:08:08* LastEditors: zdk* LastEditTime: 2024-10-18 17:18:05* FilePath: \kernel\drivers\haptics\haptic_drv.c*/#include linux/init.h //包含宏定义的头文件 #include linux/module.h //包含初始化加载模块的头文件 #include linux/fs.h #include linux/sysfs.h #include linux/miscdevice.h #include linux/platform_device.h #include linux/mod_devicetable.h #include haptic_ioctl.h//打开设备 static int haptics_open(struct inode* inode,struct file * filp) { //驱动最好不使用全局变量,所以在probe函数中获取的资源,该如何在这里拿到呢???//使用字符设备的时候 可以使用container_of结合inode-i_cdev拿到//但是杂项设备该怎么办呢?printk(%s minor%d\n,__FUNCTION__, MINOR(inode-i_rdev));return 0; }//关闭设备 static int haptics_release(struct inode* inode ,struct file* filp) {printk(%s\n,__FUNCTION__);return 0; }//ioctl static long haptics_ioctl(struct file * filp, unsigned int cmd, unsigned long arg) {int ret 0;ioctl_protocol_t msg;//反解cmd中的字段int type _IOC_TYPE(cmd);int dir _IOC_DIR(cmd);int nr _IOC_NR(cmd);int size _IOC_SIZE(cmd);printk(dir%d size%d\n,dir,size);//检验cmd是否正确//1.校验cmd_typeif(DEVICE_TYPE ! type){printk(KERN_ERR cmd type error\n);ret -1;return ret;}if(HAPTICS_READ_REG cmd)//读寄存器{//校验nrif(HAPTICS_READ_REG_NR nr){ret copy_from_user(msg, (ioctl_protocol_t __user *)arg, sizeof(ioctl_protocol_t));printk(read_reg:%#02x\n,msg.reg_addr);msg.reg_value0xff;//这里模拟读寄存器的值//将读取到的值传给用户空间ret copy_to_user((ioctl_protocol_t __user *)arg, msg, sizeof(ioctl_protocol_t));}}else if(HAPTCIS_WRITE_REG cmd)//写寄存器{//校验nrif(HAPTICS_WRITE_REG_NR nr){ret copy_from_user(msg, (ioctl_protocol_t __user *)arg, sizeof(ioctl_protocol_t));printk(write_reg:%#02x%#02x\n,msg.reg_addr,msg.reg_value);//模拟写寄存器的值}}else//{printk(KERN_ERR unknown cmd\n);}return ret; }typedef struct {struct miscdevice miscdev;//定义一个杂项设备结构体struct resource* res;int status; }haptic_miscdev_t;static int haptic_drv_probe(struct platform_device *pdev) {int ret 0;int* statusNULL;struct resource* res0NULL;struct resource* res1NULL;haptic_miscdev_t *hap_miscdevNULL;struct file_operations *haptics_fopsNULL;res0 platform_get_resource(pdev,IORESOURCE_MEM,0);res1 platform_get_resource(pdev,IORESOURCE_MEM,1);printk(res0 start%d size%d\n,(int)res0-start,(int)(res0-end-res0-start1));printk(res1 start%d size%d\n,(int)res1-start,(int)(res1-end-res1-start1));status dev_get_platdata(pdev-dev);printk(status%d\n,*status);haptics_fops devm_kzalloc(pdev-dev,sizeof(struct file_operations), GFP_KERNEL);haptics_fops-open haptics_open;haptics_fops-release haptics_release;haptics_fops-unlocked_ioctl haptics_ioctl;hap_miscdev devm_kzalloc(pdev-dev,sizeof(haptic_miscdev_t), GFP_KERNEL);hap_miscdev-res res0;hap_miscdev-status *status;hap_miscdev-miscdev.name pdev-name;hap_miscdev-miscdev.fops haptics_fops;hap_miscdev-miscdev.minor MISC_DYNAMIC_MINOR,ret misc_register(hap_miscdev-miscdev);/* save as drvdata *///platform_set_drvdata函数将设备数据信息存入在平台驱动结构体中pdev-dev-driver_data中platform_set_drvdata(pdev, hap_miscdev);return ret; }static int haptic_drv_remove(struct platform_device *pdev) {int ret 0;haptic_miscdev_t *hap_miscdev platform_get_drvdata(pdev);misc_deregister(hap_miscdev-miscdev);return ret; }static struct platform_device_id haptic_dev_id[] {{.name haptic_dev0},{.name haptic_dev1},{} };static struct platform_driver haptic_drv {.driver.name haptics_drv,.probe haptic_drv_probe,.remove haptic_drv_remove,.id_table haptic_dev_id, };static int __init haptic_drv_init(void) {int ret 0;//内核层只能使用printk不能使用printfprintk(KERN_EMERG %s\n,__FUNCTION__); ret platform_driver_register(haptic_drv);return ret; }static void __exit haptic_drv_exit(void) {platform_driver_unregister(haptic_drv);printk(KERN_EMERG %s\n,__FUNCTION__); }module_init(haptic_drv_init);//模块入口 module_exit(haptic_drv_exit);//模块出口MODULE_AUTHOR(daokuan.zhugsi-in.com);//声明作者信息 MODULE_DESCRIPTION(Haptics Device V1.0.0); //对这个模块作一个简单的描述 MODULE_LICENSE(GPL v2);//声明开源许可证// GPL 是指明 这是GNU General Public License的任意版本// “GPL v2” 是指明 这仅声明为GPL的第二版本haptic_ioctl.h#ifndef __HAPTCIS_IOCTL_H__ #define __HAPTCIS_IOCTL_H__/** Date: 2024-10-12 15:53:37* LastEditors: zdk* LastEditTime: 2024-10-18 17:22:18* FilePath: \kernel\drivers\haptics\haptic_ioctl.h*/#include linux/ioctl.h // #include sys/ioctl.h // 用户空间/*这里使用ioctl定义两个协议读寄存器和写寄存器 *用户空间和内核空间共用的头文件包含ioctl命令及相关宏定义可以理解为一份“协议”文件 */ //cmd中的type #define DEVICE_TYPE H #define HAPTICS_READ_REG_NR (0) #define HAPTICS_WRITE_REG_NR (1) #define HAPTICS_READ_REG _IO(DEVICE_TYPE,HAPTICS_READ_REG_NR) #define HAPTCIS_WRITE_REG _IO(DEVICE_TYPE,HAPTICS_WRITE_REG_NR)typedef struct {uint8_t reg_addr;uint8_t reg_value; }ioctl_protocol_t;#endif再来看看sys目录下 总结 驱动代码中最好不要使用全局变量因为驱动一般是支持多设备的如果有全局变量会有冲突。 字符设备驱动中在open函数中可以使用container_of拿到设备信息但是杂项设备驱动中怎么拿到设备信息暂时未知。
http://www.dnsts.com.cn/news/156611.html

相关文章:

  • 网站为什么要icp备案在线解压rar网站
  • 网站排名优化培训电话微梦网站建设
  • 官方网站建设需要做哪些东西wordpress 评分
  • 南山电商网站建设做盗版影视网站
  • 黄岛网站建设哪家好网站开发费分摊多少年
  • 怎么做自己的网站卖东西网站计数器代码js
  • 潍坊网站制作苏宁易购如何进行网站的建设和维护
  • 优秀企业网站建设价格网络市场营销
  • 快速建站全流程详细指导手册赣州市网络科技有限公司
  • 泉州关键词网站排名凡科网站登录入
  • 如何快速做单页面网站2016优秀网站设计
  • 合肥网站建设zgkr怎么把网站设置为信任网站
  • 二次元WordPress关键词优化营销
  • 网站分享对联广告专业制作网站公司吗
  • 哪个网站可以做投资回测深圳装修公司排名100强
  • 池州网站制作新乡做网站费用
  • 电商网站平台建设方案wordpress标签链接分类目录
  • 商务网站建设的基本步骤公司做网站需要提供什么条件
  • dw手机网站怎么做外贸网站推广服务
  • 百度官网网站wordpress页面内
  • 网站按钮确定后图片怎么做php商城网站开发实例视频
  • 局门户网站的建设方案网站建设公司简介范文
  • 网站友链更多标签的适用场景
  • 广州企业网站seowordpress自定义登录
  • 漫画网站怎么做优秀企业宣传ppt
  • 如何在头条上做网站推广济南全网推广设计开发
  • 用dw做的网站生成链接吗网站建设策划书有哪些内容
  • 网站建设硬件投入表网站域名怎么解释
  • 苏州哪里做网站好赣州百度
  • 可以做猫头像的网站汶上网站开发