1. 程式人生 > >Linux(2.6.35.7)字元裝置驅動註冊介面

Linux(2.6.35.7)字元裝置驅動註冊介面

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);
}
  1. major : 裝置的主裝置號
  2. name : 裝置的名字(字串)
  3. 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);
}
  1. major: 已註冊裝置的主裝置號
  2. 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)
  1. from: 主裝置號+次裝置號
  2. count: 註冊裝置的個數
  3. 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)
  1. dev: 裝置號
  2. baseminor: 次裝置號的起始號
  3. count: 裝置個數
  4. 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