linux usb枚举过程分析之守护进程及其唤醒【转】
转自:http://blog.csdn.net/xuelin273/article/details/38646765
usb热插拔,即usb设备可以实现即插即用,像U盘一样,插到电脑里就可以用,不用时可以直接拔除,这个动作不会影响USB设备使用性能。
在linx 系统中,usb热插拔由两部分方面共同实现,即内核空间和用户空间,内核由一个守护进程实现,用户空间由udev 程序实现。在内核空间里,有一个专门用于监控usb hub的状态的守护进程,守护进程通过等待队列实现,等待队列平时处理休眠状态,当usb hub上状态变化时(即有usb设备从usb hub上插入或拔出)时,便会去唤醒等待队列,然后去实现usb设备枚举,枚举成功后,向linux系统注册usb设备,并通过kobject_event通知用户空间,有设备插入或拔出,用户空间里有一个专门用于实现动态加载设备节点的程序udev,当它收到内核通知后,能够动态创建usb设备节点,这样便实现了usb的热插拔。
本文主要从usb设备枚举最基本的几个方面进行讲解,即usb守护进程、守护进程如何唤醒、被谁唤醒。
一.守护进程
- khubd_task = kthread_run(hub_thread, NULL, "khubd");
- if (!IS_ERR(khubd_task))
- return 0;
- static int hub_thread(void *__unused)
- {
- set_freezable();
- do {
- hub_events();
- wait_event_freezable(khubd_wait,
- !list_empty(&hub_event_list) ||
- kthread_should_stop());
- } while (!kthread_should_stop() || !list_empty(&hub_event_list));
- pr_debug("%s: khubd exiting\n", usbcore_name);
- return 0;
- }
第3行的set_freezable作用是清除当前线程标志flags中的PF_NOFREEZE位,表示当前线程能进入挂起或休眠状态。
- static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
二 .守护进程唤醒
- static void kick_khubd(struct usb_hub *hub)
- {
- unsigned long flags;
- spin_lock_irqsave(&hub_event_lock, flags);
- if (!hub->disconnected && list_empty(&hub->event_list)) {
- list_add_tail(&hub->event_list, &hub_event_list);
- /* Suppress autosuspend until khubd runs */
- usb_autopm_get_interface_no_resume(
- to_usb_interface(hub->intfdev));
- wake_up(&khubd_wait);
- }
- spin_unlock_irqrestore(&hub_event_lock, flags);
- }
第7行,将hub的event_list添加到hub_event_list列表,用于满足守护进程被唤醒时的条件。
- hub->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!hub->urb) {
- ret = -ENOMEM;
- goto fail;
- }
- usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval);
urb的回调函数为hub_irq:
- static void hub_irq(struct urb *urb)
- {
- struct usb_hub *hub = urb->context;
- int status = urb->status;
- unsigned i;
- unsigned long bits;
- switch (status) {
- case -ENOENT: /* synchronous unlink */
- case -ECONNRESET: /* async unlink */
- case -ESHUTDOWN: /* hardware going away */
- return;
- default: /* presumably an error */
- /* Cause a hub reset after 10 consecutive errors */
- dev_dbg (hub->intfdev, "transfer --> %d\n", status);
- if ((++hub->nerrors < 10) || hub->error)
- goto resubmit;
- hub->error = status;
- /* FALL THROUGH */
- /* let khubd handle things */
- case 0: /* we got data: port status changed */
- bits = 0;
- for (i = 0; i < urb->actual_length; ++i)
- bits |= ((unsigned long) ((*hub->buffer)[i]))
- << (i*8);
- hub->event_bits[0] = bits;
- break;
- }
- hub->nerrors = 0;
- /* Something happened, let khubd figure it out */
- kick_khubd(hub);
- resubmit:
- if (hub->quiescing)
- return;
- if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
- && status != -ENODEV && status != -EPERM)
- dev_err (hub->intfdev, "resubmit --> %d\n", status);
- }
在hub_irq中可以看到,如果urb被成功提交给控制器,并成功获取port状态,就会调用kick_khubd唤醒守护进程;
- retval = usb_hcd_request_irqs(hcd, irqnum, irqflags);
- if (retval)
- goto err_request_irq;
- if (ints & OHCI_INTR_RHSC) {
- ohci_vdbg(ohci, "rhsc\n");
- ohci->next_statechange = jiffies + STATECHANGE_DELAY;
- ohci_writel(ohci, OHCI_INTR_RD | OHCI_INTR_RHSC, ®s->intrstatus);
- ohci_writel(ohci, OHCI_INTR_RHSC, ®s->intrdisable);
- usb_hcd_poll_rh_status(hcd);
- }
当port上状态发生变化时,就会调用usb_hcd_poll_rh_status去查询usb root hub port状态,并调用hub中interrupt urb的回调函数hub_irq,最终去唤醒usb守护进程。
linux usb枚举过程分析之守护进程及其唤醒【转】的更多相关文章
- Linux中的两种守护进程stand alone和xinetd
Linux中的两种守护进程stand alone和xinetd --http://www.cnblogs.com/itech/archive/2010/12/27/1914846.html#top 一 ...
- Windows 和 Linux 上Redis的安装守护进程配置
# Windows 和 Linux 上Redis的安装守护进程配置 Redis 简介 Redis是目前最常用的非关系型数据库(NOSql)之一,常以Key-Value的形式存储.Redis读写速度 ...
- ASP.NET Core Linux下为 dotnet 创建守护进程(必备知识)
前言 在上篇文章中介绍了如何在 Docker 容器中部署我们的 asp.net core 应用程序,本篇主要是怎么样为我们在 Linux 或者 macOs 中部署的 dotnet 程序创建一个守护进程 ...
- ASP.ENT Core Linux 下 为 donet创建守护进程(转载)
原文地址:http://www.cnblogs.com/savorboard/p/dotnetcore-supervisor.html 前言 在上篇文章中介绍了如何在 Docker 容器中部署我们的 ...
- [Linux] PHP程序员玩转Linux系列-使用supervisor实现守护进程
1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 3.PHP程序员玩转Linux系列-搭建FTP代码开发环境 4.PHP程序员玩转L ...
- linux下编写简单的守护进程
搭建linux服务器的时候,需要写一个简单的守护进程来监控服务的运行情况,shell脚本如下: #!/bin/sh function daemon() { while true do server=` ...
- Linux网络编程学习(四) -----守护进程的建立(第三章)
本文介绍一个例程daemon_init() #include <sys/types.h> #include <signal.h> #include <unistd.h&g ...
- Linux下性能监控、守护进程与计划任务管理
目录 一:监视系统进程(ps .top) 二:查看网络连接信息 (netstat) 三:文件进程.端口关联(lsof) 四:计划任务管理(at .crontab) at crontab 一:监视系统进 ...
- Linux学习笔记(9)-守护进程
明天学这个!! ---------------------------------------------------------- 守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终 ...
随机推荐
- 『编程题全队』Alpha 阶段冲刺博客Day7
1.每日站立式会议 1.会议照片 2.昨天已完成的工作统计 孙志威: 1.添加了网络通信管理类 2.稍微修改了燃尽图模块ChartWidget 3.在主窗口中添加了用户信息框 4.重构了项目中的文件结 ...
- CentOS下 NFS的简单使用以及windows 关在linux的NFS存储方法
1. 全部安装的情况下NFS已经安装到服务器上面了,如果没有安装的话 需要使用如下命令进行安装 yum -y install nfs-utils rpcbind 2. 创建需要使用的NFS目录 mkd ...
- PHP操作Redis数据库常用方法
Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. Redis支持的数据类型有 Stirng(字符串), Lis ...
- BOM之screen对象
前面的话 screen对象在javascript编程中,比较冷门,不太常用.screen对象用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素高度和宽度等.本文将详细介绍screen对 ...
- Swap HDU - 2819 (有关矩阵的二分匹配)
题意见大佬:https://www.cnblogs.com/gj-Acit/archive/2013/08/17/3265502.html 题目大意很明确,交换图的某些行或者是某些列(可以都换),使得 ...
- SPOJ QTREE2 (LCA - 倍增 在线)
You are given a tree (an undirected acyclic connected graph) with N nodes, and edges numbered 1, 2, ...
- (NOI2014)(bzoj3669)魔法森林
LCT裸题,不会的可以来这里看看. 步入正题,现将边按a排序,依次加入每一条边,同时维护路径上的最小生成树上的最大边权,如果两点不连通,就直接连通. 如果两点已经连通,就将该边与路径上较小的一条比较, ...
- 【Revit API】创建共享参数
话不多说,直接上代码 var app = doc.Application; app.SharedParametersFilename = sharedParamFilePath; Definition ...
- luogu2679 [NOIp2015]子串 (dp)
设f[i][j][k][b]表示在A串第i位.这是第j组.B串第k位.i号选不选(b=0/1) 那么就有$f[i][j][k][1]=(A[i]==B[k])*(f[i-1][j-1][k][0]+f ...
- 前端学习 -- Css -- 字体的几个属性学习
font-style可以用来设置文字的斜体 - 可选值: normal,默认值,文字正常显示 italic 文字会以斜体显示 oblique 文字会以倾斜的效果显示 - 大部分浏览器都不会对倾斜和斜体 ...