字符设备---多个设备
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);
以上是关于字符设备---多个设备的主要内容,如果未能解决你的问题,请参考以下文章