字符设备---多个设备

方法是:

(1)xxx_open函数中用struct file的文件私有数据指针保存struct mycdev结构体指针

(2)read/write函数中 struct mycdev *mycd = file->private_data;

  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/slab.h>
  7 #include <asm/uaccess.h>
  8 #include "dev_fifo_head.h"
  9
 10 //指定的主设备号
 11 #define MAJOR_NUM 250
 12
 13 //自己的字符设备
 14 struct mycdev
 15 {
 16     int len;
 17     unsigned char buffer[50];
 18     struct cdev cdev;
 19 };
 20
 21 MODULE_LICENSE("GPL");
 22
 23 //设备号
 24 static dev_t dev_num = {0};
 25
 26 //全局gcd
 27 struct mycdev *gcd;
 28
 29 //设备类
 30 struct class *cls;
 31
 32 //获得用户传递的数据,根据它来决定注册的设备个数
 33 static int ndevices = 1;
 34 module_param(ndevices, int, 0644);
 35 MODULE_PARM_DESC(ndevices, "The number of devices for register.\n");
 36
 37
 38 //打开设备
 39 static int dev_fifo_open(struct inode *inode, struct file *file)
 40 {
 41     struct mycdev *cd;
 42
 43     printk("dev_fifo_open success!\n");
 44
 45     //用struct file的文件私有数据指针保存struct mycdev结构体指针
 46     cd = container_of(inode->i_cdev,struct mycdev,cdev);
 47     file->private_data = cd;
 48
 49     return 0;
 50 }
 51
 52 //读设备
 53 static ssize_t dev_fifo_read(struct file *file, char __user *ubuf, size_t size, loff_t *ppos)
 54 {
 55     int n;
 56     int ret;
 57     char *kbuf;
 58     struct mycdev *mycd = file->private_data;
 59
 60     printk("read *ppos : %lld\n",*ppos);
 61
 62     if(*ppos == mycd->len)
 63         return 0;
 64
 65     //请求大大小 > buffer剩余的字节数 :读取实际记得字节数
 66     if(size > mycd->len - *ppos)
 67         n = mycd->len - *ppos;
 68     else
 69         n = size;
 70
 71     printk("n = %d\n",n);
 72     //从上一次文件位置指针的位置开始读取数据
 73     kbuf = mycd->buffer + *ppos;
 74
 75     //拷贝数据到用户空间
 76     ret = copy_to_user(ubuf,kbuf, n);
 77     if(ret != 0)
 78         return -EFAULT;
 79
 80     //更新文件位置指针的值
 81     *ppos += n;
 82
 83     printk("dev_fifo_read success!\n");
 84
 85     return n;
 86 }
 87
 88 //写设备
 89 static ssize_t dev_fifo_write(struct file *file, const char __user *ubuf, size_t size, loff_t *ppos)
 90 {
 91     int n;
 92     int ret;
 93     char *kbuf;
 94     struct mycdev *mycd = file->private_data;
 95
 96     printk("write *ppos : %lld\n",*ppos);
 97
 98     //已经到达buffer尾部了
 99     if(*ppos == sizeof(mycd->buffer))
100         return -1;
101
102     //请求大大小 > buffer剩余的字节数(有多少空间就写多少数据)
103     if(size > sizeof(mycd->buffer) - *ppos)
104         n = sizeof(mycd->buffer) - *ppos;
105     else
106         n = size;
107
108     //从上一次文件位置指针的位置开始写入数据
109     kbuf = mycd->buffer + *ppos;
110
111     //拷贝数据到内核空间
112     ret = copy_from_user(kbuf, ubuf, n);
113     if(ret != 0)
114         return -EFAULT;
115
116     //更新文件位置指针的值
117     *ppos += n;
118
119     //更新dev_fifo.len
120     mycd->len += n;
121
122     printk("dev_fifo_write success!\n");
123     return n;
124 }
125
126 //linux 内核在2.6以后,已经废弃了ioctl函数指针结构,取而代之的是unlocked_ioctl
127 long dev_fifo_unlocked_ioctl(struct file *file, unsigned int cmd,
128     unsigned long arg)
129 {
130     int ret = 0;
131     struct mycdev *mycd = file->private_data;
132
133     switch(cmd)
134     {
135         case DEV_FIFO_CLEAN:
136             printk("CMD:CLEAN\n");
137             memset(mycd->buffer, 0, sizeof(mycd->buffer));
138             break;
139
140         case DEV_FIFO_SETVALUE:
141             printk("CMD:SETVALUE\n");
142             mycd->len = arg;
143             break;
144
145         case DEV_FIFO_GETVALUE:
146             printk("CMD:GETVALUE\n");
147             ret = put_user(mycd->len, (int *)arg);
148             break;
149
150         default:
151             return -EFAULT;
152     }
153
154     return ret;
155 }
156
157
158 //设备操作函数接口
159 static const struct file_operations fifo_operations = {
160     .owner = THIS_MODULE,
161     .open = dev_fifo_open,
162     .read = dev_fifo_read,
163     .write = dev_fifo_write,
164     .unlocked_ioctl = dev_fifo_unlocked_ioctl,
165 };
166
167
168 //模块入口
169 int __init dev_fifo_init(void)
170 {
171     int i = 0;
172     int n = 0;
173     int ret;
174     struct device *device;
175
176     gcd = kzalloc(ndevices * sizeof(struct mycdev), GFP_KERNEL);
177     if(!gcd){
178         return -ENOMEM;
179     }
180
181     //设备号 : 主设备号(12bit) | 次设备号(20bit)
182     dev_num = MKDEV(MAJOR_NUM, 0);
183
184     //静态注册设备号
185     ret = register_chrdev_region(dev_num,ndevices,"dev_fifo");
186     if(ret < 0){
187
188         //静态注册失败,进行动态注册设备号
189         ret = alloc_chrdev_region(&dev_num,0,ndevices,"dev_fifo");
190         if(ret < 0){
191             printk("Fail to register_chrdev_region\n");
192             goto err_register_chrdev_region;
193         }
194     }
195
196     //创建设备类
197     cls = class_create(THIS_MODULE, "dev_fifo");
198     if(IS_ERR(cls)){
199         ret = PTR_ERR(cls);
200         goto err_class_create;
201     }
202
203     printk("ndevices : %d\n",ndevices);
204
205     for(n = 0;n < ndevices;n ++)
206     {
207         //初始化字符设备
208         cdev_init(&gcd[n].cdev,&fifo_operations);
209
210         //添加设备到操作系统
211         ret = cdev_add(&gcd[n].cdev,dev_num + n,1);
212         if (ret < 0)
213         {
214             goto err_cdev_add;
215         }
216         //导出设备信息到用户空间(/sys/class/类名/设备名)
217         device = device_create(cls,NULL,dev_num + n,NULL,"dev_fifo%d",n);
218         if(IS_ERR(device)){
219             ret = PTR_ERR(device);
220             printk("Fail to device_create\n");
221             goto err_device_create;
222         }
223     }
224     printk("Register dev_fito to system,ok!\n");
225
226
227     return 0;
228
229 err_device_create:
230     //将已经导出的设备信息除去
231     for(i = 0;i < n;i ++)
232     {
233         device_destroy(cls,dev_num + i);
234     }
235
236 err_cdev_add:
237     //将已经添加的全部除去
238     for(i = 0;i < n;i ++)
239     {
240         cdev_del(&gcd[i].cdev);
241     }
242
243 err_class_create:
244     unregister_chrdev_region(dev_num, ndevices);
245
246 err_register_chrdev_region:
247     return ret;
248
249 }
250
251 void __exit dev_fifo_exit(void)
252 {
253     int i;
254
255     //删除sysfs文件系统中的设备
256     for(i = 0;i < ndevices;i ++)
257     {
258         device_destroy(cls,dev_num + i);
259     }
260
261     //删除系统中的设备类
262     class_destroy(cls);
263
264     //从系统中删除添加的字符设备
265     for(i = 0;i < ndevices;i ++)
266     {
267         cdev_del(&gcd[i].cdev);
268     }
269
270     //释放申请的设备号
271     unregister_chrdev_region(dev_num, ndevices);
272
273     return;
274 }
275
276
277 module_init(dev_fifo_init);
278 module_exit(dev_fifo_exit);
时间: 2024-08-26 16:30:54

