网站建设运营方案 团队免费建站的站点网站

pingmian/2026/1/22 2:32:27/文章来源:
网站建设运营方案 团队,免费建站的站点网站,wordpress伪静态文件,河南建设信息网首页以下内容源于朱有鹏嵌入式课程的学习与整理#xff0c;如有侵权请告知删除。 一、注册字符设备驱动的老接口 在《字符设备驱动基础》里#xff0c;注册字符设备驱动使用的函数是register_chrdev()函数。 该函数的介绍#xff0c;见博客字符设备驱动基础3——使用register_ch…以下内容源于朱有鹏嵌入式课程的学习与整理如有侵权请告知删除。 一、注册字符设备驱动的老接口 在《字符设备驱动基础》里注册字符设备驱动使用的函数是register_chrdev()函数。 该函数的介绍见博客字符设备驱动基础3——使用register_chrdev()函数注册字符设备。 值得一提的是该函数同时完成设备号的分配以及驱动的注册。 二、注册字符设备驱动的新接口 1、概述 1注册设备驱动的新方法 注册设备驱动的新方法将以前的register_chrdev()函数完成的工作拆分为两个步骤。 主步骤一注册设备号 主要涉及register_chrdev_region()函数 或 alloc_chrdev_region()函数。 这两个函数的功能都是分配设备号根据情况选其一即可。 register_chrdev_region()函数其传参表示想索要某个设备号。 alloc_chrdev_region()函数是让内核自动分配设备号。 主步骤二注册设备驱动 主要涉及cdev_add()函数。 2其他涉及的函数 cdev_init函数初始化主要将cdev和fops关联起来。 cdev_alloc函数分配空间 cdev_del函数注销设备驱动 unregister_chrdev_region注销设备号 3涉及的新结构体 struct cdev结构体。 4注册、注销字符设备驱动的流程 注册字符设备驱动的流程 先使用register_chrdev_region()函数申请设备号然后使用cdev_alloc函数来给struct cdev结构体分配空间接着使用cdev_init函数来初始化最后使用cdev_add()函数注册设备驱动。 注销字符设备驱动的流程 先使用cdev_del()函数注销设备驱动再使用unregister_chrdev_region()函数注销设备号。 2、新接口的介绍 1struct cdev结构体 该结构体定义在文件\include\linux\cdev.h文件中内容如下 struct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops; //文件操作函数集struct list_head list;dev_t dev; //设备号unsigned int count; }; 其中dev表示设备号含主次设备号它属于dev_t类型其实就是init类型。 设备号由主设备号和次设备号组成在\include\linux\kdev_t.h文件中有这样的宏定义 #define MAJOR(dev) ((dev)8) //从设备号中提取主设备号 #define MINOR(dev) ((dev) 0xff) //从设备号中提取次设备号 #define MKDEV(ma,mi) ((ma)8 | (mi)) //由主次设备号得到设备号 2register_chrdev_region()函数 此函数定义在/fs/char_dev.c文件中用于向内核注册即申请一组字符设备的设备编号这就是函数名字带有“region”区域、范围的原因。 这一组字符设备的主设备号相同而次设备号不同所以使用参数提供这组字符设备的统一的名字name、这组字符设备的数量即次设备号的数目count、这组字符设备的设备编号的起始编号from。 函数的内容如下 /*** register_chrdev_region() - register a range of device numbers* from: the first in the desired range of device numbers; must include* the major number.* count: the number of consecutive device numbers required* name: the name of the device or driver.** Return value is zero on success, a negative error code on failure.*/ int register_chrdev_region(dev_t from, unsigned count, const char *name) {struct char_device_struct *cd;dev_t to from count;dev_t n, next;for (n from; n to; n next) {next MKDEV(MAJOR(n)1, 0);if (next to)next to;cd __register_chrdev_region(MAJOR(n), MINOR(n),next - n, name);if (IS_ERR(cd))goto fail;}return 0; fail:to n;for (n from; n to; n next) {next MKDEV(MAJOR(n)1, 0);kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));}return PTR_ERR(cd); } 参数含义 1from 要分配的设备编号范围的初始值初始所以才叫from次设备号常设为0。 2count 连续编号范围或者说次设备的数目。 3name 设备名称 (通过/proc/devices可以查看到)。 假如主设备号是 200次设备号有0、1、2、3则 from 为MKDEV200,0MKDEV用来合成设备号0表示起始次设备号count为4表示有四个次设备号。 结构体struct char_device_struct的定义 static struct char_device_struct {struct char_device_struct *next;unsigned int major; //主设备的编号unsigned int baseminor; //次设备的起始编号int minorct; //次设备的数目char name[64]; //设备或者说驱动的名字struct cdev *cdev; //指向 字符设备驱动程序描述符 的指针 } *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; //#define CHRDEV_MAJOR_HASH_SIZE 255 由该结构体的定义可知内核中一共有255个主设备号。同一主设备号下的不同设备它们的次设备号是按起始次设备号递增排序的。这些同主设备号而不同次设备号的设备统一用一个struct char_device_struct结构体来描述。 总结使用register_chrdev_region()函数申请设备号时要事先明确申请哪个主次设备号这要通过cat /proc/devices来查看哪些主设备号没有被使用。有没有自动分配主次设备号的函数呢有的那就是下面的alloc_chrdev_region函数。 3alloc_chrdev_region()函数 此函数位于/fs/char_dev.c文件中用于让内核自动分配设备号。 函数的内容如下 /*** alloc_chrdev_region() - register a range of char device numbers* dev: output parameter for first assigned number* baseminor: first of the requested range of minor numbers* count: the number of minor numbers required* name: the name of the associated device or driver** Allocates a range of char device numbers. The major number will be* chosen dynamically, and returned (along with the first minor number)* in dev. Returns zero or a negative error code.*/ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name) {struct char_device_struct *cd;cd __register_chrdev_region(0, baseminor, count, name);if (IS_ERR(cd))return PTR_ERR(cd);*dev MKDEV(cd-major, cd-baseminor);return 0; } 如果设备号成功分配则把分配的设备号放入第一个参数dev中它是输出型参数。 4cdev_init()函数               此函数位于/fs/char_dev.c文件中函数的内容如下 /*** cdev_init() - initialize a cdev structure* cdev: the structure to initialize* fops: the file_operations for this device** Initializes cdev, remembering fops, making it ready to add to the* system with cdev_add().*/ void cdev_init(struct cdev *cdev, const struct file_operations *fops) {memset(cdev, 0, sizeof *cdev);INIT_LIST_HEAD(cdev-list);kobject_init(cdev-kobj, ktype_cdev_default);cdev-ops fops; } 函数主要作用是将cdev设备的体现与fops驱动的体现关联起来即把文件操作结构体指针赋值给cdev的ops。 可以不使用此函数直接用下面的代码。 //cdev_init(pcdev, test_fops);pcdev-owner THIS_MODULE; pcdev-ops test_fops; 5cdev_add()函数 此函数位于/fs/char_dev.c文件中内容如下 /*** cdev_add() - add a char device to the system* p: the cdev structure for the device* dev: the first device number for which this device is responsible* count: the number of consecutive minor numbers corresponding to this* device** cdev_add() adds the device represented by p to the system, making it* live immediately. A negative error code is returned on failure.*/ int cdev_add(struct cdev *p, dev_t dev, unsigned count) {p-dev dev;p-count count;return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); } 这个函数的作用是注册设备驱动。 这个函数主要是填充struct cdev结构体变量的成员dev和count。 注意前面在cdev_init函数中已经填充了struct cdev结构体变量的成员ops。 6cdev_alloc()函数 此函数位于/fs/char_dev.c文件中用于申请存放struct cdev结构体变量的空间。 此函数的内容如下 /*** cdev_alloc() - allocate a cdev structure** Allocates and returns a cdev structure, or NULL on failure.*/ struct cdev *cdev_alloc(void) {struct cdev *p kzalloc(sizeof(struct cdev), GFP_KERNEL);if (p) {INIT_LIST_HEAD(p-list);kobject_init(p-kobj, ktype_cdev_dynamic);}return p; } 其实也可以直接定义一个struct cdev结构体变量不过这个变量分配在数据段整个程序运行期间都存在不够灵活。 static struct cdev test_cdev; 而采用cdev_alloc()函数来申请存放struct cdev结构体变量的空间这个空间是在堆上的。我们可以在数据段上定义一个struct cdev结构体指针用来指向cdev_alloc()函数申请的空间这个指针只占4个字节。 //static struct cdev test_cdev; //这个变量分配在数据段整个程序运行期间都存在不够灵活static struct cdev *pcdev; //只占4个字节之后cdev_alloc给它实例化分配在堆上可以按需分配。由cdev_del释放 pcdev cdev_alloc(); // 给pcdev分配内存指针实例化 三、代码示例 1、注册字符设备驱动的代码 // 使用新的cdev接口来注册字符设备驱动需要2步// 第1步注册主次设备号mydev MKDEV(MYMAJOR, 0);//MYMAJOR在这里是200这里合成了要申请的设备号即200,0retval register_chrdev_region(mydev, MYCNT, MYNAME);//这里申请刚才合成的设备号if (retval) {printk(KERN_ERR Unable to register minors for %s\n, MYNAME);return -EINVAL;}printk(KERN_INFO register_chrdev_region success\n);// 第2步注册字符设备驱动cdev_init(test_cdev, test_fops);//这步其实可以用其他代码来代替retval cdev_add(test_cdev, mydev, MYCNT);//注册字符设备驱动if (retval) {printk(KERN_ERR Unable to cdev_add\n);return -EINVAL;}printk(KERN_INFO cdev_add success\n); 2、注销字符设备驱动的代码  // 使用新的接口来注销字符设备驱动注销分2步// 第一步真正注销字符设备驱动用cdev_delcdev_del(test_cdev);// 第二步去注销申请的主次设备号unregister_chrdev_region(mydev, MYCNT); 3、完整的程序 1驱动源代码 #include linux/module.h // module_init module_exit #include linux/init.h // __init __exit #include linux/fs.h #include asm/uaccess.h #include mach/regs-gpio.h #include mach/gpio-bank.h // arch/arm/mach-s5pv210/include/mach/gpio-bank.h #include linux/string.h #include linux/io.h #include linux/ioport.h #include linux/cdev.h#define MYMAJOR 200 //注意通过cat /proc/devices查看这个200主设备号是否被占用 #define MYCNT 1 //表示次设备号只有一个 #define MYNAME testchar //表示设备或者说驱动混在一起的的名字#define GPJ0CON S5PV210_GPJ0CON #define GPJ0DAT S5PV210_GPJ0DAT#define rGPJ0CON *((volatile unsigned int *)GPJ0CON) #define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT)#define GPJ0CON_PA 0xe0200240 #define GPJ0DAT_PA 0xe0200244unsigned int *pGPJ0CON; unsigned int *pGPJ0DAT;int mymajor; static dev_t mydev; static struct cdev test_cdev; char kbuf[100]; // 内核空间的bufstatic int test_chrdev_open(struct inode *inode, struct file *file) {printk(KERN_INFO test_chrdev_open\n);rGPJ0CON 0x11111111;rGPJ0DAT ((03) | (04) | (05)); // 亮return 0; }static int test_chrdev_release(struct inode *inode, struct file *file) {printk(KERN_INFO test_chrdev_release\n);rGPJ0DAT ((13) | (14) | (15));return 0; }ssize_t test_chrdev_read(struct file *file, char __user *ubuf, size_t count, \loff_t *ppos) {int ret -1;printk(KERN_INFO test_chrdev_read\n);ret copy_to_user(ubuf, kbuf, count);if (ret){printk(KERN_ERR copy_to_user fail\n);return -EINVAL;}printk(KERN_INFO copy_to_user success..\n);return 0; }// 写函数的本质就是将应用层传递过来的数据先复制到内核中 // 然后将之以正确的方式写入硬件完成操作。 static ssize_t test_chrdev_write(struct file *file, const char __user *ubuf,size_t count, loff_t *ppos) {int ret -1;printk(KERN_INFO test_chrdev_write\n);// 使用该函数将应用层传过来的ubuf中的内容拷贝到驱动空间中的一个buf中//memcpy(kbuf, ubuf); // 不行因为2个不在一个地址空间中memset(kbuf, 0, sizeof(kbuf));ret copy_from_user(kbuf, ubuf, count);if (ret){printk(KERN_ERR copy_from_user fail\n);return -EINVAL;}printk(KERN_INFO copy_from_user success..\n);if (kbuf[0] 1){rGPJ0DAT ((03) | (04) | (05));}else if (kbuf[0] 0){rGPJ0DAT ((13) | (14) | (15));}return 0; }// 自定义一个file_operations结构体变量并且去填充 static const struct file_operations test_fops {.owner THIS_MODULE, // 惯例直接写即可.open test_chrdev_open, // 将来应用open打开这个设备时实际调用的.release test_chrdev_release, // 就是这个.open对应的函数.write test_chrdev_write,.read test_chrdev_read, };// 模块安装函数 static int __init chrdev_init(void) { int retval;printk(KERN_INFO chrdev_init helloworld init\n);/*// 在module_init宏调用的函数中去注册字符设备驱动// major传0进去表示要让内核帮我们自动分配一个合适的空白的没被使用的主设备号// 内核如果成功分配就会返回分配的主设备好如果分配失败会返回负数mymajor register_chrdev(0, MYNAME, test_fops);if (mymajor 0){printk(KERN_ERR register_chrdev fail\n);return -EINVAL;}printk(KERN_INFO register_chrdev success... mymajor %d.\n, mymajor); */ // 使用新的cdev接口来注册字符设备驱动// 新的接口注册字符设备驱动需要2步// 第1步注册/分配主次设备号mydev MKDEV(MYMAJOR, 0);retval register_chrdev_region(mydev, MYCNT, MYNAME);if (retval) {printk(KERN_ERR Unable to register minors for %s\n, MYNAME);return -EINVAL;}printk(KERN_INFO register_chrdev_region success\n);// 第2步注册字符设备驱动cdev_init(test_cdev, test_fops);retval cdev_add(test_cdev, mydev, MYCNT);if (retval) {printk(KERN_ERR Unable to cdev_add\n);return -EINVAL;}printk(KERN_INFO cdev_add success\n);// 使用动态映射的方式来操作寄存器if (!request_mem_region(GPJ0CON_PA, 4, GPJ0CON))return -EINVAL;if (!request_mem_region(GPJ0DAT_PA, 4, GPJ0CON))return -EINVAL;pGPJ0CON ioremap(GPJ0CON_PA, 4);pGPJ0DAT ioremap(GPJ0DAT_PA, 4);*pGPJ0CON 0x11111111;*pGPJ0DAT ((03) | (04) | (05)); // 亮return 0; }// 模块卸载函数 static void __exit chrdev_exit(void) {printk(KERN_INFO chrdev_exit helloworld exit\n);*pGPJ0DAT ((13) | (14) | (15)); // 解除映射iounmap(pGPJ0CON);iounmap(pGPJ0DAT);release_mem_region(GPJ0CON_PA, 4);release_mem_region(GPJ0DAT_PA, 4);/* // 在module_exit宏调用的函数中去注销字符设备驱动unregister_chrdev(mymajor, MYNAME); */ // 使用新的接口来注销字符设备驱动// 注销分2步// 第一步真正注销字符设备驱动用cdev_delcdev_del(test_cdev);// 第二步去注销申请的主次设备号unregister_chrdev_region(mydev, MYCNT); }module_init(chrdev_init); module_exit(chrdev_exit);// MODULE_xxx这种宏作用是用来添加模块描述信息 MODULE_LICENSE(GPL); // 描述模块的许可证 MODULE_AUTHOR(aston); // 描述模块的作者 MODULE_DESCRIPTION(module test); // 描述模块的介绍信息 MODULE_ALIAS(alias xxx); // 描述模块的别名信息 2应用层代码 #include stdio.h #include sys/types.h #include sys/stat.h #include fcntl.h #include string.h#define FILE /dev/test char buf[100];int main(void) {int fd -1;int i 0;fd open(FILE, O_RDWR);if (fd 0){printf(open %s error.\n, FILE);return -1;}printf(open %s success..\n, FILE);while (1){memset(buf, 0 , sizeof(buf));printf(请输入 on 或者 off 或者 flash 或者 quit \n);scanf(%s, buf);if (!strcmp(buf, on)){write(fd, 1, 1);}else if (!strcmp(buf, off)){write(fd, 0, 1);}else if (!strcmp(buf, flash)){for (i0; i3; i){write(fd, 1, 1);sleep(1);write(fd, 0, 1);sleep(1);}} else if (!strcmp(buf, quit)){break;}elsebreak;}close(fd); return 0; }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/86985.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

