zoukankan      html  css  js  c++  java
  • Android4.0.3 USB OTG底层插入上报过程分析(1)

    下面的两个宏是PM8058的MMP11(R15),MMP12(P15)管脚。
    #define EXT_CHG_VALID_MPP 10
    #define EXT_CHG_VALID_MPP_2 11

    static struct pm8xxx_mpp_init_info isl_mpp[] = {
        PM8058_MPP_INIT(EXT_CHG_VALID_MPP, D_INPUT,
            PM8058_MPP_DIG_LEVEL_S3, DIN_TO_INT),
        PM8058_MPP_INIT(EXT_CHG_VALID_MPP_2, D_BI_DIR,
            PM8058_MPP_DIG_LEVEL_S3, BI_PULLUP_10KOHM),
    };

    //配置管脚功能函数
    #if defined(CONFIG_SMB137B_CHARGER) || defined(CONFIG_SMB137B_CHARGER_MODULE)
    static int smb137b_detection_setup(void)
    {
        int ret = 0, i;

        for (i = 0; i < ARRAY_SIZE(isl_mpp); i++) {
            ret = pm8xxx_mpp_config(isl_mpp[i].mpp,&isl_mpp[i].config);
        }

        return ret;
    }

    static struct smb137b_platform_data smb137b_data __initdata = {
        .chg_detection_config = smb137b_detection_setup,
        .valid_n_gpio = PM8058_MPP_PM_TO_SYS(10),
        .batt_mah_rating = 950,
    };

    static struct i2c_board_info smb137b_charger_i2c_info[] __initdata = {
        {
            I2C_BOARD_INFO("smb137b", 0x08),
            .irq = PM8058_IRQ_BASE + PM8058_CBLPWR_IRQ,//计算后的irq值=464
            .platform_data = &smb137b_data,
        },
    };
    #endif


    static int __devinit smb137b_probe(struct i2c_client *client,const struct i2c_device_id *id)

        /*配置usb检测管脚*/
        if (pdata->chg_detection_config)
            ret = pdata->chg_detection_config();

        /*用该检测gpio引脚前,申请该GPIO*/
        ret = gpio_request(pdata->valid_n_gpio, "smb137b_charger_valid");

        /*申请中断,该中断号码为464*/
        ret = request_threaded_irq(client->irq, NULL,smb137b_valid_handler,
                        IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
                        "smb137b_charger_valid", client);

        /*先读取一次检测管脚值*/
        ret = gpio_get_value_cansleep(smb137b_chg->valid_n_gpio);
        if (!ret) {

            /*上报usb的插入状态*/
            msm_charger_notify_event(smb137b_chg->adapter_hw_chg[0],CHG_INSERTED_EVENT);
            smb137b_chg->usb_status = SMB137B_PRESENT;
        }

    /*以后的处理都是在中断中进行处理*/
    static irqreturn_t smb137b_valid_handler(int irq, void *dev_id)
    {
        struct smb137b_data *smb137b_chg;

        smb137b_chg = i2c_get_clientdata(client);
        smb137b_chg->current_hw_chg = smb137b_chg->adapter_hw_chg[0];
        
        /*读出检测管脚的电平值*/
        val = gpio_get_value_cansleep(smb137b_chg->valid_n_gpio);

        if (val) {
            if (smb137b_chg->usb_status != SMB137B_ABSENT) {
                smb137b_chg->usb_status = SMB137B_ABSENT;
                /*如果为高电平,通知usb移出*/
                msm_charger_notify_event(smb137b_chg->current_hw_chg,CHG_REMOVED_EVENT);
            }
        } else if (smb137b_chg->usb_status == SMB137B_ABSENT) {
                smb137b_chg->usb_status = SMB137B_PRESENT;
                /*如果为高电平,通知usb插入*/
                msm_charger_notify_event(smb137b_chg->current_hw_chg,CHG_INSERTED_EVENT);
            }

    下面进入发通知流程继续跟踪
    int msm_charger_notify_event(struct msm_hardware_charger *hw_chg,
            enum msm_hardware_charger_event event)
    {
        /*把该消息加入循环队列中*/
        msm_chg_enqueue_event(hw_chg, event);
        
        /*调度work*/
        queue_work(msm_chg.event_wq_thread, &msm_chg.queue_work);
        return 0;
    }
    下面的两行是在static int __init msm_charger_init(void)函数中进行初始化的:

    INIT_WORK(&msm_chg.queue_work, process_events);
    msm_chg.event_wq_thread = create_workqueue("msm_charger_eventd");   
    该work的处理函数如下:
    static void process_events(struct work_struct *work)
    {
        struct msm_charger_event *event;
        int rc;
        /*循环处理等待队列中的消息*/
        do {
            rc = msm_chg_dequeue_event(&event);
            if (!rc)
                /*对单个的event进行处理*/
                handle_event(event->hw_chg, event->event);
        } while (!rc);
    }
    下面进入具体的handle_event函数分析:
    static void handle_event(struct msm_hardware_charger *hw_chg, int event)
    {
        struct msm_hardware_charger_priv *priv = NULL;

        if (hw_chg)
            priv = hw_chg->charger_private;

        switch (event) {
            case CHG_INSERTED_EVENT:
                if (hw_chg->type == CHG_TYPE_USB) {
                    .................
                    priv->hw_chg_state = CHG_PRESENT_STATE;

                    /*上报usb插入事件*/
                    notify_usb_of_the_plugin_event(priv, 1);
                    .........................
                break;
            case CHG_REMOVED_EVENT:
                if (hw_chg->type == CHG_TYPE_USB) {
                    ...............
                    usb_chg_current = 0;

                    /*上报usb移出事件*/
                    notify_usb_of_the_plugin_event(priv, 0);
                    ........................
                }
                break;
    }

    /*进入notify_usb_of_the_plugin_event函数继续跟踪*/
    static void notify_usb_of_the_plugin_event(struct msm_hardware_charger_priv
            *hw_chg, int plugin)
    {
        plugin = !!plugin;
        if (plugin == 1 && usb_notified_of_insertion == 0) {
            usb_notified_of_insertion = 1;
            if (notify_vbus_state_func_ptr) {
                /*调用回调函数*/
                (*notify_vbus_state_func_ptr) (plugin);
        }
        if (plugin == 0 && usb_notified_of_insertion == 1) {
            if (notify_vbus_state_func_ptr) {
                (*notify_vbus_state_func_ptr) (plugin);
            } 
            usb_notified_of_insertion = 0;
        }
    }
    /*下面进入回调函数的跟踪*/
    /*在板级初始化时定义了一个全局函数指针*/
    notify_vbus_state notify_vbus_state_func_ptr;

    /*该函数指针在该回调函数中赋值*/
    static int msm_hsusb_pmic_vbus_notif_init(void (*callback)(int online),
                                    int init)
    {
        int ret = -ENOTSUPP;
        if (machine_is_msm8x60_s9000() || pmic_id_notif_supported)) {
            if (init)
                ret = msm_charger_register_vbus_sn(callback);
            else {
                msm_charger_unregister_vbus_sn(callback);
                ret = 0;
            }
        } 
    }
    int msm_charger_register_vbus_sn(void (*callback)(int))
    {
        notify_vbus_state_func_ptr = callback;
        return 0;
    }

    /*该回调函数注册的时机如下*/
    #if defined(CONFIG_USB_GADGET_MSM_72K) || defined(CONFIG_USB_EHCI_MSM_72K)
    static struct msm_otg_platform_data msm_otg_pdata = {
        ................
    #ifdef CONFIG_BATTERY_MSM8X60
        .pmic_vbus_notif_init    = msm_hsusb_pmic_vbus_notif_init,
    #endif
        .........................

    };
    #endif
    /*把该平台数据赋值给平台设备*/
    msm_device_otg.dev.platform_data = &msm_otg_pdata;

    /*注册该平台设备*/
    static struct platform_device *surf_devices[] __initdata = {
    #if defined(CONFIG_USB_GADGET_MSM_72K) || defined(CONFIG_USB_EHCI_HCD)
        &msm_device_otg,
    #endif

    static void __init msm8x60_init(struct msm_board_data *board_data)

        platform_add_devices(surf_devices,ARRAY_SIZE(surf_devices));

    static int __init msm_otg_probe(struct platform_device *pdev)
    {
        ..............
        /*初始化work工作队列*/
        INIT_WORK(&dev->sm_work, msm_otg_sm_work);
        dev->wq = alloc_workqueue("k_otg", WQ_NON_REENTRANT, 0);
        ..................
        /*调用回调函数,为全局函数指针赋值*/
        if (dev->pdata->pmic_vbus_notif_init) {
            ret = dev->pdata->pmic_vbus_notif_init
                (&msm_otg_set_vbus_state, 1);
            if (!ret) {
                dev->pmic_vbus_notif_supp = 1;
            } 
        }
        ...............
        .......................
    }
    /*然后用该函数上报plug的值*/
    void msm_otg_set_vbus_state(int online)
    {
        struct msm_otg *dev = the_msm_otg;

        /*如果上报插入事件,就设置B_SESS_VLD标志位*/
        if (online)
            set_bit(B_SESS_VLD, &dev->inputs);
        /*如果上报移除事件,就清除B_SESS_VLD标志位*/
        else
            clear_bit(B_SESS_VLD, &dev->inputs);
        
        /*获得wakelock锁*/
        wake_lock(&dev->wlock);
        
        /*调度工作队列中的work*/
        queue_work(dev->wq, &dev->sm_work);
    }
    /*下面进入work继续跟踪*/
    static void msm_otg_sm_work(struct work_struct *w)

        enum usb_otg_state state;
        state = dev->otg.state;
        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);
                }

                if ((test_bit(ID, &dev->inputs)) && !test_bit(ID_A, &dev->inputs)) {
                    /*改变otg的状态机状态为OTG_STATE_B_IDLE*/
                    dev->otg.state = OTG_STATE_B_IDLE;
                } 
                work = 1;
                break;
            case OTG_STATE_B_IDLE:
                if (test_bit(B_SESS_VLD, &dev->inputs) && !test_bit(ID_B, &dev->inputs)) {
                /*改变otg的状态机状态为OTG_STATE_B_PERIPHERAL*/
                dev->otg.state = OTG_STATE_B_PERIPHERAL;

                msm_otg_set_power(&dev->otg, 0);
                
                /*启动外围设备*/
                msm_otg_start_peripheral(&dev->otg, 1);
            } 
            break;
        /*如果work为1,则继续调度work*/
        if (work)
            queue_work(dev->wq, &dev->sm_work);

    /*上面的work牵涉到两个函数,通过寄存器的值判断,设置相应的位域*/
    static int is_host(void)
    {
        struct msm_otg *dev = the_msm_otg;

        if (dev->pdata->otg_mode == OTG_ID)
        {
            /*读出该寄存器的第8位,如果读出的为1,则返回0,即该设备为B device*/
            return (OTGSC_ID & readl(USB_OTGSC)) ? 0 : 1;
        }
    }

    static int is_b_sess_vld(void)
    {
        struct msm_otg *dev = the_msm_otg;

        if (dev->pdata->otg_mode == OTG_ID)
        {
            /*读出该寄存器的第11位,如果为1,则返回1,该寄存器在spec中说明如下:Indicates that the Vbus is above the B session valid threshold.*/
            return (OTGSC_BSV & readl(USB_OTGSC)) ? 1 : 0;
        }
    }
    /*下面进入msm_otg_start_peripheral函数进行分析*/
    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);
        } 
    }
    /*设置gadget的vbus*/
    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);
    }
    /*调用底层gadget的回调函数*/
    gadget->ops->vbus_session(gadget, 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 = kzalloc(sizeof(struct usb_info), GFP_KERNEL);
        ui->gadget.ops = &msm72k_ops;
    }
    /*看下vbus的回调函数*/
    static int msm72k_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
    {
        /*设置vbus的状态*/
        msm_hsusb_set_vbus_state(is_active);
        return 0;
    }
    /*继续跟踪设置vbus的状态*/
    void msm_hsusb_set_vbus_state(int online)
    {
        struct usb_info *ui = the_usb_info;

        /*根据传入的状态设置usb的状态位*/
        if (online) {
            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;
        }
        
        /*调度usb的工作队列*/
        if (in_interrupt()) {
            schedule_work(&ui->work);
        } else {
            usb_do_work(&ui->work);
            return;
        }
    }
    /*在usb_do_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 long iflags;
        unsigned flags, _vbus;

        for (;;) {
            spin_lock_irqsave(&ui->lock, iflags);
            flags = ui->flags;
            ui->flags = 0;
            _vbus = is_usb_online(ui);
            spin_unlock_irqrestore(&ui->lock, iflags);

            /* give up if we have nothing to do */
            if (flags == 0)
                break;

            switch (ui->state) {
            case USB_STATE_IDLE:
                if (flags & USB_FLAG_START) {
                    int ret;
                    /*重启设备控制器*/
                    usb_reset(ui);
                    
                    /*申请中断处理函数*/
                    ret = request_irq(otg->irq, usb_interrupt,IRQF_SHARED,ui->pdev->name, ui);
                    ui->irq = otg->irq;
                    
                    /*改变设备状态*/
                    ui->state = USB_STATE_ONLINE;
                    usb_do_work_check_vbus(ui);
                    
                    /*使能D+数据线上的上拉电阻*/
                    msm72k_pullup_internal(&ui->gadget, 1);
                break;
            case USB_STATE_ONLINE:
                if (flags & USB_FLAG_SUSPEND) {
                    int maxpower = usb_get_max_power(ui);
                    otg_set_power(ui->xceiv, 0);
                    break;
                }
                if (flags & USB_FLAG_CONFIGURED) {
                    int maxpower = usb_get_max_power(ui);
                    switch_set_state(&ui->sdev,atomic_read(&ui->configured));
                    ui->chg_current = maxpower;
                    otg_set_power(ui->xceiv, maxpower);
                    break;
                }
                if (flags & USB_FLAG_RESET) {
                    msm72k_pullup_internal(&ui->gadget, 0);
                    usb_reset(ui);
                    msm72k_pullup_internal(&ui->gadget, 1);
                    break;
                }
                break;
            case USB_STATE_OFFLINE:
                if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) {
                    /*重启设备控制器*/
                    usb_reset(ui);

                    /*改变设备状态*/
                    ui->state = USB_STATE_ONLINE;
                    usb_do_work_check_vbus(ui);

                    /*申请中断处理函数*/
                    ret = request_irq(otg->irq, usb_interrupt,IRQF_SHARED,ui->pdev->name, ui);
                    ui->irq = otg->irq;

                    /*使能D+数据线上的上拉电阻*/
                    msm72k_pullup_internal(&ui->gadget, 1);
                }
                break;
            }
        }
    }

    /*中断函数的实时处理*/
    static irqreturn_t usb_interrupt(int irq, void *data)
    {
        struct usb_info *ui = data;
        unsigned n;
        unsigned long flags;

        n = readl(USB_USBSTS);
        writel(n, USB_USBSTS);
        
        /*端口变化探测*/
        if (n & STS_PCI) {
            msm_hsusb_set_speed(ui);
            if (atomic_read(&ui->configured)) {
                ui->usb_state = USB_STATE_CONFIGURED;
                ui->flags = USB_FLAG_CONFIGURED;
                ui->driver->resume(&ui->gadget);
                schedule_work(&ui->work);
            } else {
                msm_hsusb_set_state(USB_STATE_DEFAULT);
            }
        }
        /*usb重启*/
        if (n & STS_URI) {
            dev_dbg(&ui->pdev->dev, "reset ");
            ui->gadget.speed = USB_SPEED_UNKNOWN;
            msm_hsusb_set_state(USB_STATE_DEFAULT);
            ......................
        }
        /*usb挂起状态*/
        if (n & STS_SLI) {
            dev_dbg(&ui->pdev->dev, "suspend ");
            ui->usb_state = USB_STATE_SUSPENDED;
            ui->flags = USB_FLAG_SUSPEND;
            ui->driver->suspend(&ui->gadget);
            schedule_work(&ui->work);
        }
        /*usb事务传输完成中断*/
        if (n & STS_UI) {
            n = readl(USB_ENDPTSETUPSTAT);
            if (n & EPT_RX(0))
                handle_setup(ui);

            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;
    }
  • 相关阅读:
    SPOJ SAMER08A
    SPOJ TRAFFICN
    CS Academy Set Subtraction
    CS Academy Bad Triplet
    CF Round 432 C. Five Dimensional Points
    CF Round 432 B. Arpa and an exam about geometry
    SPOJ INVCNT
    CS Academy Palindromic Tree
    身体训练
    简单瞎搞题
  • 原文地址:https://www.cnblogs.com/LoongEmbedded/p/5298172.html
Copyright © 2011-2022 走看看