字符设备驱动高级篇6——内核提供的读写寄存器接口
来源:互联网 发布:成都家政公司办公软件 编辑:程序博客网 时间:2024/05/16 04:37
以下内容源于朱有鹏《物联网大讲堂》课程的学习整理,如有侵权,请告知删除。
1、前面访问寄存器的方式
通过定义指向寄存器的指针,然后解引用来对寄存器进行操作。
(1)行不行?sure!
(2)好不好?不好,因为ARM体系中内存和IO统一编址的,但有其他体系(如X86)不是统一编址的,因此不具有可移植性!
2、内核提供的寄存器读写接口
这些接口具有移植性,在Io.h文件中。
(1)writel写寄存器,readl读寄存器
(2)iowrite32和ioread32
3、代码实践
#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>#define MYMAJOR200#define MYNAME"testchar"#define GPJ0CONS5PV210_GPJ0CON#define GPJ0DATS5PV210_GPJ0DAT#define rGPJ0CON*((volatile unsigned int *)GPJ0CON)#define rGPJ0DAT*((volatile unsigned int *)GPJ0DAT)#define GPJ0CON_PA0xe0200240#define GPJ0DAT_PA 0xe0200244#define S5P_GPJ0REG(x)(x)#define S5P_GPJ0CONS5P_GPJ0REG(0)#define S5P_GPJ0DATS5P_GPJ0REG(4)unsigned int *pGPJ0CON;unsigned int *pGPJ0DAT;static void __iomem *baseaddr;// 寄存器的虚拟地址的基地址int mymajor;char kbuf[100];// 内核空间的bufstatic int test_chrdev_open(struct inode *inode, struct file *file){// 这个函数中真正应该放置的是打开这个设备的硬件操作代码部分// 但是现在暂时我们写不了这么多,所以用一个printk打印个信息来做代表。printk(KERN_INFO "test_chrdev_open\n");rGPJ0CON = 0x11111111;rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));// 亮return 0;}static int test_chrdev_release(struct inode *inode, struct file *file){printk(KERN_INFO "test_chrdev_release\n");rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));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 = ((0<<3) | (0<<4) | (0<<5));}else if (kbuf[0] == '0'){rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));}/*// 真正的驱动中,数据从应用层复制到驱动中后,我们就要根据这个数据// 去写硬件完成硬件的操作。所以这下面就应该是操作硬件的代码if (!strcmp(kbuf, "on")){rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));}else if (!strcmp(kbuf, "off")){rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));}*/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){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);/*// 使用动态映射的方式来操作寄存器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 = ((0<<3) | (0<<4) | (0<<5));// 亮// 测试1:用2次ioremap得到的动态映射虚拟地址来操作,测试成功//writel(0x11111111, pGPJ0CON);//writel(((0<<3) | (0<<4) | (0<<5)), pGPJ0DAT);// 测试2:用静态映射的虚拟地址来操作,测试成功//writel(0x11111111, GPJ0CON);//writel(((0<<3) | (0<<4) | (0<<5)), GPJ0DAT);// 测试3:用1次ioremap映射多个寄存器得到虚拟地址,测试成功if (!request_mem_region(GPJ0CON_PA, 8, "GPJ0BASE"))return -EINVAL;baseaddr = ioremap(GPJ0CON_PA, 8);writel(0x11111111, baseaddr + S5P_GPJ0CON);writel(((0<<3) | (0<<4) | (0<<5)), baseaddr + S5P_GPJ0DAT);return 0;}// 模块下载函数static void __exit chrdev_exit(void){printk(KERN_INFO "chrdev_exit helloworld exit\n");//*pGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));//writel(((1<<3) | (1<<4) | (1<<5)), pGPJ0DAT);//writel(((1<<3) | (1<<4) | (1<<5)), GPJ0DAT);writel(((1<<3) | (1<<4) | (1<<5)), baseaddr + S5P_GPJ0DAT);/*// 解除映射iounmap(pGPJ0CON);iounmap(pGPJ0DAT);release_mem_region(GPJ0CON_PA, 4);release_mem_region(GPJ0DAT_PA, 4);*/iounmap(baseaddr);release_mem_region(baseaddr, 8);// 在module_exit宏调用的函数中去注销字符设备驱动unregister_chrdev(mymajor, MYNAME);//rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));}module_init(chrdev_init);module_exit(chrdev_exit);// MODULE_xxx这种宏作用是用来添加模块描述信息MODULE_LICENSE("GPL");// 描述模块的许可证MODULE_AUTHOR("aston");// 描述模块的作者MODULE_DESCRIPTION("module test");// 描述模块的介绍信息MODULE_ALIAS("alias xxx");// 描述模块的别名信息
阅读全文
0 0
- 字符设备驱动高级篇6——内核提供的读写寄存器接口
- 字符设备驱动基础篇4——字符设备驱动读写接口的操作实践
- 内核提供的读写寄存器接口实现可移植性
- 字符设备驱动高级篇3——自动创建字符设备驱动的设备文件
- 字符设备驱动高级篇5——静态映射表、动态映射结构体方式操作寄存器
- 字符设备驱动高级篇1——新接口介绍
- 字符设备驱动高级篇2——字符设备驱动注册代码分析
- 设备驱动学习之字符设备驱动内核代码分析(一)——设备号申请接口
- 利用linux 内核所提供的input子系统编写字符设备驱动的步骤
- 高级字符设备驱动
- [设备驱动] 最简单的内核设备驱动--字符驱动
- 高级字符设备驱动-内核等待队列笔记
- linux高级字符设备驱动之 二 内核等待队列
- 国嵌视频学习——高级字符设备驱动
- Linux驱动学习(四)——高级字符设备驱动程序
- 字符设备驱动高级篇4——设备类(自动创建和删除设备文件的作用)相关代码分析
- 设备驱动学习之字符设备驱动内核代码分析(二)——字符设备结构体cdev
- 高级字符设备驱动01
- 07读书笔记之详解四种基本布局
- IIS+php环境下:上传文件出现:windows server PHP Warning: mkdir(): Permission denied 解决办法
- Kotlin-42.kotlin调用Java之四(Call Java from Kotlin)
- ubuntu 服务器搭建 Shadowsocks 服务
- 初入c++(三)this指针,友元函数,友元类
- 字符设备驱动高级篇6——内核提供的读写寄存器接口
- java应用中,调用第三方api如何处理异常(系统异常、操作异常等等)
- 社工库
- token和sign
- 锐速ServerSpeeder无限带宽破解版一键安装包
- 包含排斥原理
- 简单搞定Shuffle机制运行原理
- 如何给ubuntu14.04.1切换内核以安装锐速
- 安卓游戏开发一(超级玛丽)