1,设备描述符globalmem的代码如下所示:
1 /* 2 * a simple char device driver: globalmem without mutex 3 * 4 * Copyright (C) 2014 Barry Song (baohua@kernel.org) 5 * 6 * Licensed under GPLv2 or later. 7 */ 8 9 #include <linux/module.h> 10 #include <linux/fs.h> 11 #include <linux/init.h> 12 #include <linux/cdev.h> 13 #include <linux/slab.h> 14 #include <linux/uaccess.h> 15 16 #define GLOBALMEM_SIZE 0x1000 17 #define MEM_CLEAR 0x1 18 #define GLOBALMEM_MAJOR 230 19 20 static int globalmem_major = GLOBALMEM_MAJOR; 21 module_param(globalmem_major, int, S_IRUGO); 22 23 struct globalmem_dev { 24 struct cdev cdev; 25 unsigned char mem[GLOBALMEM_SIZE]; 26 }; 27 28 struct globalmem_dev *globalmem_devp; 29 30 static int globalmem_open(struct inode *inode, struct file *filp) 31 { 32 filp->private_data = globalmem_devp; 33 return 0; 34 } 35 36 static int globalmem_release(struct inode *inode, struct file *filp) 37 { 38 return 0; 39 } 40 41 static long globalmem_ioctl(struct file *filp, unsigned int cmd, 42 unsigned long arg) 43 { 44 struct globalmem_dev *dev = filp->private_data; 45 46 switch (cmd) { 47 case MEM_CLEAR: 48 memset(dev->mem, 0, GLOBALMEM_SIZE); 49 printk(KERN_INFO "globalmem is set to zero\n"); 50 break; 51 52 default: 53 return -EINVAL; 54 } 55 56 return 0; 57 } 58 59 static ssize_t globalmem_read(struct file *filp, char __user * buf, size_t size, 60 loff_t * ppos) 61 { 62 unsigned long p = *ppos; 63 unsigned int count = size; 64 int ret = 0; 65 struct globalmem_dev *dev = filp->private_data; 66 67 if (p >= GLOBALMEM_SIZE) 68 return 0; 69 if (count > GLOBALMEM_SIZE - p) 70 count = GLOBALMEM_SIZE - p; 71 72 if (copy_to_user(buf, dev->mem + p, count)) { 73 ret = -EFAULT; 74 } else { 75 *ppos += count; 76 ret = count; 77 78 printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p); 79 } 80 81 return ret; 82 } 83 84 static ssize_t globalmem_write(struct file *filp, const char __user * buf, 85 size_t size, loff_t * ppos) 86 { 87 unsigned long p = *ppos; 88 unsigned int count = size; 89 int ret = 0; 90 struct globalmem_dev *dev = filp->private_data; 91 92 if (p >= GLOBALMEM_SIZE) 93 return 0; 94 if (count > GLOBALMEM_SIZE - p) 95 count = GLOBALMEM_SIZE - p; 96 97 if (copy_from_user(dev->mem + p, buf, count)) 98 ret = -EFAULT; 99 else { 100 *ppos += count; 101 ret = count; 102 103 printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p); 104 } 105 106 return ret; 107 } 108 109 static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig) 110 { 111 loff_t ret = 0; 112 switch (orig) { 113 case 0: 114 if (offset < 0) { 115 ret = -EINVAL; 116 break; 117 } 118 if ((unsigned int)offset > GLOBALMEM_SIZE) { 119 ret = -EINVAL; 120 break; 121 } 122 filp->f_pos = (unsigned int)offset; 123 ret = filp->f_pos; 124 break; 125 case 1: 126 if ((filp->f_pos + offset) > GLOBALMEM_SIZE) { 127 ret = -EINVAL; 128 break; 129 } 130 if ((filp->f_pos + offset) < 0) { 131 ret = -EINVAL; 132 break; 133 } 134 filp->f_pos += offset; 135 ret = filp->f_pos; 136 break; 137 default: 138 ret = -EINVAL; 139 break; 140 } 141 return ret; 142 } 143 144 static const struct file_operations globalmem_fops = { 145 .owner = THIS_MODULE, 146 .llseek = globalmem_llseek, 147 .read = globalmem_read, 148 .write = globalmem_write, 149 .unlocked_ioctl = globalmem_ioctl, 150 .open = globalmem_open, 151 .release = globalmem_release, 152 }; 153 154 static void globalmem_setup_cdev(struct globalmem_dev *dev, int index) 155 { 156 int err, devno = MKDEV(globalmem_major, index); 157 158 cdev_init(&dev->cdev, &globalmem_fops); 159 dev->cdev.owner = THIS_MODULE; 160 err = cdev_add(&dev->cdev, devno, 1); 161 if (err) 162 printk(KERN_NOTICE "Error %d adding globalmem%d", err, index); 163 } 164 165 static int __init globalmem_init(void) 166 { 167 int ret; 168 dev_t devno = MKDEV(globalmem_major, 0); 169 170 if (globalmem_major) 171 ret = register_chrdev_region(devno, 1, "globalmem"); 172 else { 173 ret = alloc_chrdev_region(&devno, 0, 1, "globalmem"); 174 globalmem_major = MAJOR(devno); 175 } 176 if (ret < 0) 177 return ret; 178 179 globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL); 180 if (!globalmem_devp) { 181 ret = -ENOMEM; 182 goto fail_malloc; 183 } 184 185 globalmem_setup_cdev(globalmem_devp, 0); 186 return 0; 187 188 fail_malloc: 189 unregister_chrdev_region(devno, 1); 190 return ret; 191 } 192 module_init(globalmem_init); 193 194 static void __exit globalmem_exit(void) 195 { 196 cdev_del(&globalmem_devp->cdev); 197 kfree(globalmem_devp); 198 unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); 199 } 200 module_exit(globalmem_exit); 201 202 MODULE_AUTHOR("Barry Song <baohua@kernel.org>"); 203 MODULE_LICENSE("GPL v2");
1.1 l68行的globalmem_init()中的 dev_t devno = MKDEV(globalmem_major, 0);
1)其中dev_t的定义如下所示:
typedef __u32 __kernel_dev_t; typedef __kernel_fd_set fd_set; typedef __kernel_dev_t dev_t;
dev_t实际上是32bit的无符号类型;
2)MKDEV()原型如下所示:
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
dev_t devno = MKDEV(globalmem_major, 0);----表示主设备号是globalmem_major,次设备号是0;通过MKDEV之后,得到的是32位的设备号
MAJOR是通过设备号获取主设备号;MINOR是通过设备号获取次设备号;12位为主设备号,20位为次设备号
1.2 第171行 ret = register_chrdev_region(devno, 1, "globalmem"); register_chrdev_region的原型如下所示:from表示设备号起始地址,count表示设备个数,*name表示设备名
1 /** 2 * register_chrdev_region() - register a range of device numbers 3 * @from: the first in the desired range of device numbers; must include 4 * the major number. 5 * @count: the number of consecutive device numbers required 6 * @name: the name of the device or driver. 7 * 8 * Return value is zero on success, a negative error code on failure. 9 */ 10 int register_chrdev_region(dev_t from, unsigned count, const char *name) 11 { 12 struct char_device_struct *cd; 13 dev_t to = from + count; 14 dev_t n, next; 15 16 for (n = from; n < to; n = next) { 17 next = MKDEV(MAJOR(n)+1, 0); 18 if (next > to) 19 next = to; 20 cd = __register_chrdev_region(MAJOR(n), MINOR(n), 21 next - n, name); 22 if (IS_ERR(cd)) 23 goto fail; 24 } 25 return 0; 26 fail: 27 to = n; 28 for (n = from; n < to; n = next) { 29 next = MKDEV(MAJOR(n)+1, 0); 30 kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); 31 } 32 return PTR_ERR(cd); 33 }
1.3 第179行 globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
1)kzalloc的源码如下所示:
/** * kzalloc - allocate memory. The memory is set to zero. * @size: how many bytes of memory are required. * @flags: the type of memory to allocate (see kmalloc). */ static inline void *kzalloc(size_t size, gfp_t flags) { return kmalloc(size, flags | __GFP_ZERO); }
其中gfp_t定义为 typedef unsigned __bitwise__ gfp_t; 是bitwise类型的,个人理解类似独热码
2)GFP_KERNEL定义如下所示:
#define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS)
其中__GFP_WAIT等的定义如下所示:
1 /* Plain integer GFP bitmasks. Do not use this directly. */ 2 #define ___GFP_DMA 0x01u 3 #define ___GFP_HIGHMEM 0x02u 4 #define ___GFP_DMA32 0x04u 5 #define ___GFP_MOVABLE 0x08u 6 #define ___GFP_WAIT 0x10u 7 #define ___GFP_HIGH 0x20u 8 #define ___GFP_IO 0x40u 9 #define ___GFP_FS 0x80u 10 #define ___GFP_COLD 0x100u 11 #define ___GFP_NOWARN 0x200u 12 #define ___GFP_REPEAT 0x400u 13 #define ___GFP_NOFAIL 0x800u 14 #define ___GFP_NORETRY 0x1000u 15 #define ___GFP_MEMALLOC 0x2000u 16 #define ___GFP_COMP 0x4000u 17 #define ___GFP_ZERO 0x8000u 18 #define ___GFP_NOMEMALLOC 0x10000u 19 #define ___GFP_HARDWALL 0x20000u 20 #define ___GFP_THISNODE 0x40000u 21 #define ___GFP_RECLAIMABLE 0x80000u 22 #define ___GFP_NOTRACK 0x200000u 23 #define ___GFP_NO_KSWAPD 0x400000u 24 #define ___GFP_OTHER_NODE 0x800000u 25 #define ___GFP_WRITE 0x1000000
1.4 在globalmem_setup_cdev中进行了cdev_init和cdev_add操作,其中cdev_init的globalmem_fops是144行的file_operations函数,file_operations中的open等函数又单独实现,这里不再详细注解;
1.5在globalmem_exit函数中,先调用cdev_del删除已经add的globalmem字符设备,然后调用kfree释放globalmem_devp的空间;之后unregiter_chrdev_region解除注册
2,mult_globalmem
当有多个同类型的字符设备globalmem的时候,字符设备驱动的修改点也比较少,具体代码如下所示:
1 /* 2 * a simple char device driver: globalmem without mutex 3 * 4 * Copyright (C) 2014 Barry Song (baohua@kernel.org) 5 * 6 * Licensed under GPLv2 or later. 7 */ 8 9 #include <linux/module.h> 10 #include <linux/fs.h> 11 #include <linux/init.h> 12 #include <linux/cdev.h> 13 #include <linux/slab.h> 14 #include <linux/uaccess.h> 15 16 #define GLOBALMEM_SIZE 0x1000 17 #define MEM_CLEAR 0x1 18 #define GLOBALMEM_MAJOR 230 19 #define DEVICE_NUM 10 #表示10个同样的字符设备 20 21 static int globalmem_major = GLOBALMEM_MAJOR; 22 module_param(globalmem_major, int, S_IRUGO); 23 24 struct globalmem_dev { 25 struct cdev cdev; 26 unsigned char mem[GLOBALMEM_SIZE]; 27 }; 28 29 struct globalmem_dev *globalmem_devp; 30 31 static int globalmem_open(struct inode *inode, struct file *filp) 32 { 33 struct globalmem_dev *dev = container_of(inode->i_cdev, 34 struct globalmem_dev, cdev); 35 filp->private_data = dev; 36 return 0; 37 } 38 39 static int globalmem_release(struct inode *inode, struct file *filp) 40 { 41 return 0; 42 } 43 44 static long globalmem_ioctl(struct file *filp, unsigned int cmd, 45 unsigned long arg) 46 { 47 struct globalmem_dev *dev = filp->private_data; 48 49 switch (cmd) { 50 case MEM_CLEAR: 51 memset(dev->mem, 0, GLOBALMEM_SIZE); 52 printk(KERN_INFO "globalmem is set to zero\n"); 53 break; 54 55 default: 56 return -EINVAL; 57 } 58 59 return 0; 60 } 61 62 static ssize_t globalmem_read(struct file *filp, char __user * buf, size_t size, 63 loff_t * ppos) 64 { 65 unsigned long p = *ppos; 66 unsigned int count = size; 67 int ret = 0; 68 struct globalmem_dev *dev = filp->private_data; 69 70 if (p >= GLOBALMEM_SIZE) 71 return 0; 72 if (count > GLOBALMEM_SIZE - p) 73 count = GLOBALMEM_SIZE - p; 74 75 if (copy_to_user(buf, dev->mem + p, count)) { 76 ret = -EFAULT; 77 } else { 78 *ppos += count; 79 ret = count; 80 81 printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p); 82 } 83 84 return ret; 85 } 86 87 static ssize_t globalmem_write(struct file *filp, const char __user * buf, 88 size_t size, loff_t * ppos) 89 { 90 unsigned long p = *ppos; 91 unsigned int count = size; 92 int ret = 0; 93 struct globalmem_dev *dev = filp->private_data; 94 95 if (p >= GLOBALMEM_SIZE) 96 return 0; 97 if (count > GLOBALMEM_SIZE - p) 98 count = GLOBALMEM_SIZE - p; 99 100 if (copy_from_user(dev->mem + p, buf, count)) 101 ret = -EFAULT; 102 else { 103 *ppos += count; 104 ret = count; 105 106 printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p); 107 } 108 109 return ret; 110 } 111 112 static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig) 113 { 114 loff_t ret = 0; 115 switch (orig) { 116 case 0: 117 if (offset < 0) { 118 ret = -EINVAL; 119 break; 120 } 121 if ((unsigned int)offset > GLOBALMEM_SIZE) { 122 ret = -EINVAL; 123 break; 124 } 125 filp->f_pos = (unsigned int)offset; 126 ret = filp->f_pos; 127 break; 128 case 1: 129 if ((filp->f_pos + offset) > GLOBALMEM_SIZE) { 130 ret = -EINVAL; 131 break; 132 } 133 if ((filp->f_pos + offset) < 0) { 134 ret = -EINVAL; 135 break; 136 } 137 filp->f_pos += offset; 138 ret = filp->f_pos; 139 break; 140 default: 141 ret = -EINVAL; 142 break; 143 } 144 return ret; 145 } 146 147 static const struct file_operations globalmem_fops = { 148 .owner = THIS_MODULE, 149 .llseek = globalmem_llseek, 150 .read = globalmem_read, 151 .write = globalmem_write, 152 .unlocked_ioctl = globalmem_ioctl, 153 .open = globalmem_open, 154 .release = globalmem_release, 155 }; 156 157 static void globalmem_setup_cdev(struct globalmem_dev *dev, int index) 158 { 159 int err, devno = MKDEV(globalmem_major, index); 160 161 cdev_init(&dev->cdev, &globalmem_fops); 162 dev->cdev.owner = THIS_MODULE; 163 err = cdev_add(&dev->cdev, devno, 1); 164 if (err) 165 printk(KERN_NOTICE "Error %d adding globalmem%d", err, index); 166 } 167 168 static int __init globalmem_init(void) 169 { 170 int ret; 171 int i; 172 dev_t devno = MKDEV(globalmem_major, 0); 173 174 if (globalmem_major) 175 ret = register_chrdev_region(devno, DEVICE_NUM, "globalmem"); #注册10个,设备号累加 176 else { 177 ret = alloc_chrdev_region(&devno, 0, DEVICE_NUM, "globalmem"); 178 globalmem_major = MAJOR(devno); 179 } 180 if (ret < 0) 181 return ret; 182 183 globalmem_devp = kzalloc(sizeof(struct globalmem_dev) * DEVICE_NUM, GFP_KERNEL); 184 if (!globalmem_devp) { 185 ret = -ENOMEM; 186 goto fail_malloc; 187 } 188 189 for (i = 0; i < DEVICE_NUM; i++) 190 globalmem_setup_cdev(globalmem_devp + i, i); 191 192 return 0; 193 194 fail_malloc: 195 unregister_chrdev_region(devno, DEVICE_NUM); 196 return ret; 197 } 198 module_init(globalmem_init); 199 200 static void __exit globalmem_exit(void) 201 { 202 int i; 203 for (i = 0; i < DEVICE_NUM; i++) 204 cdev_del(&(globalmem_devp + i)->cdev); 205 kfree(globalmem_devp); 206 unregister_chrdev_region(MKDEV(globalmem_major, 0), DEVICE_NUM); 207 } 208 module_exit(globalmem_exit); 209 210 MODULE_AUTHOR("Barry Song <baohua@kernel.org>"); 211 MODULE_LICENSE("GPL v2");
mult_globalmem和globalmem的主要区别是在register_chrdev_region的时候指定了个数;对每个字符设备单独进行globalmem_setup_cdev,进行add;
相应的在cdev_del时每个单独进行,unregister的时候,需要指定个数
globalmem_open函数中的container_of在下面的文章中进行分析。
标签:struct,--,GFP,dev,int,globalmem,mult,ret From: https://www.cnblogs.com/zhiminyu/p/17572123.html