字符设备驱动体验,字符设备驱动学习

                字符设备驱动学习

  在Linux系统中,驱动程序通常采用内核模块的程序结构来进行编码。因此,编译/安装一个驱动程序,其实质就是编译/安装一个内核模块。

一、编译安装字符设备驱动程序

memdev文件中:在这个文件里和真实的硬件无关,只是虚构了一个数组

  1 #include <linux/module.h>
  2 #include <linux/fs.h>
  3 #include <linux/init.h>
  4 #include <linux/cdev.h>
  5 #include <asm/uaccess.h>
  6
  7
  8 int dev1_registers[5];
  9 int dev2_registers[5];
 10
 11 struct cdev cdev;
 12 dev_t devno;
 13
 14 /*文件打开函数*/
 15 int mem_open(struct inode *inode, struct file *filp)
 16 {
 17     /*获取次设备号*/
 18     int num = MINOR(inode->i_rdev);
 19
 20     if (num==0)
 21         filp->private_data = dev1_registers;
 22     else if(num == 1)
 23         filp->private_data = dev2_registers;
 24     else
 25         return -ENODEV;  //无效的次设备号
 26
 27     return 0;
 28 }
 29
 30 /*文件释放函数*/
 31 int mem_release(struct inode *inode, struct file *filp)
 32 {
 33   return 0;
 34 }
 35
 36 /*读函数*/
 37 static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
 38 {
 39   unsigned long p =  *ppos;
 40   unsigned int count = size;
 41   int ret = 0;
 42   int *register_addr = filp->private_data; /*获取设备的寄存器基地址*/
 43
 44   /*判断读位置是否有效*/
 45   if (p >= 5*sizeof(int))
 46     return 0;
 47   if (count > 5*sizeof(int) - p)
 48     count = 5*sizeof(int) - p;
 49
 50   /*读数据到用户空间*/
 51   if (copy_to_user(buf, register_addr+p, count))
 52   {
 53     ret = -EFAULT;
 54   }
 55   else
 56   {
 57     *ppos += count;
 58     ret = count;
 59   }
 60
 61   return ret;
 62 }
 63
 64 /*写函数*/
 65 static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
 66 {
 67   unsigned long p =  *ppos;
 68   unsigned int count = size;
 69   int ret = 0;
 70   int *register_addr = filp->private_data; /*获取设备的寄存器地址*/
 71
 72   /*分析和获取有效的写长度*/
 73   if (p >= 5*sizeof(int))
 74     return 0;
 75   if (count > 5*sizeof(int) - p)
 76     count = 5*sizeof(int) - p;
 77
 78   /*从用户空间写入数据*/
 79   if (copy_from_user(register_addr + p, buf, count))
 80     ret = -EFAULT;
 81   else
 82   {
 83     *ppos += count;
 84     ret = count;
 85   }
 86
 87   return ret;
 88 }
 89
 90 /* seek文件定位函数 */
 91 static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
 92 {
 93     loff_t newpos;
 94
 95     switch(whence) {
 96       case SEEK_SET:
 97         newpos = offset;
 98         break;
 99
100       case SEEK_CUR:
101         newpos = filp->f_pos + offset;
102         break;
103
104       case SEEK_END:
105         newpos = 5*sizeof(int)-1 + offset;
106         break;
107
108       default:
109         return -EINVAL;
110     }
111     if ((newpos<0) || (newpos>5*sizeof(int)))
112         return -EINVAL;
113
114     filp->f_pos = newpos;
115     return newpos;
116
117 }
118
119 /*文件操作结构体*/
120 static const struct file_operations mem_fops =
121 {
122   .llseek = mem_llseek,
123   .read = mem_read,
124   .write = mem_write,
125   .open = mem_open,
126   .release = mem_release,
127 };
128
129 /*设备驱动模块加载函数*/
130 static int memdev_init(void)
131 {
132   /*初始化cdev结构*/
133   cdev_init(&cdev, &mem_fops);
134
135   /* 注册字符设备 */
136   alloc_chrdev_region(&devno, 0, 2, "memdev");
137   cdev_add(&cdev, devno, 2);
138 }
139
140 /*模块卸载函数*/
141 static void memdev_exit(void)
142 {
143   cdev_del(&cdev);   /*注销设备*/
144   unregister_chrdev_region(devno, 2); /*释放设备号*/
145 }
146
147 MODULE_LICENSE("GPL");
148
149 module_init(memdev_init);
150 module_exit(memdev_exit);

该文件的Makefile文件中:

1 obj-m := memdev.o
2 KDIR := /home/kernel/kernel/linux-ok6410  //我的内核代码路径
3 all:
4     make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
5 clean:
6     rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order

二、字符设备文件

  

  以上图片可以完整体现出应用程序、字符设备文件、以及设备驱动之间的依赖关系。字符设备文件通过主设备号对应设备驱动程序、二应用程序通过文件名对应字符设备文件

  通过字符设备文件,应用程序可以使用相应的字符设备驱动程序来控制字符设备。这里需要提及一下创建字符设备文件的方法有两种:

