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_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中的id如idVendor ,idProduct, bDeviceClass等参数进行匹配。

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;

}

#ifdef  CONFIG_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.3  usb_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函数。

intusb_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函数。下面就是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 =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

intusb_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,还注册了两个古怪的驱动,这些种种让人不解。不过这些都将会在后面的学习中来了解这些。

三.总结

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

linux usb初始化相关推荐

  1. linux usb host复位,Linux USB Host-Controller的初始化代码框架分析

    Linux USB Host-Controller的初始化代码框架分析 http://blog.csdn.net/zkami usb_hcd_omap_probe (const struct hc_d ...

  2. Linux USB 驱动开发(五)—— USB驱动程序开发过程简单总结

    http://blog.csdn.net/zqixiao_09/article/details/51057086 设备驱动程序是操作系统内核和机器硬件之间的接口,由一组函数和一些私有数据组成,是应用程 ...

  3. linux usb驱动

    0.usb协议     usb的版本:     硬件         usb 1.0     OHCI        微软                 硬件 > 软件         usb ...

  4. Linux USB驱动框架分析 【转】

    转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...

  5. linux usb声卡 submit urb,linux usb urb详解

    linux usb urb详解 谨以此文纪念过往的岁月 一.前言 在前文中看过了hub的驱动以及host的驱动还有usb设备的驱动,在把这些东西关联起来的东东中,一个很重要的urb(usb reque ...

  6. linux usb键盘驱动详解

    1.首先我们通过上节的代码中修改,来打印下键盘驱动的数据到底是怎样的 先来回忆下,我们之前写的鼠标驱动的id_table是这样: 所以我们要修改id_table,使这个驱动为键盘的驱动,如下图所示: ...

  7. linux usb驱动中的urb详解

    linux 内核中的 USB 代码和所有的 USB 设备通讯使用称为 urb 的东西( USB request block). 这个请求块用 struct urb 结构描述并且可在 include/l ...

  8. Linux USB驱动程序设计

    Linux USB驱动程序设计 1. USB发展史 USB(Universal Serial Bus ),通用串行总线,是一种外部总线标准,用于规范电脑与外部设备的连接和通讯. USB是在1994年底 ...

  9. Linux USB设备驱动程序设计 和 USB下载线驱动设计

    Linux USB设备驱动程序设计 和 USB下载线驱动设计 USB设备驱动模型 USB设备包括配置(configuration).接口(interface)和端点(endpoint),一个USB设备 ...

最新文章

  1. FPGA设计——全局曝光CMOS图像采集与USB2.0显示
  2. SharePoint 2007 文件夹或者文件名过长
  3. H5活动刮刮卡功能的实现与注意事项
  4. 【转】【C++学习笔记】C++异常处理
  5. 调整的飞秋官网幅度还非常的大
  6. 利用RC.EXE和RCDLL.DLL创建VB6资源文件
  7. 1091 N-自守数 (15 分)—PAT (Basic Level) Practice (中文)
  8. HDU 6143 Killer Names
  9. 一种解决常见的80/443端口被占用导致steamcommunity 302服务无法启动的方法
  10. pandas中的freq和inferred_freq等时间参数究竟有哪些
  11. 博士补贴75万、本硕补贴45万!小县城重金揽才,开启硕博抢人大战!
  12. 个人发展分析:SWOT
  13. 音质好的无线蓝牙耳机品牌?盘点音质超好的蓝牙耳机推荐
  14. Android 仿钉钉、微信 群聊组合头像
  15. Mybatis中的_parameter
  16. 王者荣耀进阶教学攻速/移速/减伤机制/视野/意识
  17. 黑得漂亮!SyScan360黑客大会展示17秒攻陷IE
  18. 如何在 PC 上识别微信二维码
  19. EBS 报表开发:XML Publisher Excel模板
  20. 理工男,我感觉 win10 挺好用的,一点不卡,为什么有那么多人买Macbook 呢?

热门文章

  1. 面试官:说说微信和淘宝扫码登录背后的实现原理?
  2. Spring Cloud Alibaba基础教程:Nacos的数据持久化
  3. php 自动登录脚本_php利用cookie实现自动登录的方法
  4. mysql ora01031_ORA-01031:insufficient privileges解决方法
  5. int?和int的区别
  6. leetcode二维查找
  7. assert self.binded
  8. “pybind11::module_::def”: 未找到匹配的重载函数
  9. python边缘检测
  10. vector 指针 的指针