usb安装linux初始化,linux usb初始化

linux usb初始化

谨以此文纪念过往的岁月

一.前言

对于usb的普通驱动,我们了解了不少,但是对于usb的真正核心还是不是太理解。该文中对于usb的初始化进行一定的学习,如有不对之处,请各位多多指教。

二.usb子系统初始化。

话说在linux启动之初,就会将usb子系统初始化完成,亦如input子系统和V4L2一样。usb_init就完成了初始化以及启动usb hub守护进程。那来看usb_init中的各个函数的实现。

2.1 ksuspend_usb_init

static int ksuspend_usb_init(void)

{

ksuspend_usb_wq

= create_freezeable_workqueue("ksuspend_usbd");

if

(!ksuspend_usb_wq)

return

-ENOMEM;

return 0;

}

创建一个名为ksuspend_usbd的工作队列。不过在该函数说明中也说明了,该函数在多CPU中并不能很好的工作。也许大家对这个函数会很奇怪,不知道该工作队列的作用。

这个工作队列如何使用的,将在看usbsuspend和resume时再具体看这个东东具体有什么用。

2.2 bus_register

在usb_init中第二个调用的函数是bus_register(&usb_bus_type);这个应该很熟悉吧,注册一个usb总线,其会在/sys/bus下创建一个usb的文件夹,在其中会创建bus属性文件和drivers和devices文件夹,以后所有的usb设备和usb驱动都会在这两个文件夹下。bus总线需要指明device和driver匹配的规则,例如platform bus以name进行匹配,而usb则以id进行匹配。对于bus_register在前文中讲述多,这里不多此一举了。那主要来看usb bus的特征。

struct bus_type usb_bus_type = {

.name ="usb",--定义bus的name,这个也会是在/sys/bus下看见的文件夹得名称。

.match =usb_device_match,--定义bus的device和driver的匹配规则

.uevent =usb_uevent,--usb的触发事件处理。

};

下面来看usb的匹配规则函数。不过有一点需要说明的是一般usb的驱动为usb的interface的驱动,而不是usb设备的驱动。为了方便描述,并没有加以说明,要注意了。

static int usb_device_(struct

device *dev, struct device_driver *drv)

{

if

(is_usb_device(dev)) {--判断是否为usb

device

if (!is_usb_device_driver(drv)) --判断是否为为usb device的驱动。interface驱动不能与device匹配。

return

0;

return

1;--这个不是主要的,下面才是真正的驱动和设备的匹配。

} else {

struct

usb_interface *intf;

struct

usb_driver *usb_drv;

const

struct usb_device_id *id;

if (is_usb_device_driver(drv))--usb device driver不能驱动interface。

return

0;

intf =

to_usb_interface(dev);--取得设备的当前interface

usb_drv =

to_usb_driver(drv);--取得驱动。

id = usb_match_id(intf, usb_drv->id_table);--真正的匹配规则。对于这个函数我们就不加描述。感兴趣的可以去看具体的实现,其实这个函数的额实现也很简单。就是对usb interface中的id如idVendor,idProduct, bDeviceClass等参数进行匹配。

if (id)

return

1;

id =

usb_match_dynamic_id(intf, usb_drv);

if (id)

return

1;

}

return 0;

}

对于usbmatch比较好理解,而usb_uevent中,则定义了usb的热插拔的处理函数。这个的作用就是将设备的信息存储到env中,可以供用户空间读。对于设备的信息,我们可以通过在用户空间的程序中读取/proc/bus/usb/下的文件取得这些设备的信息。

static int usb_uevent(struct device

*dev, struct kobj_uevent_env *env)

{

struct

usb_device *usb_dev;

if

(is_usb_device(dev))

usb_dev

= to_usb_device(dev);

else

{

struct

usb_interface *intf = to_usb_interface(dev);

usb_dev

= interface_to_usbdev(intf);

}

if

(usb_dev->devnum < 0) {

return -ENODEV;

}

if

(!usb_dev->bus) {

return -ENODEV;

}

#ifdefCONFIG_USB_DEVICEFS--添加设备名称

if

(add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",

usb_dev->bus->busnum,

usb_dev->devnum))

return

-ENOMEM;

#endif

if

(add_uevent_var(env, "PRODUCT=%x/%x/%x",--添加设备id

le16_to_cpu(usb_dev->descriptor.idVendor),

le16_to_cpu(usb_dev->descriptor.idProduct),

le16_to_cpu(usb_dev->descriptor.bcdDevice)))

return

-ENOMEM;

if

(add_uevent_var(env, "TYPE=%d/%d/%d",--添加设备类型。

usb_dev->descriptor.bDeviceClass,

usb_dev->descriptor.bDeviceSubClass,

usb_dev->descriptor.bDeviceProtocol))