1.使用mknod命令
  mknod  /dev/文件名  c  主设备号   次设备号

  当然在使用mknod创建的时候需要注意不能使得创建的文件名在这之前就存在,还有主设备号可以通过cat proc/devices命令进行查看,与内核模块相对应的设备号。

2.使用函数在驱动程序中创建

这里我们使用mknod /dev/memdev c 252 0 对我们的虚拟设备文件驱动创建设备文件

三、应用程序的编写

write.c文件:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <fcntl.h>
 6 int main()
 7 {
 8     int src = 2013;
 9     int fd=0;
10     fd = open("/dev/memdev",O_RDWR); //以可读可写的方式打开
11     write(fd,&src,sizeof(int));
12     close(fd);
13     return 0;
14 }

read.c文件:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <fcntl.h>
 6
 7 int main()
 8 {
 9     int dst = 0;
10     int fd = 0;
11     fd = open("/dev/memdev",O_RDWR);
12     read(fd,&dst,sizeof(int));
13     printf("dat is %d\n",dst);
14     close(fd);
15     return 0;
16 }

3.1编译运行文件

3.1.1编译

3.1.2运行

  当然在运行之前得先查看开发板上面有没有应用程序需要的库文件运行:arm-linux-readelf -d write_mem,在到开发板的/lib/目录下面查看是否有这个库,如果没有则可以对文件进行动态编译或者移植库

时间: 2024-10-18 17:17:17

字符设备驱动体验,字符设备驱动学习的相关文章

字符设备驱动、平台设备驱动、设备驱动模型、sysfs的关系

Linux驱动开发的童鞋们来膜拜吧:-)  学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关联的分析.对于开发者而言,能够熟悉某一点并分享出来已很难得,但对于专注传授技术和经验给

[kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联

转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关

linux驱动之字符设备

第一部分:字符设备工作过程1.系统调用和驱动程序的关联关键结构体:struct file_operation:file_operation结构体的每一个成员的名字都对应着一个系统调用.用户进程利用系统调用在对设备文件进行诸如read/write操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数.这是linux的设备驱动程序工作的基本原理.编写设备驱动程序的主要工作就是编写子函数,并填充file_operations的各个域.

深入浅出~Linux设备驱动之字符设备驱动

一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的字符设备有鼠标.键盘.串口.控制台和LED设备等. 块设备:是指可以从设备的任意位置读取一定长度数据的设备.块设备包括硬盘.磁盘.U盘和SD卡等. 每一个字符设备或块设备都在/dev目录下对应一个设备文件.linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备

【驱动】——字符设备驱动程序

字符设备不得不说的那些事: 一: 设备号:主设备号,次设备号: 数据类型 dev_t(unsigned int) 定义设备号  高12位主设备号 低20位次设备号: 二: 设备号的作用: 应用程序通过主设备号找到驱动程序: 三:如何分配设备号: ①:静态分配: 1: cat /proc/devices 查看linux系统哪个设备号没有被占用: 2: dev_t dev_id = MKDEV(主设备号,次设备号)  根据你的设备个数分配次设备号 如果设备个数只有一个,一般此设备号从0开始: 3: 

【转】深入浅出:Linux设备驱动之字符设备驱动

深入浅出:Linux设备驱动之字符设备驱动 一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的字符设备有鼠标.键盘.串口.控制台和LED设备等. 块设备:是指可以从设备的任意位置读取一定长度数据的设备.块设备包括硬盘.磁盘.U盘和SD卡等. 每一个字符设备或块设备都在/dev目录下对应一个设备文件.linux用户程序通过设备文件(或称

Linux设备驱动之字符设备驱动

一.linux系统将设备分为3类:字符设备.块设备.网络设备. 应用程序调用的流程框图: 三种设备的定义分别如下, 字符设备:只能一个字节一个字节的读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后顺序进行.字符设备是面向流的设备,常见的字符设备如鼠标.键盘.串口.控制台.LED等. 块设备:是指可以从设备的任意位置读取一定长度的数据设备.块设备如硬盘.磁盘.U盘和SD卡等存储设备. 网络设备:网络设备比较特殊,不在是对文件进行操作,而是由专门的网络接口来实现.应用程序不能直接访

驱动篇-字符驱动入门(完美解决cat echo 字符设备乱码的问题)(一)

闲来无事,整理一下驱动入门知识! 大部分与网上整理的差不多,我主要想说的有两个特别的地方,刚入门的人看别人整理的肯定都不知道怎么测试.或者测试结果不像他们所写的那样! 第一点就是用mknod创建的设备名,设备号不能随便写,必须你所写的源文件命名的一致. 比如你在c文件中定义 #define DEV_NAME "chardev" 那么设备名就是chardev 设备号可以通过 cat /proc/devices |grep chardev 得到主设备号. [email protected]

驱动笔记 - 字符设备常用函数

字符设备: 静态申请设备号int register_chrdev_region(dev_t from, unsigned count,const char *name)申请使用从from开始的count个设备号(主设备号不变,次设备号增加)from:希望申请使用的设备号count:希望申请使用的设备号数目name:设备文件 动态分配设备号int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const ch