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

网站质作网页制作首页代码模板

网站质作,网页制作首页代码模板,本溪北京网站建设,移动宽带一年240元所学内容来自百问网 目录 1. 文件在内核中的表示 2. 打开字符设备节点时#xff0c;内核中也有对应的struct file 3. 编写驱动程序步骤 4. 相关知识点 4.1 涉及函数解析 4.2 module_init/module_exit的实现 4.3 register_chrdev的内部实现 4.4 class_destroy/device_…所学内容来自百问网 目录 1. 文件在内核中的表示 2. 打开字符设备节点时内核中也有对应的struct file 3. 编写驱动程序步骤 4. 相关知识点 4.1 涉及函数解析 4.2 module_init/module_exit的实现 4.3 register_chrdev的内部实现 4.4 class_destroy/device_create 浅析 5. 示例代码 5.1 驱动代码 5.2 应用代码 5.3 Makefile 5.4 效果 1. 文件在内核中的表示 APP 打开文件时可以得到一个整数这个整数被称为文件句柄。对于APP 的每一个文件句柄在内核里面都有一个“struct file”与之对应。 使用open打开文件时传入的flags、mode等参数会被记录在内核中对应的struct file结构体里(f_flags、f_mode) int open(const char *pathname, int flags, mode_t mode); 去读写文件时文件的当前偏移地址也会保存在 struct file 结构体的 f_pos 成员里。 2. 打开字符设备节点时内核中也有对应的struct file 注意这个结构体中的结构体struct file_operations *f_op这是由驱 动程序提供的。 结构体struct file_operations的定义如下 3. 编写驱动程序步骤 1.确定主设备号也可以让内核分配 2.定义自己的file_operations结构体 3.实现对应的drv_open/drv_read/drv_write 等函数填入file_operations结构体 4.把file_operations 结构体告诉内核register_chrdev 5.得有一个入口函数安装驱动程序时就会去调用这个入口函数 6.有入口函数就应该有出口函数卸载驱动程序时出口函数调用 unregister_chrdev 7.其他完善提供设备信息自动创建设备节点class_create, device_create 4. 相关知识点 4.1 涉及函数解析 将数据从内核空间复制到用户空间 unsigned long copy_to_user(void __user *to, const void *from, unsigned long n); void __user *to指向用户空间的指针表示数据复制的目标地址 const void *from指向内核空间的指针表示数据复制的源地址 unsigned long n要复制的字节数 返回值函数返回未能复制的字节数。如果返回值为0则表示全部复制成功 将数据从用户空间复制到内核空间 unsigned long copy_from_user(void *to, const void __user *from, unsigned long n); void *to指向内核空间的指针表示数据复制的目标地址 const void __user *from指向用户空间的指针表示数据复制的源地址 unsigned long n要复制的字节数 返回值函数返回未能复制的字节数。如果返回值为0则表示全部复制成功 从文件中读取数据到用户空间缓冲区 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); struct file *指向file结构体的指针代表要读取的文件 char __user *指向用户空间缓冲区的指针用于存储从文件中读取的数据 size_t要读取的字节数 loff_t *指向文件中的偏移量的指针表示从文件的哪个位置开始读取 返回值返回实际读取的字节数。如果读取失败返回负值 将用户空间缓冲区的数据写入文件 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); struct file *指向file结构体的指针代表要写入的文件 const char __user *指向用户空间缓冲区的指针包含要写入文件的数据 size_t要写入的字节数 loff_t *指向文件中的偏移量的指针表示从文件的哪个位置开始写入 返回值返回实际写入的字节数。如果写入失败返回负值 打开文件并初始化file结构体 int (*open) (struct inode *, struct file *); struct inode *指向inode结构体的指针代表要打开的文件的元数据 struct file *指向file结构体的指针用于存储打开文件的相关信息 返回值如果打开成功返回0如果失败返回负值 释放文件资源包括关闭文件、释放内存等 int (*release) (struct inode *, struct file *); struct inode *指向inode结构体的指针代表要释放的文件的元数据 struct file *指向file结构体的指针包含要释放的文件的相关信息 返回值如果释放成功返回0如果失败返回负值 4.2 module_init/module_exit的实现 一个驱动程序有入口函数、出口函数代码如下 module_init(hello_init); module_exit(hello_exit); 驱动程序可以被编进内核里也可以被编译为ko文件后手工加载。对于这 两种形式“module_init/module_exit”这2个宏是不一样的。在内核文件 “include\linux\module.h”中可以看到这2个宏 module_init(initfn) 宏用于声明模块初始化函数。当模块被加载到内核时initfn函数会被自动调用。这个函数通常用于执行模块所需的任何初始化任务比如注册设备、分配内存、初始化数据结构等。 module_exit(exitfn)宏用于声明模块退出函数。当模块从内核中卸载时exitfn函数会被自动调用。这个函数通常用于执行模块卸载前的任何清理任务比如注销设备、释放内存、清理数据结构等。 4.3 register_chrdev的内部实现 register_chrdev函数源码如下 static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops) { return __register_chrdev(major, 0, 256, name, fops); } 它调用__register_chrdev函数这个函数的代码精简如下 01 int __register_chrdev(unsigned int major, unsigned int baseminor, 02             unsigned int count, const char *name, 03               const struct file_operations *fops) 04 { 05     struct char_device_struct *cd; 06     struct cdev *cdev; 07     int err -ENOMEM; 08   09     cd __register_chrdev_region(major, baseminor, count, name); 10   11     cdev cdev_alloc(); 12   13     cdev-owner fops-owner; 14     cdev-ops fops; 15     kobject_set_name(cdev-kobj, %s, name); 16   17     err cdev_add(cdev, MKDEV(cd-major, baseminor), count); 18 } 这个函数主要的代码是第09行、第11~15行、第17行。 第09行调用__register_chrdev_region函数来“注册字符设备的区域” 它仅仅是查看设备号(major, baseminor)到(major, baseminorcount-1) 有没有被占用如果未被占用的话就使用这块区域。 内核中存在着一个chrdevs数组 static struct char_device_struct { struct char_device_struct *next;  unsigned int major; unsigned int baseminor; int minorct; char name[64]; struct cdev *cdev;     /* will die */ } *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; 去访问它的时候并不是直接使用主设备号major来确定数组项而是使用如下函数来确定数组项 /* index in the above */ static inline int major_to_index(unsigned major) { return major % CHRDEV_MAJOR_HASH_SIZE; } 上述代码中CHRDEV_MAJOR_HASH_SIZE等于255。比如主设备号1、256 都会使用chardevs[1]。chardevs[1]是一个链表链表里有多个 char_device_struct结构体某个结构体表示主设备号为1的设备某个结构 体表示主设备号为256的设备。 chardevs的结构图如图1.6所示 由此可见 1.chrdevs[i]数组项是一个链表头 链表里每一个元素都是一个char_device_struct结构体每个元素表示 一个驱动程序。 char_device_struct结构体内容如下 struct char_device_struct { struct char_device_struct *next; unsigned int major; unsigned int baseminor; int minorct; char name[64]; struct cdev *cdev;     /* will die */ } 它指定了主设备号major、次设备号baseminor、个数minorct在cdev 中含有file_operations结构体。 char_device_struct结构体的含义是主次设备号为(major, baseminor)、(major, baseminor1)、(major, baseminor2)、(major, baseminor minorct-1)的这些设备都使用同一个file_operations来操作。 2.在图1.6中chardevs[1]中有3个驱动程序 第1个char_device_struct结构体对应主次设备号(1, 0)、(1, 1)这 是第1个驱动程序。 第2个char_device_struct结构体对应主次设备号(1, 2)、(1, 2)、……、 (1, 11)这是第2个驱动程序。 第3个char_device_struct结构体对应主次设备号(256, 0)这是第3 个驱动程序。 第11~15行分配一个cdev结构体并设置它它含有file_operations 结构体。 第17行调用cdev_add把cdev结构体注册进内核里cdev_add函数代码 如下 01 int cdev_add(struct cdev *p, dev_t dev, unsigned count) 02 { 03     int error; 04   05     p-dev dev; 06     p-count count; 07   08     error kobj_map(cdev_map, dev, count, NULL, 09             exact_match, exact_lock, p); 10     if (error)   11         return error; 12   13     kobject_get(p-kobj.parent); 14   15     return 0; 16 } 这个函数涉及kobj的操作这是一个通用的链表操作函数。它的作用是 把cdev结构体放入cdev_map链表中对应的索引值是“dev”到“devcount 1”。以后可以从cdev_map链表中快速地使用索引值取出对应的cdev。 比如执行以下代码 err cdev_add(cdev, MKDEV(1, 2), 10); 其中的MKDEV(1,2)构造出一个整数“18 | 2”即0x102上述代码将 cdev放入cdev_map链表中对应的索引值是0x102到0x10c(即0x10210)。 以后根据这10个数值(0x102、0x103、0x104、……、0x10c)中任意一个都 可以快速地从cdev_map链表中取出cdev结构体。 APP打开某个字符设备节点时进入内核。在内核里根据字符设备节点的主、 次设备号计算出一个数值(major8 | minor即inode-i_rdev)然后使 用这个数值从cdev_map中快速得到cdev再从cdev中得到file_operations 结构体。 关键函数如下 在打开文件的过程中可以看到并未涉及chrdevs都是使用cdev_map。 所以可以看到在chrdevs的定义中看到如下注释 4.4 class_destroy/device_create 浅析 驱动程序的核心是 file_operations 结构体分配、设置、注册它。 “class_destroy/device_create”函数知识起一些辅助作用在/sys目录下 创建一些目录、文件这样Linux系统中的APP(比如udev、mdev)就可以根据 这些目录或文件来创建设备节点。 以下代码将会在“/sys/class”目录下创建一个子目录“hello_class” hello_class class_create(THIS_MODULE, hello_class); 以下代码将会在“/sys/class/hello_class”目录下创建一个文件 “hello” device_create(hello_class, NULL, MKDEV(major, 0), NULL, hello); 5. 示例代码 5.1 驱动代码 #include linux/module.h #include linux/fs.h #include linux/errno.h #include linux/miscdevice.h #include linux/kernel.h #include linux/major.h #include linux/mutex.h #include linux/proc_fs.h #include linux/seq_file.h #include linux/stat.h #include linux/init.h #include linux/device.h #include linux/tty.h #include linux/kmod.h #include linux/gfp.h ​ //1.确定主设备号也可以让内核分配 static int major 0; static char kernel_buf[1024]; static struct class *hello_class; #define MIN(a,b) (a b ? a : b) //3.实现对应的drv_open/drv_read/drv_write 等函数填入file_operations结构体 static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) {int ret;printk(%s %s line %d\n,__FILE__,__FUNCTION__,__LINE__);ret copy_to_user(buf, kernel_buf, MIN(1024,size));return MIN(1024,size); } static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset) {int ret;printk(%s %s line %d\n,__FILE__,__FUNCTION__,__LINE__);ret copy_from_user(kernel_buf, buf, MIN(1024,size));return MIN(1024,size); } static int hello_drv_open (struct inode *node, struct file *file) {printk(%s %s line %d\n,__FILE__,__FUNCTION__,__LINE__);return 0; } static int hello_drv_close (struct inode *node, struct file *file) {printk(%s %s line %d\n,__FILE__,__FUNCTION__,__LINE__);return 0; } ​ //2.定义自己的file_operations结构体 static struct file_operations hello_drv {.owner THIS_MODULE,.open hello_drv_open,.read hello_drv_read,.write hello_drv_write,.release hello_drv_close, }; ​ //4.把file_operations 结构体告诉内核register_chrdev //5.得有一个入口函数安装驱动程序时就会去调用这个入口函数 static int __init hello_init(void) {int err;major register_chrdev(0,hello,hello_drv); ​hello_class class_create(THIS_MODULE, hello_class);err PTR_ERR(hello_class);if(IS_ERR(hello_class)){unregister_chrdev(major,hello);return -1;} ​device_create(hello_class, NULL, MKDEV(major, 0), NULL, hello);return 0; } //6.有入口函数就应该有出口函数卸载驱动程序时出口函数调用 unregister_chrdev static void __exit hello_exit(void) {printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);device_destroy(hello_class, MKDEV(major, 0));class_destroy(hello_class);unregister_chrdev(major, hello); } ​ //7.其他完善提供设备信息自动创建设备节点class_create, device_create module_init(hello_init); module_exit(hello_exit); // 声明许可证类型 MODULE_LICENSE(GPL); 5.2 应用代码 #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include stdio.h #include string.h ​ /*./hello_drv_test -w abc./hello_drv_test -r */ int main(int argc,char **argv) {int fd;char buf[1024];int len; ​// 判断参数if(argc 2){printf(Usage: %s -w string\n,argv[0]);printf(       %s -r\n,argv[0]);return -1;} ​// 打开文件fd open(/dev/hello,O_RDWR);if(fd -1){printf(can not open file /dev/hello\n);return -1;} ​// 写文件或读文件if((strcmp(argv[1],-w) 0) (argc 3)){len strlen(argv[2]) 1;len len 1024 ? len : 1024;write(fd,argv[2],len);}else{len read(fd,buf,1024);buf[1023] \0;printf(APP read : %s\n,buf);} ​close(fd);return 0; } 5.3 Makefile # 1. 使用不同的开发板内核时, 一定要修改KERN_DIR # 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量: # 2.1 ARCH,         比如: export ARCHarm64 # 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILEaarch64-linux-gnu- # 2.3 PATH,         比如: export PATH$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin # 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同, #       请参考各开发板的高级用户使用手册 ​ // 此处使用的是IMX6U_6ULL开发板 KERN_DIR /home/book/100ask_imx6ull-sdk/Linux-4.9.88 ​ all:make -C $(KERN_DIR) Mpwd modules $(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c ​ clean:make -C $(KERN_DIR) Mpwd modules cleanrm -rf modules.orderrm -f hello_drv_test ​ obj-m hello_drv.o 5.4 效果 linux: 开发板 装载驱动 查看驱动是否转载成功 执行程序
http://www.dnsts.com.cn/news/181579.html

