Linux字符设备驱动--No.3
Posted embeded-linux
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux字符设备驱动--No.3相关的知识,希望对你有一定的参考价值。
字符驱动(按键)初始化函数分析:
1 int charDrvInit(void) 2 { 3 4 devNum = MKDEV(reg_major, reg_minor); 5 6 printk(KERN_EMERG"devNum is %d ", devNum); 7 if(OK == register_chrdev_region(devNum, subDevNum, DEVICE_NAME)) 8 { 9 printk(KERN_EMERG"register_chrdev_region ok "); 10 } 11 else 12 { 13 printk(KERN_EMERG"register_chrdev_region error "); 14 return ERROR; 15 } 16
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;
1 static struct char_device_struct { 2 struct char_device_struct *next; 3 unsigned int major; 4 unsigned int baseminor; 5 int minorct; 6 char name[64]; 7 struct cdev *cdev; /* will die */ 8 } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
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);
1 /* 2 * Register a single major with a specified minor range. 3 * 4 * If major == 0 this functions will dynamically allocate a major and return 5 * its number. 6 * 7 * If major > 0 this function will attempt to reserve the passed range of 8 * minors and will return zero on success. 9 * 10 * Returns a -ve errno on failure. 11 */ 12 static struct char_device_struct * 13 __register_chrdev_region(unsigned int major, unsigned int baseminor, 14 int minorct, const char *name) 15 { 16 struct char_device_struct *cd, **cp; 17 int ret = 0; 18 int i; 19 20 cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL); 21 if (cd == NULL) 22 return ERR_PTR(-ENOMEM); 23 24 mutex_lock(&chrdevs_lock); 25 26 /* temporary */
//如果主设备号为零,则自动分配主设备号(从大到小)并返回 27 if (major == 0) { 28 for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) { 29 if (chrdevs[i] == NULL) 30 break; 31 } 32 33 if (i == 0) { 34 ret = -EBUSY; 35 goto out; 36 } 37 major = i; 38 ret = major; 39 } 40 41 cd->major = major; 42 cd->baseminor = baseminor; 43 cd->minorct = minorct; 44 strlcpy(cd->name, name, sizeof(cd->name)); 45 46 i = major_to_index(major); 47
1 /* index in the above */ 2 static inline int major_to_index(unsigned major) 3 { 4 return major % CHRDEV_MAJOR_HASH_SIZE; 5 }
48 for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) 49 if ((*cp)->major > major || 50 ((*cp)->major == major && 51 (((*cp)->baseminor >= baseminor) || 52 ((*cp)->baseminor + (*cp)->minorct > baseminor)))) 53 break; 54 55 /* Check for overlapping minor ranges. */ 56 if (*cp && (*cp)->major == major) { 57 int old_min = (*cp)->baseminor; 58 int old_max = (*cp)->baseminor + (*cp)->minorct - 1; 59 int new_min = baseminor; 60 int new_max = baseminor + minorct - 1; 61 62 /* New driver overlaps from the left. */ 63 if (new_max >= old_min && new_max <= old_max) { 64 ret = -EBUSY; 65 goto out; 66 } 67 68 /* New driver overlaps from the right. */ 69 if (new_min <= old_max && new_min >= old_min) { 70 ret = -EBUSY; 71 goto out; 72 } 73 } 74 75 cd->next = *cp; 76 *cp = cd; 77 mutex_unlock(&chrdevs_lock); 78 return cd; 79 out: 80 mutex_unlock(&chrdevs_lock); 81 kfree(cd); 82 return ERR_PTR(ret); 83 }
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 }
17 18 gDev = kzalloc(sizeof(struct cdev), GFP_KERNEL); 19 gFile = kzalloc(sizeof(struct file_operations), GFP_KERNEL); 20 21 gFile->open = butsOpen; 22 //注册设备函数到file_operations结构体gFile 23 24 //gDev->owner = THIS_MODULE; 25 gFile->owner = THIS_MODULE; 26 cdev_init(gDev, gFile); 27 //在cdev结构体中添加指针指向file_operations结构体gFile 28 cdev_add(gDev, devNum, 3); 29 //建立设备号与cdev结构体联系 30 printk(KERN_EMERG"button driver initial done... "); 31 return 0; 32 }
以上是关于Linux字符设备驱动--No.3的主要内容,如果未能解决你的问题,请参考以下文章