return

-ENOMEM;

return

0;

}

对于uevent的理解可能比较难懂一点,不过你可以把uevent的操作看成将一些设备和驱动的信息写到/proc下对应的文件中,让usrspcae的用户程序可以读取从而获取设备的信息。

2.3usb_host_init

也许从这个函数名上看不出这个函数的具体应用是什么,既然看函数名不知道干什么,那我们来看该函数的具体实现。你会发现这个函数好像挺简单的,就是创建一个usb host类。

int usb_host_init(void)

{

int

retval = 0;

usb_host_class

= class_create(THIS_MODULE, "usb_host");

if

(IS_ERR(usb_host_class))

retval

= PTR_ERR(usb_host_class);

return

retval;

}

关于这个设备类有什么用,以后再说,咱们还是继续usb init的主线来看usb。

2.4 usb_major_init

注册usb major其实是注册一个以USB_MAJOR为主设备号的cdev。不过其还分配了256个从设备号。提供一个公共的open函数。

int (void)

{

int

error;

error

= register_chrdev(USB_MAJOR, "usb", &usb_fops);

if

(error)

printk(KERN_ERR

"Unable to get major %d for usb devices\n",

USB_MAJOR);

return

error;

}

对于每一个usb设备的打开都会先调用主设备的open,而后根据不同的设备调用不同的open函数。下面就是cdev的ops操作集。

static const struct file_operations

usb_fops = {

.owner

=THIS_MODULE,

.open

=usb_open,

};

static int usb_open(struct inode *

inode, struct file * file)

{

int

minor = iminor(inode);

const

struct file_operations *c;

int

err = -ENODEV;

const

struct file_operations *old_fops, *new_fops = NULL;

lock_kernel();

down_read(&minor_rwsem);

c

= [minor];

--关于这个全局变量在以后的usb设备注册时会看到,这里先有个底。

if

(!c || !(new_fops = fops_get(c)))

goto

done;

old_fops

= file->f_op;

file->f_op

= new_fops;

/*

Curiouser and curiouser... NULL ->open() as "no device" ? */

if

(file->f_op->open)

err

= file->f_op->open(inode,file);--调用真正的open

if

(err) {

fops_put(file->f_op);

file->f_op

= fops_get(old_fops);

}

fops_put(old_fops);

done:

up_read(&minor_rwsem);

unlock_kernel();

return

err;

}

其实上面的公共的open就是提供一个对于所有的usb设备的公共接口,真正的open其实是usb_minors中存储的fops->open.

2.5 usb_register

该函数是注册usbfs_driver驱动。不过注册该驱动不知是为什么。

2.6 usb_devio_init

对于这个函数就更加困惑了,这个同样是注册一个以USB_DEVICE_DEV为主设备号的cdev设备。

int __init usb_devio_init(void)

{

int

retval;

retval

= register_chrdev_region(, USB_DEVICE_MAX,

"usb_device");

if

(retval) {

goto

out;

}

cdev_init(&usb_device_cdev,

&usbdev_file_operations);

retval

= cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);

if

(retval) {

goto

error_cdev;

}

usb_classdev_class

= class_create(THIS_MODULE, "usb_device");

if

(IS_ERR(usb_classdev_class)) {

goto

out;

}

usb_classdev_class->dev_kobj

= NULL;

usb_register_notify(&usbdev_nb);

return

retval;

}

关于这个函数具体有什么用,以后再看,先跳过。

2.7 usbfs_init

int __init usbfs_init(void)

{

int

retval;

retval

= register_filesystem(&usb_fs_type); --注册filesystem

if

(retval)

return

retval;

usb_register_notify(&usbfs_nb);

usbdir

= proc_mkdir("bus/usb", NULL);--为usbfs创建挂载点

return

0;

}

2.8 usb_hub_init

int (void)

{

if

(usb_register(&hub_driver) < 0) {--注册hub驱动

printk(KERN_ERR

"%s: can't register hub driver\n",

usbcore_name);

return

-1;

}

khubd_task

= kthread_run(hub_thread, NULL, "khubd"); --创建hub守护进程

if

(!IS_ERR(khubd_task))

return

0;

usb_deregister(&hub_driver);

return

-1;

}

2.9 usb_register_device_driver

注册一个通用usb驱动。usb_register_device_driver(&usb_generic_driver,

THIS_MODULE);

OK,到此usb init是看完了,不过这里面却有种种的迷雾,让人不解困惑。比如为什么要注册两个usb major,还注册了两个古怪的驱动,这些种种让人不解。不过这些都将会在后面的学习中来了解这些。

三.总结

对于大牛们而言,也许这些东西很简单,不过对于我这个菜鸟而言,却是那么的难弄。在此本文也仅仅是对自己学习的一个记录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值