Linux 自带的耳机拔插检测驱动
今天golang学习网给大家带来了《Linux 自带的耳机拔插检测驱动》,其中涉及到的知识点包括等等,无论你是小白还是老手,都适合看一看哦~有好的建议也欢迎大家在评论留言,若是看完有所收获,也希望大家能多多点赞支持呀!一起加油学习~
Linux系统默认的耳机插拔检测驱动程序被整合在声卡驱动中,这使得耳机插拔状态能够通过输入子系统进行报告。
这一功能的具体实现位于kernel-5.15版本的sound/soc/generic/simple-card-utils.c文件中。
571 int asoc_simple_init_jack(struct snd_soc_card *card,
572 struct asoc_simple_jack *sjack,
573 int is_hp, char *prefix,
574 char *pin)
575 {
576 struct device *dev = card->dev;
577 enum of_gpio_flags flags;
578 char prop[128];
579 char *pin_name;
580 char *gpio_name;
581 int mask;
582 int det;
583
584 if (!prefix)
585 prefix = "";
586
587 sjack->gpio.gpio = -ENOENT;
588
589 if (is_hp) {
590 snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
591 pin_name = pin ? pin : "Headphones";
592 gpio_name = "Headphone detection";
593 mask = SND_JACK_HEADPHONE;
594 } else {
595 snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
596 pin_name = pin ? pin : "Mic Jack";
597 gpio_name = "Mic detection";
598 mask = SND_JACK_MICROPHONE;
599 }
600
601 det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
602 if (det == -EPROBE_DEFER)
603 return -EPROBE_DEFER;
604
605 if (gpio_is_valid(det)) {
606 sjack->pin.pin = pin_name;
607 sjack->pin.mask = mask;
608
609 sjack->gpio.name = gpio_name;
610 sjack->gpio.report = mask;
611 sjack->gpio.gpio = det;
612 sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW);
613 sjack->gpio.debounce_time = 150;
614
615 snd_soc_card_jack_new(card, pin_name, mask,
616 &sjack->jack,
617 &sjack->pin, 1);
618
619 snd_soc_jack_add_gpios(&sjack->jack, 1,
620 &sjack->gpio);
621 }
622
623 return 0;
624 }
625 EXPORT_SYMBOL_GPL(asoc_simple_init_jack);
第 589~593 行,【构建】用于查找设备树中 GPIO 属性的属性名称 prop。设置 pin_name 为”Headphones”,表示插孔的名称。设置 gpio_name 为 “Headphone detection”,表示 GPIO 的名称。设置 mask 为 SND_JACK_HEADPHONE,表示这是一个耳机插孔。
第 601 行,使用设备树函数 of_get_named_gpio_flags 获取与属性名称 prop 关联的 GPIO 描述符,并存储在 det 中。如果 GPIO 未定义,det 将为负数。
第 606~613 行,如果设置了检测 GPIO,那么设置结构体指针 sjack 的一些属性。设置插孔的引脚信息,比如 sjack->pin.pin 引脚名字。设置耳机插孔的一些 GPIO 关联信息,如 sjack->gpio.gpio 是表示 GPIO 描述符,sjack->gpio.invert 表示根据设备树中的属性决定是否反转 GPIO 状态,GPIO_ACTIVE_LOW 是低电平表示活动,当耳机插入时,检测脚将被拉低,说明是低有效。debounce_time 这个是设置消抖时间,防止误检测。
第 615 行,这里将耳机插孔与声卡绑定。
第 619 行,绑定 GPIO,就会触发耳机插拨事件。
函数名重定义:/include/sound/simple_card_utils.h
14 #define asoc_simple_init_hp(card, sjack, prefix) \ 15 asoc_simple_init_jack(card, sjack, 1, prefix, NULL) 16 #define asoc_simple_init_mic(card, sjack, prefix) \ 17 asoc_simple_init_jack(card, sjack, 0, prefix, NULL)
在声卡驱动 probe 时调用
dts 中配置声卡节点 compatible = “simple-audio-card”
734 static const struct of_device_id simple_of_match[] = {
735 { .compatible = "simple-audio-card", },
736 { .compatible = "simple-scu-audio-card",
737 .data = (void *)DPCM_SELECTABLE },
738 {},
739 };
740 MODULE_DEVICE_TABLE(of, simple_of_match);
614 static int simple_soc_probe(struct snd_soc_card *card)
615 {
616 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
617 int ret;
618
619 ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
620 if (ret return ret;
622
623 ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
624 if (ret return ret;
626
627 return 0;
628 }
这个驱动文件负责声卡的初始化,音频流管理,控制接口等。在第 619 行,调用了耳机检测 IO 初始化的代码。
耳机拔插上报 flow
asoc_simple_init_jack 会调用 snd_soc_card_jack_new,添加检测管脚 pins,进而一路调用下来
60 int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
61 struct snd_soc_jack *jack,
62 struct snd_soc_jack_pin *pins, unsigned int num_pins)
63 {
64 int ret;
65
66 mutex_init(&jack->mutex);
67 jack->card = card;
68 INIT_LIST_HEAD(&jack->pins);
69 INIT_LIST_HEAD(&jack->jack_zones);
70 BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
71
72 ret = snd_jack_new(card->snd_card, id, type, &jack->jack, false, false);
73 if (ret)
74 goto end;
75
76 if (num_pins)
77 ret = snd_soc_jack_add_pins(jack, num_pins, pins);
78 end:
79 return soc_card_ret(card, ret);
80 }
81 EXPORT_SYMBOL_GPL(snd_soc_card_jack_new);
137 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
138 struct snd_soc_jack_pin *pins)
139 {
140 int i;
141
142 for (i = 0; i if (!pins[i].pin) {
144 dev_err(jack->card->dev, "ASoC: No name for pin %d\n",
145 i);
146 return -EINVAL;
147 }
148 if (!pins[i].mask) {
149 dev_err(jack->card->dev, "ASoC: No mask for pin %d"
150 " (%s)\n", i, pins[i].pin);
151 return -EINVAL;
152 }
153
154 INIT_LIST_HEAD(&pins[i].list);
155 list_add(&(pins[i].list), &jack->pins);
156 snd_jack_add_new_kctl(jack->jack, pins[i].pin, pins[i].mask);
157 }
158
159 /* Update to reflect the last reported status; canned jack
160 * implementations are likely to set their state before the
161 * card has an opportunity to associate pins.
162 */
163 snd_soc_jack_report(jack, 0, 0);
164
165 return 0;
166 }
167 EXPORT_SYMBOL_GPL(snd_soc_jack_add_pins);
34 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
35 {
36 struct snd_soc_dapm_context *dapm;
37 struct snd_soc_jack_pin *pin;
38 unsigned int sync = 0;
39
40 if (!jack)
41 return;
42 trace_snd_soc_jack_report(jack, mask, status);
43
44 dapm = &jack->card->dapm;
45
46 mutex_lock(&jack->mutex);
47
48 jack->status &= ~mask;
49 jack->status |= status & mask;
50
51 trace_snd_soc_jack_notify(jack, status);
52
53 list_for_each_entry(pin, &jack->pins, list) {
54 int enable = pin->mask & jack->status;
55
56 if (pin->invert)
57 enable = !enable;
58
59 if (enable)
60 snd_soc_dapm_enable_pin(dapm, pin->pin);
61 else
62 snd_soc_dapm_disable_pin(dapm, pin->pin);
63
64 /* we need to sync for this case only */
65 sync = 1;
66 }
67
68 /* Report before the DAPM sync to help users updating micbias status */
69 blocking_notifier_call_chain(&jack->notifier, jack->status, jack);
70
71 if (sync)
72 snd_soc_dapm_sync(dapm);
73
74 snd_jack_report(jack->jack, jack->status);
75
76 mutex_unlock(&jack->mutex);
77 }
78 EXPORT_SYMBOL_GPL(snd_soc_jack_report);
652 void snd_jack_report(struct snd_jack *jack, int status)
653 {
654 struct snd_jack_kctl *jack_kctl;
655 unsigned int mask_bits = 0;
656 #ifdef CONFIG_SND_JACK_INPUT_DEV
657 int i;
658 #endif
659
660 if (!jack)
661 return;
662
663 jack->hw_status_cache = status;
664
665 list_for_each_entry(jack_kctl, &jack->kctl_list, list)
666 if (jack_kctl->sw_inject_enable)
667 mask_bits |= jack_kctl->mask_bits;
668 else
669 snd_kctl_jack_report(jack->card, jack_kctl->kctl,
670 status & jack_kctl->mask_bits);
671
672 #ifdef CONFIG_SND_JACK_INPUT_DEV
673 mutex_lock(&jack->input_dev_lock);
674 if (!jack->input_dev) {
675 mutex_unlock(&jack->input_dev_lock);
676 return;
677 }
678
679 for (i = 0; i key); i++) {
680 int testbit = ((SND_JACK_BTN_0 >> i) & ~mask_bits);
681
682 if (jack->type & testbit)
683 input_report_key(jack->input_dev, jack->key[i],
684 status & testbit);
685 }
686
687 for (i = 0; i if (jack->type & testbit)
691 input_report_switch(jack->input_dev,
692 jack_switch_types[i],
693 status & testbit);
694 }
695
696 input_sync(jack->input_dev);
697 mutex_unlock(&jack->input_dev_lock);
698 #endif /* CONFIG_SND_JACK_INPUT_DEV */
699 }
700 EXPORT_SYMBOL(snd_jack_report);
第 683 行,input 上报事件,参数 1 为耳机事件类型,参数 2 为耳机事件键值,参数 3 表示耳机插拨的状态。第 696 行,同步事件。
若你要使用 Linux 自带的耳机拔插检测驱动,则需要在对应的声卡驱动的 dts 节点中声明你所使用的 GPIO 口,加载时就会自动帮你配置好检测逻辑。

Linux 自带的耳机拔插检测功能有限,大部分平台都有自己的耳机检测逻辑,例如 RK 平台的耳机检测在这:
kernel/drivers/headset_observe/rockchip_headset_core.c
MTK 平台的耳机拔插检测驱动在:
kernel/drivers/misc/mediatek/accdet/
kernel/sound/soc/codecs/mt6xxx-accdet.c
到这里,我们也就讲完了《Linux 自带的耳机拔插检测驱动》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于Linux,Linux系统,Shell脚本,Linux命令,linux入门,linux教程,linux学习,嵌入式Linux的知识点!
-
- 文章 · linux | 5秒前 |
- 如何查看Linux文件所属的软件包
- 478浏览 收藏
-
- 文章 · linux | 1分钟前 |
- LINUXstrace和ltrace命令使用教程
- 481浏览 收藏
-
- 文章 · linux | 8分钟前 |
- LINUX设置PATH变量永久生效方法
- 492浏览 收藏
-
- 文章 · linux | 18分钟前 |
- Linux代理设置方法:终端export配置详解
- 370浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux命令安装路径查询技巧
- 152浏览 收藏
-
- 文章 · linux | 2小时前 | 权限 ssh-keygen 免密登录 SSH密钥 ssh-copy-id
- LinuxSSH密钥生成与免密设置教程
- 272浏览 收藏
-
- 文章 · linux | 4小时前 | Linux 激活 venv virtualenv Python虚拟环境
- Linux下如何创建Python虚拟环境
- 418浏览 收藏
-
- 文章 · linux | 5小时前 |
- LINUXwatch命令使用教程与实战详解
- 430浏览 收藏
-
- 文章 · linux | 5小时前 |
- Linux修改SSH端口教程详解
- 316浏览 收藏
-
- 文章 · linux | 15小时前 |
- 查看SELinux状态的几种方法
- 408浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3213次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3427次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3457次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4566次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3833次使用
-
- 命令行工具:应对Linux服务器安全挑战的利器
- 2023-10-04 501浏览
-
- 如何使用Docker进行容器的水平伸缩和负载均衡
- 2023-11-07 501浏览
-
- linux .profile的作用是什么
- 2024-04-07 501浏览
-
- 如何解决s权限位引发postfix及crontab异常
- 2024-11-21 501浏览
-
- 如何通过脚本自动化Linux上的K8S安装
- 2025-02-17 501浏览

对象
