Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1575153
  • 博文数量: 204
  • 博客积分: 2215
  • 博客等级: 大尉
  • 技术积分: 4426
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-06 08:03
个人简介

气质,源于心灵的自信!

文章存档

2018年(1)

2017年(1)

2016年(1)

2015年(18)

2014年(20)

2013年(30)

2012年(119)

2011年(14)

分类: LINUX

2012-09-06 18:07:37

本分析基于android4.0.4代码,高通8260平台
//插入usb a cable前的状态是 OTG_STATE_B_IDLE
static void msm_otg_sm_work(struct work_struct *w)
{

    switch (state) {
        case OTG_STATE_UNDEFINED:
             {
                if (!dev->otg.host || !is_host())
                    set_bit(ID, &dev->inputs);//什么都不插入,初始化时会设置该位

                if (dev->otg.gadget && is_b_sess_vld())
                    set_bit(B_SESS_VLD, &dev->inputs);
            }
            spin_lock_irqsave(&dev->lock, flags);
            if ((test_bit(ID, &dev->inputs)) &&
                    !test_bit(ID_A, &dev->inputs)) {
                dev->otg.state = OTG_STATE_B_IDLE;//什么都不插入,初始化时的状态
            }
            work = 1;
            break;
        case OTG_STATE_B_IDLE:
        dev->otg.default_a = 0;
        ..............    
         else {//初始时,会停留在OTG_STATE_B_IDLE状态并睡眠
            msm_otg_set_power(&dev->otg, 0);
            pr_debug("entering into lpm\n");
            pr_info("%s: -->>entering into lpm.\n",__func__);
            msm_otg_put_suspend(dev);

            if (dev->pdata->ldo_set_voltage)
                dev->pdata->ldo_set_voltage(3075);
        }
        break;
    }
    if (work)
        queue_work(dev->wq, &dev->sm_work);
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------
//插入usb a cable前的状态是 OTG_STATE_B_IDLE
static void msm_otg_sm_work(struct work_struct *w)
{

    switch (state) {
        case OTG_STATE_B_IDLE:
            dev->otg.default_a = 0;
            if (!test_bit(ID, &dev->inputs) || test_bit(ID_A, &dev->inputs)) {//此时的id=0
                pr_debug("!id || id_A\n");
                clear_bit(B_BUS_REQ, &dev->inputs);
                otg_reset(&dev->otg, 0);

                spin_lock_irqsave(&dev->lock, flags);
                dev->otg.state = OTG_STATE_A_IDLE;//状态迁移到OTG_STATE_A_IDLE,迁移到a idle
                spin_unlock_irqrestore(&dev->lock, flags);
                msm_otg_set_power(&dev->otg, 0);
                work = 1;
            }
            break;
        //继续调度work
        case OTG_STATE_A_IDLE:
            dev->otg.default_a = 1;
            if (!test_bit(A_BUS_DROP, &dev->inputs) &&
                    (test_bit(A_SRP_DET, &dev->inputs) ||
                     test_bit(A_BUS_REQ, &dev->inputs))) {//A_BUS_REQ = 1
                pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");

                clear_bit(A_SRP_DET, &dev->inputs);
                /* Disable SRP detection */
                writel((readl(USB_OTGSC) & ~OTGSC_INTR_STS_MASK) &
                        ~OTGSC_DPIE, USB_OTGSC);

                spin_lock_irqsave(&dev->lock, flags);
                dev->otg.state = OTG_STATE_A_WAIT_VRISE;//状态迁移到OTG_STATE_A_WAIT_VRISE,等待电压达到a的门限
                spin_unlock_irqrestore(&dev->lock, flags);
                /* ACA: ID_A: Stop charging untill enumeration */
                if (test_bit(ID_A, &dev->inputs))
                    msm_otg_set_power(&dev->otg, 0);
                else
                    dev->pdata->vbus_power(USB_PHY_INTEGRATED, 1);
                msm_otg_start_timer(dev, TA_WAIT_VRISE, A_WAIT_VRISE);
                /* no need to schedule work now */
            }
            break;
        case OTG_STATE_A_WAIT_VRISE:
            if (test_bit(A_VBUS_VLD, &dev->inputs)) {
                    pr_debug("a_vbus_vld\n");
                    spin_lock_irqsave(&dev->lock, flags);
                    dev->otg.state = OTG_STATE_A_WAIT_BCON;//状态迁移到OTG_STATE_A_WAIT_BCON,等待外围设备插入
                    spin_unlock_irqrestore(&dev->lock, flags);
                    if (TA_WAIT_BCON > 0)
                        msm_otg_start_timer(dev, TA_WAIT_BCON,
                            A_WAIT_BCON);
                    /* Start HCD to detect peripherals. */
                    pr_info("%s:----------->>>>>>>>%d.\n",__func__,__LINE__);
                    msm_otg_start_host(&dev->otg, REQUEST_START);//在这里启动主机控制器
                }
            break;
        //插入usb a cable时状态迁移到此,下面分析插入u盘的状态迁移

        case OTG_STATE_A_WAIT_BCON:
             if (test_bit(B_CONN, &dev->inputs)) {
                    pr_debug("b_conn\n");
                    msm_otg_del_timer(dev);
                    /* HCD is added already. just move to
                     * A_HOST state.
                     */
                    spin_lock_irqsave(&dev->lock, flags);
                    dev->otg.state = OTG_STATE_A_HOST;//状态迁移到OTG_STATE_A_HOST,作为主机开始工作
                    spin_unlock_irqrestore(&dev->lock, flags);
                    if (test_bit(ID_A, &dev->inputs)) {
                        atomic_set(&dev->chg_type, USB_CHG_TYPE__SDP);
                        msm_otg_set_power(&dev->otg,
                            USB_IDCHG_MIN - get_aca_bmaxpower(dev));
                    }
                }
            break;
        //拔出u盘时
        case OTG_STATE_A_HOST:
             if (!test_bit(B_CONN, &dev->inputs)) {
                    pr_debug("!b_conn\n");
                    spin_lock_irqsave(&dev->lock, flags);
                    dev->otg.state = OTG_STATE_A_WAIT_BCON;//状态迁移到等待外围设备插入
                    spin_unlock_irqrestore(&dev->lock, flags);
                    if (TA_WAIT_BCON > 0)
                        msm_otg_start_timer(dev, TA_WAIT_BCON, A_WAIT_BCON);
                }
            break;
        //其中插入,拔出u盘触发的条件是通知链
        static int usbdev_notify(struct notifier_block *self,
                    unsigned long action, void *device)
        {
            enum usb_otg_state state;
            struct msm_otg *dev = container_of(self, struct msm_otg, usbdev_nb);
            struct usb_device *udev = device;
            int work = 1;

            spin_lock_irqsave(&dev->lock, flags);
            state = dev->otg.state;//当前的状态机状态
            spin_unlock_irqrestore(&dev->lock, flags);

            switch (state) {
            case OTG_STATE_A_WAIT_BCON:
                if (action == USB_DEVICE_ADD) {//u盘插入时会设置dev->inputs相应的位
                    pr_debug("B_CONN set\n");
                    set_bit(B_CONN, &dev->inputs);
                    ...........
                }
                break;
            case OTG_STATE_A_HOST:
                if (action == USB_DEVICE_REMOVE) {//u盘拔出时会清除dev->inputs相应的位
                    pr_debug("B_CONN clear\n");
                    clear_bit(B_CONN, &dev->inputs);
                    set_aca_bmaxpower(dev, 0);
                }
                break;
            default:
                work = 0;
                break;
            }
        do_work:
            if (work) {
                wake_lock(&dev->wlock);
                queue_work(dev->wq, &dev->sm_work);//调度work,改变状态机的迁移状态
            }
        }
        //拔掉hub时的状态
        case OTG_STATE_A_WAIT_BCON:
            if ((test_bit(ID, &dev->inputs) &&//拔出时id =1
                    !test_bit(ID_A, &dev->inputs)) ||
                    test_bit(A_BUS_DROP, &dev->inputs) ||
                    test_bit(A_WAIT_BCON, &dev->tmouts)) {
                pr_debug("id_f/b/c || a_bus_drop ||"
                        "a_wait_bcon_tmout\n");
                if (test_bit(A_WAIT_BCON, &dev->tmouts))
                    msm_otg_send_event(&dev->otg,
                        OTG_EVENT_DEV_CONN_TMOUT);
                msm_otg_del_timer(dev);
                clear_bit(A_BUS_REQ, &dev->inputs);
                msm_otg_start_host(&dev->otg, REQUEST_STOP);
                /* Reset both phy and link */
                otg_reset(&dev->otg, 1);
                /* ACA: ID_A with NO accessory, just the A plug is
                 * attached to ACA: Use IDCHG_MAX for charging
                 */
                if (test_bit(ID_A, &dev->inputs))
                    msm_otg_set_power(&dev->otg, USB_IDCHG_MAX);
                else
                    dev->pdata->vbus_power(USB_PHY_INTEGRATED, 0);
                spin_lock_irqsave(&dev->lock, flags);
                dev->otg.state = OTG_STATE_A_WAIT_VFALL;//状态机迁移,等待a的电压门限降下
                spin_unlock_irqrestore(&dev->lock, flags);
                msm_otg_start_timer(dev, TA_WAIT_VFALL, A_WAIT_VFALL);
            }
            break;
        //等待电压将下来
        case OTG_STATE_A_WAIT_VFALL:
            if (test_bit(A_WAIT_VFALL, &dev->tmouts)) {
                clear_bit(A_VBUS_VLD, &dev->inputs);
                spin_lock_irqsave(&dev->lock, flags);
                dev->otg.state = OTG_STATE_A_IDLE;//继续迁移到a idle
                spin_unlock_irqrestore(&dev->lock, flags);
                work = 1;
            }
            break;
        //状态机继续迁移
        case OTG_STATE_A_IDLE:
            dev->otg.default_a = 1;
            if (test_bit(ID, &dev->inputs) &&//id = 1
                    !test_bit(ID_A, &dev->inputs)) {
                pr_debug("id && !id_a\n");
                dev->otg.default_a = 0;
                otg_reset(&dev->otg, 0);
                spin_lock_irqsave(&dev->lock, flags);
                dev->otg.state = OTG_STATE_B_IDLE;//迁移到b idle
                spin_unlock_irqrestore(&dev->lock, flags);
                msm_otg_set_power(&dev->otg, 0);
                work = 1;
            }
            break;
    }
    if (work)
        queue_work(dev->wq, &dev->sm_work);
}
阅读(3154) | 评论(4) | 转发(1) |
给主人留下些什么吧!~~

haijian01142012-11-12 10:28:51

老大 最近发现一个问题,在高通8225的板子上,从电脑向手机的外置SD卡拷贝一个大于1.2G的文件时,有时会出现USB重新reset的现象并导致传输中断,关闭usb mass storage,概率挺高的,我查了下发现是在msm72k_udc.c下的usb_interrupt()函数中出现了STS_URI的中断,所导致的USB重新复位连接,我想问下STS_URI中断在什么情况下可能会产生呢?我现在不知道STS_URI中断怎么产生的,你是否有出现过这样的问题呢?

haijian01142012-09-27 17:25:11

shangbaogen: * ID_A: Configure device to act as host and don't supply VBUS. In this state
  the device can charge as well.
* ID_B: Keep the device in IDLE state a.....
哦好的 之前我还不知道去哪里找 谢谢啦 我看下

shangbaogen2012-09-27 16:24:48

haijian0114: ID_A,ID_B,ID_C使用在msm_otg->inputs分别代表的是什么呢?.....
* ID_A: Configure device to act as host and don't supply VBUS. In this state
  the device can charge as well.
* ID_B: Keep the device in IDLE state and allow charging.
* ID_C: Configure device to act as peripheral and allow charging.

具体的你看下kernel的这个文档:
\kernel\Documentation\usb\msm_otg.txt文档讲的有,这是otg的高级功能,牵涉到hnp,srp,我还没仔细看。

haijian01142012-09-27 15:16:26

ID_A,ID_B,ID_C使用在msm_otg->inputs分别代表的是什么呢?