相关文章:

  • 有没有专门做商铺招商的网站建设部相关网站
  • 保定百度网站建设wordpress免费建站吗
  • 如何制作博客网站垦利网页设计
  • 什么是网站建设与优化昆山装饰公司网站建设
  • 网站优化建设郑州兼职网站建设
  • 做新标准大学英语网站c2c电子商务平台举例
  • wordpress明文密码网站推广优化哪家正规
  • 国内男女直接做的视频网站网站开发 微信 支付
  • 招聘网站策划书网站域名是什么东西
  • 怎么在网站上做链接多语言社交网站开发
  • 济南网站seo优化安徽网站推广公司
  • 网站SEO建设摘要他达拉非功效与作用主要会有哪些
  • 团购网站模板下载三亚河北建设招聘信息网站
  • 成都网站建设索q479185700网站建设和管理工作
  • 邯郸建设网站html网页模板怎么使用
  • 天津武清做网站的公司做电影网站还能赚钱
  • 微股东微网站制作平台怎么在网上卖东西到国外
  • 免费搭建网站教程重庆建站培训
  • 深圳做兼职的网站炫酷的企业网站模板
  • 网站做某个关键词排名该怎么做弄美团网站的一般一个做赚多少钱
  • 网站搭建是哪个岗位做的事儿wordpress广告代码
  • 如何做好品牌网站建设策划书小企业公司网站建设
  • 手机网站返回按钮怎么做做宣传可以在哪些网站上发布
  • 网站制作北京网站建设公司哪家好企业网站改版新闻
  • 做网站要学会那些汉中 网站建设
  • 淄博公司做网站软件开发工程师面试自我介绍
  • 网站做双拼域名什么意思创造力网站设计
  • 个人电脑做网站主机wordpress添加商品
  • 如何查询网站是否有做4043d动画制作教程视频
  • 网站建设之前必须 域名备案下载app安装