#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字符驱动设备(动态映射)的更多相关文章

  1. 旧接口注册LED字符驱动设备(静态映射)

    #include <linux/init.h> // __init __exit #include <linux/module.h> // module_init module ...

  2. 新接口注册LED字符驱动设备

    #include <linux/init.h> // __init __exit #include <linux/module.h> // module_init module ...

  3. 嵌入式Linux学习笔记(三) 字符型设备驱动--LED的驱动开发

    在成功构建了一个能够运行在开发板平台的系统后,下一步就要正式开始应用的开发(这里前提是有一定的C语言基础,对ARM体系的软/硬件,这部分有疑问可能要参考其它教程),根据需求仔细分解任务,可以发现包含的 ...

  4. Linux内核驱动学习(三)字符型设备驱动之初体验

    Linux字符型设备驱动之初体验 文章目录 Linux字符型设备驱动之初体验 前言 框架 字符型设备 程序实现 cdev kobj owner file_operations dev_t 设备注册过程 ...

  5. linux驱动初探之字符驱动

    关键字:字符驱动.动态生成设备节点.helloworld linux驱动编程,个人觉得第一件事就是配置好平台文件,这里以字符设备,也就是传说中的helloworld为例~ 此驱动程序基于linux3. ...

  6. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  7. 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl

    基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl 0. 导语 在嵌入式的道路上寻寻觅觅很久,进入嵌入式这个行业也有几年的时间了,从2011年后 ...

  8. fl2440 platform总线led字符设备驱动

    首先需要知道的是,设备跟驱动是分开的.设备通过struct device来定义,也可以自己将结构体封装到自己定义的device结构体中: 例如:struct platform_device: 在inc ...

  9. linux设备驱动归纳总结(三):1.字符型设备之设备申请【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-59416.html linux设备驱动归纳总结(三):1.字符型设备之设备申请 操作系统:Ubunru ...

随机推荐

  1. 设置mysql数据表列自动递增以及数据行插入操作

    创建mysql数据表,设置id列递增.主键create table running_log ( id int primary key auto_increment, routename varchar ...

  2. Django【第11篇】:Django之分页升级版本(组件)

    分页组件 一.分页的实现与使用 class Pagination(object): """ 自定义分页 """ def __init__(s ...

  3. TLS漏洞:超过50万个电子邮件服务器容易受黑客攻击,太可怕了

    2019年在流行的开源Exim电子邮件服务器软件中发现了一个关键的远程执行代码漏洞,至少有超过50万个电子邮件服务器容易受到远程黑客攻击.Exim是一种广泛使用的开源邮件传输代理(MTA)软件,为类似 ...

  4. scrapy处理post请求的传参和日志等级

    一.Scrapy的日志等级 - 在使用scrapy crawl spiderFileName运行程序时,在终端里打印输出的就是scrapy的日志信息. - 日志信息的种类: ERROR : 一般错误 ...

  5. 【python实例】判断质数:for-break-else

    """ for 变量 in 容器: 遍历--break 如果执行到了break语句, 则else不会被执行 else: break语句没有被执行时, 执行else &qu ...

  6. IO流,字节流复制文件,字符流+缓冲复制文件

    JAVAIO如果按流向分:输入流和输出流两种 输入流的基类:InputStream   Reader 输出流的基类:OutputStream   Writer 如果按数据单元划分:字节流和字符流 字节 ...

  7. 使用 flex 弹性布局 ,相关教程记录

    一.Flex布局是什么? Flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性. 任何一个容器都可以指定为Flex布局. .box1{ dis ...

  8. go语言实战 摘抄

    append 函数append会智能地处理底层数组的容量增长.在切片的容量小于1000个元素时,总是会成倍地增加容量.一旦元素个数超过1000,容量的增长因子就会设为1.25, 也就是每次增加25%的 ...

  9. 安装JDK ,提示 错误1316 指定的账户已存在

    基于情况: 安装了一个JDK 后,在文件目录中删除了相关文件,之后再次安装,提示  错误1316 指定的账户已存在 造成原因:安装JDK,相当于安装了一个软件,要使用系统的软件卸载功能卸载,不能只删除 ...

  10. 170814-17关于javaweb的知识点

    1.   静态web项目.动态web项目区别                                         WEB-INF                               ...