Linux 字符驱动

char_driver.c

  1 #include <linux/module.h>
  2 #include <linux/slab.h>      //kmalloc
  3 #include <linux/cdev.h>      //cdev
  4 #include <linux/fs.h>          //register_chrdev_region
  5 #include <linux/device.h>    //class_create
  6 #include <asm/uaccess.h>    //copy_from_user copy_to_user
  7 #include <linux/timer.h>     //timer
  8 #include <linux/sched.h>    //jiffies
  9 #include <linux/poll.h>
 10 #include "char_driver.h"
 11
 12
 13 static int val = 200;
 14 static struct timer_list char_driver_timer;
 15
 16 static DECLARE_WAIT_QUEUE_HEAD(char_driver_queue);
 17
 18
 19
 20 static P_CHAR_DRIVER pDriver = NULL;
 21 static unsigned char value = 0;
 22 static unsigned char ready = 0;
 23
 24 static void char_driver_timer_func(unsigned long arg)
 25 {
 26     printk(KERN_INFO"Kernel Timer\n");
 27     memset(pDriver->data,value,DATASIZE);
 28     ready = 1;
 29     value++;
 30     mod_timer(&char_driver_timer,jiffies + (2 * HZ));
 31
 32     //防止应用层crtl+c结束进程,内核定时器无法停止
 33     if(value >= 60)
 34     {
 35         printk(KERN_INFO"del timer\r\n");
 36         del_timer(&char_driver_timer);
 37     }
 38 }
 39
 40 static void _init_timer(unsigned long data,unsigned long expires)
 41 {
 42     init_timer(&char_driver_timer);
 43
 44     //超时时间,定时间隔
 45     char_driver_timer.expires = jiffies + (expires * HZ);
 46     char_driver_timer.data = data;
 47     char_driver_timer.function = char_driver_timer_func;
 48 }
 49
 50
 51
 52
 53
 54 //OPEN
 55 static ssize_t char_driver_open(struct inode *inode, struct file *filp)
 56 {
 57     int minor = 0;
 58     minor = MINOR(inode->i_rdev);
 59     if(minor<0 || minor>TOTALDEVICE)
 60     {
 61         printk(KERN_ERR"open failed!Wrong minor\n");
 62     }
 63     filp->private_data = pDriver->data;
 64     printk(KERN_NOTICE"open\n");
 65     return 0;
 66 }
 67
 68 //release
 69 static ssize_t char_driver_release(struct inode *inode, struct file *filp)
 70 {
 71     printk(KERN_NOTICE"release\n");
 72
 73     return 0;
 74 }
 75
 76 //read
 77 static ssize_t char_driver_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
 78 {
 79     printk(KERN_NOTICE"read\n");
 80     copy_to_user(buf,filp->private_data,count);
 81     return 0;
 82 }
 83
 84
 85 //write
 86 static ssize_t char_driver_write (struct file *filp, const char __user *buf, size_t count,loff_t *ppos)
 87 {
 88     printk(KERN_NOTICE"write\n");
 89     copy_from_user(filp->private_data,buf,count);
 90     return 0;
 91 }
 92
 93 //poll
 94 static unsigned int char_driver_poll (struct file *filp, struct poll_table_struct *wait)
 95 {
 96     int mask = 0;
 97     printk(KERN_INFO"poll\n");
 98
 99     poll_wait(filp,&char_driver_queue,wait);
100
101     if(1 == ready)
102     {
103         ready = 0;
104         mask |= POLLIN |POLLRDNORM;
105     }
106
107     return mask;
108 }
109 //mmap
110 static int char_driver_mmap (struct file *filp, struct vm_area_struct *p)
111 {
112     printk(KERN_NOTICE"mmap\n");
113     return 0;
114 }
115 static long char_driver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
116 {
117     char magic = 0;
118     //char * p  = (char*)arg;
119     int  * p2 = (int*)arg;
120     printk(KERN_NOTICE"ioctl\n");
121     magic = _IOC_TYPE(cmd);
122     if(CHAR_DRIVER_MAGIC != magic)
123     {
124         printk(KERN_ERR"error magic\n");
125         return -EINVAL;
126     }
127     else
128     {
129         switch(cmd)
130         {
131             //数据清零
132             case CHAR_DRIVER_CLEAR:
133                 memset(filp->private_data,0,DATASIZE);
134                 break;
135
136             //将测试VAL返回
137             case CHAR_DRIVER_GET_VAL:
138                 *p2 = val;
139                 break;
140             //设置val
141             case CHAR_DRIVER_SET_VAL:
142                 val = arg;
143                 break;
144             //
145             case CHAR_DRIVER_SET_MEM:
146                 memset(filp->private_data,arg,DATASIZE);
147                 break;
148
149             //开启定时器,从参数传来的数开始自增1
150             case CHAR_DRIVER_START:
151
152                 //定时器2s间隔
153                 _init_timer(arg,2);
154                 value = (unsigned char)arg;
155                 add_timer(&char_driver_timer);
156                 break;
157
158             //停止定时器
159             case CHAR_DRIVER_STOP:
160                 printk(KERN_INFO"del timer\n");
161                 del_timer(&char_driver_timer);
162                 break;
163             default:
164                 break;
165
166         }
167     }
168
169     return 0;
170 }
171
172 static const struct file_operations char_driver_fops =
173 {
174     .owner             = THIS_MODULE,
175     .open            = char_driver_open,
176     .release         = char_driver_release,
177     .read             = char_driver_read,
178     .write           = char_driver_write,
179     .poll             = char_driver_poll,
180     .mmap            = char_driver_mmap,
181     .unlocked_ioctl = char_driver_ioctl,
182 };
183
184
185 int char_driver_init(void)
186 {
187     unsigned char  i    = 0;
188     int         ret     = 0;
189
190
191     printk(KERN_NOTICE "char_driver_init\n");
192
193     //申请内核空间内存
194     pDriver = (P_CHAR_DRIVER)kzalloc(sizeof(CHAR_DRIVER),GFP_KERNEL);
195
196     if(NULL == pDriver)
197     {
198         printk(KERN_NOTICE"Kmalloc Error\n");
199         return -ENOMEM;
200     }
201     pDriver->majornum = MAJORNUM;
202
203     //构建设备号
204     pDriver->DeviceNum = MKDEV(pDriver->majornum,0);
205
206     //静态注册设备
207     ret = register_chrdev_region(pDriver->DeviceNum, TOTALDEVICE, DEVICENAME);
208
209     //静态注册失败,动态注册
210     if(ret < 0)
211     {
212         ret = alloc_chrdev_region(&pDriver->DeviceNum,0,TOTALDEVICE, DEVICENAME);
213         if(ret < 0)
214         {
215             printk(KERN_ERR"chrdev_region failed!\n");
216             unregister_chrdev_region(pDriver->DeviceNum,TOTALDEVICE);
217             return -ENOMEM;
218         }
219
220         //动态注册设备后,更新主设备号
221         pDriver->majornum = MAJOR(pDriver->DeviceNum);
222     }
223
224     //注册完毕,初始化设备
225     cdev_init(&pDriver->cdev, &char_driver_fops);
226     pDriver->cdev.owner = THIS_MODULE;
227     pDriver->cdev.ops    = &char_driver_fops;
228
229     //初始化完毕,添加设备
230     ret = cdev_add(&pDriver->cdev,pDriver->DeviceNum,TOTALDEVICE);
231     if(ret < 0 )
232     {
233         printk(KERN_ERR"cdev_add failed!\n");
234         unregister_chrdev_region(pDriver->DeviceNum,TOTALDEVICE);
235         return -ENOMEM;
236     }
237
238     //添加设备成功,在/sys下产生系统文件接口
239     pDriver->chardriver_class =  class_create(THIS_MODULE, DEVICENAME);
240
241     //创建class失败,注销和删除
242     if(NULL == pDriver->chardriver_class)
243     {
244         printk(KERN_ERR"class_create failed!\n");
245         unregister_chrdev_region(pDriver->DeviceNum,TOTALDEVICE);
246         class_destroy(pDriver->chardriver_class);
247         return -ENOMEM;
248     }
249
250     //在dev下产生设备文件
251     for(i=0;i<TOTALDEVICE;i++)
252     {
253         device_create(pDriver->chardriver_class, NULL, MKDEV(pDriver->majornum, i),DEVICENAME,"xym%d",i);
254     }
255
256     _init_timer(5,5);
257
258     return 0;
259 }
260
261 void char_driver_exit(void)
262 {
263     unsigned char i = 0;
264
265
266     //注销
267     unregister_chrdev_region(pDriver->DeviceNum,TOTALDEVICE);
268
269     //删除设备
270     cdev_del(&pDriver->cdev);
271
272     //删除/dev下设备文件
273     for(i=0;i<TOTALDEVICE;i++)
274     {
275         device_destroy(pDriver->chardriver_class,MKDEV(pDriver->majornum,i));
276     }
277
278     //删除class
279     class_destroy(pDriver->chardriver_class);
280
281     //销毁内核内存
282     if(NULL != pDriver)
283     {
284         kfree(pDriver);
285     }
286
287     del_timer(&char_driver_timer);
288
289     printk(KERN_NOTICE "char_driver_exit\n");
290 }
291
292
293 MODULE_AUTHOR("XinYuMing");
294 MODULE_ALIAS ("XYM‘sDriver");
295 MODULE_DESCRIPTION("A Char Driver for Test");
296 MODULE_LICENSE("Dual BSD/GPL");
297 MODULE_VERSION("V1.0");
298
299 module_init(char_driver_init);
300 module_exit(char_driver_exit);  

