Linux那些事儿之我是Hub(大结局)挂起自动化

原创 2007年09月28日 17:56:00

目睹了当今大学校园的素质流氓化,kiss公开化,消费白领化,上课梦游化,逃课普遍化,补考专业化之后,区里的人们很时髦的提出了一个挂起自动化的概念.

接下来的一个话题就是autosuspend/autoresume.

所谓的autosuspend就是driver自己判断是否需要挂起,而之前的suspend/resume是受外界影响的,比如说PM core统一的系统级的挂起,或者用户通过sysfs来触发的.于是我们现在就来看driver是如何自己判断的.首先从autosuspend_check看起,因为这个函数我们已经见过了,只是没有讲,usb_suspend_both中就会调用它.它来自drivers/usb/core/driver.c:

    930 /* Internal routine to check whether we may autosuspend a device. */

    931 static int autosuspend_check(struct usb_device *udev)

    932 {

    933         int                     i;

    934         struct usb_interface    *intf;

    935         unsigned long           suspend_time;

    936

    937         /* For autosuspend, fail fast if anything is in use or autosuspend

    938          * is disabled.  Also fail if any interfaces require remote wakeup

    939          * but it isn't available.

    940          */

    941         udev->do_remote_wakeup = device_may_wakeup(&udev->dev);

    942         if (udev->pm_usage_cnt > 0)

    943                 return -EBUSY;

    944         if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)

    945                 return -EPERM;

    946

    947         suspend_time = udev->last_busy + udev->autosuspend_delay;

    948         if (udev->actconfig) {

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

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

    951                         if (!is_active(intf))

    952                                 continue;

    953                         if (intf->pm_usage_cnt > 0)

    954                                 return -EBUSY;

    955                         if (intf->needs_remote_wakeup &&

    956                                         !udev->do_remote_wakeup) {

    957                                 dev_dbg(&udev->dev, "remote wakeup needed "

    958                                                 "for autosuspend/n");

    959                                 return -EOPNOTSUPP;

    960                         }

    961                 }

    962         }

    963

    964         /* If everything is okay but the device hasn't been idle for long

    965          * enough, queue a delayed autosuspend request.

    966          */

    967         if (time_after(suspend_time, jiffies)) {

968                 if (!timer_pending(&udev->autosuspend.timer)) {

    969

    970                         /* The value of jiffies may change between the

    971                          * time_after() comparison above and the subtraction

    972                          * below.  That's okay; the system behaves sanely

    973                          * when a timer is registered for the present moment

    974                          * or for the past.

    975                          */

    976                         queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,

    977                                         suspend_time - jiffies);

    978                         }

    979                 return -EAGAIN;

    980         }

    981         return 0;

    982 }

首先, 获得do_remote_wakeup,打不打开remote wakeup的功能是可以选择的.所以每次要记录下来.

pm_usage_cnt表示引用计数,自动挂起的第一个重要条件就是pm_usage_cnt0.即只有一个设备没有被使用了我们才能把它挂起,否则比如你正在和恋人视频聊天,突然给你挂起,那你肯定会把开源社区的所有人的母亲都给问候一遍.

autosuspend_delay,也是在八大函数之一的usb_alloc_dev中赋的值,默认就是2HZ,当然你可以自己设置,因为它是通过usbcore的模块参数usb_autosuspend_delay来设置的. usb_autosuspend_delay缺省值为2.另外这个值我们也可以通过sysfs来设置,如下所示:

localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # ls /sys/bus/usb/devices/1-1/power/

autosuspend  level  state  wakeup

autosuspend文件就是记录这个值的,以秒为单位.

localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # cat /sys/bus/usb/devices/1-1/power/autosuspend

2

可以看到,我没有设置过的话,它这个值就是2.这个值的意思是如果设备闲置了2s,那么它将被自动挂起,这就是autosuspend的目的,你可以把它设为负值,为负就表示设备不能被autosuspend,如果设备此时正处于suspended状态而你写一个负值进去,它将立刻被唤醒.写个0则表示设备将立刻被autosuspended.

再来看autosuspend_disabled.前面我们有看到一个autoresume_disabled,这两个变量的含义都如字面意义一样.这两个变量都可以通过sysfs来改变,

localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # ls /sys/bus/usb/devices/1-1/power/

autosuspend  level  state  wakeup

这里的这个level就是反映的设备的电源级别,确切的说它就是通过sysfs为用户提供了一个自己挂起设备的方法.

localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # cat /sys/bus/usb/devices/1-1/power/level

auto

它可以为auto/on/suspend,这里我们看到它是auto,auto是最为常见的级别,on就意味着我们不允许设备进行autosuspend,autosuspenddisable,或者说这里的autosuspend_disabled被设置为了1.如果是suspend,就意味着我们不允许设备进行autoresume,并且强迫设备进入suspended状态.即我们设置autoresume_disabled1,并且调用usb_external_suspend_device()去挂起设备,这就是sysfs提供给用户的suspend单个设备的方法.

auto状态意味着autosuspend_disabledautoresume_disabled都没有设置,即都为0,任其自然.

到这里你就能明白为什么我们当初在usb_resume中以及在usb_resume_both中会判断udev->autoresume_disabled.因为设置了这个flag就等于对resume宣判了死刑.同样这里对udev->autosuspend_disabled的判断也是一样的道理.

last_busy,struct usb_device的成员,unsigned long last_busy,有注释说time of last use,不过我不知道该如何用中文表达,只可意会不能言传.不过没关系,我们慢慢看就明白了,其实你会发现在resume之后会更新它,suspend之前也会更新它.你搜索一下源代码就会发现,其实这个变量基本上就被赋了一个值,那就是传说中的jiffies,所以它实际上就是记录着这么一个时间值,我们这里947,给一个局部变量suspend_time赋值,赋的就是udev->last_busy加上udev->autosuspend_delay,我们马上就会看到suspend_time干嘛用的.

948962,这一段就是判断各种异常条件,只有这些通通满足了才有必要作autosuspend. 其中,needs_remote_wakeup咱们在hub_probe()中见过,它是struct usb_interface的一个成员,unsigned needs_remote_wakeup,缺省值就是1.咱们在hub_probe中也是设置为1.如果设备需要remote wakeup,do_remote_wakeup被设置为了0,那么就是说我本来需要被远程唤醒的,你却把我这项功能禁掉了,那么对于这种情况,这里保险起见,就不进行autosuspend,因为万一把设备催眠了之后唤不醒了那就糟了,省电是省电了,设备醒不过来了,除非重起机器否则没办法了,这就属于捡了芝麻丢了西瓜的情况,咱们当然不能做.

964行的注释说的很明白,如果一切Okay,咱们才进行下面的代码,

这里有两个时间方面的函数,time_after,这个函数返回真如果从时间上来看,第一个参数在第二个参数之后.这里就是说如果suspend_timejiffies,我们刚才刚看了suspend_time的赋值,缺省来说suspend_time就比jiffies要多一个autosuspend_delay,2秒钟,所以这里为真.

第二个函数timer_pending就是判断一个计时器到点了没有,如果没有到点,即所谓的pending状态,那么函数返回真,否则返回0.这里参数是udev->autosuspend.timer,这个东东我们在八大函数之一的usb_alloc_dev中调用INIT_DELAYED_WORK进行了初始化,进一步跟踪会发现实际上是调用init_timer()来初始化timer,init_timertimer->entry.next=NULL,我们不用管这句话啥意思,但是我们可以看到,timer_pending就是一个内联函数,来自include/linux/timer.h,

     51 /**

     52  * timer_pending - is a timer pending?

     53  * @timer: the timer in question

     54  *

     55  * timer_pending will tell whether a given timer is currently pending,

     56  * or not. Callers must ensure serialization wrt. other operations done

     57  * to this timer, eg. interrupt contexts, or other CPUs on SMP.

     58  *

     59  * return value: 1 if the timer is pending, 0 if not.

     60  */

     61 static inline int timer_pending(const struct timer_list * timer)

     62 {

     63         return timer->entry.next != NULL;

     64 }

