您的位置:首页 > 其它

miscdevice混杂设备驱动

2015-09-05 17:06 387 查看
定义:字符设备的一种,它们共享一个主设备号(10),但次设备号不同,所有的混杂设备形成一个链表,对设备访问时内核根据次设备号查找到相应的miscdevice设备。

例如:触摸屏,LED,按键,串口。

即:为了节约主设备号,将某些设备用链表的形式连接在一起,最后通过查找次设备区分。这里用主设备无法匹配出设备驱动,只能找到链表,再通过次设备号,才能找到设备驱动。而之前所学的,一般字符设备,通过主设备号,就能找到设备驱动了。

混杂设备驱动内置有自动创建设备节点的代码,所以编译好之后,能自动创建设备节点。

相关的宏,定义在 kernel/include/linux/miscdevice.h



[cpp] view
plaincopy

#ifndef _LINUX_MISCDEVICE_H

#define _LINUX_MISCDEVICE_H

#include <linux/module.h>

#include <linux/major.h>

/*

* These allocations are managed by device@lanana.org. If you use an

* entry that is not in assigned your entry may well be moved and

* reassigned, or set dynamic if a fixed value is not justified.

*/

#define PSMOUSE_MINOR 1

#define MS_BUSMOUSE_MINOR 2

#define ATIXL_BUSMOUSE_MINOR 3

/*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */

#define ATARIMOUSE_MINOR 5

#define SUN_MOUSE_MINOR 6

#define APOLLO_MOUSE_MINOR 7

#define PC110PAD_MINOR 9

/*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */

#define WATCHDOG_MINOR 130 /* Watchdog timer */

#define TEMP_MINOR 131 /* Temperature Sensor */

#define RTC_MINOR 135

#define EFI_RTC_MINOR 136 /* EFI Time services */

#define SUN_OPENPROM_MINOR 139

#define DMAPI_MINOR 140 /* DMAPI */

#define NVRAM_MINOR 144

#define SGI_MMTIMER 153

#define STORE_QUEUE_MINOR 155

#define I2O_MINOR 166

#define MICROCODE_MINOR 184

#define TUN_MINOR 200

#define MWAVE_MINOR 219 /* ACP/Mwave Modem */

#define MPT_MINOR 220

#define MPT2SAS_MINOR 221

#define HPET_MINOR 228

#define FUSE_MINOR 229

#define KVM_MINOR 232

#define BTRFS_MINOR 234

#define AUTOFS_MINOR 235

#define MISC_DYNAMIC_MINOR 255

struct device;

struct miscdevice {

int minor;
//次设备号

const char *name;
//设备名

const struct file_operations *fops;//文件操作

struct list_head list;
//形成链表

struct device *parent;

struct device *this_device;

const char *nodename;

mode_t mode;

};

extern int misc_register(struct miscdevice * misc);
//混杂设备注册

extern int misc_deregister(struct miscdevice *misc);
//混杂设备注销

#define MODULE_ALIAS_MISCDEV(minor) \

MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \

"-" __stringify(minor))

#endif

杂项设备的核心函数的定义位于:kernel/drivers/char/misc.c

/**

* misc_register - register a miscellaneous device

* @misc: device structure

*

* Register a miscellaneous device with the kernel. If the minor

* number is set to %MISC_DYNAMIC_MINOR a minor number is assigned

* and placed in the minor field of the structure. For other cases

* the minor number requested is used.

*

* The structure passed is linked into the kernel and may not be

* destroyed until it has been unregistered.

*

* A zero is returned on success and a negative errno code for

* failure.

*/

int misc_register(struct miscdevice * misc)

