字符设备---多个设备

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符设备---多个设备相关的知识,希望对你有一定的参考价值。

方法是:

(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);

 

以上是关于字符设备---多个设备的主要内容,如果未能解决你的问题,请参考以下文章

Linux字符设备驱动实现

一个活动或单独活动中的多个片段

活动/片段转换是不是与棒棒糖之前的设备兼容?

一个主设备号是如何支持多个次设备?

添加两个窗格的平板电脑布局会导致在移动设备中找不到视图(小于w600dp)

如何处理单个活动的多个片段