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;
    }
  • 相关阅读:
    通过注册表找网站绝对路径
    西普学院Crypto之用户名和密码
    西普学院Crypto之一段奇怪的代码
    西普学院Crypto之先有鸡还是先有蛋
    西普学院Crypto之摩擦摩擦
    西普学院Crypto之凯撒是罗马共和国杰出的军事统帅
    各类文件的文件头标志[转]
    收藏的几个脑图
    同源策略详解及绕过[转]
    Python学习#1
  • 原文地址:https://www.cnblogs.com/LoongEmbedded/p/5298172.html
Copyright © 2011-2022 走看看