字符设备---多个设备的相关文章

linux字符设备-自动创建设备号和设备节点

Linux字符设备-自动创建设备号和设备节点 先写一个自动分配字符设备号和设备节点的例子及APP 手动安装步骤: Insmod my_char_dev.ko 不需要再安装设备节点 然后是测试app ./my_char_dev_app 1 1 #include <linux/module.h> 2 #include <linux/init.h> 3 #include <linux/io.h> 4 #include <linux/fs.h> 5 #include

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

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

驱动开发--【字符设备、块设备简介】【sky原创】

驱动开发   字符设备,块设备,网络设备 字符设备 以字节流的方式访问, 不能随机访问 有例外,显卡.EEPROM可以随机访问 EEPROM可以擦写1亿次,是一种字符设备,可以随机访问 读写是直接访问硬件的 flash 擦写次数有限,一百万次,容易有坏块 块设备 能随机访问 以”块“为单位进行访问 块大小一般为512字节 块的大小由硬件决定 是内核进行数据传输的基本单位 硬盘结构: 格式化分区是以柱面为单位的,即硬盘的柱面 如果有10个盘面,就有十个柱面 对于嵌入式设备 如果是flash的话,结

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

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

Linux平台块设备到字符设备(裸设备)的三种映射方式(转载)

在Linux平台oracle rac的组建过程中,如果使用ASM+RAW的存储方式的话,由于asm不支持块设备,支持持字符访问设备,所以需要配置将Block Device Drive转变成Character Device Drive的访问方式.但是在Linux平台中,不像aix和HP-UX中,默认提供了块设备对应的字符设备文件,需要我们手工的将块设备映射为字符设备.在此,我们提供三种方式来讲块设备绑定到裸设备上,这三种方式创建裸设备的方式完全一样,区别在于对oracle用户的权限的处理方式不同,

