目的:

通过I/O端口方式访问RTC的秒寄存器;

由于本人从来没看过linux方面的书籍,也只是会在终端用些常用的命令而已,这次老大叫我学着通过I/O端口方式直接去读写寄存器。于是我在google中搜索,得到了一些答案,比如要先申请内存空间,再用ioremap映射到虚拟空间啊之类的。我学着网上的例子,写好了我的第一份代码。编译时竟然找不到头文件,非常头疼,头文件明明在那儿,怎么就找不到呢?在这里非常感谢,linux内核涉及与实现QQ群里面各位师哥师姐的鼎力相助,尽管说什么我都不懂,他们还是非常耐心。在群里大哥的指引下,我有了思路。要么添加系统调用,要么写个驱动。这里我选择了第二种方法。

方案:

引用群里大哥给我画的图片,感谢!

过程:

1. 编写驱动

#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/moduleparam.h>
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/seq_file.h>
#include <linux/cdev.h> #include <asm/uaccess.h> /* copy_*_user */
#include <asm/io.h> #define DEVICE_NAME "rtcport"
#define DEVICE_MAJOR 250 #ifndef BCD_TO_BIN
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)»4)*10)
#endif dev_t dev = 0;
static struct resource *rtc_resource;
static struct cdev my_dev;
static int RTC_open(struct inode *inode,struct file *filp)
{
printk("open device\n");
return 0;
} static int RTC_close(struct inode *inode,struct file *filp)
{
printk("close device\n");
return 0;
}
static int RTC_read(struct file *filp, char __user *buf, loff_t *f_pos)
{
outb(0,0x70);
int test=inb(0x71);
printk(KERN_DEBUG "second is %02X\n",test);
return 0;
} static int RTC_write(void)
{
return 0;
} static struct file_operations fops={
.owner=THIS_MODULE,
.open=RTC_open,
.release=RTC_close,
.read=RTC_read,
.write=RTC_write,
};
int RTC_init(void)
{
int ret;
//ret=register_chrdev(DEVICE_MAJOR,DEVICE_NAME,&fops);
ret=alloc_chrdev_region(&dev,0,1,DEVICE_NAME);
if (ret < 0) {
printk("RTC: can't get major %d\n", MAJOR(dev));
return ret;
}
printk("Register device successfully!\n");
release_region(0x70, 0x02);
rtc_resource = request_region(0x70,0x02,DEVICE_NAME);
if(rtc_resource == NULL)
{
printk("Unable to register RTC I/O addresses\n");
return -1;
}
cdev_init(&my_dev,&fops);
my_dev.owner=THIS_MODULE;
my_dev.ops=&fops;
ret=cdev_add(&my_dev,MKDEV(MAJOR(dev),0),1);
if(ret<0)
{
printk("RTC: can't add device");
} return 0;
} void RTC_exit(void)
{
// unregister_chrdev(DEVICE_MAJOR,DEVICE_NAME);
// devfs_remove(DEVICE_NAME);
release_region(0x70,0x02);
cdev_del(&my_dev);
unregister_chrdev_region(dev,1);
printk("Device has been unregistered!\n");
} MODULE_LICENSE("GPL");
MODULE_AUTHOR("HJW");
module_init(RTC_init);
module_exit(RTC_exit);

2. Makefile

obj-m += rtc_port.o
ccflags-y=-I/root/testdxx
all:
make $(ccflags-y) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

说明:ccflags-y是需要包括的头文件的路径,如果不需要依赖自定义的头文件,可去除。

3.make clean(注:若第一次编译,此步骤可略过)

4.make(ls可以看到在路径下多了一些文件)

5. 将模块Insmod进内核

insmod rtc_port.ko

注释:有同学说,诶怎么一点打印信息都没有,原因是printk本身就不会把信息打印到屏幕上,如果有需要的话,大家可以自己去搜索搜索。

6.执行cat /proc/devices可以看到我们新添加的字符型设备rtcport

7.将rtcport创建dev节点

mknod /dev/rtcport c 237 0

8.应用程序app.cpp

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h> int main(void)
{
int fd;
char buf[20];
fd=open("/dev/rtcport",O_RDWR);
if (fd<0)
{
perror("open");
return -1;
}
for(int i=0;i<60;i++)
{
read(fd,buf,20);
sleep(1);
}
close(fd);
return 0;
}

9. 输出结果dmesg

10 总结

本文只是介绍了完整的步骤,很多小的知识点都没有提及。下面我将进行概括:

1) 模块的格式

关键函数:Init exit之类的;

2)字符型设备的动态注册(动态注册可以减少设备冲突的概率)

关键函数:

alloc_chrdev_region(&dev,0,1,DEVICE_NAME);

cdev_init;

cdev_add

等等

注:释放的关键函数请参见代码;

3) i/o端口的映射

关键函数:

request_region;

release_region;

小的知识点大家可以边google边对照我的代码,希望这篇文章可以帮助大家少走弯路!

11.展望

下一步是研究IPMI source code,非常渴望能找到志同道合的朋友,大家有过这方面的研究可以给我留言,非常感谢!