所以很显然,这个函数将返回0.因为timer->entry.next==NULL.当然,我是说第一次.以后就不一样了. 因为这里queue_delayed_work()会执行,我们前面已经提过,所以这行的意思就很简单了,udev->autosuspend这个任务加入到ksuspend_usb_wq这个工作队列中去.并且设置了延时suspend_time – jiffies,基本上这就意味着2秒之后就调用udev->autosuspend所对应的函数,即我们在usb_alloc_dev中用INIT_DELAYED_WORK注册的那个函数usb_autosuspend_work函数.因此我们就可以继续看usb_autosuspend_work这个函数了,来自drivers/usb/core/driver.c:

   1209 /* usb_autosuspend_work - callback routine to autosuspend a USB device */

   1210 void usb_autosuspend_work(struct work_struct *work)

   1211 {

   1212         struct usb_device *udev =

   1213                 container_of(work, struct usb_device, autosuspend.work);

   1214

   1215         usb_autopm_do_device(udev, 0);

   1216 }

其实调用的是usb_autopm_do_device,

   1182 /* Internal routine to adjust a device's usage counter and change

   1183  * its autosuspend state.

   1184  */

   1185 static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)

   1186 {

   1187         int     status = 0;

   1188

   1189         usb_pm_lock(udev);

   1190         udev->auto_pm = 1;

   1191         udev->pm_usage_cnt += inc_usage_cnt;

   1192         WARN_ON(udev->pm_usage_cnt < 0);

   1193         if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {

   1194                 if (udev->state == USB_STATE_SUSPENDED)

   1195                         status = usb_resume_both(udev);

   1196                 if (status != 0)

   1197                         udev->pm_usage_cnt -= inc_usage_cnt;

   1198                 else if (inc_usage_cnt)

   1199                         udev->last_busy = jiffies;

   1200         } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {

   1201                 if (inc_usage_cnt)

   1202                         udev->last_busy = jiffies;

   1203                 status = usb_suspend_both(udev, PMSG_SUSPEND);

   1204         }

   1205         usb_pm_unlock(udev);

   1206         return status;

   1207 }

1193,inc_usage_cnt咱们传递进来的是0,但你会发现有的函数传递进来的是1,比如usb_autoresume_device,有的函数传递进来的是-1,比如usb_autosuspend_device,还有另一个地方, usb_try_autosuspend_device,传递进来的也是0.不过在2.6.22.1的内核中,总共也就这四处调用了usb_autopm_do_device这个函数.所以我们这里一并来看.

对于inc_usage_cnt大于等于0的情况,如果pm_usage_cnt也大于0,那么如果设备此时又处于SUSPENDED状态,那么我们就调用usb_resume_both把它给恢复过来,恢复过来之后,设置last_busyjiffies,记录下这一神圣的时刻.如果没能恢复,那么就把pm_usage_cnt减回去.

如果inc_usage_cnt小于等于0,如果pm_usage_cnt也小于等于0,那么没什么好说的,把设备给挂起,挂起之前用last_busy记录下设备活着的那一时刻.

由于咱们这个情景传递进来的inc_usage_cnt0,所以last_busy没有改变.pm_usage_cnt也没有改变,这就意味着咱们并不做什么引用计数上的改变,只是纯粹的check,如果当前引用计数大于0而设备居然是挂起的状态,那么赶紧唤醒,如果当前引用计数已经小于等于0,那么就自觉地挂起.

于是我们接下来要做的是两件事情,第一个,看一下另外三个调用usb_autopm_do_device的函数,第二个,回到usb_suspend_both中去看一下autosuspend_check是在什么情景下被调用的.

先看第二个问题,回过头来看usb_suspend_both,发现,1042行和1068,如果udev->auto_pm不为0,就调用autosuspend_check,auto_pm不为0恰恰是在usb_autopm_do_device中设置的,比如这里的1190,还有一种可能是在usb_autopm_do_interface中设置的.后者我们暂时先不看.

调用usb_suspend_both的地方总共有三处,usb_autopm_do_device/usb_autopm_do_interface/usb_external_suspend_device,很显然,前两者属于同一情况,它们属于autosuspend/autoresume类型的,第三者属于另一种情况,它属于对非autosuspend的支持,即对PM core或者sysfs接口的支持.usb_external_suspend_device,调用usb_suspend_both之前先设置了auto_pm0.