【原创】-- linux 字符设备,块设备,网络设备

参考地址:http://blog.chinaunix.net/uid-26322998-id-2981874.html 1.块设备 系统中能够随机(不需要按顺序)访问固定大小数据片(chunks)的设备被称作块设备,这些数据片就称作块.最常见的块设备是硬盘,除此以外,还有软盘驱动器.CD-ROM驱动器和闪存等等许多其他块设备.注意,它们都是以安装文件系统的方式使用的——这也是块设备一般的访问方式.一般访问单位为512k的整数倍. 2.字符设备 另一种基本的设备类型是字符设备.字符设备按照字符流的

自动创建字符设备驱动的设备文件结点

(1)什么是udev?应用层的一个应用程序(2)内核驱动和应用层udev之间有一套信息传输机制(netlink协议)(3)应用层启用udev,内核驱动中使用相应接口(4)驱动注册和注销时信息会被传给udev,由udev在应用层进行设备文件的创建和删除5.3.7.3.内核驱动设备类相关函数(驱动接口)(1)class_create(2)device_create 首先要注册字符设备 创建一个设备类   在/sys/class下会有一个adb文件 创建一个dev,    insmod时  在/dev

Linux中设备号及设备文件【转】

本文转载自:http://blog.csdn.net/ymangu666/article/details/39292651 主.次设备号 应用程序可以通过对/dev 目录下的设备文件读写,从而访问实际的设备.1)每个设备文件对应有两个设备号:主设备号,次设备号① 主设备号:标识该设备的类型,也表示了该设备所使用的驱动程序:  驱动程序在初始化时,会注册它的驱动及对应主设备号到系统中,可以通过/proc/devices 文件来驱动系统设备的主设备号.② 次设备号:表示使用同一设备驱动程序的不同硬件

设备与驱动的关系以及设备号、设备文件

Linux设备分类Linux下的设备通常分为三类,字符设备,块设备和网络设备. 字符设备 一个字符设备是一种字节流设备,对设备的存取只能按顺序按字节的存取而不能随机访问,字符设备没有请求缓冲区,所有的访问请求都是按顺序执行的.Linux下的大多设备都是字符设备.应用程序是通过字符设备节点来访问字符设备的.设备节点一般都由mknod命令都创建在/dev目录下,下面的例子显示了串口设备的设备节点.字符设备文件的第一个标志是前面的“c”标志. root#ls -l /dev/ttyS[0-3]crw-

Linux设备驱动--块设备(一)之概念和框架

基本概念   块设备(blockdevice) --- 是一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存放暂时的数据,待条件成熟后,从缓存一次性写入设备或者从设备一次性读到缓冲区. 字符设备(Character device) ---是一个顺序的数据流设备,对这种设备的读写是按字符进行的,而且这些字符是连续地形成一个数据流.他不具备缓冲区,所以对这种设备的读写是实时的. 扇区(Sectors):任何块设备硬件对数据处理的基本单位.通常,1个扇区的大小为512byt