char_driver.h

 1 #ifndef __CHAR_DRIVER__
 2 #define __CHAR_DRIVER__
 3
 4 #include <linux/ioctl.h>
 5
 6
 7
 8 #define MAJORNUM    255            //主设备号
 9 #define TOTALDEVICE    4            //设备数量
10 #define DEVICENAME    "MYCHAR"    //设备名称
11 #define DATASIZE    10
12
13
14 #define CHAR_DRIVER_MAGIC ‘o‘
15 #define CHAR_DRIVER_GET_VAL            _IOR(CHAR_DRIVER_MAGIC,0,int) //返回val的值
16 #define CHAR_DRIVER_SET_VAL            _IOW(CHAR_DRIVER_MAGIC,1,int)
17 #define CHAR_DRIVER_CLEAR            _IO(CHAR_DRIVER_MAGIC,2)
18 #define CHAR_DRIVER_SET_MEM            _IOW(CHAR_DRIVER_MAGIC,3,char)
19 #define CHAR_DRIVER_START            _IOW(CHAR_DRIVER_MAGIC,4,unsigned long)
20 #define CHAR_DRIVER_STOP            _IO(CHAR_DRIVER_MAGIC,5)
21
22
23 struct _CHAR_DRIVER
24 {
25     int majornum;                    //主设备号
26     struct cdev cdev;                 //字符设备结构
27     struct class *chardriver_class; //设备类
28     dev_t DeviceNum;                //设备号
29
30     unsigned char data[DATASIZE];
31 };
32
33 typedef struct _CHAR_DRIVER  CHAR_DRIVER;
34 typedef struct _CHAR_DRIVER* P_CHAR_DRIVER;
35
36
37
38
39 #endif

