Linux(2.6.35.7)字元裝置驅動註冊介面
阿新 • • 發佈:2019-02-15
1. 老介面
(1)註冊函式
static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)
{
return __register_chrdev(major, 0, 256, name, fops);
}
- major : 裝置的主裝置號
- name : 裝置的名字(字串)
- fops : file_operations結構體
若major = 0,表示裝置號由核心自動分配,分配原則是分配一個未使用的最大的裝置號(1 ~ 254)
使用 register_chrdev
(2)登出函式
static inline void unregister_chrdev(unsigned int major, const char *name)
{
__unregister_chrdev(major, 0, 256, name);
}
- major: 已註冊裝置的主裝置號
- name: 已註冊裝置的名字
註冊例程
led_major = register_chrdev(0, DEVICE_NAME, &led_fops);
if(led_major < 0) {
printk(KERN_ERR "register chrdev failed.\n" );
return -EINVAL;
}
printk(KERN_INFO "register chrdev success. device major: %d\n", led_major);
登出例程
unregister_chrdev(led_major, DEVICE_NAME);
2. 新介面
新介面與老介面最大的不同在於把register_chrdev
函式中一次完成的事情(申請裝置號、註冊裝置號、註冊裝置)拆分出來各自處理。
(1) 註冊裝置號
【1】手動分配主次裝置號
int register_chrdev_region(dev_t from, unsigned count, const char *name)
- from: 主裝置號+次裝置號
- count: 註冊裝置的個數
- name: 裝置的名字
使用這個函式前需要通過巨集***MKDEV***得到主次裝置號
例程
from = MKDEV(250, 0);
register_chrdev_region(from, 1, "Test");
【2】自動分配主次裝置號
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
- dev: 裝置號
- baseminor: 次裝置號的起始號
- count: 裝置個數
- name: 裝置名
例程
retval = alloc_chrdev_region(&led_dev, 0, 1, DEVICE_NAME); // 分配主次裝置號
if(retval) {
printk(KERN_ERR "alloc_chrdev_region failed.\n");
goto alloc_region_err;
}
printk(KERN_INFO "major = %d, minor = %d\n", MAJOR(led_dev), MINOR(led_dev));
(2)註冊裝置
[1] 申請cdev結構體的記憶體空間
struct cdev *cdev_alloc(void)
{
struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
if (p) {
INIT_LIST_HEAD(&p->list);
kobject_init(&p->kobj, &ktype_cdev_dynamic);
}
return p;
}
[2] 將cdev和file_operations繫結
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
}
[3] 註冊裝置
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
p->dev = dev;
p->count = count;
return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}
例程
pcdev = cdev_alloc(); // 申請cdev記憶體空間
if(NULL == pcdev) {
printk(KERN_ERR "cdev_alloc failed.\n");
goto alloc_cdev_err;
}
// 繫結file_operations
pcdev->owner = THIS_MODULE;
pcdev->ops = &led_fops;
retval = cdev_add(pcdev, led_dev, 1); // 註冊裝置
if(retval) {
printk(KERN_ERR "cdev_add failed.\n");
goto add_cdev_err;
}
注意
若使用alloc_chrdev_region
來分配裝置號,則繫結file_operations
時可以直接繫結而不需要使用cdev_init
。