discuz怎么做h5网站网站建设哪家服务态度好

1.参数说明:lower_case_table_names0表名存储为给定的大小和比较是区分大小写的lower_case_table_names 1表名存储在磁盘是小写的,但是比较的时候是不区分大小写lower_case_table_names2表名存储为给定的大小写但是比较的时候是小写的unix,linux下lower_…

苏州网站设计公司兴田德润怎么样个人养老保险查询

2019独角兽企业重金招聘Python工程师标准>>> MySql中的varchar类型(转) 今天新开始的项目在做数据库设计,发现自己对MySql的varchar类型还不熟悉,故又上网收集资料整理如下。 1.varchar类型的变化 MySQL 数据库的va…

网站建设报告家教总结动画设计师工作内容

Hbase:HBase 底层原理详解(深度好文,建议收藏) - 腾讯云开发者社区-腾讯云 Hbase架构图 同一个列族如果有多个store,那么这些store在不同的region Hbase写流程(读比写慢) MemStore Flush Hbas…

广州网站优化哪里有网站维护内容有哪些

在过去的几年中,我越来越听到有关“云”服务的信息。 最初,我并不是很想尝试一下。 但是几个月后(一年?),我决定看看这是怎么回事。 我从事Java EE开发已经超过7年了,所以我决定看看将Java EE应…