char_test_app.c

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <fcntl.h>
  4 #include <string.h>
  5 #include <sys/ioctl.h>
  6 #include <signal.h>
  7 #include <stdlib.h>
  8
  9 #define DEVICEPATH0 "/dev/xym0"
 10 #define DEVICEPATH1 "/dev/xym1"
 11
 12
 13
 14
 15 #define CHAR_DRIVER_MAGIC ‘o‘
 16 #define CHAR_DRIVER_GET_VAL            _IOR(CHAR_DRIVER_MAGIC,0,int) //返回val的值
 17 #define CHAR_DRIVER_SET_VAL            _IOW(CHAR_DRIVER_MAGIC,1,int)
 18 #define CHAR_DRIVER_CLEAR            _IO(CHAR_DRIVER_MAGIC,2)
 19 #define CHAR_DRIVER_SET_MEM            _IOW(CHAR_DRIVER_MAGIC,3,char)
 20 #define CHAR_DRIVER_START            _IOW(CHAR_DRIVER_MAGIC,4,unsigned long)
 21 #define CHAR_DRIVER_STOP            _IO(CHAR_DRIVER_MAGIC,5)
 22 #define DATASIZE                    (unsigned char)10
 23
 24 int fd0 = 0;
 25
 26 //捕获crtl c,删除内核定时器,退出程序
 27 void signal_func(int sig)
 28 {
 29
 30     printf("sig ----------- %d\n",sig);
 31     ioctl(fd0,CHAR_DRIVER_STOP);
 32     exit(0);
 33
 34 }
 35
 36 int main(void)
 37 {
 38
 39     int val = 0;
 40     char c = ‘a‘;
 41     int i=0;
 42     fd_set fds;
 43     struct timeval timeout;
 44     unsigned char buf[DATASIZE] = {0};
 45
 46     signal(SIGINT, signal_func);
 47
 48
 49     fd0 = open(DEVICEPATH0,O_RDWR);
 50     if(fd0 < 0)
 51     {
 52         printf("Open file fd0 faild!\n");
 53     }
 54
 55     //读取驱动的中的某个值
 56     ioctl(fd0,CHAR_DRIVER_GET_VAL,&val);
 57     printf("val --- %d\n",val);
 58
 59     //设置驱动中的某个值
 60     ioctl(fd0,CHAR_DRIVER_SET_VAL,300);
 61     ioctl(fd0,CHAR_DRIVER_GET_VAL,&val);
 62     printf("val --- %d\n",val);
 63
 64     //驱动中原始数据
 65     read(fd0,buf,sizeof(buf));
 66     for(i=0;i<sizeof(buf);i++)
 67     {
 68         printf("%d ",buf[i]);
 69     }
 70     printf("\n");
 71
 72     //写成11
 73     memset(buf,0x11,sizeof(buf));
 74     write(fd0,buf,sizeof(buf));
 75     read(fd0,buf,sizeof(buf));
 76     for(i=0;i<sizeof(buf);i++)
 77     {
 78         printf("%d ",buf[i]);
 79     }
 80     printf("\n");
 81
 82     //清空
 83     ioctl(fd0,CHAR_DRIVER_CLEAR);
 84     read(fd0,buf,sizeof(buf));
 85     for(i=0;i<sizeof(buf);i++)
 86     {
 87         printf("%d ",buf[i]);
 88     }
 89     printf("\n");
 90
 91     //格式化
 92     ioctl(fd0,CHAR_DRIVER_SET_MEM,c);
 93     read(fd0,buf,sizeof(buf));
 94     for(i=0;i<sizeof(buf);i++)
 95     {
 96         printf("%d ",buf[i]);
 97     }
 98     printf("\n");
 99
100     //从55开始2s增加1
101     ioctl(fd0,CHAR_DRIVER_START,55);
102     while(1)
103     {
104         FD_ZERO(&fds);
105         FD_SET(fd0, &fds);
106         timeout.tv_sec     = 0;
107         timeout.tv_usec = 1000000;
108         switch (select(fd0 + 1, &fds, NULL, NULL, &timeout))
109         {
110             case -1:
111                 printf("wrong\n");
112                 break;
113             case 0:
114                 printf("time out\n");
115                 break;
116             default:
117                 printf("I get it\n");
118                 read(fd0,buf,sizeof(buf));
119                 for(i=0;i<sizeof(buf);i++)
120                 {
121                     printf("%d ",buf[i]);
122                 }
123                 printf("\n");
124                 break;
125         }
126     }
127
128     return 0;
129 }