{

struct miscdevice *c;

dev_t dev;

int err = 0;

INIT_LIST_HEAD(&misc->list);

mutex_lock(&misc_mtx);

list_for_each_entry(c, &misc_list, list) {

if (c->minor == misc->minor) {

mutex_unlock(&misc_mtx);

return -EBUSY;

}

}

if (misc->minor == MISC_DYNAMIC_MINOR) { //#define MISC_DYNAMIC_MINOR 255

int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); //#define DYNAMIC_MINORS 64 /* like dynamic majors */

if (i >= DYNAMIC_MINORS) {

mutex_unlock(&misc_mtx);

return -EBUSY;

}

misc->minor = DYNAMIC_MINORS - i - 1;

set_bit(i, misc_minors);

}

//获得设备号

dev = MKDEV(MISC_MAJOR, misc->minor); //#define MISC_MAJOR 10 // 在 kernel/include/linux/major.h 中定义。

misc->this_device = device_create(misc_class, misc->parent, dev, misc, "%s", misc->name);//说明了混杂设备驱动内部有自动设备驱动,可自动

//创建设备节点

if (IS_ERR(misc->this_device)) {

int i = DYNAMIC_MINORS - misc->minor - 1;

if (i < DYNAMIC_MINORS && i >= 0)

clear_bit(i, misc_minors);

err = PTR_ERR(misc->this_device);

goto out;

}

/*

* Add it to the front, so that later devices can "override"

* earlier defaults

*/

list_add(&misc->list, &misc_list);

out:

mutex_unlock(&misc_mtx);

return err;

}

/**

* misc_deregister - unregister a miscellaneous device

* @misc: device to unregister

*

* Unregister a miscellaneous device that was previously

* successfully registered with misc_register(). Success

* is indicated by a zero return, a negative errno code

* indicates an error.

*/

int misc_deregister(struct miscdevice *misc)

{

int i = DYNAMIC_MINORS - misc->minor - 1;

if (list_empty(&misc->list))

return -EINVAL;

mutex_lock(&misc_mtx);

list_del(&misc->list);

device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));

if (i < DYNAMIC_MINORS && i >= 0)

clear_bit(i, misc_minors);

EXPORT_SYMBOL(misc_register);

EXPORT_SYMBOL(misc_deregister);

static char *misc_devnode(struct device *dev, mode_t *mode)

{

struct miscdevice *c = dev_get_drvdata(dev);

if (mode && c->mode)

*mode = c->mode;

if (c->nodename)

return kstrdup(c->nodename, GFP_KERNEL);

return NULL;

}

static int __init misc_init(void)

{

int err;

#ifdef CONFIG_PROC_FS

proc_create("misc", 0, NULL, &misc_proc_fops);

#endif

misc_class = class_create(THIS_MODULE, "misc");

err = PTR_ERR(misc_class);

if (IS_ERR(misc_class))

goto fail_remove;

err = -EIO;

if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))

goto fail_printk;

misc_class->devnode = misc_devnode;

return 0;

fail_printk:

printk("unable to get major %d for misc devices\n", MISC_MAJOR);

class_destroy(misc_class);

fail_remove:

remove_proc_entry("misc", NULL);

return err;

}

subsys_initcall(misc_init);

以下是创建自动设备节点相关代码

"kernel/drivers/base/core.c"

struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)

{

va_list vargs;

struct device *dev;

va_start(vargs, fmt);

dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);

va_end(vargs);

return dev;

}

EXPORT_SYMBOL_GPL(device_create);

static int __match_devt(struct device *dev, void *data)

{

dev_t *devt = data;

return dev->devt == *devt;

}

/**

* device_destroy - removes a device that was created with device_create()

* @class: pointer to the struct class that this device was registered with

* @devt: the dev_t of the device that was previously registered

*

* This call unregisters and cleans up a device that was created with a

* call to device_create().

*/

void device_destroy(struct class *class, dev_t devt)

{

struct device *dev;

dev = class_find_device(class, NULL, &devt, __match_devt);

if (dev) {

put_device(dev);

device_unregister(dev);

}

}

EXPORT_SYMBOL_GPL(device_destroy);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: