广州网站建设 易企建站,网站建设从零开始 教程,电商网站开发需要什么语言,超级软文原文网址#xff08;转载请注明出处#xff09;#xff1a;
链接#xff1a;http://t.csdnimg.cn/VxZsA
源码基于#xff1a;Android Q 文章目录 1.USB驱动介绍2.charger-manager拔插事件分发 在展锐8541平台上加载了extcon-usb-gpio 驱动#xff0c;这个驱动可以检测…原文网址转载请注明出处
链接http://t.csdnimg.cn/VxZsA
源码基于Android Q 文章目录 1.USB驱动介绍2.charger-manager拔插事件分发 在展锐8541平台上加载了extcon-usb-gpio 驱动这个驱动可以检测USB 的插拔动作。 1.USB驱动介绍
USB驱动文件
bsp/kernel/kernel4.14/drivers/extcon/Makefile...
obj-$(CONFIG_EXTCON_USB_GPIO) extcon-usb-gpio.o
...代码
bsp/kernel/kernel4.14/drivers/extcon/extcon-usb-gpio.cstatic const struct of_device_id usb_extcon_dt_match[] {{ .compatible linux,extcon-usb-gpio, },{ /* sentinel */ }
};static struct platform_driver usb_extcon_driver {.probe usb_extcon_probe, // probe 函数驱动匹配到了对应的设备后会调用此函数.remove usb_extcon_remove, // 设备移除后会调用此函数.driver {.name extcon-usb-gpio,.pm usb_extcon_pm_ops,.of_match_table usb_extcon_dt_match, // 用于匹配dts文件里的设备如果有compatible 相同的设备后才会调用probe 函数},.id_table usb_extcon_platform_ids,
};module_platform_driver(usb_extcon_driver); // 该驱动的入口函数接着查看probe 函数里面有两个中断分别是id-gpio和 vbus-gpio
bsp/kernel/kernel4.14/drivers/extcon/extcon-usb-gpio.cstatic int usb_extcon_probe(struct platform_device *pdev)
{...info-id_gpiod devm_gpiod_get_optional(pdev-dev, id, GPIOD_IN);info-vbus_gpiod devm_gpiod_get_optional(pdev-dev, vbus, GPIOD_IN);...if (info-id_gpiod)// 用于防抖的ret gpiod_set_debounce(info-id_gpiod, USB_GPIO_DEBOUNCE_MS * 1000);if (!ret info-vbus_gpiod)ret gpiod_set_debounce(info-vbus_gpiod, USB_GPIO_DEBOUNCE_MS * 1000);...if (info-id_gpiod) {info-id_irq gpiod_to_irq(info-id_gpiod); // 将id-gpio 口设置为中断模式...// 设置中断条件发生中断是调用usb_irq_handler() 方法当GPIO 上拉或者下拉时触发中断ret devm_request_threaded_irq(dev, info-id_irq, NULL,usb_irq_handler,IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING | IRQF_ONESHOT,pdev-name, info);...}if (info-vbus_gpiod) {info-vbus_irq gpiod_to_irq(info-vbus_gpiod); // 将vbus-gpio 口设置为中断模式...// 设置中断条件发生中断是调用usb_irq_handler() 方法当GPIO 上拉或者下拉时触发中断ret devm_request_threaded_irq(dev, info-vbus_irq, NULL,usb_irq_handler,IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING | IRQF_ONESHOT,pdev-name, info);...}...
}当id-gpio 和 vbus-gpio 口上拉或者下拉时触发中断调用usb_irq_handler() 中断上拉或者下拉代表USB 的插入和拔出。
bsp/kernel/kernel4.14/drivers/extcon/extcon-usb-gpio.cstatic irqreturn_t usb_irq_handler(int irq, void *dev_id)
{struct usb_extcon_info *info dev_id;queue_delayed_work(system_power_efficient_wq, info-wq_detcable,info-debounce_jiffies);return IRQ_HANDLED;
}static int usb_extcon_probe(struct platform_device *pdev)
{...INIT_DELAYED_WORK(info-wq_detcable, usb_extcon_detect_cable); // 初始化工作队列wq_detcable 为usb_extcon_detect_cable() 方法...
}static void usb_extcon_detect_cable(struct work_struct *work)
{int id, vbus;struct usb_extcon_info *info container_of(to_delayed_work(work),struct usb_extcon_info,wq_detcable);/* check ID and VBUS and update cable state */id info-id_gpiod ?gpiod_get_value_cansleep(info-id_gpiod) : 1;vbus info-vbus_gpiod ?gpiod_get_value_cansleep(info-vbus_gpiod) : id;/* at first we clean states which are no longer active */if (id)extcon_set_state_sync(info-edev, EXTCON_USB_HOST, false);if (!vbus)extcon_set_state_sync(info-edev, EXTCON_USB, false);if (!id) {extcon_set_state_sync(info-edev, EXTCON_USB_HOST, true);} else {if (vbus)extcon_set_state_sync(info-edev, EXTCON_USB, true);}
}在USB插拔触发中断时会调用info-wq_detcable 工作队列即会调用usb_extcon_detect_cable() 方法之后会通过extcon_set_state_sync() 方法设置USB 的状态
bsp/kernel/kernel4.14/drivers/extcon/extcon.cint extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, bool state)
{int ret, index;unsigned long flags;index find_cable_index_by_id(edev, id);if (index 0)return index;/* Check whether the external connectors state is changed. */spin_lock_irqsave(edev-lock, flags);ret is_extcon_changed(edev, index, state); // 检查USB状态是否发生了变化spin_unlock_irqrestore(edev-lock, flags);if (!ret)return 0;ret extcon_set_state(edev, id, state); // 设置USB 的连接状态但是不会通知USB 状态的改变if (ret 0)return ret;return extcon_sync(edev, id); // 设置USB 的连接状态并通知其他模块
}
EXPORT_SYMBOL_GPL(extcon_set_state_sync);int extcon_sync(struct extcon_dev *edev, unsigned int id)
{...// 通过这个方法通知某个注册了USB 状态改变的模块raw_notifier_call_chain(edev-nh[index], state, edev);// 通过这个方法通知所有注册了USB 状态改变的模块raw_notifier_call_chain(edev-nh_all, state, edev);...kobject_uevent_env(edev-dev.kobj, KOBJ_CHANGE, envp); // 通过UEvent 通知用户空间USB发生了改变free_page((unsigned long)prop_buf);return 0;
}
EXPORT_SYMBOL_GPL(extcon_sync);bsp/kernel/kernel4.14/kernel/notifier.cint raw_notifier_call_chain(struct raw_notifier_head *nh,unsigned long val, void *v)
{return __raw_notifier_call_chain(nh, val, v, -1, NULL);
}
EXPORT_SYMBOL_GPL(raw_notifier_call_chain);int __raw_notifier_call_chain(struct raw_notifier_head *nh,unsigned long val, void *v,int nr_to_call, int *nr_calls)
{return notifier_call_chain(nh-head, val, v, nr_to_call, nr_calls);
}
EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);static int notifier_call_chain(struct notifier_block **nl,unsigned long val, void *v,int nr_to_call, int *nr_calls)
{int ret NOTIFY_DONE;struct notifier_block *nb, *next_nb;nb rcu_dereference_raw(*nl);// 循环读取所有的notifier_block, 然后调用它的notifier_call() 方法while (nb nr_to_call) {next_nb rcu_dereference_raw(nb-next);...ret nb-notifier_call(nb, val, v);if (nr_calls)(*nr_calls);if (ret NOTIFY_STOP_MASK)break;nb next_nb;nr_to_call--;}return ret;
}
NOKPROBE_SYMBOL(notifier_call_chain);从log分析可以看到nb-notifier_call() 方法会调用sprd_hsphy_vbus_notify() 方法
[14:53:40:749] [ 51.173699] c2 [c0111ebc] (unwind_backtrace) from [c010ced0] (show_stack0x20/0x24)␍␊
[14:53:40:757] [ 51.181677] c2 [c010ced0] (show_stack) from [c0b13884] (dump_stack0xa4/0xd8)␍␊
[14:53:40:761] [ 51.189129] c2 [c0b13884] (dump_stack) from [c06c8f18] (sprd_hsphy_vbus_notify0x48/0x30c)␍␊
[14:53:40:774] [ 51.197722] c2 [c06c8f18] (sprd_hsphy_vbus_notify) from [c014f0a0] (notifier_call_chain0x74/0xac)␍␊
[14:53:40:779] [ 51.207006] c2 [c014f0a0] (notifier_call_chain) from [c014f12c] (raw_notifier_call_chain0x28/0x30)␍␊
[14:53:40:792] [ 51.216371] c2 [c014f12c] (raw_notifier_call_chain) from [c0880468] (extcon_sync0x78/0x1e4)␍␊
[14:53:40:801] [ 51.225137] c2 [c0880468] (extcon_sync) from [c0880bcc] (extcon_set_state_sync0x7c/0x90)␍␊
[14:53:40:806] [ 51.233639] c2 [c0880bcc] (extcon_set_state_sync) from [c0881e60] (usb_extcon_detect_cable0xa8/0xac)␍␊
[14:53:40:815] [ 51.243185] c2 [c0881e60] (usb_extcon_detect_cable) from [c0147d40] (process_one_work0x290/0x4a8)␍␊
[14:53:40:825] [ 51.252466] c2 [c0147d40] (process_one_work) from [c0148590] (worker_thread0x2f8/0x478)␍␊
[14:53:40:833] [ 51.260887] c2 [c0148590] (worker_thread) from [c014d564] (kthread0x148/0x164)␍␊
[14:53:40:844] [ 51.268519] c2 [c014d564] (kthread) from [c0108814] (ret_from_fork0x14/0x20)接着查看sprd_hsphy_vbus_notify() 方法的流程
bsp/kernel/kernel4.14/drivers/usb/phy/phy-sprd-sharkle.cstatic int sprd_hsphy_vbus_notify(struct notifier_block *nb,unsigned long event, void *data)
{struct usb_phy *usb_phy container_of(nb, struct usb_phy, vbus_nb);struct sprd_hsphy *phy container_of(usb_phy, struct sprd_hsphy, phy);...// event 的值是我们传入的USB 状态(state),state 1 表示USB 插入否则没有插入if (event) {/* usb vbus valid */reg readl_relaxed(phy-base REG_AP_AHB_OTG_PHY_TEST);reg | (MASK_AP_AHB_OTG_VBUS_VALID_EXT |MASK_AP_AHB_OTG_VBUS_VALID_PHYREG);writel_relaxed(reg, phy-base REG_AP_AHB_OTG_PHY_TEST);usb_phy_set_charger_state(usb_phy, USB_CHARGER_PRESENT);} else {/* usb vbus invalid */reg readl_relaxed(phy-base REG_AP_AHB_OTG_PHY_TEST);reg ~(MASK_AP_AHB_OTG_VBUS_VALID_PHYREG |MASK_AP_AHB_OTG_VBUS_VALID_EXT);writel_relaxed(reg, phy-base REG_AP_AHB_OTG_PHY_TEST);usb_phy_set_charger_state(usb_phy, USB_CHARGER_ABSENT);}return 0;
}bsp/kernel/kernel4.14/drivers/usb/phy/phy.cvoid usb_phy_set_charger_state(struct usb_phy *usb_phy,enum usb_charger_state state)
{...usb_phy-chg_state state;if (usb_phy-chg_state ! USB_CHARGER_PRESENT)usb_phy-chg_type UNKNOWN_TYPE;schedule_work(usb_phy-chg_work);
}
EXPORT_SYMBOL_GPL(usb_phy_set_charger_state);static void usb_charger_init(struct usb_phy *usb_phy)
{usb_phy-chg_type UNKNOWN_TYPE;usb_phy-chg_state USB_CHARGER_DEFAULT;usb_phy_set_default_current(usb_phy);INIT_WORK(usb_phy-chg_work, usb_phy_notify_charger_work); // 初始化usb_phy-chg_work 工作队列
}调用usb_phy_set_charger_state() 方法后会调用usb_phy_notify_charger_work() 方法
bsp/kernel/kernel4.14/drivers/usb/phy/phy.cstatic void usb_phy_notify_charger_work(struct work_struct *work)
{...// 判断USB的插入状态如果是插入状态则走USB_CHARGER_PRESENT 分支switch (usb_phy-chg_state) {case USB_CHARGER_PRESENT:if (usb_phy-chg_type UNKNOWN_TYPE)usb_phy-chg_type usb_phy-charger_detect(usb_phy);usb_phy_get_charger_current(usb_phy, min, max);atomic_notifier_call_chain(usb_phy-notifier, max, usb_phy); //调用usb_phy中注册的回调方法snprintf(uchger_state, ARRAY_SIZE(uchger_state),USB_CHARGER_STATE%s, USB_CHARGER_PRESENT);break;case USB_CHARGER_ABSENT:usb_phy_set_default_current(usb_phy);atomic_notifier_call_chain(usb_phy-notifier, 0, usb_phy); //调用usb_phy中注册的回调方法snprintf(uchger_state, ARRAY_SIZE(uchger_state),USB_CHARGER_STATE%s, USB_CHARGER_ABSENT);break;default:...// 使用ueven 通知方法通知用户kobject_uevent_env(usb_phy-dev-kobj, KOBJ_CHANGE, envp);
}bsp/kernel/kernel4.14/kernel/notifier.cint atomic_notifier_call_chain(struct atomic_notifier_head *nh,unsigned long val, void *v)
{return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
}int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,unsigned long val, void *v,int nr_to_call, int *nr_calls)
{...ret notifier_call_chain(nh-head, val, v, nr_to_call, nr_calls);...return ret;
}static int notifier_call_chain(struct notifier_block **nl,unsigned long val, void *v,int nr_to_call, int *nr_calls)
{...nb rcu_dereference_raw(*nl); // 这个nb 是usb_phy 通知块的头部块// 回调所有注册的notifier_call 函数while (nb nr_to_call) {next_nb rcu_dereference_raw(nb-next);...ret nb-notifier_call(nb, val, v);if (nr_calls)(*nr_calls);if (ret NOTIFY_STOP_MASK)break;nb next_nb;nr_to_call--;}return ret;
}从usb_phy_notify_charger_work() 方法传入的nh是usb_phy。
2.charger-manager拔插事件分发
以charger-manager 为例在charger-manager.c 的charger_manager_policy_init() 方法中注册了usb_phy.notifier_call 方法
bsp/kernel/kernel4.14/drivers/power/supply/charger-manager.cstatic int charger_manager_policy_init(struct charger_manager *cm)
{...cm-policy.usb_notify.notifier_call policy_usb_change_callback;ret usb_register_notifier(cm-policy.usb_phy, cm-policy.usb_notify);...
}bsp/kernel/kernel4.14/include/linux/usb/phy.hstatic inline int
usb_register_notifier(struct usb_phy *x, struct notifier_block *nb)
{return atomic_notifier_chain_register(x-notifier, nb);
}bsp/kernel/kernel4.14/kernel/notifier.cint atomic_notifier_chain_register(struct atomic_notifier_head *nh,struct notifier_block *n)
{...ret notifier_chain_register(nh-head, n);...
}// 将usb_notify 通知块添加到usb_phy 里通知块的头部
static int notifier_chain_register(struct notifier_block **nl,struct notifier_block *n)
{while ((*nl) ! NULL) {if (n-priority (*nl)-priority)break;nl ((*nl)-next);}n-next *nl;rcu_assign_pointer(*nl, n);return 0;
}所以在我们插入USB时会调用到charger-manager.c::policy_usb_change_callback() 方法