转自:http://blog.csdn.net/aaronychen/article/details/3928479

LinuxUSB suspend/resume源码分析

Author:aaron

 

本文主要从自己开发的一个USB驱动的例子来深入讲解linux内核是如何支持USB设备的休眠和唤醒的,

最近我在为我们公司的一个模块写linux下的驱动, 其中之一就是要支持USB的休眠唤醒问题, 实际上linux内核对USB的这个功能的支持还是比较新的, 也就是最近几年的事.

一  打开/关闭USB suspend/resuem功能

要让linux支持usb suspend/resuem, 当然先要把内核中这个功能的代码编译进去咯, 即要在make menuconfig时打开对这项功能的支持.

第一个打开的项是CONFIG_PM, 即整个系统的电源管理, USB suspend/resuem只是整个电源管理的一个自系统. 只有打开了这个功能才能让USB的这个特性能用.

第二个要打开的当让是USB自己的开关了CONFIG_USB_SUSPEND. 即打开了这个功能后我们只要在我们自己的驱动里简单调用下USB core提供的函数接口就能使我们的设备休眠了.

二 源码分析

在2.6.19之前的代码中不支持USB自动休眠的功能, 它只能是在host休眠情况下才会让USB设备也休眠. 所以如果我们要让自己的设备在不使用的情况下就休眠就得自己添加相应的代码, 幸运的是我们不需要添加复杂的代码就能达到这个目的, 因为USB core里提供了几个接口可以直接让我们的驱动调用以把我们的设备置入休眠状态.

下面我们以2.6.16的代码为例来分析下USB设备是如何进入休眠的.

Drivers/usr/core/hub.c:

int usb_suspend_device(struct usb_device *udev)

{

#ifdef      CONFIG_USB_SUSPEND

if (udev->state == USB_STATE_NOTATTACHED)

return -ENODEV;

return __usb_suspend_device(udev, udev->portnum);

#else

/* NOTE:  udev->state unchanged, it's not lying ... */

udev->dev.power.power_state = PMSG_SUSPEND;

return 0;

#endif

}

没错, 在我们的驱动里只要在适当的地方调用这个函数就可以使我们的设备休眠了. 但是需要注意的是,  内核没有EXPORT这个函数, 因此如果我们的驱动要编译成模块的话, 我们只有修改内核以EXPORT这个函数了.

实际上真正干正事的函数是__usb_suspend_device

Drivers/usr/core/hub.c:

static int __usb_suspend_device (struct usb_device *udev, int port1)

{

int   status = 0;

/* caller owns the udev device lock */

if (port1 < 0)

return port1;

/*如果设备已休眠或还没attach上则直接返回*/

if (udev->state == USB_STATE_SUSPENDED

|| udev->state == USB_STATE_NOTATTACHED) {

return 0;

}

/* all interfaces must already be suspended */

/*要休眠设备, 首先必须要设备下的每个interface都可以休眠才行*/

if (udev->actconfig) {

int   i;

for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {

struct usb_interface       *intf;

intf = udev->actconfig->interface[i];

if (is_active(intf)) {   /*如果某个interface处于活动状态则不能休眠*/

dev_dbg(&intf->dev, "nyet suspended/n");

return -EBUSY;

}

}

}

/* we only change a device's upstream USB link.

* root hubs have no upstream USB link.

*/

/*干正事的一个函数*/

if (udev->parent)

status = hub_port_suspend(hdev_to_hub(udev->parent), port1,

udev);

if (status == 0)

udev->dev.power.power_state = PMSG_SUSPEND;   /*保存设备状态*/

return status;

}

第一个参数是要休眠的USB设备, 第二个参数是该USB设备所连接到的hub的某个端口.

从这个函数我们可以大概猜测到, 要一个设备休眠原理就是要把这个设备attach到的那个端口休眠掉.

没错USB spec规定了只要把设备所attach上的那个端口disable掉, 那么这条路径上就没有任何传输了, 在过了一段时间后设备端应该会产生一个suspend的中断, 以让设备进入休眠状态.

Drivers/usr/core/hub.c:

static int hub_port_suspend(struct usb_hub *hub, int port1,

struct usb_device *udev)

{

int   status;

// dev_dbg(hub->intfdev, "suspend port %d/n", port1);

/* enable remote wakeup when appropriate; this lets the device

* wake up the upstream hub (including maybe the root hub).

*

* NOTE:  OTG devices may issue remote wakeup (or SRP) even when

* we don't explicitly enable it here.

*/

/*如果设备支持远程唤醒功能, 则打开此功能*/

if (device_may_wakeup(&udev->dev)) {

status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),

USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,

USB_DEVICE_REMOTE_WAKEUP, 0,

NULL, 0,

USB_CTRL_SET_TIMEOUT);

if (status)

dev_dbg(&udev->dev,

"won't remote wakeup, status %d/n",

status);

}

/* see 7.1.7.6 */

/*^_^看usb spec 7.1.7.6吧, 这个命令就是把hub的这个port disable掉, 这样就达到休眠的目的了*/

status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);

if (status) {

dev_dbg(hub->intfdev,

"can't suspend port %d, status %d/n",

port1, status);

/* paranoia:  "should not happen" */

(void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),

USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,

USB_DEVICE_REMOTE_WAKEUP, 0,

NULL, 0,

USB_CTRL_SET_TIMEOUT);

} else {

/* device has up to 10 msec to fully suspend */

dev_dbg(&udev->dev, "usb suspend/n");

usb_set_device_state(udev, USB_STATE_SUSPENDED);  /*设置设备状态*/

msleep(10);

}

return status;

}

