Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1569857
  • 博文数量: 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-08-24 15:27:15

下面跟踪进入设备控制器时的流程。

static void msm_otg_start_peripheral(struct otg_transceiver *xceiv, int on)
{
    struct msm_otg *dev = container_of(xceiv, struct msm_otg, otg);
    ...........

    if (on) {//打开设备控制器
        ...........
        usb_gadget_vbus_connect(xceiv->gadget);
    } else {//关闭设备控制器
        atomic_set(&dev->chg_type, USB_CHG_TYPE__INVALID);//设置充电器的类型为无效
        usb_gadget_vbus_disconnect(xceiv->gadget);
        ...............
    }
}
static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget)
{
    if (!gadget->ops->vbus_session)
        return -EOPNOTSUPP;
    return gadget->ops->vbus_session(gadget, 1);
}
static inline int usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
{
    if (!gadget->ops->vbus_session)
        return -EOPNOTSUPP;
    return gadget->ops->vbus_session(gadget, 0);
}
上面两个函数都调用gadget->ops->vbus_session(gadget, 0/1)函数,该函数的回调注册的地方为:
static const struct usb_gadget_ops msm72k_ops = {
    .get_frame    = msm72k_get_frame,
    .vbus_session    = msm72k_udc_vbus_session,
    .vbus_draw    = msm72k_udc_vbus_draw,
    .pullup        = msm72k_pullup,
    .wakeup        = msm72k_wakeup,
    .set_selfpowered = msm72k_set_selfpowered,
};
static int msm72k_probe(struct platform_device *pdev)
{
    .............
    ui->gadget.ops = &msm72k_ops;
    ............


看下回调函数的实现:
static int msm72k_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
{
    struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
    struct msm_otg *otg = to_msm_otg(ui->xceiv);

    if (is_active || atomic_read(&otg->chg_type) == USB_CHG_TYPE__WALLCHARGER
            || atomic_read(&otg->chg_type) == USB_CHG_TYPE__DOCKCHARGER)
        wake_lock(&ui->wlock);//如果为active锁定wakelock

    msm_hsusb_set_vbus_state(is_active);
    return 0;
}
void msm_hsusb_set_vbus_state(int online)
{
    unsigned long flags;
    struct usb_info *ui = the_usb_info;


    if (online) {//根据online的值,设置ui的状态
        ui->usb_state = USB_STATE_POWERED;
        ui->flags |= USB_FLAG_VBUS_ONLINE;
    } else {
        ui->gadget.speed = USB_SPEED_UNKNOWN;
        ui->usb_state = USB_STATE_NOTATTACHED;
        ui->flags |= USB_FLAG_VBUS_OFFLINE;
    }
    if (in_interrupt()) {//如果处于中断中,则用系统是schedule_work调度
        schedule_work(&ui->work);
    } else {//直接调度
        spin_unlock_irqrestore(&ui->lock, flags);
        usb_do_work(&ui->work);//调度work
        return;
    }

}
static int __init android_probe(struct platform_device *pdev)

    usb_composite_register(&android_usb_driver);
        usb_gadget_register_driver(&composite_driver);
            usb_start(ui);
                ui->flags |= USB_FLAG_START;//设置初始flag标记
                schedule_work(&ui->work);//调度work----------------------------------------->111


//下面看下调度的work
static int usb_get_max_power(struct usb_info *ui)
{
    suspended = ui->usb_state == USB_STATE_SUSPENDED ? 1 : 0;//如果为suspend状态,则返回0
    configured = atomic_read(&ui->configured);// 如果没有配置也返回0
    bmaxpow = ui->b_max_pow;//返回最大值

    if (suspended || !configured)
        return 0;
    return bmaxpow;
}
其中ui->b_max_pow的赋值流程如下:
static irqreturn_t usb_interrupt()//中断中进行枚举
    handle_setup(ui);
        ui->driver->setup();
            composite_setup()//回调函数
                static int set_config()
                    usb_gadget_vbus_draw(gadget, power);//设置能拉到的电流
                        gadget->ops->vbus_draw(gadget, mA);
                            msm72k_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
                                    ui->b_max_pow = mA;//保存到ui->b_max_pow中
                                    ui->flags = USB_FLAG_CONFIGURED;//设置flag为config
                                    schedule_work(&ui->work);//调度work

static void usb_do_work(struct work_struct *w)
{
    struct usb_info *ui = container_of(w, struct usb_info, work);
    struct msm_otg *otg = to_msm_otg(ui->xceiv);
    unsigned flags, _vbus;

    for (;;) {
        flags = ui->flags;//读出flag
        ui->flags = 0;//读出后清零
        _vbus = is_usb_online(ui);//第一次,结果为_vbus=0,插入是_vbus=1

        /* give up if we have nothing to do */
        if (flags == 0)//第一再次循环时,走到这里退出for循环
            break;

        switch (ui->state) {
        case USB_STATE_IDLE://初始值为0
            if (flags & USB_FLAG_START) {//第一次为USB_FLAG_START
                if (!_vbus) {
                    ui->state = USB_STATE_OFFLINE;//第一次,置usb状态为USB_STATE_OFFLINE
                    break;//跳出该switch语句
                }
            break;
        case USB_STATE_ONLINE://继续从上一个状态循环
            if (atomic_read(&ui->offline_pending)) {//控制器重启的时候会走该分支
                switch_set_state(&ui->sdev, 0);
                atomic_set(&ui->offline_pending, 0);
            }

            if (flags & USB_FLAG_VBUS_OFFLINE) {
                ui->chg_current = 0;//设置当前充电电流为0
                dev_dbg(&ui->pdev->dev,"msm72k_udc: ONLINE -> OFFLINE\n");
                atomic_set(&ui->running, 0);//设置running为0
                atomic_set(&ui->configured, 0);//设置配置为0

                if (ui->driver) {
                    dev_dbg(&ui->pdev->dev,"usb: notify offline\n");
                    ui->driver->disconnect(&ui->gadget);//调用driver的断开函数
                }
                ............
                msm72k_pullup_internal(&ui->gadget, 0);//下拉D+线电阻
                ...........
                switch_set_state(&ui->sdev, 0);//上报offline的状态
                ui->state = USB_STATE_OFFLINE;//设置usb的状态为USB_STATE_OFFLINE
                usb_do_work_check_vbus(ui);//判断是否处于离线状态,并设置ui->flags |= USB_FLAG_VBUS_ONLINE,或者USB_FLAG_VBUS_OFFLINE
                .................
                break;
            }
            if (flags & USB_FLAG_SUSPEND) {//---------------------->222
                int maxpower = usb_get_max_power(ui);//获得最大电流
                if (maxpower < 0){//插入usb进入该状态时,进入该分支
                    break;}

                otg_set_power(ui->xceiv, 0);//设置最大电流为0
                if (release_wlocks)
                    wake_unlock(&ui->wlock);
                break;
            }
            if (flags & USB_FLAG_CONFIGURED) {//------------------------------->333
                int maxpower = usb_get_max_power(ui);//获得最大电流
                switch_set_state(&ui->sdev,atomic_read(&ui->configured));//发送sent uevent SWITCH_NAME=MSM72K_UDC , SWITCH_STATE=online.
                ui->chg_current = maxpower;//保存当前的充电电流
                if (maxpower < 0)
                      break;
                otg_set_power(ui->xceiv, maxpower);//设置最大电流
                break;
            }
            if (flags & USB_FLAG_RESET) {
                dev_dbg(&ui->pdev->dev,"msm72k_udc: ONLINE -> RESET\n");
                msm72k_pullup_internal(&ui->gadget, 0);//写寄存器USBCMD_RS,控制D+下拉
                usb_reset(ui);//reset udc控制器,并atomic_set(&ui->running, 1);
                msm72k_pullup_internal(&ui->gadget, 1);//写寄存器USBCMD_RS,控制D+上拉
                dev_dbg(&ui->pdev->dev,"msm72k_udc: RESET -> ONLINE\n");
                break;
            }
            break;
        case USB_STATE_OFFLINE:
            if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) {//插入usb cable时进入该分支
                ...............
                dev_dbg(&ui->pdev->dev,"msm72k_udc: OFFLINE -> ONLINE\n");
                usb_reset(ui);//reset udc控制器,并atomic_set(&ui->running, 1);
                ui->state = USB_STATE_ONLINE;//改变ui->state的状态
                usb_do_work_check_vbus(ui);//判断是否处于离线状态,并设置ui->flags |= USB_FLAG_VBUS_ONLINE,或者USB_FLAG_VBUS_OFFLINE
                ret = request_irq(otg->irq, usb_interrupt,IRQF_SHARED,ui->pdev->name, ui);//申请irq中断
                ui->irq = otg->irq;//保存中断
                enable_irq_wake(otg->irq);//设置该irq为系统唤醒源

                if (!atomic_read(&ui->softconnect))
                    break;
                msm72k_pullup_internal(&ui->gadget, 1);//把D+数据线拉高
                ................
            }
            break;
        }
        if (is_usb_online(ui))
            switch_set_state(&ui->sdev_cable, 1);
        else{//第一次初始化时,上报usb cable没有插入的状态    
            switch_set_state(&ui->sdev_cable, 0);}
    }
}
下面分析下状态机的触发流程:
1、android_probe初始化,会调度usb_do_work,当没有usb cable插入的时候,ui->state = USB_STATE_IDLE,ui->flag = USB_FLAG_START,进入状态机,并判断_vbus,由于是第一次,_vbus为0,ui->state = USB_STATE_OFFLINE,然后上报usb cable没有插入,然后再次进入for循环,由于flag值没有变化为0,则跳出该for循环。
2、当插入usb cable时,由于调度了设备控制器的流程,然后调用usb_do_work,设置了标记ui->flags |= USB_FLAG_VBUS_ONLINE;由于没有插入前的状态为ui->state = USB_STATE_OFFLINE,所以
继续进入状态机,设置状态为ui->state = USB_STATE_ONLINE,然后检测flag的状态有没有改变,对ui->flag重新赋值,上报usb cable插入。然后usb_interruput触发了中断,设置ui->flags = USB_FLAG_SUSPEND,然后调度work,再次进入状态机。由于maxpower小于0,则退出switch语句,再次上报usb cable插入。继续进入for循环,由于flag状态没有改变,在退出for循环。在usb_interruput中,接收到端口变化中断,则置ui->flags = USB_FLAG_CONFIGURED,然后调度work,进入状态机,上报online状态。由于maxpower为0,则退出swtich语句,然后上报usb_cable插入。
3、当usb拔出的时候,先收到suspend中断,调度work,然后会关闭设备控制器,设置ui->flags |= USB_FLAG_VBUS_OFFLINE的状态,然后调度usb_do_work,进入状态机,上报offline的状态,设置usb的状态为USB_STATE_OFFLINE,设置running为0等,上报usb cable拔出,继续进入状态机循环,然后没有状态改变时退出for循环。

在usb中断中改变状态,然后调度work
static irqreturn_t usb_interruput(int irq, void *data)//该中断和上面的msm_otg_irq为共享中断,公用中断号132
{
    struct usb_info *ui = data;
    unsigned n;
    unsigned long flags;

    n = readl(USB_USBSTS);//读取状态寄存器的值
    writel(n, USB_USBSTS);//清除该状态寄存器

    if (!atomic_read(&ui->running))//还在重启中是忽略该中断
        return IRQ_HANDLED;

    if (n & STS_PCI) {//端口变化中断,当端口进入全速或者高速模式时,或者端口退出全速或高速模式由于接收到usb reset信号,或者suspend event。
        msm_hsusb_set_speed(ui);//读取硬件寄存器USB_PORTSC,设置端口速度
        if (atomic_read(&ui->configured)) {//查看配置是否为1?
            wake_lock(&ui->wlock);//锁定wakelock
            ui->usb_state = USB_STATE_CONFIGURED;//改变usb状态
            ui->flags = USB_FLAG_CONFIGURED;//改变flag标记
            ui->driver->resume(&ui->gadget);//唤醒gadget
            schedule_work(&ui->work);//调度work------------------------------->333
        } else {
            msm_hsusb_set_state(USB_STATE_DEFAULT);//如果不为1,则设置the_usb_info->usb_state = USB_STATE_DEFAULT;
        }
    }

    if (n & STS_URI) {//当设备控制器检测到usb reset信号时,执行该分支,并且进入USB_STATE_DEFAULT的状态
        dev_dbg(&ui->pdev->dev, "reset\n");
        ui->gadget.speed = USB_SPEED_UNKNOWN;//设置usb的速度为unknow
        msm_hsusb_set_state(USB_STATE_DEFAULT);//设置usb的状态为默认状态
        ...............
        if (atomic_read(&ui->configured)) {//如果有配置
            /*做一些清理工作*/
        }
        ...............
    }

    if (n & STS_SLI) {//处于suspend状态
        dev_dbg(&ui->pdev->dev, "suspend\n");
        ui->usb_state = USB_STATE_SUSPENDED;//改变状态
        ui->flags = USB_FLAG_SUSPEND;//改变flag
        ui->driver->suspend(&ui->gadget);
        schedule_work(&ui->work);//调度usb_do_work-------------------------------------------->222

    }

    if (n & STS_UI) {//由传输事务引起的中断,或者是接收到short packeage.
        n = readl(USB_ENDPTSETUPSTAT);
        if (n & EPT_RX(0))
            handle_setup(ui);//usb枚举过程

        n = readl(USB_ENDPTCOMPLETE);
        writel(n, USB_ENDPTCOMPLETE);
        while (n) {
            unsigned bit = __ffs(n);
            handle_endpoint(ui, bit);//处理端点传输
            n = n & (~(1 << bit));
        }
    }
    return IRQ_HANDLED;
}

阅读(5245) | 评论(5) | 转发(5) |
给主人留下些什么吧!~~

haijian01142012-10-12 13:56:02

shangbaogen: 我感觉不用看那么细吧!先把总体框架给掌握了,到时哪个地方要是真出问题的话,再仔细看想关的代码就行了,otg 加上主机控制器,设备控制器,已经很庞大了,细节.....
嗯好的 吸取你的建议

shangbaogen2012-10-12 13:13:45

haijian0114: 哦好的,你说枚举过程中ep0_queue_ack_complete(),ep0_status_phase(),ep0_status_complete()等一些有关回复ACK信号的函数是否有必要仔细研究呢,这些一般都不.....
我感觉不用看那么细吧!先把总体框架给掌握了,到时哪个地方要是真出问题的话,再仔细看想关的代码就行了,otg 加上主机控制器,设备控制器,已经很庞大了,细节暂时就别跟啦!建议而已!

haijian01142012-10-12 09:38:27

shangbaogen: 那个函数我也没进去仔细看过,我现在基本关注的是主要流程,等有空了,我瞅瞅!.....
哦好的,你说枚举过程中ep0_queue_ack_complete(),ep0_status_phase(),ep0_status_complete()等一些有关回复ACK信号的函数是否有必要仔细研究呢,这些一般都不会有问题吧,我发现获取设备描述符和获取字符描述符的枚举过程会被多次的执行,不知道为什么,是否本来就这样呢

shangbaogen2012-10-11 16:43:17

haijian0114: 老大有空可不可以分析一下usb_reset的流程呢 跟这个流程很多都不知道为什么他要这么做.....
那个函数我也没进去仔细看过,我现在基本关注的是主要流程,等有空了,我瞅瞅!

haijian01142012-10-11 16:09:35

老大有空可不可以分析一下usb_reset的流程呢 跟这个流程很多都不知道为什么他要这么做