Linux-2.6驱动开发 7 设备命名

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目录下创建设备文件。

如下以androidinit进程为例:

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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值