南宁网站制作公司哪家好网站制作的语言

摘要: 本文主要介绍了七种功能强大的聊天机器人开发平台的特点与优点。聊天机器人发布平台是用户访问和使用聊天机器人的媒介,现在流行的一些聊天机器人发布平台有FB Messenger、Kik、Slack、Telegram以及WeChat。而聊天机器人开发平台是可以创建聊天机器…

帝国cms做电影网站如何制作自己想要的图片

课程链接:北京大学陆俊林老师的计算机组成原理课 1. 电子计算机的兴起 原因:二战对计算能力的需求世界上第一台通用电子计算机 ENIAC(Electronic Numerical Integrator And Computer):时间:1946&#xff1…

政工网站建设方案北京 网站 建设

原理&#xff1a;遍历下的/proc/%s/task/%s/status所有文件&#xff0c;两个%s都为pid号。 注&#xff1a;多线程下&#xff0c;只打印一个pid/task下的所有目录&#xff0c;即可收集各个线程对应的信息。 $ cat ps.c #include <stdio.h> #include <stdlib.h> #in…

做博客网站什么空间好网站开发原创动漫

JQuery $.ajax() $.ajax({type: POST, //请求方式 一般是get&#xff0c;posturl: url , // 这是必需的&#xff0c;规定把请求发送到哪个 URLdata: data , //这个是可选。映射或字符串值。规定连同请求发送到服务器的数据。java中用request.getPara…

网站开发中背景图片怎么弄全屏网站备案 链接

近日公众号出现了 出现该公众号提供的服务出现故障的错误提示 百度了一下这种错误的可能性 在这里插入图片描述 1. 程序后台未回复微信success 2. 5秒内无响应 3. 授权给了多个第三方平台&#xff0c;其中一个不可用。 4. ToUserName和 FromUserName 参数不正确无法找到接收…

公司网站建设请示163企业邮箱费用

文章目录 鼠标状态改变限制鼠标活动区域 鼠标状态改变 void QApplication::setOverrideCursor (const QCursor & cursor,bool replace FALSE ) // 设置应用程序强制光标为 cursor QApplication::restoreOverrideCursor() // 撤销最近一次的设置每一个setOverrideCursor…

在手机上怎么制作网站个人简历word可编辑

前言&#xff1a; 最近的几场面试都问到了http的相关知识点&#xff0c;博主在此结合书籍和网上资料做下总结。本篇文章讲收录到秋招专题&#xff0c;该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。 如果文章有什么需要改进的地方欢迎大佬提出&#xff0c;对大佬有帮…

寿光网站建设哪家好wordpress启用memcache

Android NDK开发详解之JNI中的库文件 简介工作原理流程原生 activity 和应用 简介 本部分简要介绍了 NDK 的工作原理。Android NDK 是一组使您能将 C 或 C&#xff08;“原生代码”&#xff09;嵌入到 Android 应用中的工具。能够在 Android 应用中使用原生代码对于想执行以下…

门户网站建设解决方案常州网络推广价格

在工业互联网的背景下&#xff0c;电厂三维数字孪生大屏系统正在逐渐成为电力行业的重要技术。通过创建电厂的虚拟模型&#xff0c;这个数字孪生系统可以实现对实际电厂的实时监控&#xff0c;预测维护需求&#xff0c;优化运营效率&#xff0c;甚至在某些情况下&#xff0c;能…

合肥做网站公司广州 网站开发 骏域

Laravel特点&#xff1a;1、“artisan”命令行工具&#xff0c;可以自动化完成手动的工作&#xff1b;2、“migration”管理数据库和版本控制&#xff1b;3、测试功能也很强大&#xff1b;4、适合应用各种开发模式TDD、DDD和BDD&#xff1b;5、支持Composer包管理工具。Laravel…

实用网站开发做seo需要投入的成本

注入方式 set方法注入 构造函数注入 p名称空间注入 spel注入(#表示理解为引用) 练习代码&#xff1a; <!-- 第二天 set注入 index:索引 ref:引用对象 type:参数类型--><bean name"person" class"com.spring.bean.Person"><constructor-a…

石家庄网站建设蓝龙网络推广员招聘

由于实际生产需要&#xff0c;软件系统的运行&#xff0c;会产生大量的日志文件&#xff0c;有时候一天就能产生超过百万条log记录&#xff0c;那么为了能够处理日志文件&#xff0c;查询并且找到我们想要的报错信息&#xff0c;因此不得不考虑怎么实现&#xff0c;打开大日志文…

网站除了做流量还需要什么高端企业网站建设好的公司

2024年广西职业院校技能大赛 中职组《网络安全》赛项样题 目录 任务一 登录安全加固 任务二 数据库加固&#xff08;Data&#xff09; 任务三 Web安全加固(Web) 任务四 流量完整性保护&#xff08;Web,Data&#xff09; 任务五 事件监控 任务一 应急响应 任务二 …

做公众号主页面的有哪些网站中国国际旅行社官网线路

Apache Spark是一个强大的分布式计算框架&#xff0c;用于处理大规模数据。在Spark中&#xff0c;数据加载与保存是数据处理流程的关键步骤之一。本文将深入探讨Spark中数据加载与保存的基本概念和常见操作&#xff0c;包括加载不同数据源、保存数据到不同格式以及性能优化等方…

网站换域名了怎么办重庆文旅急了

回文日期 原文链接&#xff1a;https://www.acwing.com/problem/content/468/ 由于只有八位数&#xff0c;而且回文串左右对称&#xff0c;因此可以只枚举左半边。然后判断&#xff1a; 整个八位数日期是否合法是否在范围内 一共枚举1e4个数。判断过程是常数级别的&#xff0…