OK, 很简单把usb设备attach上的那个port disable掉, 就可以达到休眠的目的了(当然实际上它只是把这个port所在的那条链路上的传输停掉, 至于设备是否真会休眠要考设备本省的, 正常情况下, 设备硬件会检测总线上是否有传输, 如没有则把设备转入suspend状态).

OK, 理解了USB设备如何休眠, 那么对于USB设备如何唤醒就很清楚了, 就是重新enable那个port就行了. 这里就不在分析了.

因此假如说我们的设备要在打开之后禁止休眠, 在关闭之后才允许休眠, 该怎么做呢? 呵呵,只要在驱动的open函数里resume设备, 在close函数里suspend设备就行了.

至于2.6.19以后的版本, 加入了自动休眠的功能, 具体实现原理可以参考由fudan_abc写的<<linux那些事儿之HUB>>

转载于:https://www.cnblogs.com/sky-heaven/p/4979931.html

Linux下USB suspend/resume源码分析【转】相关推荐

  1. linux nat源码分析,Linux下NAT/NAPT规则源码分析

    前面有一篇文章分析了为什么在PREROUTING做DNAT对本地连接不起作用?本文再紧接着上文,深入分析一下NAT/NAPT的规则. 事情的起因要从上的那篇的文章说起,因为我的本科生毕业设计也是做P2 ...

  2. 通用USB设备驱动源码分析

    通用USB设备驱动源码分析 Author:aaron 前段时间写了篇<qualcomm usb modem驱动小结>的文章, 描述了自己如何为高通的一个usb modem设备写驱动的过程, ...

  3. Linux Kernel 2.6.9源码分析 -- send/recieve 报文

    Linux Kernel 2.6.9源码分析 – send/recieve 报文 可用户socket报文读写的函数有以下几对: ssize_t read(int fd, void *buf, size ...

  4. Linux ALSA驱动之Platform源码分析(wm8350.c)

    1.Platform概述 ASoC被分为Machine,Platform和Codec三大部件,Platform驱动的主要作用是完成音频数据的管理,最终通过CPU的数字音频接口(DA〉把音频数据传送给C ...

  5. Linux kernel 3.10内核源码分析--进程上下文切换

    一.疑问 进程调度时,当被选中的next进程不是current进程时,需要进行上下文切换. 进行上下文切换时,有一些问题不太容易理解,比如: 1.进程上下文切换必然发生在内核态吗? 2.上下文切换后原 ...

  6. 基于Linux的UART驱动框架源码分析笔记

    文章目录 前言 一.I.MX6ULL串口接收和发送方式 1.非DMA方式 1.1.接收方式 1.2 发送方式 2.DMA方式 2.1.接收方式 2.2 发送方式 二.UART驱动注册 1.uart_r ...

  7. vfp赋值超过7位出错_JDK1.7下的HashMap的源码分析

    源码分析jdk1.7下的HashMap 我们都知道1.7版本的hashmap的底层是数组加链表构成的,那么今天我们就来自己分析一波源码~ 篇幅有点长,废话不多说,直接开始分析~ 「属性声明」 //初始 ...

  8. linux ptrace 内核源码分析,linux 3.5.4 ptrace源码分析分析(系列一)

    ptrace是linux系统中为了调试专门设立的一种系统调用.要想调试调试一个进程,有两种方式: PTRACE_TRACEME和PTRACE_ATTACH.这两种方式的主要区别可以概括为: PTRAC ...

  9. Linux下如何编译Android源码~~~

    使用的是putty.exe软件 本身机器windows环境连接服务器的linux环境编译android putty.exe界面在上面有提到了 输入你的账号密码后会进入 这样的效果就算是成功了可以ls就 ...

最新文章

  1. 95后程序员业余帮人鉴定毒蘑菇,竟成百万粉丝的网络大V!
  2. kali2018.2安装配置OpenVAS-9及错误处置
  3. 判断字符串是不是数字
  4. 字符编码总结(UTF-8,UNICODE)
  5. 求数组的子数组之和的最大值
  6. makefile文件中的依赖关系理解
  7. 凯斯西储大学计算机工程排名,[转载]凯斯西储大学排名及世界排名【研究生】...
  8. 职业生涯第一次:老板让我写个 BUG!
  9. BZOJ2366 : 多重历史
  10. 树莓派2代干货帖(第一天)按图索骥的搭建
  11. LC60 Permutation Sequence
  12. hikaricp mysql_JAVA连接数据库 #03# HikariCP
  13. 搞懂:1.数据流图UML2.单代号网络图绘制3.双代号网络图绘制、工作计算法、关键路径法(含例题)
  14. 栈的应用:火车调度问题
  15. MATLAB--特征值和特征向量 及具体应用
  16. javascript(String, Array, Math, Date, Object)方法整理
  17. Suse linux 命令行
  18. CSS文本超过两行用省略号代替(兼容所有浏览器)
  19. 使用 idea查看类关系图形
  20. 美元指数是什么,为什么会对伦敦金有影响

热门文章

  1. Nagios+mutt+msmtp 无法发送邮件的问题!
  2. 写出一个超强的lighttpd模块
  3. javax/management/DynamicMBean
  4. html景图片怎么设置百分比,8个风光照片拍摄技巧
  5. 面试官:你都工作3年了,连选择排序法都不会,我怎么能选择你
  6. docker删除es数据_docker问题:quot;rpc error: code = 2 desc = containerd: container ...quot;
  7. python精品课_【人生苦短,我用Python】Python免费精品课连载(1)——Python入门
  8. 如何从 Ubuntu 中彻底卸载 Google Chrome
  9. 如何在Linux系统上部署接口测试环境
  10. 单片机开发项目全局变量太多怎么管理?