Linux 自带的耳机拔插检测驱动

Linux 自带的耳机拔插检测驱动是混在声卡驱动中,耳机拔插状态通过 input 子系统上报。

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 < 0)
621  		return ret;
622  
623  	ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
624  	if (ret < 0)
625  		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 < count; i++) {
143  		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 < ARRAY_SIZE(jack->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 < ARRAY_SIZE(jack_switch_types); i++) {
688  		int testbit = ((1 << i) & ~mask_bits);
689  
690  		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 行,上报事件,参数 1 为耳机事件类型,参数 2 为耳机事件键值,参数 3 表示耳机插拨的状态。

第 696 行,同步事件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/751597.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#按下enter键时keydown无响应的问题

KeyPreview已经设置为true了之后&#xff0c;按下enter键keydown不响应&#xff0c;但会根据系统默认的响应方法&#xff08;重复按下焦点所在button键&#xff09;做出响应。 解决方法&#xff1a; 在Form类中添加函数&#xff1a; protected override bool ProcessDialogKe…

AWTK 开源串口屏的配置文件

配置文件 每个 HMI 应用程序都需要一个配置文件&#xff0c;用于配置 HMI 的基本信息、服务、持久化、告警信息、历史数据等。 文件位置 design/default/data/settings.json基本配置 name - 名称&#xff08;必须配置&#xff0c;只能用字母、数字、下划线&#xff09; se…

如果网络不好 如何下载huggingface上的模型

很多朋友网络不太好&#xff0c;有时候上不了huggingface这样的国外网站&#xff1b; 或者网络流量不太够&#xff0c;想要下载一些stable diffusion模型&#xff0c;或者其他人工智能的大模型的时候&#xff0c;看到动辄几个G的模型文件&#xff0c;不太舍得下载&#xff1b;…

5 张图带你了解分布式事务 Saga 模式中的状态机

大家好&#xff0c;我是君哥。 状态机在我们的工作中应用非常广泛&#xff0c;今天聊一聊分布式事务中间件 Seata 中 Saga 模式的状态机。 1 状态机简介 状态机是一个数学模型&#xff0c;它将工作中的运行状态和流转规则抽象出来&#xff0c;可以协调相关信号来完成预先设定…

Pycharm安装阿里云通义码灵插件图文教程

前提&#xff1a;必须安装pycharm&#xff0c;可以访问 pycharm下载链接打开页面下载 点击下载后&#xff0c;将下载文件打开&#xff0c;然后无脑安装&#xff0c;安装好后继续看。 然后就安装好了&#xff0c;然后关闭安装&#xff0c;然后打开pycharm即可。 &#x1f680;…

【XML】xml转Freemind思维导图

通过以下代码可以将xml转换为Freemind软件的思维导图&#xff0c;方便查看各数据结构该代码运行需要安装lxml库 pip install lxml使用方式示例 python xml2mm.py *.xml *.mm转化完成示例&#xff0c;使用Freemind软件打开&#xff0c;该软件在ubuntu的软件商店中即可下载pyth…

如何在idea中配置tomcat服务器,然后部署一个项目

文章目录 前言第一步 先新建一个空项目第二步 添加框架支持第三步 添加配置及如何部署最后一步 运行及检查有没有问题总结 前言 本章学习的是在idea中配置tomcat服务器&#xff0c;然后部署一个项目 如果没有下载Tomcat服务器的可以在上一个博客观看下载及手动部署&#xff0c;…

es6有哪些新特性?

ES6&#xff08;ECMAScript 2015&#xff09;引入了许多新特性&#xff0c;使 JavaScript 更加现代化、强大和易用。以下是一些 ES6 的主要新特性&#xff1a; let 和 const 声明&#xff1a;引入了 let 和 const 关键字用于声明变量&#xff0c;let声明的变量具有块级作用域&a…

Ubuntu系统中尚未安装NVIDIA驱动程序

当执行命令&#xff1a; nvidia-smi提示 Command nvidia-smi not found, but can be installed with:apt install nvidia-340 # version 340.108-0ubuntu5.20.04.2, or apt install nvidia-utils-390 # version 390.157-0ubuntu0.20.04.1 apt install nvidia-utils-450-ser…

【通信原理笔记】【二】随机信号分析——2.2 平稳随机过程

文章目录 前言一、平稳随机过程1.1 广义平稳过程1.2 遍历性 二、两个随机过程之间的关系2.1 联合平稳2.2 随机过程的相关关系2.2.1 随机变量的不相关2.2.2 随机过程的不相关 总结 前言 我们学习了随机信号以及随机信号的相关函数与功率谱的计算方法&#xff0c;但是这种计算还…

如何利用图像识别算法检测人是否打领带

使用图像识别算法来检测图像中的人是否打了领带&#xff0c;可以分为几个步骤来进行&#xff1a; 图像收集与预处理&#xff1a; 收集大量包含人的图像数据&#xff0c;其中一些图像中人打了领带&#xff0c;另一些则没有。对这些图像进行预处理&#xff0c;如大小归一化、灰度…

【Python进阶】关于argparse库的使用:便捷参数读取,解析,编写

文章目录 1 实例化参数类&#xff0c;增加参数2 解析命令行参数3 处理参数4 综合示例 在Python中&#xff0c; parser包通常指的是 argparse模块&#xff0c;它是Python标准库中的一部分&#xff0c;用于解析命令行参数。 argparse模块使得编写命令行接口变得更加简单和灵活…

线程常用方法

一常用方法第一组 1.setName 设置线程名称&#xff0c;使之与参数name相同&#xff1b; 2.getName 返回该线程的名字&#xff1b; 3.start 使该线程开始执行&#xff0c;java虚拟机底层调用该线程的statr0方法&#xff1b; 4.run …

前端学习之css伪元素选择器

伪元素选择器 &#xff08;注释是对各个内容的解释与理解&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>伪元素选择器</title><!-- 双冒号开头一般都称为伪元素&#xff0c;…

C#在企业级应用软件开发中的实践深度探讨

C#在企业级应用软件开发中的实践深度探讨 一、引言 企业级应用软件通常要求高度的稳定性、安全性、可扩展性以及复杂的业务逻辑处理能力。C#作为.NET平台上的主流语言&#xff0c;配合现代化的开发框架和工具&#xff0c;为构建此类软件提供了强大的支持。本文将深入剖析使用C#…

代码随想录算法训练营day24 | 回溯算法理论基础、77.组合

目录 回溯算法定义回溯法的效率回溯法解决的问题回溯算法模板 组合思路解题方法复杂度Code 总结 回溯算法 定义 回溯法也叫做回溯搜索法&#xff0c;它是一种搜索的方式。 回溯是递归的副产品&#xff0c;只要有递归就会有回溯。 回溯函数也就是递归函数&#xff0c;指的都…

面向对象编程第三式: 多态 (Java篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

(三)OpenOFDM符号对齐

符号对齐 模块&#xff1a;sync_long.v输入&#xff1a;I (16), Q (16), phase_offset (32), short_gi (1)输出&#xff1a;long_preamble_detected (1), fft_re (16), fft_im (16) 检测到数据包后&#xff0c;下一步是精确确定每个 OFDM 符号的起始位置。在802.11中&#xf…

vue2+vant2+Laravel7 实现多图上传到七牛云

后端接口 1、路由&#xff0c;在 routes/api.php 中 Route::resource(photos, PhotoController)->only(store);2、创建对应控制器 <?php namespace App\Http\Controllers; use Illuminate\Http\Request;class PhotoController extends Controller {/**** 上传图片* p…

深度学习-基于机器学习的语音情感识别系统的设计

概要 语音识别在现实中有着极为重要的应用&#xff0c;现在语音内容的识别技术已日趋成熟。当前语音情感识别是研究热点之一&#xff0c;它可以帮助AI和人更好地互动、可以帮助心理医生临床诊断、帮助随时随地高效测谎等。本文采用了中科院自动化所的CASIA语料库作为样本&#…