Chinaunix首页 | 论坛 | 博客
  • 博客访问: 34789
  • 博文数量: 14
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 13
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-17 14:40
文章分类
文章存档

2014年(14)

我的朋友

分类: LINUX

2014-09-15 14:47:47

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

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;
}

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