所以,对于autosuspend,usb_suspend_both首先会调用autosuspend_check,进而usb_autopm_do_device会被调用,而后者又会根据实际情况调用usb_suspend_both或者usb_resume_both.

而对于非autosuspend,usb_suspend_both虽然也会被调用,但是autosuspend_check是不会执行的.

那么我们现在来看是另外三种调用usb_autopm_do_device的情况.三个函数全都来自drivers/usb/core/driver.c:

   1218 /**

   1219  * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces

   1220  * @udev: the usb_device to autosuspend

   1221  *

   1222  * This routine should be called when a core subsystem is finished using

   1223  * @udev and wants to allow it to autosuspend.  Examples would be when

   1224  * @udev's device file in usbfs is closed or after a configuration change.

   1225  *

   1226  * @udev's usage counter is decremented.  If it or any of the usage counters

   1227  * for an active interface is greater than 0, no autosuspend request will be

   1228  * queued.  (If an interface driver does not support autosuspend then its

   1229  * usage counter is permanently positive.)  Furthermore, if an interface

   1230  * driver requires remote-wakeup capability during autosuspend but remote

   1231  * wakeup is disabled, the autosuspend will fail.

   1232  *

   1233  * Often the caller will hold @udev's device lock, but this is not

   1234  * necessary.

   1235  *

   1236  * This routine can run only in process context.

   1237  */

   1238 void usb_autosuspend_device(struct usb_device *udev)

   1239 {

   1240         int     status;

   1241

   1242         status = usb_autopm_do_device(udev, -1);

   1243         // dev_dbg(&udev->dev, "%s: cnt %d/n",

   1244         //              __FUNCTION__, udev->pm_usage_cnt);

   1245 }

   1246

   1247 /**

   1248  * usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces

   1249  * @udev: the usb_device to autosuspend

   1250  *

   1251  * This routine should be called when a core subsystem thinks @udev may

   1252  * be ready to autosuspend.

   1253  *

   1254  * @udev's usage counter left unchanged.  If it or any of the usage counters

   1255  * for an active interface is greater than 0, or autosuspend is not allowed

   1256  * for any other reason, no autosuspend request will be queued.

   1257  *

   1258  * This routine can run only in process context.

   1259  */

   1260 void usb_try_autosuspend_device(struct usb_device *udev)

   1261 {

   1262         usb_autopm_do_device(udev, 0);

   1263         // dev_dbg(&udev->dev, "%s: cnt %d/n",

   1264         //              __FUNCTION__, udev->pm_usage_cnt);

   1265 }

   1266

   1267 /**

   1268  * usb_autoresume_device - immediately autoresume a USB device and its interfaces

   1269  * @udev: the usb_device to autoresume

   1270  *

   1271  * This routine should be called when a core subsystem wants to use @udev

   1272  * and needs to guarantee that it is not suspended.  No autosuspend will

   1273  * occur until usb_autosuspend_device is called.  (Note that this will not

   1274  * prevent suspend events originating in the PM core.)  Examples would be

   1275  * when @udev's device file in usbfs is opened or when a remote-wakeup

   1276  * request is received.

   1277  *

   1278  * @udev's usage counter is incremented to prevent subsequent autosuspends.

   1279  * However if the autoresume fails then the usage counter is re-decremented.

   1280  *

   1281  * Often the caller will hold @udev's device lock, but this is not

   1282  * necessary (and attempting it might cause deadlock).

   1283  *

   1284  * This routine can run only in process context.

   1285  */

   1286 int usb_autoresume_device(struct usb_device *udev)

   1287 {

   1288         int     status;

   1289

   1290         status = usb_autopm_do_device(udev, 1);

   1291         // dev_dbg(&udev->dev, "%s: status %d cnt %d/n",

   1292         //              __FUNCTION__, status, udev->pm_usage_cnt);

   1293         return status;

   1294 }

不看不知道,一看吓一跳,竟然都是如此赤裸裸的调用usb_autopm_do_device函数,用黎叔的话说,那叫一点儿技术含量都没有!

