• Android usb子系统的 电源管理 流程分析




    对的处理器是高通MSM8260,主要是针对一些挂起唤醒流程进行分析,以便对整个usb框架流程更好的理解。

     
    由于linux中的电源管理比较复杂,我就找了一个统一的接口,也就是 要想操纵usb的电源管理 必定要调的函数。顺便说下,跟踪代码最好的方法是用WARN_ON(1)打调用栈。

    先看电源管理子系统的一些初始化:



    /*系统初始化所用的结构体*/
    struct device {

     .....
     struct dev_pm_info power;  //电源管理结构体
     .....
    };



    /*该结构体定义如下*/
    struct dev_pm_info {

     pm_message_t  power_state;
     unsigned int  can_wakeup:1;  //can_wakeup标志 表示设备(或驱动)物理上 支持唤醒事件
     unsigned int  should_wakeup:1;  //should_wakeup标志 控制设备是否应该尝试启用他的唤醒机制
     unsigned  async_suspend:1;
     enum dpm_state  status;  /* Owned by the PM core */

    #ifdef CONFIG_PM_SLEEP
     struct list_head entry;  //链接到dpm_list链表的节点
     struct completion completion;
    #endif

    #ifdef CONFIG_PM_RUNTIME
     struct timer_list suspend_timer;  //处理自动挂起的timer
     unsigned long  timer_expires;
     struct work_struct work;  //请求处理用的work
     wait_queue_head_t wait_queue;  //等待队列头
     spinlock_t  lock;
     atomic_t  usage_count;
     atomic_t  child_count;
     unsigned int  disable_depth:3;
     unsigned int  ignore_children:1;
     unsigned int  idle_notification:1;
     unsigned int  request_pending:1;
     unsigned int  deferred_resume:1;
     unsigned int  run_wake:1;
     unsigned int  runtime_auto:1;
     enum rpm_request request;
     enum rpm_status  runtime_status;
     int   runtime_error;
    #endif
    };



    /*在设备加入设备驱动模型时,对设备进行初始化*/
    device_initialize(&dev->dev);

    void device_initialize(struct device *dev)
    {
     ............
     device_pm_init(dev);  //继续进行初始化
     ...............
    }
     
    void device_pm_init(struct device *dev)
    {
     dev->power.status = DPM_ON;
     init_completion(&dev->power.completion);
     complete_all(&dev->power.completion);
     pm_runtime_init(dev);  //调用该函数继续进行初始化
    }

    void pm_runtime_init(struct device *dev)
    {
     spin_lock_init(&dev->power.lock);
     dev->power.runtime_status = RPM_SUSPENDED;
     dev->power.idle_notification = false;
     dev->power.disable_depth = 1; //初始化时,disable该pm runtime功能
     atomic_set(&dev->power.usage_count, 0);
     dev->power.runtime_error = 0;
     atomic_set(&dev->power.child_count, 0);
     pm_suspend_ignore_children(dev, false);
     dev->power.runtime_auto = true;
     dev->power.request_pending = false;
     dev->power.request = RPM_REQ_NONE;
     dev->power.deferred_resume = false;
     INIT_WORK(&dev->power.work, pm_runtime_work);  //处理autosuspend请求用的work
     
     /*处理work请求定时器*/
     dev->power.timer_expires = 0;
     setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,(unsigned long)dev);
     init_waitqueue_head(&dev->power.wait_queue);//初始化等待队列
    }
     
    ***************************************************************
    /*注册的usb总线级别的操作*/
    static int usb_runtime_suspend(struct device *dev)//usb的挂机函数
    {
     int status = 0;
     /* A USB device can be suspended if it passes the various autosuspend
      * checks.  Runtime suspend for a USB device means suspending all the
      * interfaces and then the device itself.
      */
     if (is_usb_device(dev)) {//针对usb设备
      struct usb_device *udev = to_usb_device(dev);
      if (autosuspend_check(udev) != 0)//是否支持自动挂起?
            return -EAGAIN;
      status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);// 如果不支持,则继续挂机流程
      /* If an interface fails the suspend, adjust the last_busy
       * time so that we don't get another suspend attempt right
       * away.
       */
      if (status) {
       udev->last_busy = jiffies + (udev->autosuspend_delay == 0 ? HZ/2 : 0);
      }
      /* Prevent the parent from suspending immediately after */
      else if (udev->parent) {
       udev->parent->last_busy = jiffies;
      }
     }
     /* Runtime suspend for a USB interface doesn't mean anything. */
     return status;
    }
     
    static int usb_runtime_resume(struct device *dev)//usb的唤醒函数
    {
     /* Runtime resume for a USB device means resuming both the device
      * and all its interfaces.
      */
     if (is_usb_device(dev)) {
      struct usb_device *udev = to_usb_device(dev);
      int   status;
      status = usb_resume_both(udev, PMSG_AUTO_RESUME);
      udev->last_busy = jiffies;
      return status;
     }
     /* Runtime resume for a USB interface doesn't mean anything. */
     return 0;
    }
    static int usb_runtime_idle(struct device *dev)//usb设备的idle函数
    {
     /* An idle USB device can be suspended if it passes the various
      * autosuspend checks.  An idle interface can be suspended at
      * any time.
      */
     if (is_usb_device(dev)) {
      struct usb_device *udev = to_usb_device(dev);
      if (autosuspend_check(udev) != 0)//支持自动挂起
       return 0;
     }
     pm_runtime_suspend(dev);
     return 0;
    }
    static struct dev_pm_ops usb_bus_pm_ops = {
     .runtime_suspend = usb_runtime_suspend,
     .runtime_resume = usb_runtime_resume,
     .runtime_idle =  usb_runtime_idle,
    };
    struct bus_type usb_bus_type = {
     .name =  "usb",
     .match = usb_device_match,
     .uevent = usb_uevent,
     .pm =  &usb_bus_pm_ops,
    };

    上面是系统和usb子系统的电源管理初始化部分。


    /**************************************************************************/
    usb子系统电源管理的调用过程,必须要调用下面两个函数,就从这两个函数开始跟起。
    /*驱动调用的接口开始,传入的是usb设备结构体或者usb接口设备结构体*/
    static inline int pm_runtime_put(struct device *dev)
    {
     return __pm_runtime_put(dev, false);
    }
    static inline int pm_runtime_put_sync(struct device *dev)
    {
     return __pm_runtime_put(dev, true);
    }
     
    上面两个函数一个是同步的一个是不同步的。先跟同步的:
    /*当sync为true时,走的如下流程*/
    int __pm_runtime_put(struct device *dev, bool sync)
    {
     int retval = 0;
     if (atomic_dec_and_test(&dev->power.usage_count))
      retval = sync ? pm_runtime_idle(dev) : pm_request_idle(dev);
     return retval;
    }
    int pm_runtime_idle(struct device *dev)
    {
     int retval;
     spin_lock_irq(&dev->power.lock);
     retval = __pm_runtime_idle(dev);
     spin_unlock_irq(&dev->power.lock);
     return retval;
    }

    static int __pm_runtime_idle(struct device *dev)
     __releases(&dev->power.lock) __acquires(&dev->power.lock)
    {
     dev->power.idle_notification = true;
     if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {
      spin_unlock_irq(&dev->power.lock);
      dev->bus->pm->runtime_idle(dev);//调用usb总线的idle函数
      spin_lock_irq(&dev->power.lock);
     } else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
      spin_unlock_irq(&dev->power.lock);
      dev->type->pm->runtime_idle(dev);
      spin_lock_irq(&dev->power.lock);
     } else if (dev->class && dev->class->pm
         && dev->class->pm->runtime_idle) {
      spin_unlock_irq(&dev->power.lock);
      dev->class->pm->runtime_idle(dev);
      spin_lock_irq(&dev->power.lock);
     }
     dev->power.idle_notification = false;
     wake_up_all(&dev->power.wait_queue);
     out:
     return retval;
    }
     
    /*usb总线的idle函数如下*/
    static int usb_runtime_idle(struct device *dev)
    {
     /* An idle USB device can be suspended if it passes the various
      * autosuspend checks.  An idle interface can be suspended at
      * any time.
      */
     if (is_usb_device(dev)) {
      struct usb_device *udev = to_usb_device(dev);
      if (autosuspend_check(udev) != 0)//检测是否自动挂起,如果是自动挂起的话,走自动挂起流程
       return 0;
     }
     pm_runtime_suspend(dev);//如果不是自动挂起,则继续suspend
     return 0;
    }
     
    int pm_runtime_suspend(struct device *dev)
    {
     int retval;
     spin_lock_irq(&dev->power.lock);
     retval = __pm_runtime_suspend(dev, false);
     spin_unlock_irq(&dev->power.lock);
     return retval;
    }
     
    int __pm_runtime_suspend(struct device *dev, bool from_wq)
     __releases(&dev->power.lock) __acquires(&dev->power.lock)
    {
     struct device *parent = NULL;
     bool notify = false;
     int retval = 0;
     dev_dbg(dev, "__pm_runtime_suspend()%s! ",
      from_wq ? " from workqueue" : "");
     repeat:
     /* Other scheduled or pending requests need to be canceled. */
     pm_runtime_cancel_pending(dev);
     if (dev->power.runtime_status == RPM_SUSPENDING) {
      DEFINE_WAIT(wait);
      if (from_wq) {
       retval = -EINPROGRESS;
       goto out;
      }
      /* Wait for the other suspend running in parallel with us. */
      for (;;) {
       prepare_to_wait(&dev->power.wait_queue, &wait, TASK_UNINTERRUPTIBLE);
       if (dev->power.runtime_status != RPM_SUSPENDING)
        break;
       spin_unlock_irq(&dev->power.lock);
       schedule();
       spin_lock_irq(&dev->power.lock);
      }
      finish_wait(&dev->power.wait_queue, &wait);
      goto repeat;
     }
     dev->power.runtime_status = RPM_SUSPENDING;
     dev->power.deferred_resume = false;
     if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
      spin_unlock_irq(&dev->power.lock);
      retval = dev->bus->pm->runtime_suspend(dev);//调用总线的runtime suspend函数
      spin_lock_irq(&dev->power.lock);
      dev->power.runtime_error = retval;
     } else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend) {
      spin_unlock_irq(&dev->power.lock);
      retval = dev->type->pm->runtime_suspend(dev);
      spin_lock_irq(&dev->power.lock);
      dev->power.runtime_error = retval;
     } else if (dev->class && dev->class->pm
         && dev->class->pm->runtime_suspend) {
      spin_unlock_irq(&dev->power.lock);
      retval = dev->class->pm->runtime_suspend(dev);
      spin_lock_irq(&dev->power.lock);
      dev->power.runtime_error = retval;
     } else {
      retval = -ENOSYS;
     }
     wake_up_all(&dev->power.wait_queue);
     if (dev->power.deferred_resume) {
      __pm_runtime_resume(dev, false);
      retval = -EAGAIN;
      goto out;
     }
     if (notify)
      __pm_runtime_idle(dev);
     if (parent && !parent->power.ignore_children) {
      spin_unlock_irq(&dev->power.lock);
      pm_request_idle(parent);
      spin_lock_irq(&dev->power.lock);
     }
     out:
     dev_dbg(dev, "__pm_runtime_suspend() returns %d! ", retval);
     return retval;
    }
    static int usb_runtime_suspend(struct device *dev)
    {
     int status = 0;
     /* A USB device can be suspended if it passes the various autosuspend
      * checks.  Runtime suspend for a USB device means suspending all the
      * interfaces and then the device itself.
      */
     if (is_usb_device(dev)) {
      struct usb_device *udev = to_usb_device(dev);
      if (autosuspend_check(udev) != 0)//是否自動挂起,如果是走自动挂起流程
       return -EAGAIN;
      status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);//否则继续suspend
      /* If an interface fails the suspend, adjust the last_busy
       * time so that we don't get another suspend attempt right
       * away.
       */
      if (status) {
       udev->last_busy = jiffies +(udev->autosuspend_delay == 0 ? HZ/2 : 0);
      }
      /* Prevent the parent from suspending immediately after */
      else if (udev->parent) {
       udev->parent->last_busy = jiffies;
      }
     }
     /* Runtime suspend for a USB interface doesn't mean anything. */
     return status;
    }
    static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
    {
     int   status = 0;
     int   i = 0, n = 0;
     struct usb_interface *intf;
     if (udev->state == USB_STATE_NOTATTACHED || udev->state == USB_STATE_SUSPENDED)
      goto done;
     /* Suspend all the interfaces and then udev itself */
     if (udev->actconfig) {//挂起所有的接口
      n = udev->actconfig->desc.bNumInterfaces;
      for (i = n - 1; i >= 0; --i) {
       intf = udev->actconfig->interface[i];
       status = usb_suspend_interface(udev, intf, msg);
       if (status != 0)
        break;
      }
     }
     if (status == 0)
      status = usb_suspend_device(udev, msg);//挂起该设备本身
     /* If the suspend failed, resume interfaces that did get suspended */
     if (status != 0) {
      msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
      while (++i < n) {
       intf = udev->actconfig->interface[i];
       usb_resume_interface(udev, intf, msg, 0);
      }
     /* If the suspend succeeded then prevent any more URB submissions
      * and flush any outstanding URBs.
      */
     } else {
      udev->can_submit = 0;
      for (i = 0; i < 16; ++i) {
       usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
       usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
      }
     }
     done:
     dev_vdbg(&udev->dev, "%s: status %d ", __func__, status);
     return status;
    }
    static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
    {
     struct usb_device_driver *udriver;
     int    status = 0;
     if (udev->state == USB_STATE_NOTATTACHED ||
       udev->state == USB_STATE_SUSPENDED)
      goto done;
     /* For devices that don't have a driver, we do a generic suspend. */
     if (udev->dev.driver)
      udriver = to_usb_device_driver(udev->dev.driver);
     else {
      udev->do_remote_wakeup = 0;
      udriver = &usb_generic_driver;
     }
     status = udriver->suspend(udev, msg);//调用通用的设备驱动挂起函数
     done:
     dev_vdbg(&udev->dev, "%s: status %d ", __func__, status);
     return status;
    }
    static int generic_suspend(struct usb_device *udev, pm_message_t msg)
    {
     int rc;
     /* Normal USB devices suspend through their upstream port.
      * Root hubs don't have upstream ports to suspend,
      * so we have to shut down their downstream HC-to-USB
      * interfaces manually by doing a bus (or "global") suspend.
      */
     if (!udev->parent)//针对root hub的
      rc = hcd_bus_suspend(udev, msg);//挂起root hub
     /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
     else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
      rc = 0;
     else
      rc = usb_port_suspend(udev, msg);//挂起每个端口设备
     return rc;
    }
    *********************************************************************
    下面是自动挂起的流程(上面的蓝色字体标出调用的地方),最终也会走到generic_suspend,相当于两条小溪最终汇成一起。
    /* Internal routine to check whether we may autosuspend a device. */
    static int autosuspend_check(struct usb_device *udev)
    {
     int   w, i;
     struct usb_interface *intf;
     unsigned long  suspend_time, j;
     /* Fail if autosuspend is disabled, or any interfaces are in use, or
      * any interface drivers require remote wakeup but it isn't available.
      */
     w = 0;
     if (udev->actconfig) {
      for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
       intf = udev->actconfig->interface[i];
       /* We don't need to check interfaces that are
        * disabled for runtime PM.  Either they are unbound
        * or else their drivers don't support autosuspend
        * and so they are permanently active.
        */
       if (intf->dev.power.disable_depth)
        continue;
       if (atomic_read(&intf->dev.power.usage_count) > 0)
        return -EBUSY;
       w |= intf->needs_remote_wakeup;
       /* Don't allow autosuspend if the device will need
        * a reset-resume and any of its interface drivers
        * doesn't include support or needs remote wakeup.
        */
       if (udev->quirks & USB_QUIRK_RESET_RESUME) {
        struct usb_driver *driver;
        driver = to_usb_driver(intf->dev.driver);
        if (!driver->reset_resume ||
          intf->needs_remote_wakeup)
         return -EOPNOTSUPP;
       }
      }
     }
     if (w && !device_can_wakeup(&udev->dev)) {
      dev_dbg(&udev->dev, "remote wakeup needed for autosuspend ");
      return -EOPNOTSUPP;
     }
     udev->do_remote_wakeup = w;
     /* If everything is okay but the device hasn't been idle for long
      * enough, queue a delayed autosuspend request.
      */
     j = ACCESS_ONCE(jiffies);
     suspend_time = udev->last_busy + udev->autosuspend_delay;
     if (time_before(j, suspend_time)) {
      pm_schedule_suspend(&udev->dev, jiffies_to_msecs(round_jiffies_up_relative(suspend_time - j)));//调度
      return -EAGAIN;
     }
     return 0;
    }
     
    /**
     * pm_schedule_suspend - Set up a timer to submit a suspend request in future.
     * @dev: Device to suspend.
     * @delay: Time to wait before submitting a suspend request, in milliseconds.
     */
    int pm_schedule_suspend(struct device *dev, unsigned int delay)
    {
     unsigned long flags;
     int retval = 0;
     spin_lock_irqsave(&dev->power.lock, flags);
     if (dev->power.runtime_error) {
      retval = -EINVAL;
      goto out;
     }
     if (!delay) {
      retval = __pm_request_suspend(dev);//如果没有delay,则立即执行
      goto out;
     }
     pm_runtime_deactivate_timer(dev);
     if (dev->power.request_pending) {
      /*
       * Pending resume requests take precedence over us, but any
       * other pending requests have to be canceled.
       */
      if (dev->power.request == RPM_REQ_RESUME) {
       retval = -EAGAIN;
       goto out;
      }
      dev->power.request = RPM_REQ_NONE;
     }
     if (dev->power.runtime_status == RPM_SUSPENDED)
      retval = 1;
     else if (atomic_read(&dev->power.usage_count) > 0
         || dev->power.disable_depth > 0)
      retval = -EAGAIN;
     else if (!pm_children_suspended(dev))
      retval = -EBUSY;
     if (retval)
      goto out;
     dev->power.timer_expires = jiffies + msecs_to_jiffies(delay);
     if (!dev->power.timer_expires)
      dev->power.timer_expires = 1;
     mod_timer(&dev->power.suspend_timer, dev->power.timer_expires);//如果有超时,等待定时器到期,执行处理函数pm_suspend_timer_fn
     out:
     spin_unlock_irqrestore(&dev->power.lock, flags);
     return retval;
    }
     /*定时器到期处理函数*/
    static void pm_suspend_timer_fn(unsigned long data)
    {
     struct device *dev = (struct device *)data;
     unsigned long flags;
     unsigned long expires;
     spin_lock_irqsave(&dev->power.lock, flags);
     expires = dev->power.timer_expires;
     /* If 'expire' is after 'jiffies' we've been called too early. */
     if (expires > 0 && !time_after(expires, jiffies)) {
      dev->power.timer_expires = 0;
      __pm_request_suspend(dev);//定时器到时,执行该函数
     }
     spin_unlock_irqrestore(&dev->power.lock, flags);
    }
     
    /*无论是定时器超时,还是直接调用,都会调用下面该函数*/
    static int __pm_request_suspend(struct device *dev)
    {
     int retval = 0;
     if (dev->power.runtime_error)
      return -EINVAL;
     if (dev->power.runtime_status == RPM_SUSPENDED)
      retval = 1;
     else if (atomic_read(&dev->power.usage_count) > 0
         || dev->power.disable_depth > 0)
      retval = -EAGAIN;
     else if (dev->power.runtime_status == RPM_SUSPENDING)
      retval = -EINPROGRESS;
     else if (!pm_children_suspended(dev))
      retval = -EBUSY;
     if (retval < 0)
      return retval;
     pm_runtime_deactivate_timer(dev);
     if (dev->power.request_pending) {
      /*
       * Pending resume requests take precedence over us, but we can
       * overtake any other pending request.
       */
      if (dev->power.request == RPM_REQ_RESUME)
       retval = -EAGAIN;
      else if (dev->power.request != RPM_REQ_SUSPEND)
       dev->power.request = retval ?
          RPM_REQ_NONE : RPM_REQ_SUSPEND;
      return retval;
     } else if (retval) {
      return retval;
     }
     dev->power.request = RPM_REQ_SUSPEND;//请求状态为suspend
     dev->power.request_pending = true;
     queue_work(pm_wq, &dev->power.work);//调度work
     return 0;
    }

    static void pm_runtime_work(struct work_struct *work)
    {
     struct device *dev = container_of(work, struct device, power.work);
     enum rpm_request req;
     spin_lock_irq(&dev->power.lock);
     if (!dev->power.request_pending)
      goto out;
     req = dev->power.request;
     dev->power.request = RPM_REQ_NONE;
     dev->power.request_pending = false;
     switch (req) {
     case RPM_REQ_NONE:
      break;
     case RPM_REQ_IDLE:
      __pm_runtime_idle(dev);
      break;
     case RPM_REQ_SUSPEND:
      __pm_runtime_suspend(dev, true); //调用suspend函数
      break;
     case RPM_REQ_RESUME:
      __pm_runtime_resume(dev, true);
      break;
     }
     out:
     spin_unlock_irq(&dev->power.lock);
    }
    int __pm_runtime_suspend(struct device *dev, bool from_wq)
     __releases(&dev->power.lock) __acquires(&dev->power.lock)
    {
     struct device *parent = NULL;
     bool notify = false;
     int retval = 0;
     dev_dbg(dev, "__pm_runtime_suspend()%s! ",from_wq ? " from workqueue" : "");
     ...................
     if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
      spin_unlock_irq(&dev->power.lock);
      retval = dev->bus->pm->runtime_suspend(dev);//调用usb总线的runtime_suspend函数
      spin_lock_irq(&dev->power.lock);
      dev->power.runtime_error = retval;
     }
     ...................
     out:
     dev_dbg(dev, "__pm_runtime_suspend() returns %d! ", retval);
     return retval;
    }
    static int usb_runtime_suspend(struct device *dev)
    {
     int status = 0;
     if (is_usb_device(dev)) {
      struct usb_device *udev = to_usb_device(dev);
      if (autosuspend_check(udev) != 0)
       return -EAGAIN;
      status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);//3
     ...............
     return status;
    }
    static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
    {
     int   status = 0;
     int   i = 0, n = 0;
     struct usb_interface *intf;
     if (udev->state == USB_STATE_NOTATTACHED ||
       udev->state == USB_STATE_SUSPENDED)
      goto done;
     /* Suspend all the interfaces and then udev itself */
     if (udev->actconfig) {//挂起所以端口
      n = udev->actconfig->desc.bNumInterfaces;
      for (i = n - 1; i >= 0; --i) {
       intf = udev->actconfig->interface[i];
       status = usb_suspend_interface(udev, intf, msg);
       if (status != 0)
        break;
      }
     }
     if (status == 0)
      status = usb_suspend_device(udev, msg);//挂起usb设备本身
      ..............
     } else {
      udev->can_submit = 0;
      for (i = 0; i < 16; ++i) {
       usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
       usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
      }
     }
     done:
     dev_vdbg(&udev->dev, "%s: status %d ", __func__, status);
     return status;
    }
    static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)

     if (udev->dev.driver)
      udriver = to_usb_device_driver(udev->dev.driver);
     else {
      udev->do_remote_wakeup = 0;
      udriver = &usb_generic_driver;
     }
     status = udriver->suspend(udev, msg);//5
     done:
     dev_vdbg(&udev->dev, "%s: status %d ", __func__, status);
     return status;
    }
     
    struct usb_device_driver usb_generic_driver = {
     .name = "usb",
     .probe = generic_probe,
     .disconnect = generic_disconnect,
    #ifdef CONFIG_PM
     .suspend = generic_suspend,//6
     .resume = generic_resume,
    #endif
     .supports_autosuspend = 1,
    };
    static int generic_suspend(struct usb_device *udev, pm_message_t msg)
    {
     int rc;
     if (!udev->parent)
      rc = hcd_bus_suspend(udev, msg);//7
     /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
     else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
      rc = 0;
     else
      rc = usb_port_suspend(udev, msg);
     return rc;
    }
     
    ***************************************************
    /*通用usb设备的suspend函数,上面的自动挂起和正常挂起都会走*/
    static int generic_suspend(struct usb_device *udev, pm_message_t msg)
    {
     int rc;
     /* Normal USB devices suspend through their upstream port.
      * Root hubs don't have upstream ports to suspend,
      * so we have to shut down their downstream HC-to-USB
      * interfaces manually by doing a bus (or "global") suspend.
      */
     if (!udev->parent)//针对root hub
      rc = hcd_bus_suspend(udev, msg);//挂起root hub的下流口
     /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
     else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
      rc = 0;
     else
      rc = usb_port_suspend(udev, msg);//关闭usb设备的上流口
     return rc;
    }
     
    int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
    {
     struct usb_hub *hub = hdev_to_hub(udev->parent);
     int  port1 = udev->portnum;
     int  status;
     // dev_dbg(hub->intfdev, "suspend port %d ", 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 (udev->do_remote_wakeup) {
      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);
     }
     /* see 7.1.7.6 */
     status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);
      
     /* device has up to 10 msec to fully suspend */
     dev_dbg(&udev->dev, "usb %ssuspend ",(msg.event & PM_EVENT_AUTO ? "auto-" : ""));
     usb_set_device_state(udev, USB_STATE_SUSPENDED);//设置usb设备为挂起状态
     msleep(10);
     }
     return status;
    }
     
    /*挂起root hub*/
    int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
    {
     struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
     int  status;
     int  old_state = hcd->state;
     dev_dbg(&rhdev->dev, "bus %s%s ",
       (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "suspend");
     if (!hcd->driver->bus_suspend) {
      status = -ENOENT;
     } else {
      hcd->state = HC_STATE_QUIESCING;
      status = hcd->driver->bus_suspend(hcd);//调用主机控制器driver的bus suspend
     }
     if (status == 0) {
      usb_set_device_state(rhdev, USB_STATE_SUSPENDED);//设置root hub设备的状态为suspend状态
      hcd->state = HC_STATE_SUSPENDED;
     } else {
      hcd->state = old_state;
      dev_dbg(&rhdev->dev, "bus %s fail, err %d ","suspend", status);
     }
     return status;
    }
    static struct hc_driver msm_hc_driver = {
     .description  = hcd_name,
     .product_desc   = "Qualcomm On-Chip EHCI Host Controller",
     .hcd_priv_size   = sizeof(struct msmusb_hcd),
     /*
      * generic hardware linkage
      */
     .irq    = ehci_msm_irq,
     .flags    = HCD_USB2,
     .reset    = ehci_msm_reset,
     .start    = ehci_msm_run,
     .stop   = ehci_stop,
     .shutdown  = ehci_shutdown,
     /*
      * managing i/o requests and associated device resources
      */
     .urb_enqueue  = ehci_urb_enqueue,
     .urb_dequeue  = ehci_urb_dequeue,
     .endpoint_disable = ehci_endpoint_disable,
     /*
      * scheduling support
      */
     .get_frame_number = ehci_get_frame,
     /*
      * root hub support
      */
     .hub_status_data = ehci_hub_status_data,
     .hub_control  = ehci_hub_control,
     .bus_suspend  = ehci_msm_bus_suspend,//调用该suspend函数
     .bus_resume  = ehci_msm_bus_resume,
     .relinquish_port = ehci_relinquish_port,
     .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
    };
    static int ehci_msm_bus_suspend(struct usb_hcd *hcd)
    {
     int ret;
     struct msmusb_hcd *mhcd = hcd_to_mhcd(hcd);
     struct device *dev = hcd->self.controller;
     ret = ehci_bus_suspend(hcd);//root hub挂起
     if (ret) {
      pr_err("ehci_bus suspend faield ");
      return ret;
     }
     
    /*下面是挂起otg控制器*/
     if (PHY_TYPE(mhcd->pdata->phy_info) == USB_PHY_INTEGRATED)
      ret = otg_set_suspend(mhcd->xceiv, 1);//otg挂起,调用该函数
     else
      ret = usb_lpm_enter(hcd);
     pm_runtime_put_noidle(dev);
     pm_runtime_suspend(dev);
     wake_unlock(&mhcd->wlock);
     return ret;
    }
    static inline int otg_set_suspend(struct otg_transceiver *otg, int suspend)
    {
     if (otg->set_suspend != NULL)
      return otg->set_suspend(otg, suspend);
     else
      return 0;
    }
    dev->otg.set_suspend = msm_otg_set_suspend;

    static int msm_otg_set_suspend(struct otg_transceiver *xceiv, int suspend)
    {
     struct msm_otg *dev = container_of(xceiv, struct msm_otg, otg);
     enum usb_otg_state state;
     unsigned long flags;
     if (!dev || (dev != the_msm_otg))
      return -ENODEV;
     spin_lock_irqsave(&dev->lock, flags);
     state = dev->otg.state;
     spin_unlock_irqrestore(&dev->lock, flags);
     pr_debug("suspend request in state: %s ",
       state_string(state));
     if (suspend) {
      switch (state) {
    #ifndef CONFIG_MSM_OTG_ENABLE_A_WAIT_BCON_TIMEOUT
      case OTG_STATE_A_WAIT_BCON:
       if (test_bit(ID_A, &dev->inputs))
        msm_otg_set_power(xceiv, USB_IDCHG_MIN - 100);
       msm_otg_put_suspend(dev);//如果没有usb设备连接,则进入该函数
       break;
    #endif
      case OTG_STATE_A_HOST:
       clear_bit(A_BUS_REQ, &dev->inputs);
       wake_lock(&dev->wlock);
       queue_work(dev->wq, &dev->sm_work);
       break;
      case OTG_STATE_B_PERIPHERAL:
       if (xceiv->gadget->b_hnp_enable) {
        set_bit(A_BUS_SUSPEND, &dev->inputs);
        set_bit(B_BUS_REQ, &dev->inputs);
        wake_lock(&dev->wlock);
        queue_work(dev->wq, &dev->sm_work);
       }
       break;
      case OTG_STATE_A_PERIPHERAL:
       msm_otg_start_timer(dev, TA_BIDL_ADIS,
         A_BIDL_ADIS);
       break;
      default:
       break;
      }
     } else {
      unsigned long timeout;
      switch (state) {
      case OTG_STATE_A_PERIPHERAL:
       /* A-peripheral observed activity on bus.
        * clear A_BIDL_ADIS timer.
        */
       msm_otg_del_timer(dev);
       break;
      case OTG_STATE_A_SUSPEND:
       /* Remote wakeup or resume */
       set_bit(A_BUS_REQ, &dev->inputs);
       spin_lock_irqsave(&dev->lock, flags);
       dev->otg.state = OTG_STATE_A_HOST;
       spin_unlock_irqrestore(&dev->lock, flags);
       if (test_bit(ID_A, &dev->inputs) &&
        (get_aca_bmaxpower(dev) < USB_IDCHG_MIN))
        msm_otg_set_power(xceiv,
         USB_IDCHG_MIN - get_aca_bmaxpower(dev));
       break;
      default:
       break;
      }
      if (suspend == atomic_read(&dev->in_lpm))
       return 0;
      disable_irq(dev->irq);
      if (dev->pmic_vbus_notif_supp)
       if (can_phy_power_collapse(dev) &&
         dev->pdata->ldo_enable)
        dev->pdata->ldo_enable(1);
      msm_otg_get_resume(dev);
      if (!is_phy_clk_disabled())
       goto out;
      timeout = jiffies + usecs_to_jiffies(100);
      enable_phy_clk();
      while (is_phy_clk_disabled()) {
       if (time_after(jiffies, timeout)) {
        pr_err("%s: Unable to wakeup phy ", __func__);
        /* Reset both phy and link */
        otg_reset(&dev->otg, 1);
        break;
       }
       udelay(10);
      }
      if (dev->pmic_id_notif_supp) {
       dev->pdata->pmic_id_notif_init(
        &msm_otg_set_id_state, 0);
       dev->pmic_id_notif_supp = 0;
       enable_idgnd(dev);
      }
    out:
      enable_idabc(dev);
      enable_irq(dev->irq);
     }
     return 0;
    }
    //上面是主机控制器调用到的该流程.
     
    //设备控制器直接调用该函数是设备进入suspend状态
    /***************************************************************/
    static void msm_otg_put_suspend(struct msm_otg *dev)
    {
    #ifdef CONFIG_PM_RUNTIME
     pm_runtime_put_sync(dev->otg.dev);//调用该函数,注意:传入的是平台设备
     if (!atomic_read(&dev->in_lpm))
      pm_runtime_get_sync(dev->otg.dev);
    #else
     msm_otg_suspend(dev);
    #endif
    }
    static inline int pm_runtime_put_sync(struct device *dev)
    {
     return __pm_runtime_put(dev, true);//调用该函数
    }
    int __pm_runtime_put(struct device *dev, bool sync)
    {
     int retval = 0;
     if (atomic_dec_and_test(&dev->power.usage_count))
      retval = sync ? pm_runtime_idle(dev)/*调用该函数*/: pm_request_idle(dev);
     return retval;
    }
    int pm_runtime_idle(struct device *dev)
    {
     int retval;
     spin_lock_irq(&dev->power.lock);
     retval = __pm_runtime_idle(dev);//调用该函数
     spin_unlock_irq(&dev->power.lock);
     return retval;
    }
    static int __pm_runtime_idle(struct device *dev)
     __releases(&dev->power.lock) __acquires(&dev->power.lock)
    {
     int retval = 0;
     
     ...............
     dev->power.idle_notification = true;
     if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {
      spin_unlock_irq(&dev->power.lock);
      dev->bus->pm->runtime_idle(dev);//调用该函数
      spin_lock_irq(&dev->power.lock);
     } else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
      spin_unlock_irq(&dev->power.lock);
      dev->type->pm->runtime_idle(dev);
      spin_lock_irq(&dev->power.lock);
     } else if (dev->class && dev->class->pm
         && dev->class->pm->runtime_idle) {
      spin_unlock_irq(&dev->power.lock);
      dev->class->pm->runtime_idle(dev);
      spin_lock_irq(&dev->power.lock);
     }
     dev->power.idle_notification = false;
     wake_up_all(&dev->power.wait_queue);
     out:
     return retval;
    }
    static const struct dev_pm_ops platform_dev_pm_ops = {
     .prepare = platform_pm_prepare,
     .complete = platform_pm_complete,
     .suspend = platform_pm_suspend,
     .resume = platform_pm_resume,
     .freeze = platform_pm_freeze,
     .thaw = platform_pm_thaw,
     .poweroff = platform_pm_poweroff,
     .restore = platform_pm_restore,
     .suspend_noirq = platform_pm_suspend_noirq,
     .resume_noirq = platform_pm_resume_noirq,
     .freeze_noirq = platform_pm_freeze_noirq,
     .thaw_noirq = platform_pm_thaw_noirq,
     .poweroff_noirq = platform_pm_poweroff_noirq,
     .restore_noirq = platform_pm_restore_noirq,
     .runtime_suspend = platform_pm_runtime_suspend,
     .runtime_resume = platform_pm_runtime_resume,
     .runtime_idle = platform_pm_runtime_idle,//调用该处的函数
    };
    struct bus_type platform_bus_type = {
     .name  = "platform",
     .dev_attrs = platform_dev_attrs,
     .match  = platform_match,
     .uevent = platform_uevent,
     .pm  = &platform_dev_pm_ops,
    };
    int __weak platform_pm_runtime_idle(struct device *dev)
    {
     return pm_generic_runtime_idle(dev);//调用该函数
    };
    int pm_generic_runtime_idle(struct device *dev)
    {
     const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
     if (pm && pm->runtime_idle) {
      int ret = pm->runtime_idle(dev);
      if (ret)
       return ret;
     }
     pm_runtime_suspend(dev);//调用该函数
     return 0;
    }
    int pm_runtime_suspend(struct device *dev)
    {
     int retval;
     spin_lock_irq(&dev->power.lock);
     retval = __pm_runtime_suspend(dev, false);//调用该函数
     spin_unlock_irq(&dev->power.lock);
     return retval;
    }
    int __pm_runtime_suspend(struct device *dev, bool from_wq)
     __releases(&dev->power.lock) __acquires(&dev->power.lock)
    {
     struct device *parent = NULL;
     bool notify = false;
     int retval = 0;
     dev_dbg(dev, "__pm_runtime_suspend()%s! ",from_wq ? " from workqueue" : "");
     repeat:
     dev->power.runtime_status = RPM_SUSPENDING;
     dev->power.deferred_resume = false;
     if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
      spin_unlock_irq(&dev->power.lock);
      retval = dev->bus->pm->runtime_suspend(dev); //调用平台总线的suspend函数
      spin_lock_irq(&dev->power.lock);
      dev->power.runtime_error = retval;
     } else if (dev->type && dev->type->pm
         && dev->type->pm->runtime_suspend) {
      spin_unlock_irq(&dev->power.lock);
      retval = dev->type->pm->runtime_suspend(dev);
      spin_lock_irq(&dev->power.lock);
      dev->power.runtime_error = retval;
     } else if (dev->class && dev->class->pm
         && dev->class->pm->runtime_suspend) {
      spin_unlock_irq(&dev->power.lock);
      retval = dev->class->pm->runtime_suspend(dev);
      spin_lock_irq(&dev->power.lock);
      dev->power.runtime_error = retval;
     } else {
      retval = -ENOSYS;
     }
     if (notify)
      __pm_runtime_idle(dev);
     if (parent && !parent->power.ignore_children) {
      spin_unlock_irq(&dev->power.lock);
      pm_request_idle(parent);
      spin_lock_irq(&dev->power.lock);
     }
     out:
     dev_dbg(dev, "__pm_runtime_suspend() returns %d! ", retval);
     return retval;
    }
    int __weak platform_pm_runtime_suspend(struct device *dev)
    {
     return pm_generic_runtime_suspend(dev);
    };
     
    int pm_generic_runtime_suspend(struct device *dev)
    {
     const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
     int ret;
     ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL;//调用平台驱动的runtime_suspend函数
     return ret;
    }
     
    /*平台驱动的注册函数*/
    /*******************************************************************/
    static int msm_otg_runtime_suspend(struct device *dev)
    {
     struct msm_otg *otg = the_msm_otg;
     dev_dbg(dev, "pm_runtime: suspending... ");
     msm_otg_suspend(otg);
     return  0;
    }
    static int msm_otg_runtime_resume(struct device *dev)
    {
     struct msm_otg *otg = the_msm_otg;
     dev_dbg(dev, "pm_runtime: resuming... ");
     msm_otg_resume(otg);
     return  0;
    }
    static int msm_otg_runtime_idle(struct device *dev)
    {
     dev_dbg(dev, "pm_runtime: idling... ");
     return  0;
    }
    static struct dev_pm_ops msm_otg_dev_pm_ops = {
     .runtime_suspend = msm_otg_runtime_suspend,
     .runtime_resume = msm_otg_runtime_resume,
     .runtime_idle = msm_otg_runtime_idle,
    };
    static struct platform_driver msm_otg_driver = {
     .remove = __exit_p(msm_otg_remove),
     .driver = {
      .name = DRIVER_NAME,
      .owner = THIS_MODULE,
      .pm = &msm_otg_dev_pm_ops,
     },
    };
    /*******************************************************************/

    static int msm_otg_suspend(struct msm_otg *dev)
    {
     unsigned long timeout;
     bool host_bus_suspend;
     unsigned ret;
     enum chg_type chg_type = atomic_read(&dev->chg_type);
     unsigned long flags;
     disable_irq(dev->irq);
     if (atomic_read(&dev->in_lpm))
      goto out;
     atomic_set(&dev->in_lpm, 1);//设置low power mode为1,唤醒的时候要判断该标记
     ...............
     if (dev->pdata->config_vddcx)
      dev->pdata->config_vddcx(0);
     pr_info("%s: usb in low power mode ", __func__);
     return 0;
    }
    到此整个睡眠流程分析完了。









  • 相关阅读:
    NX二次开发-UFUN设置显示状态抑制显示UF_DISP_set_display
    NX二次开发-使用NXOPEN C++向导模板做二次开发
    ANTV/G6 怎么按条件自定义节点颜色(Graphin)
    js数组去重及数组对象去重
    vue组件老胡机抽奖(转载)
    Kafka第二节
    Kafka第一节
    更改idea的database数据库连接的ddl格式
    不推荐别的了,IDEA 自带的数据库工具就很牛逼!
    MongoDB 按照时间段查询某个物理机的CPU使用率,按照时间倒序排序,取出最新的5条数据
  • 原文地址:https://www.cnblogs.com/liulaolaiu/p/11744567.html
Copyright © 2020-2023  润新知