Linux-2.6驱动开发 7 设备命名
7 设备命名7.1 设备名称/dev里的文件的三个重要部分:Major(主号),Minor(次号),名称。主号代表类型,次号代表设备;应用程序打开设备路径后,系统会去主号代表的这类设备驱动搜索与次号匹配的驱动。Major Minor Name0 Unnamed devices (e.g. non-device mounts) 0 = re
7 设备命名
7.1 设备名称
/dev里的文件的三个重要部分:Major(主号),Minor(次号),名称。
主号代表类型,次号代表设备;应用程序打开设备路径后,系统会去主号代表的这类设备驱动搜索与次号匹配的驱动。
Major Minor Name
0 Unnamed devices (e.g. non-device mounts)
0 = reserved as null device number
See block major 144, 145, 146 for expansion areas.
1 char Memory devices
1 = /dev/mem Physical memory access
2 = /dev/kmem Kernel virtual memory access
3 = /dev/null Null device
4 = /dev/port I/O port access
5 = /dev/zero Null byte source
6 = /dev/core OBSOLETE - replaced by /proc/kcore
7 = /dev/full Returns ENOSPC on write
8 = /dev/random Nondeterministic random number gen.
9 = /dev/urandom Faster, less secure random number gen.
10 = /dev/aio Asynchronous I/O notification interface
11 = /dev/kmsg Writes to this come out as printk's
12 = /dev/oldmem Used by crashdump kernels to access
the memory of the kernel that crashed.
1 block RAM disk
0 = /dev/ram0 First RAM disk
1 = /dev/ram1 Second RAM disk
...
250 = /dev/initrd Initial RAM disk {2.6}
Older kernels had /dev/ramdisk (1, 1) here.
/dev/initrd refers to a RAM disk which was preloaded
by the boot loader; newer kernels use /dev/ram0 for
the initrd.
2 char Pseudo-TTY masters
0 = /dev/ptyp0 First PTY master
1 = /dev/ptyp1 Second PTY master
...
255 = /dev/ptyef 256th PTY master
Pseudo-tty's are named as follows:
* Masters are "pty", slaves are "tty";
* the fourth letter is one of pqrstuvwxyzabcde indicating
the 1st through 16th series of 16 pseudo-ttys each, and
* the fifth letter is one of 0123456789abcdef indicating
the position within the series.
These are the old-style (BSD) PTY devices; Unix98
devices are on major 128 and above and use the PTY
master multiplex (/dev/ptmx) to acquire a PTY on
demand.
...
其他部分参阅<<附录一>>。
7.2 sysfs
Sysfs是基于ram的一种文件系统;它的功能是将内核里的数据结构、属性、链接等导出到用户空间,也就是内核启动后创建了如下目录及目录下的文件。
block/
bus/
class/
dev/
devices/
firmware/
net/
fs/
7.3 总线类型
驱动在注册时要标明属于哪种总线类型,总线类型有如下几种:
platform
i2c
scsi
usb
serio
mmc
sdio
ac97
w1
hid
如下是platform总线类型驱动的注册:
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
if (drv->pm)
drv->driver.pm = &drv->pm->base;
return driver_register(&drv->driver);
}
7.4 主号和次号
驱动注册时通过device_create函数指定设备号,驱动注册后,会以“add”事件用uevent方式通知用户空间,告知有新设备加入;uevent含有该设备的主号和次号,用户程序就可以根据这个来创建/dev 下的设备文件了。
如下是驱动注册后发起的uevent:
static int dev_uevent(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env)
{
struct device *dev = to_dev(kobj);
int retval = 0;
/* add the major/minor if present */
if (MAJOR(dev->devt)) {
add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
}
...
}
如下以字符设备为例,说明设备号的注册:
Driver/char/misc.c
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) {
int i = DYNAMIC_MINORS;
while (--i >= 0)
if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
break;
if (i<0) {
mutex_unlock(&misc_mtx);
return -EBUSY;
}
misc->minor = i;
}
if (misc->minor < DYNAMIC_MINORS)
misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
dev = MKDEV(MISC_MAJOR, misc->minor);
misc->this_device = device_create(misc_class, misc->parent, dev, NULL,
"%s", misc->name);
if (IS_ERR(misc->this_device)) {
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_DYNAMIC_MINOR,则进行动态分配。
7.5 设备命名
设备名称是与设备号一起注册的,如7.5所提到的
device_create(misc_class, misc->parent, dev, NULL,"%s", misc->name);
如下以字符设备为例,说明设备在/dev目录下设备文件的命名:
static struct miscdevice hsdetect_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "micco_hsdetect",
.fops = &hsdetect_fops,
};
ret = misc_register(&hsdetect_miscdev);
micco_hsdetect 就是该驱动在/dev目录下设备文件的名称.
7.6 创建设备文件
通过捕获uevent事件,识别到有新设备加入,则根据uevent附带的设备号,使用mknod函数在/dev目录下创建设备文件。
如下以android的init进程为例:
static void make_device(const char *path, int block, int major, int minor)
{
unsigned uid;
unsigned gid;
mode_t mode;
dev_t dev;
if(major > 255 || minor > 255)
return;
mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
dev = (major << 8) | minor;
mknod(path, mode, dev);
chown(path, uid, gid);
}
static void handle_device_event(struct uevent *uevent)
{
char devpath[96];
char *base, *name;
int block;
/* if it's not a /dev device, nothing to do */
if((uevent->major < 0) || (uevent->minor < 0))
return;
/* do we have a name? */
name = strrchr(uevent->path, '/');
if(!name)
return;
name++;
/* too-long names would overrun our buffer */
if(strlen(name) > 64)
return;
/* are we block or char? where should we live? */
if(!strncmp(uevent->subsystem, "block", 5)) {
block = 1;
base = "/dev/block/";
mkdir(base, 0755);
} else {
block = 0;
/* this should probably be configurable somehow */
if(!strncmp(uevent->subsystem, "graphics", 8)) {
base = "/dev/graphics/";
mkdir(base, 0755);
} else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
base = "/dev/oncrpc/";
mkdir(base, 0755);
} else if (!strncmp(uevent->subsystem, "adsp", 4)) {
base = "/dev/adsp/";
mkdir(base, 0755);
} else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
base = "/dev/msm_camera/";
mkdir(base, 0755);
} else if(!strncmp(uevent->subsystem, "input", 5)) {
base = "/dev/input/";
mkdir(base, 0755);
} else if(!strncmp(uevent->subsystem, "mtd", 3)) {
base = "/dev/mtd/";
mkdir(base, 0755);
} else if(!strncmp(uevent->subsystem, "sound", 5)) {
//base = "/dev/snd/";
//mkdir(base, 0755);
base = "/dev/";
} else if(!strncmp(uevent->subsystem, "misc", 4) &&
!strncmp(name, "log_", 4)) {
base = "/dev/log/";
mkdir(base, 0755);
name += 4;
} else
base = "/dev/";
}
snprintf(devpath, sizeof(devpath), "%s%s", base, name);
if(!strcmp(uevent->action, "add")) {
make_device(devpath, block, uevent->major, uevent->minor);
return;
}
if(!strcmp(uevent->action, "remove")) {
unlink(devpath);
return;
}
}
更多推荐
所有评论(0)