有错误请留言

时间: 2024-08-01 11:29:44

Linux 字符驱动的相关文章

Linux字符驱动

学习完了字符驱动,是按照宋宝华的Linux设备驱动开发讲解学习的,代码练习敲了一遍,自己也理解了. 字符驱动主要的就是一些open,close,read,write等操作 通过上层调用到自己写的底层函数 这里写代码片 #include <linux/fs.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/errno.

05 Linux字符驱动---静态注册

1. mycdev.c 1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/cdev.h> 4 #include <linux/fs.h> 5 6 #define MAJOR_NUM 250 7 8 struct mycdev 9 { 10 struct cdev cdev; 11 }; 12 13 int mycdev_open(struct inode *inod

08 Linux字符驱动---信号量

1. mycdev.c 1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/cdev.h> 4 #include <linux/fs.h> 5 #include <linux/device.h> 6 #include <linux/err.h> 7 #include <linux/uaccess.h> 8 #include <

07 Linux字符驱动---read/write/ioctl

1. mycdev.c 1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/cdev.h> 4 #include <linux/fs.h> 5 #include <linux/device.h> 6 #include <linux/err.h> 7 #include <linux/uaccess.h> 8 #include <

linux字符设备驱动

一.字符设备.字符设备驱动与用户空间访问该设备的程序三者之间的关系. 如图,在Linux内核中使用cdev结构体来描述字符设备,通过其成员dev_t来定义设备号(分为主.次设备号)以确定字符设备的唯一性.通过其成员file_operations来定义字符设备驱动提供给VFS的接口函数,如常见的open().read().write()等. 在Linux字符设备驱动中,模块加载函数通过register_chrdev_region( ) 或alloc_chrdev_region( )来静态或者动态获

linux设备驱动第三篇:写一个简单的字符设备驱动

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存. 下面就开始学习如何写一个简单的字符设备驱动.首先我们来分解一下字符设备驱动都有那些结构或者方法组成,也就是说实现一个可以使用的字符设备驱动我们必须做些什么工作. 1.主设备号和次设备号 对于字符设备的访问是通过文件系统中的设备名称进行的.他们通常位于/dev目录下.如下: [plain] vie

Linux设备驱动基本框架(字符设备)

Linux设备驱动都是以内核模块的形式出现的,但模块不一定是驱动.驱动可以编译进内核,在配置内核时,如果把某个配置项设为m,那么它将会随着内核编译时被编译成一个模块,但是这样向内核添加驱动程序会使得内核变得很大,而且在增加.修改.删除驱动程序时需要再一次编译内核,这样做极为麻烦.所以一般的驱动程序都是采用模块化装载,在需要使用时候通过insmod装载进内核,不需要使用时用rmmod卸载驱动模块. 内核模块的主要相关命令: lsmod:查看当前内核装载有哪些模块 insmod:加载模块 rmmod

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

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

linux设备驱动第三篇:如何写一个简单的字符设备驱动?

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存. 下面就开始学习如何写一个简单的字符设备驱动.首先我们来分解一下字符设备驱动都有那些结构或者方法组成,也就是说实现一个可以使用的字符设备驱动我们必须做些什么工作. 1.主设备号和次设备号 对于字符设备的访问是通过文件系统中的设备名称进行的.他们通常位于/dev目录下.如下: [email prot