usb_debugfs_init

/**这个函数主要做了一下事情:在debugfs中创建了一个文件,并指定了操作他的函数。
*/
static int usb_debugfs_init(void)
{/**在debugfs文件系统中创建一个目录。"usb" : 目录的名称NULL  : 这个目录的父目录,如果时NULL,那么就放到debugfs目录下。(目录结构见图1)*/usb_debug_root = debugfs_create_dir("usb", NULL);if (!usb_debug_root){return -ENOENT;}/**在/sys/kernel/debug/usb目录下创建 devices文件节点。权限是 0444 ,向vfs层提供的接口函数是usbfs_devices_fops中定义的函数const struct file_operations usbfs_devices_fops = {.llseek =   usb_device_lseek,.read =     usb_device_read,.poll =     usb_device_poll,};后面详细分析这些函数*/usb_debug_devices = debugfs_create_file("devices", 0444,usb_debug_root, NULL,&usbfs_devices_fops);if (!usb_debug_devices) {debugfs_remove(usb_debug_root); //从debugfs中移除。usb_debug_root = NULL;return -ENOENT;}return 0;
}

图 1

bus_register

/**注册总线。总线也是一种设备。这个函数在以前博文中已经说过,请参考我以前的博文看一下usb总线,注册后会生成两个容器,分别盛放挂接再该总线下所有的驱动、设备。struct bus_type usb_bus_type = {.name =     "usb",.match =    usb_device_match.uevent =   usb_uevent,};下面自己注册一条总线,看一下注册总线时涉及到的重要函数。实验 见图2
*/
retval = bus_register(&usb_bus_type);
if (retval)
{goto bus_register_failed;
}       



bus_register_notifier内核通知链

/**usb总线通知链的注册。对于通知链,再上篇电源管理赏析中我们就见过了,再冻结APP、内核线程前会通知各个驱动 再启动app、内核线程之后也会通知各个驱动,看下面:当设备加入、卸载的时候 也 会发通知。1 : 设备加入devic_add(){   if (dev->bus){blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);{最终调用:ret = nb->notifier_call(nb, val, v);}}}2 : 设备卸载void device_del(){...                 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_DEL_DEVICE, dev);}   下面有一个小实验,来验证,见图3、4
*/
int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
{return blocking_notifier_chain_register(&bus->p->bus_notifier, nb);
}

图3:

int usb_major_init(void)
{int error;/**注册一个字符设备。看清楚,**这里是bus**,不是usb_device.一条总线也是一个设备。#define USB_MAJOR   180  主设备号 180向vfs层提供的操作函数集合是usb_fops看一下:static const struct file_operations usb_fops = {.owner =    THIS_MODULE,.open =     usb_open,.llseek =   noop_llseek,};这个和input子系统中提供的及其类似。甚至usb_open 和 input_open的逻辑也是极其类似的。只是usb_open中对临界区的保护机制使用的是读写锁,input_open使用的是互斥锁。内核字符设备对于open函数大部分都是这样设计。那么这样设计就是驱动分层的体现吧。由通用层转入具体设备提供的驱动层。input_open函数的赏析请见我以前的博文:http://blog.csdn.net/leesagacious/article/details/50245937*/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;
}
/**他做了哪些事情呢?很简单,字符设备的基本函数。1 : register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,"usb_device")2 : cdev_init(&usb_device_cdev, &usbdev_file_operations)3 : cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX)4 : usb_register_notify(&usbdev_nb);看一下 向vfs层提供的操作函数集const struct file_operations usbdev_file_operations = {.owner =      THIS_MODULE,.llseek =     usbdev_lseek,.read =       usbdev_read,.poll =       usbdev_poll,.unlocked_ioctl = usbdev_ioctl,#ifdef CONFIG_COMPAT.compat_ioctl =   usbdev_compat_ioctl,#endif.open =       usbdev_open,.release =    usbdev_release,};
*/
retval = usb_devio_init();
if (retval)
{goto usb_devio_init_failed;
}   
/**这个函数请见上面的流程图。最终会调用bus_register()#define usb_register(driver) \usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)bus_register()这个函数的赏析请见我以前的博文:http://blog.csdn.net/leesagacious/article/details/50200053
*/
retval = usb_register(&usbfs_driver);
if (retval)
{goto driver_register_failed;
}
/**USB设备文件系统的初始化。现在你明白了usb设备文件系统是动态产生的了吧。和sys、proc一样都是动态产生的。看他的实现:int __init usbfs_init(void){int retval;retval = register_filesystem(&usb_fs_type);//注册usb设备文件系统if (retval){return retval;}usb_register_notify(&usbfs_nb);        //usbfs_notify()函数会被调用。  usbdir = proc_mkdir("bus/usb", NULL); //创建挂载点。return 0;}
*/
retval = usbfs_init();
if (retval)
{goto fs_init_failed;
}       
/**hub的初始化。详细请看我以前的博文: http://blog.csdn.net/leesagacious/article/details/50506854主要是注册了一个hub驱动、创建了一个内核守护线程来监测hub端口的状态变化。
*/
retval = usb_hub_init();
if (retval)
{goto hub_init_failed;
}       
/**终于再最后注册了usb_device的driver到usb的核心层了。注意 : 是 usb设备驱动: usb_device_driver,不是usb_driver(每个接口对应了一个特定的功能,应有专门的驱动来和它沟通)。
*/
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
if (!retval)
{goto out;
}   

U盘驱动

/**这是一个内核线程。很重要。你可能会问:是谁创建了这个内核线程,他的作用是什么?请往下看。
*/
static int usb_stor_control_thread(void * __us)
{/**这个内核线程是再函数 : usb_stor_acquire_resources{....第二个参数是 : us_data要创建内核线程的信息被组织一个结构体 kthread_create_info  被挂接到 kthread_create_list链表上。而且 二号进程也被唤醒了,二号进程要从kthread_create_list链表上获取、创建他了。th = kthread_run(usb_stor_control_thread, us, "usb-storage");下面是 3.4内核的代码:   相比上面4.1的代码,4.1的一部到位。下面的wake_up_process(th)激活了他。th = kthread_create(usb_stor_control_thread, us, "usb-storage");....    wake_up_process(th);}转换成 us_data,这个us_data太重要了,整个架构中都有他的身影。详细分析他每一个成员再框架中的生命历程 放到下面。 */struct us_data * us = (struct us_data *)__us;/**是把u盘模拟成了一个 SCSI设备。所以再配置内核的时候,要增加对U盘的支持,而且SCSI也要支持好。既然底层是依赖SCSI,那么内核已经做了下面的事情:1 : 为Scsi_host分配内存空间,使用函数 us_to_host()2 : 添加到SCSI核心层        使用函数 us_add_host()3 : Scsi_scan_host()      他会扫描添加的设备。SCSI封装的很好,上层只要一个api就搞定了。看一下 us_to_host()这个函数,他很重要,源码的注释是这样说的 : Convert between us_data and the corresponding Scsi_Host就是再us_data和 Scsi_Host之间转换。这个函数让USB驱动与SCSI驱动关联了起来。由us_data 可以获取Scsi_host ,由Scsi_Host可以获取到us_data下面有一幅配置的图 可供参考。图5下面还有一幅图来验证这个内核线程创建的流程 图6*/struct Scsi_Host *host = us_to_host(us);/**死循环。看他什么时候 能跳出来。*/for (;;) {usb_stor_dbg(us, "*** thread sleeping\n");/**进程开始休眠。有可能会从这儿跳出死循环。看他的参数&us->cmnd_ready : 是 0。为什么?static int storage_probe(struct usb_interface *intf,const struct usb_device_id *id){int usb_stor_probe1(struct us_data **pus,struct usb_interface *intf,const struct usb_device_id *id,struct us_unusual_dev *unusual_dev){struct us_data *us;....init_completion(&us->cmnd_ready); 看这里,被初始化了。init_completion(&(us->notify));}}老版本用的是 信号量,这里用了完成量,那么 谁会调用completion()呢?往下面看。图7实验验证。他直接就睡了。*/if (wait_for_completion_interruptible(&us->cmnd_ready))break;/**被唤醒后执行的代码*/usb_stor_dbg(us, "*** thread awakened\n");mutex_lock(&(us->dev_mutex));
}   

usb3.0的U盘。

下面是插入u盘后的log: 看 storage_probe()被调用了

一定要让你彻底明白什么是USB子系统相关推荐

  1. Linux那些事儿 之 戏说USB(29)驱动的生命线(一)

    现在开始就沿着usb_generic_driver的成名之路走一走,设备的生命线你可以想当然的认为是从你的usb设备连接到hub的某个端口时开始,驱动的生命线就必须得回溯到usb子系统的初始化函数us ...

  2. Linux那些事儿 之 戏说USB(15)设备

    struct usb_device结构冗长而又杂乱 include/linux/usb.h struct usb_device {int devnum;char devpath[16];u32 rou ...

  3. Linux那些事儿 之 戏说USB(12)接口是设备的接口(一)

    前面的前面已经说了,接口是设备的接口.设备可以有多个接口,每个接口代表一个功能,每个接口对应着一个驱动.Linux设备模型的device落实在USB子系统,成了两个结构,一个是struct usb_d ...

  4. Linux那些事儿 之 戏说USB(3)我是一棵树

    从拓扑上来看,USB子系统并不以总线的方式来部署,它是一颗由几个点对点的连接构成的树. 它主要包括了USB连接.USB host controller和USB device三个部分.而USB devi ...

  5. 关于USB的8个问题

    问题一:USB的传输线结构是如何的呢? 答案一:一条USB的传输线分别由地线.电源线.D+.D-四条线构成,D+和D-是差分输入线,它使用的是3.3V的电压(注意哦,与CMOS的5V电平不同),而电源 ...

  6. Linux下的LED子系统

    最简单的led驱动就是从端口输出0或1来关闭或点亮灯.而我们这里讲的led子系统,主要是对led事件进行了分装和优化,这里我们主要讲的是可以实现跨平台的led驱动.不管你是使用三星的平台,还是Atme ...

  7. USB的八个问题和答案(转)

    http://www.amobbs.com/thread-901041-1-1.html 问题一:USB的传输线结构是如何的呢? 答案一:一条USB的传输线分别由地线.电源线.D+.D-四条线构成,D ...

  8. USB基础与重点梳理—关于USB的问题

    Q1. USB的传输线结构是如何的呢? A1: 一条USB的传输线分别由地线.电源线.D+.D-四条线构成,D+和D-是差分输入线,它使用的是3.3V的电压(注意哦,与CMOS的5V电平不同),而电源 ...

  9. Linux内核(5) - 内核学习的相关资源

    "世界上最缺的不是金钱,而是资源."当我在一份报纸上看到这句大大标题时,我的第一反应是--作者一定是个自然环保主义者,然后我在羞愧得反省自身的同时油然生出一股对这样的无产主义理想者 ...

最新文章

  1. 《LeetCode力扣练习》第8题 C语言版 (做出来就行,别问我效率。。。。)
  2. 无线传感器网络--分簇或者不分簇
  3. Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
  4. 【PC工具】github项目辅助下载工具,github高速下载
  5. 判断数组中某个元素除自身外是否和其他数据不同_算法工程师要懂的3种算法数据结构:线性表详解...
  6. JVM参数设置、分析
  7. Cloud一分钟|茅台4.5亿入股云上贵州大数据,后者已接管苹果中国iCloud; 阿里云进入印度市场,增长速度远超当地平均水平...
  8. linux内核 lts长期演进,Linux Kernel 4.19 和 5.4 生命周期延长至 6 年
  9. Hexo瞎折腾系列(6) - 将博客同时部署到Github和Coding
  10. [Beego模型] 三、高级查询
  11. C++ 已知两点坐标和半径求圆心坐标程序
  12. php解析m3u8代码,m3u8后缀 视频解析接口源码
  13. 全排列算法(字典序法、SJT Algorithm 、Heap's Algorithm)
  14. [前端面试题][‘1‘,‘2‘,‘3‘].map(parseInt)
  15. Mp3:最后的免费“午餐”
  16. 科技爱好者周刊(第 212 期):人生不短
  17. 信息安全竞赛解决方案
  18. Editplus如何设置中文页面
  19. 【python】python编译器以及安装
  20. uni-app常见知识点总结

热门文章

  1. 李德毅 | 新一代人工智能如何从传统人工智能中脱颖而出
  2. 用1、2、3、4、5、6、7、8、9这9个数字,填入□ 中使等式□□×□□□ = □□□□ 成立,每个数字恰好只用一次。
  3. 使用饿了么update组件 实现多文件上传到后台以及本地图片显示功能
  4. 为什么苹果6没有录屏_谁说苹果手机没有录屏功能的!教你这样开启,还能录制声音呢...
  5. 这4个文档排版方式掌握了,工作效率提高的不止一点点!
  6. 如何提高场馆的二次成交率?
  7. Gradle打包报错:Failed to calculate the value of task ‘:unityLibrary:compileReleaseJavaWithJavac‘
  8. 机器学习VS深度学习,两者区别在哪里?
  9. Lumion 11.0:领先的建筑可视化工具再次升级!+全版本安装包
  10. 【GANs】Generative Adversarial Nets