不过调用这三个函数的地方却很多很多.甚至我们都曾经见过,比如在usb_suspend_both中就调用了usb_autosuspend_device,用它来挂起父设备.即有这么一种可能,usb_autosuspend_device调用usb_suspend_both挂起当前设备,usb_suspend_both则调用autosuspend_check并进而是usb_autopm_do_device去挂起当前设备,usb_autopm_do_device又还是调用usb_suspend_both去挂起设备,,怎么看怎么觉得我们走进了一个迷宫,走进了一条死胡同.很明显的是你调用我我调用你,这还不挂了?其实您尽管放心,别以为写代码的兄弟们都是吃素的,事实上有一把锁专门来对付这些情况,我们看到,usb_external_suspend_device中调用usb_suspend_both的前后,调用了这两个函数:usb_pm_lock/usb_pm_unlock,usb_external_resume_device,调用usb_resume_both前后也是如此,而在usb_autopm_do_deviceusb_autopm_do_interface,也需要使用这些两个函数,即只有获得了这把锁才能去调用usb_resume_both或者usb_suspend_both.所以,你尽管放心,永远只有一个人能执行usb_suspend_both或者usb_resume_both,绝不可能陷入所谓的死胡同.所以其实你也看出来了,对于挂起,无论是不是自动化,里面终不过围绕一个函数,usb_suspend_both,对于唤醒,无论是不是自动化,里面终不过围绕一个函数,usb_resume_both,就好比,无论男人给女人讲多么浪漫的童话故事,里面终不过围绕一个字:!

我想现在是时候来做一次总结了,关于电源管理方面的总结,先说autosuspend,我们来看对usb_try_autosuspend_device的调用,前面我们在usb_external_resume_device中就看见了对它的调用,唤醒了设备之后,就尝试着看是否可以自动挂起.这其实体现的是一种勤俭节约的理念,因为autosuspend/autoresume这东西吧,纯粹是一种软件角度的主动,即从driver这边来自己做判断,凭借着第六感,当它觉得应该挂起设备的时候,它就会去尝试调用相关的挂起函数,当它觉得应该唤醒设备的时候,它就会去调用相关的唤醒函数.

那么也就是说,在整个USB子系统里,对电源管理的支持是按照两步走的.头些年,我们先实现传统的挂起/唤醒,即比如合上笔记本的时候,PM core那边会按设备树来依次调用各个驱动的suspend函数,醒来的时候则调用相应的resume函数.于是从整个usb子系统的角度来说,我们提供了usb_suspend/usb_resume这两个函数.另一方面,我们这里把函数取名为usb_external_suspend_deviceusb_external_resume_device也是针对PM core的系统睡眠(System Sleep),即我们把来自PM core的挂起请求/唤醒请求称为外部请求.usb_suspend/usb_resume内部所调用的正是这两个函数.另一种调用usb_external_suspend_device/usb_external_resume_device的情况是通过sysfs的接口,由用户来触发,即通过改变前面我们看到的sysfs下面那个level的值来触发挂起或者唤醒.

完了后来第二步,大家觉得光这样不过瘾,于是又引入了autosuspend的概念.就是说驱动程序在适当的位置,自己去调用那些挂起函数/唤醒函数.即便PM core那边没有这个需求.就比如刚才这里这个对usb_try_autosuspend_device的调用,即设备刚刚唤醒,驱动程序就去检查看看是否可以挂起设备,因为可能你不小心唤醒了它但是你也许并不使用它,那么从省电的角度来说,驱动程序有足够的理由再次把你挂起.而像这种情形有很多,我们只要搜索一下看看有多少地方调用了usb_autosuspend_device/usb_autoresume_device就可以知道,在许多地方我们都这么做了.现以我们前面见过但没有讲的一个地方为例子说一下:

当初我们在usb_reset_composite_device中看到的,3076行我们调用了usb_autoresume_device,3119行我们调用了usb_autosuspend_device.后者很好理解,把一个设备reset之后,首先就去尝试把它挂起,理由很简单,比如你开机之后,你可能只是开机,你根本没打算使用任何usb设备,那么usb这边就默认把所有的设备都给挂起.等你真正要用的时候再去唤醒.而前者的目的更加简单,就是为了阻止后者的执行,因为这两个函数都将会调用usb_autopm_do_device,而那句usb_pm_lock注定了这是一条独木桥,有你就没有我,有我便没有你.

