打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
linux usb初始化-steven
分类: LINUX
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中并不能很好的工作。也许大家对这个函数会很奇怪,不知道该工作队列的作用。
这个工作队列如何使用的,将在看usbsuspendresume时再具体看这个东东具体有什么用。
2.2 bus_register
usb_init中第二个调用的函数是bus_register(&usb_bus_type);这个应该很熟悉吧,注册一个usb总线,其会在/sys/bus下创建一个usb的文件夹,在其中会创建bususb设备和usb驱动都会在这两个文件夹下。bus属性文件和driversdevices文件夹,以后所有的总线需要指明devicedriver匹配的规则,例如platform busname进行匹配,而usb则以id进行匹配。对于bus_register在前文中讲述多,这里不多此一举了。那主要来看usb bus的特征。
struct bus_type usb_bus_type = {
.name ='usb',--定义busname,这个也会是在/sys/bus下看见的文件夹得名称。
.match =usb_device_match,--定义busdevicedriver的匹配规则
.uevent =usb_uevent,--usb的触发事件处理。
};
下面来看usb的匹配规则函数。不过有一点需要说明的是一般usb的驱动为usbinterface的驱动,而不是usb设备的驱动。为了方便描述,并没有加以说明,要注意了。
static int usb_device_match(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中的ididVendor
idProductbDeviceClass等参数进行匹配。
if (id)
return 1;
id = usb_match_dynamic_id(intf, usb_drv);
if (id)
return 1;
}
return 0;
}
对于usb match比较好理解,而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 usb_major_init(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函数。下面就是cdevops操作集。
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 = usb_minors[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_DEV, 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 usb_hub_init(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,还注册了两个古怪的驱动,这些种种让人不解。不过这些都将会在后面的学习中来了解这些。
.总结
对于大牛们而言,也许这些东西很简单,不过对于我这个菜鸟而言,却是那么的难弄。在此本文也仅仅是对自己学习的一个记录。
阅读(2552) | 评论(0) | 转发(3) |
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Linux设备模型之input子系统详解
linux输入子系统
Goldfish_events浅析
虚拟键盘、虚拟鼠标驱动
我对linux内核usb驱动sub
USB子系统学习之基础篇三(host controller)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服