register_chrdev __register_chrdev(major, 0, 256, name, fops); struct char_device_struct *cd; cd = __register_chrdev_region(major, baseminor, count, name); cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL); //如果主設(shè)備號是0的話,就會從 char_device_struct數(shù)組中選擇一個沒有分配的char_device_struct結(jié)構(gòu)體 //如果找到的話,就以其下標(biāo)作為主設(shè)備號,否則出錯返回 cd->major = major; cd->baseminor = baseminor;//第一個次設(shè)備號 cd->minorct = minorct; //此設(shè)備號的個數(shù) strlcpy(cd->name, name, sizeof(cd->name));//設(shè)置名字 i = major_to_index(major); return major % CHRDEV_MAJOR_HASH_SIZE;//只有當(dāng)指定的主設(shè)備號大于255時,i才會不等于major //下面的工作比較難懂,可以參考注釋1 cdev = cdev_alloc(); //分配字符設(shè)備結(jié)構(gòu)體 cdev->owner = fops->owner; //設(shè)置字符設(shè)備結(jié)構(gòu)體 cdev->ops = fops; kobject_set_name(&cdev->kobj, "%s", name); //向上注冊,這里用到了cd->major和baseminor err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); 之前我們編寫字符設(shè)備驅(qū)動程序只是一個register_chrdev來完成,通過我們將這個函數(shù)分解開來就看出來了,如果使用register_chrdev的話,不能指定此設(shè)備號,那么就會默認baseminor=0,count=256。這就造成了浪費!因為一個主設(shè)備號下的所有此設(shè)備號都只能對應(yīng)同一個字符設(shè)備!如果我們使用__register_chrdev_region的話,情況就變了,我們可以指定baseminor和count,這樣就可以讓一個主設(shè)備號下每一個次設(shè)備號都對應(yīng)字節(jié)的字符設(shè)備了! 注釋1: 我們用個例子來說明__register_chrdev_region做了什么: 比如我們先注冊了3個字符設(shè)備,主設(shè)備號都是2,次設(shè)備號分別是0、1~2、3,那么經(jīng)過__register_chrdev_region這個函數(shù)就會形成下面的鏈表: 注意:不好意思,這邊有個小錯誤,那就是主設(shè)備號不能是0,要從1開始,而不是0! 如果此時如果再想注冊一個字符設(shè)備,它的主設(shè)備號是257,此設(shè)備號是0,那么會形成如下鏈表: 這里面有兩點是很重要的: 第一:chrdevs的每一項并不是只對應(yīng)一個與其下表相同的主設(shè)備號,而是對應(yīng)一系列主設(shè)備號,這些主設(shè)備號=“chrdevs下表+n*255”! 第二:chrdevs的每一項主設(shè)備號相同的字符設(shè)備此設(shè)備號不能有交集,主設(shè)備號不同的字符設(shè)備此設(shè)備號可以有交集! 從而我們也看到了__register_chrdev_region這個函數(shù)的功能,其實它也是實現(xiàn)一個互斥訪問的功能!
|
|