最后再来关注一个变量,last_busy.它正是为autosuspend而生的.我们不难发现,每次设备被唤醒之后我们会把last_busy设置为当时的jiffies,每次设备将要被挂起之前我们会把last_busy设置为当时的jiffies.而真正要利用last_busy的是autosuspend_check函数,因为在该函数内,suspend_time被赋值为last_busy加上autosuspend_delay,假设后者为2s.那么就是说suspend_timelast_busy加上2.比如说我们记录下上次设备被使用的时候last_busy3250,而现在是北京时间3251,那么我们调用autosuspend_check的话就会激发一次与之相关的函数usb_autosuspend_work.反之如果现在已经是北京时间4点了,那么说明我们已经没有必要激发usb_autosuspend_work.换言之,last_busy就是被用来决定是否进行autosuspend的一个flag.last_busy记录的是设备正忙的时间,设备总是在闲置了足够长的时间才可以被挂起.很显然,没有last_busy,这个autosuspend_delay也就没法起作用了,毕竟这个2s总要在一个时间起点上开始加上去.当然,last_busysuspend_time这两个变量也只是几个月前才被加入到内核中来的,以前的内核中并没有这么两个变量.当时Alan大侠添加这个变量的目的是为了完善他的autosuspend.喜欢考古的朋友们不难从今年3月底linux-usb-devel邮件列表里挖出他当时的陈述:

This patch (as877) adds a "last_busy" field to struct usb_device, for
use by the autosuspend framework. Now if an autosuspend call comes at
a time when the device isn't busy but hasn't yet been idle for long
enough, the timer can be set to exactly the desired value. And we
will be ready to handle things like HID drivers, which can't maintain
a useful usage count and must rely on the time-of-last-use to decide
when to autosuspend.

用中文来说,就是两个理由要加入这么一个变量,一个是比如autosuspend调用发生的时候,它希望知道设备是否忙,用充分必要条件理论来说,设备不忙是autosuspend的必要条件,但这个必要条件满足了并不意味着设备会马上挂起,因为我们有一个autosuspend_delay,即我们可以设置延时,如果按默认的2s钟来说,那你设备至少要闲置了2秒钟才会被挂起.所以就需要这么一个flag,经常去记录着某个时间点,比如我们在autoresume之后的那一瞬间,又比如我们在autosuspend之前的一瞬间.道理很简单,第一,设备醒来之后那一瞬间基本上可以认为是忙的,如果不忙它干嘛不继续睡?第二,设备睡觉之前那一瞬间基本上也可以认为是忙的,如果不忙干嘛不早点睡?

引入last_busy的第二个理由是为了HID设备驱动的,比如鼠标,键盘.因为它们的挂起需要用一个时间来判断.不过我说过了,autosuspend是一个很新的理念,所以至少到2.6.22.1的内核中,HID那边还没有提供对autosuspend足够的支持,但是相信在不久的将来last_busy会被HID Drivers用到的.我们拿触摸屏来举例,我们知道苹果的ipod系列很多都是有触摸屏的,那么从驱动程序的角度来说呢,所谓的autosuspend,理想情况就是,driver能够检测到你的手指离开了触摸屏,然后隔一段时间driver就可以把设备自动挂起,反过来,driver一旦检测到你的手指回来了,它又把设备唤醒.

网友丰胸化吉问我,那为何last_busy记录的是resume之后以及suspend之前的时间,而不是记录别的时间?这其实无所谓,你想多记录几个也没人拦住你,记录这几个时间的作用就是让autosuspend能在它们之后的两秒之后再执行,并没有更多的意思.你要是觉得某个地方之后不能立刻被挂起,那么你也可以在该处记录一个last_busy.不过目前来看其它地方似乎并没有这个需求罢了.