【从零开始,从内核驱动驱动到用户空间调用】编写第一个linux驱动,通过端口访问I/O寄存器。的更多相关文章

  1. linux驱动开发:用户空间操作LCD显示简单的图片【转】

    转自:http://blog.csdn.net/changliang7731/article/details/53074616 上一章我们简单介绍了LCD的一些基本原理.当然更深奥的还有,比如gamm ...

  2. Android系统移植与驱动开发——第六章——使用实例来理解Linux驱动开发及心得

    Linux驱动的工作方式就是交互.例如向Linux打印机驱动发送一个打印命令,可以直接使用C语言函数open打开设备文件,在使用C语言函数ioctl向该驱动的设备文件发送打印命令.编写Linux驱动最 ...

  3. linux驱动开发重点关注内容--摘自《嵌入式Linux驱动模板精讲与项目实践》

    本文摘自本人拙著 <嵌入式Linux驱动模板精讲与项目实践> 初步看起来Linux设备驱动开发涉及内容非常多,而须要实现驱动的设备千差万别.事实上做一段时间驱动之后回首看来主要就是下面几点 ...

  4. 第一个Linux驱动-流水灯【转】

    转自:http://www.xuebuyuan.com/1856562.html 水平有限,描述不当之处请指出,转载请注明出处http://blog.csdn.net/vanbreaker/artic ...

  5. 一个linux 驱动升级的小问题记录

    重复踩了两次坑,所以简单记录下. 内核 3.10. 在修改了驱动的gro实现之后,进行驱动版本的升级,make && make install 之后,发现tg3的驱动,没有生效. 相同 ...

  6. 用Visual Studio 2015 编写第一个UMDF驱动遇到的问题!!

    前提:Visual Studio 2015已经成功安装了驱动环境,WDK都已经完全正常安装了,在Visual Studio 2015的菜单可以看到"Driver"菜单项了.这说明已 ...

  7. Linux 字符设备驱动开发基础(二)—— 编写简单 PWM 设备驱动【转】

    本文转载自:https://blog.csdn.net/zqixiao_09/article/details/50858776 版权声明:本文为博主原创文章,未经博主允许不得转载.    https: ...

  8. 用户空间与内核驱动的交互过程 — ioctl

    在Linux内核模块的开发过程中,经常涉及到运行在用户空间上的应用程序与内核模块进行交互,ioctl系统调用是常用的一种方式.本文并不涉及vlan的具体原理,仅通过vconfig与vlan内核模块进行 ...

  9. linux 驱动学习笔记03--Linux 内核的引导

    如图所示为 X86 PC 上从上电/复位到运行 Linux 用户空间初始进程的流程.在进入与 Linux相关代码之间,会经历如下阶段. ( 1 ) 当系统上电或复位时, CPU 会将 PC 指针赋值为 ...

随机推荐

  1. 转:你真的懂得JS吗?

    题目1 if (!("a" in window)) { var a = 1; } alert(a); // undefined, ~~~所有全局变量都是window的属性,声明语句 ...

  2. Java大顶和小顶

    http://blog.sina.com.cn/s/blog_651c9a360100o7y1.html http://blog.csdn.net/cnbird2008/article/details ...

  3. Spring boot 启动过程解析 logback

    使用 Spring Boot 默认的日志框架 Logback. 所有这些 POM 依赖的好处在于为开发 Spring 应用提供了一个良好的基础.Spring Boot 所选择的第三方库是经过考虑的,是 ...

  4. BCB6.0是垃圾的二十条理由

    我用的BCB6.0和windows2000 都是公司配的正版,我也有多年的开发经验. 1. IDE常常出现非法操作,有时重起动还会出错,须要重装BCB. 2. 自己主动完毕和智能提示功能超慢,慢到能够 ...

  5. Asp.Netserver控件开发的Grid实现(三)列编辑器

    以下是GridColumnsEditor的实现代码: GridColumnsEditor.cs using System; using System.Collections.Generic; usin ...

  6. ThinkPHP - 自定义扩展类库

    首先在想要使用类库的地方建立文件夹,文件名称随意,不能使用class 然后在配置文件中: 'AUTOLOAD_NAMESPACE' => array( 'Lib' => './Lib', ...

  7. Word中使用代码高亮插件

    Word中使用代码高亮插件 1.下载并安装:SyntaxHighlighter4Word.zip 解压,然后双击bin\word2010\Kong.SyntaxHighlighter.Word2010 ...

  8. windows环境下Mongodb分片配置

    使用MongoDB的GridFS来存储文件,以前一直使用单个服务,分布式环境也一直没有配置成功,今天参考了几位大神的文章终于配置成功,再也不用担心文件存储的性能和安全啦.以下是自己部署的过程和示例,记 ...

  9. CodeForces 22B Bargaining Table 简单DP

    题目很好理解,问你的是在所给的图中周长最长的矩形是多长嗯用坐标(x1, y1, x2, y2)表示一个矩形,暴力图中所有矩形易得递推式:(x1, y1, x2, y2)为矩形的充要条件为: (x1, ...

  10. (Problem 6)Sum square difference

    Hence the difference between the sum of the squares of the first ten natural numbers and the square ...