旧接口注册LED字符驱动设备(动态映射)
#include <linux/init.h> // __init __exit
#include <linux/module.h> // module_init module_exit #include <linux/fs.h> //file_operations #include <asm/uaccess.h> //copy_from_user copy_to_user #include <mach/regs-gpio.h>
#include <mach/gpio-bank.h> #include <asm/string.h> #include <linux/ioport.h> //request_mem_region
#include <asm/io.h> //ioremap #define S5PV210_PA_GPIOJ0CON 0xe0200240 volatile unsigned int *rGPJ0CON = NULL;
volatile unsigned int *rGPJ0DAT = NULL; static int led_open(struct inode *inode, struct file *file);
ssize_t led_read(struct file *file, char __user *user, size_t count, loff_t *loff);
ssize_t led_write(struct file *file, const char __user *user, size_t count, loff_t *loff);
static int led_release(struct inode *inode, struct file *file); static int led_major = -;
static char kbuf[] = {};
static const struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
}; int led_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "led_open successful\n");
return ;
} ssize_t led_read(struct file *file, char __user *user, size_t ucount, loff_t *loff)
{
printk(KERN_INFO "led_read successful\n");
if (copy_to_user(user,kbuf , ucount))
{
printk(KERN_INFO "copy_to_user fail\n");
return -EINVAL;
}
printk(KERN_INFO "copy_to_user successful\n");
return strlen(kbuf);
} ssize_t led_write(struct file *file, const char __user *user, size_t ucount, loff_t *loff)
{
printk(KERN_INFO "led_write successful\n");
memset(kbuf,,sizeof(kbuf));
if (copy_from_user(kbuf, user, ucount))
{
printk(KERN_INFO "copy_from_user fail\n");
return -EINVAL;
} if(!strcmp(kbuf,"on"))
{
*rGPJ0CON &=0xff000fff;
*rGPJ0CON |=0x00111000;
*rGPJ0DAT &=~((0x01<<)|(0x01<<)|(0x01<<));
}
else if(!strcmp(kbuf,"off"))
{
*rGPJ0CON &=0xff000fff;
*rGPJ0CON |=0x00111000;
*rGPJ0DAT |=((0x01<<)|(0x01<<)|(0x01<<));
}
return ucount;
printk(KERN_INFO "copy_from_user successful\n");
} int led_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "led_release successful\n");
return ;
} // 模块安装函数
static int __init chrdev_init(void)
{
int ret = -;
printk(KERN_INFO "chrdev_init successful\n"); if ((led_major = register_chrdev (, "led_dev", &led_fops)) < )
{
printk(KERN_WARNING "led_module.c: Failed to register character device.");
ret = -EINVAL;
}
if (request_mem_region(S5PV210_PA_GPIOJ0CON, , "GPIOJ0CON") == NULL)
{
printk(KERN_WARNING "failed to get memory region\n");
ret = -ENOENT;
goto err_req;
}
rGPJ0CON = ioremap(S5PV210_PA_GPIOJ0CON,);
if (rGPJ0CON == NULL)
{
printk(KERN_WARNING "fail to ioremap() region\n");
ret = -ENOENT;
goto err_map;
}
rGPJ0DAT = rGPJ0CON+;
err_map:
iounmap(rGPJ0CON); err_req:
release_mem_region(S5PV210_PA_GPIOJ0CON,); return ;
} // 模块卸载函数
static void __exit chrdev_exit(void)
{
iounmap(rGPJ0CON);
release_mem_region(S5PV210_PA_GPIOJ0CON,);
unregister_chrdev(led_major,"led_dev");
printk(KERN_INFO "chrdev_exit successful\n"); } module_init(chrdev_init);
module_exit(chrdev_exit); // MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL"); // 描述模块的许可证
MODULE_AUTHOR("musk"); // 描述模块的作者
MODULE_DESCRIPTION("module test"); // 描述模块的介绍信息
MODULE_ALIAS("alias xxx"); // 描述模块的别名信息
上述程序是led非常简陋,手动注册的字符驱动代码。真正的内核驱动不是这么简单!
一. 关于字符设备注册,静态虚拟地址请查看上篇文章《注册LED字符驱动设备(静态映射)》
二. 关于动态映射
2.1. 虚拟地址到物理地址的映射可以多对1,但是不能1对多,故可以多个动态虚拟地址和一个静态虚拟地址同事指向同一个物理地址寄存器。
2.2. 向内核申请&释放需要映射的内存资源
2.2.1. 由于soc所有的资源都是内核管理的,使用时应先申请,这样如果资源以及被其他驱动使用了则申请不到。这样可以很好的避免一个资源在两个驱动中同时被使用造成错误。
2.2.2. 申请函数request_mem_region
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
a. 参数start 是要申请资源的物理地址
b. 参数n是要申请资源的大小(单位是byte)
c. 参数name是给申请的资源起个别名
d. 成功返回非NULL失败返回NULL
2.2.2. 申请函数release_mem_region
#define release_mem_region(start,n)__release_region(&iomem_resource, (start), (n))
a. 参数start 是要申请资源的物理地址
b. 参数n是要申请资源的大小(单位是byte)
2.2.3. IO内存映射/去映射
2.2.3.1. release_mem_region申请了IO资源,接下来就是进行物理地址到虚拟地址的映射
2.2.3.2. IO内存映射函数:ioremap(cookie,size)
#define ioremap(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE)
a. 参数cookie是映射资源的物理地址
b. 参数size是映射的大小
2.2.3.3. IO内存映射函数:iounmap(cookie)
#define iounmap(cookie)__iounmap(cookie)
a. 参数cookie是映射资源的物理地址
三. 应用层调用内核
3.1. 相关代码如下
#include <stdio.h> #include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> #include <string.h> #define DEVFILE "/dev/led_dev" int main(void)
{
char buf[] = {};
int fd = -;
if((fd =open(DEVFILE, O_RDWR))<)
{
perror("open");
return -;
}
printf("open successful fd = %d\n",fd);
if(write(fd, "on", strlen("on"))<)
{
perror("write");
return -;
}
sleep();
memset(buf,,sizeof(buf));
if(read(fd, buf, )<)
{
perror("read");
return -;
}
printf("read data = %s\n",buf); if(write(fd, "off", strlen("off"))<)
{
perror("write");
return -;
}
sleep();
memset(buf,,sizeof(buf));
if(read(fd, buf, )<)
{
perror("read");
return -;
}
printf("read data = %s\n",buf); close(fd);
return ;
}
旧接口注册LED字符驱动设备(动态映射)的更多相关文章
- 旧接口注册LED字符驱动设备(静态映射)
#include <linux/init.h> // __init __exit #include <linux/module.h> // module_init module ...
- 新接口注册LED字符驱动设备
#include <linux/init.h> // __init __exit #include <linux/module.h> // module_init module ...
- 嵌入式Linux学习笔记(三) 字符型设备驱动--LED的驱动开发
在成功构建了一个能够运行在开发板平台的系统后,下一步就要正式开始应用的开发(这里前提是有一定的C语言基础,对ARM体系的软/硬件,这部分有疑问可能要参考其它教程),根据需求仔细分解任务,可以发现包含的 ...
- Linux内核驱动学习(三)字符型设备驱动之初体验
Linux字符型设备驱动之初体验 文章目录 Linux字符型设备驱动之初体验 前言 框架 字符型设备 程序实现 cdev kobj owner file_operations dev_t 设备注册过程 ...
- linux驱动初探之字符驱动
关键字:字符驱动.动态生成设备节点.helloworld linux驱动编程,个人觉得第一件事就是配置好平台文件,这里以字符设备,也就是传说中的helloworld为例~ 此驱动程序基于linux3. ...
- 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)
这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...
- 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl
基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl 0. 导语 在嵌入式的道路上寻寻觅觅很久,进入嵌入式这个行业也有几年的时间了,从2011年后 ...
- fl2440 platform总线led字符设备驱动
首先需要知道的是,设备跟驱动是分开的.设备通过struct device来定义,也可以自己将结构体封装到自己定义的device结构体中: 例如:struct platform_device: 在inc ...
- linux设备驱动归纳总结(三):1.字符型设备之设备申请【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-59416.html linux设备驱动归纳总结(三):1.字符型设备之设备申请 操作系统:Ubunru ...
随机推荐
- css使既有浮动又有左右margin的多个元素两端对其
两端对齐效果 如上图中红色的9个div它们中间有间距,而最左边和最右边是没有间距的,这种布局如果使用css3的flex来实现是非常简单的,而如果要使用float布局就需要一些特殊的技巧了. 实现原理 ...
- 表单-angular
模板表单: <form #myform="ngForm" (ngSubmit)="onsubmit(myform.value)" > <div ...
- python如何导入自定义文件和模块$PYTHONHOME$\Lib\site-packages 方法
python 中如何引用自己创建的源文件(*.py)呢? 也就是所谓的模块. 假如,你有一个自定义的源文件,文件名:saySomething.py .里面有个函数,函数名:sayHello.如下图: ...
- 【CF838E】 Convex Countour
[CF838E] Convex Countour 首先观察题目的性质 由于是凸包,因此不自交路径中的一条边\((x, y)\)的两端点只能向与\(x\)或\(y\)相邻的结点连边. 举个栗子,若选取了 ...
- 微信小程序-tabBar-注意事项
tabBar.list[0].selectedIconPath 文件格式错误,仅支持 .png..jpg..jpeg 格式
- linux运维、架构之路-Git+Jenkins实现自动化部署
一.Jenkins介绍 jenkins是一个用JAVA编写的开源的持续集成工具,运行在servlet容器中,支持软件配置管理(SCM)工具,可以执行基于APACHE ANT和APAC ...
- React native 平时积累笔记
常用插件: react-native-check-box 复选框react-native-sortable-listview 列表拖拽排序 react-native-doc-viewer 预览组件 r ...
- size_t是什么?
在32位编译器下size_t可看做unsigned int: 在64位编译器下size_t可看做unsigned long long: sizeof返回的数据类型就为size_t. C++之size_ ...
- IDEA集成Mybatis打印日志插件
MyBatis Log Plugin :把 mybatis 输出的sql日志还原成完整的sql语句. 如下图所示,点击Tools>MyBatis Log Plugin 然后运行程序后,就会看到对 ...
- CSP-S2 Review: 模拟
Luogu 1087 FBI tree #include <cstdio> #include <cstring> char s[4100]; int n; char fbi(i ...