好了,我的故事又讲完了.我知道,我并非是刻意追求娱乐技术化或者技术娱乐化,或许我只是在写一个北漂人的无奈,又或许我只是借文字以寻觅自己的未来.此时此刻,电台里放起了赵传的我是一只小小鸟,耳边响起了那耐人寻味的歌词:有时候我觉得自己是一只小小鸟,想要飞却怎么也飞不高,也许有一天我攀上了枝头(读完了大学)却成为住不起房子的人,飞上了青天(来到了北京)才发现自己从此无依无靠...每次到了夜深人静的时候我总是睡不着,我怀疑是不是只有我的明天没有变得更好,未来会怎样究竟有谁会知道,幸福是否只是一种传说我永远都找不到... 

版权声明:本文为博主原创文章,未经博主允许不得转载。

两种禁止USB autosuspend的方法

在有些情况下,由于低功耗情况下,USB硬件的bug或者提高USB resume的速度,我们需要禁止USB的 autosuspend,下面是两种方法。 1: 在bootloader的bootargs...
  • hzpeterchen
  • hzpeterchen
  • 2016年03月04日 14:19
  • 1835

linux下的USB HUB驱动

一:前言 继UHCI的驱动之后,我们对USB Control的运作有了一定的了解.在接下来的分析中,我们对USB设备的驱动做一个全面的分析,我们先从HUB的驱动说起.关于HUB,usb2.0 spe...
  • zhengmeifu
  • zhengmeifu
  • 2012年06月23日 16:07
  • 5331

Linux那些事儿 之 我是PCI(5)初始化(二)

.initcall2.init子节中的两个函数已经见识过了,该轮到.initcall3.init子节里的了,就是上边儿表中的acpi_pci_init和pci_access_init,这两个又是谁先谁...
  • mrwangwang
  • mrwangwang
  • 2014年06月12日 18:51
  • 2343

Linux那些事儿 之 我是PCI(4)初始化(一)

解析完了PCI的那些内核参数,再翻过多少座山跨过多少条河,内核就会遇到init/main.c里一个名叫do_initcalls的函数。do_initcalls对内核来说只不过是漫长冒险旅程中的一个驿站...
  • mrwangwang
  • mrwangwang
  • 2014年06月12日 17:31
  • 1188

Linux那些事儿 之 我是PCI(2)PCI全接触

中新浙江网11月6日电 近日,备受关注的浙江湖州市南浔区三人围追堵截偷车贼,致使小偷跳河溺水身亡的不作为间接故意杀人案,终于尘埃落定。     昨天,湖州市南浔区法院对三人一审判决颜克于犯故意杀人罪...
  • mrwangwang
  • mrwangwang
  • 2014年06月12日 17:26
  • 1234

Linux那些事儿 之 戏说USB(大结局)还是那个match

从上次在几米的向左走向右走遇到usb总线的那个match函数usb_device_match()开始到现在,遇到了设备,遇到了设备驱动,遇到了接口,也遇到了接口驱动,期间还多次遇到usb_device...
  • zhqh100
  • zhqh100
  • 2015年03月28日 21:18
  • 483

【连载】【FPGA黑金开发板】Verilog HDL那些事儿--GUI系统(二十五)(大结局)

声明:本文转载于http://www.cnblogs.com/kingst,版权归akuei2及黑金动力社区(http://www.heijin.org)共同所有。6.3 实验二十四:GUI系统终于写...
  • engelbert
  • engelbert
  • 2011年05月04日 14:20
  • 564

Linux用户管理详解大结局(下)

Linux用户管理详解(下) 我们已经可以通过创建不同的用户来防止其他人使用自己的账号,之后每个账户对应一个单独的用户密码,构成了一个基本的用户管理思路。为了方便管理还可以使用组来设置相同属性的...
  • disence
  • disence
  • 2012年05月03日 11:14
  • 136

Linux那些事儿之我是Hub

  • 2007年09月29日 19:44
  • 1.31MB
  • 下载

Linux那些事儿(包括Hub, Sysfs, UHCI, USB, U盘5个部分)

  • 2009年03月02日 10:43
  • 5.18MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux那些事儿之我是Hub(大结局)挂起自动化
举报原因:
原因补充:

(最多只允许输入30个字)