08.音频系统:第005课_项目实战1_耳麦拔插:第001节_驱动程序上报耳麦拔插事件

news/2024/11/29 4:38:26/

在接下来的几个小节中,会讲解几个音频的项目,现在想讲解第一个项目:对 耳麦拔插事件的处理,一起分为四个小节左右:
5.1 驱动程序上报耳麦拔插事件
5.2 在状态栏显示耳麦图标
5.3 耳麦拔插事件调用流程分析
5.4 切换声音通道流程

在讲解驱动程序之前,先讲解几个概念:
在这里插入图片描述
如上,对于耳机,有很多类型,带麦克的耳机术语叫做headset,不带麦克的术语叫做headphone:
在这里插入图片描述
上面是一个android系统,单需要播放声音的时候,cpu把数据信号发送给声卡,在声卡内部进行数模转换(DAC),然后通过运放进行播放,其中line out为原始数据,即还没有经过运放的数据,通过耳机运放称为headphone(如果有麦的耳机叫做headset),也可以听过音响进行运放,其约等于line out数据。。
在这里插入图片描述
在驱动程序中,只要支持headphone,headset以及line out这3中设备的上报就可以了。那么我们怎么上报这3中设备的拔插呢?(以下两种只能选择其中一种):
1.输入子系统:可上报输入事件,也可上报开关事件。
2.Switch State:使用UEvent系统,通过网络向应用程序上报事件。

下面是编写输入系统的流程:
在这里插入图片描述
1.分配input_dev结构体
2.设置a.能产生哪些事件(EV_SW)。b.能产生EV_SW中的哪些事件(如:headset,headset,Line out等等)。
3.注册input_dev
4.硬件相关:中断程序,使用input_event上报插入或者拔出事件。

编写驱动程序如下(其使用两种方法实现):


#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/switch.h>
#include <linux/input.h>static struct input_dev *g_virtual_input;static ssize_t input_test_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{long code;long val;char *endp;/* 如果字符串前面含有非数字, simple_strtol不能处理 */while ((*buf == ' ') || (*buf == '\t'))buf++;code = simple_strtol(buf, &endp, 0);/* 如果字符串前面含有非数字, simple_strtol不能处理 */while ((*endp == ' ') || (*endp == '\t'))endp++;val  = simple_strtol(endp, NULL, 0);printk("emulate to report EV_SW: 0x%lx 0x%lx\n", code, val);input_event(g_virtual_input, EV_SW, code, val);input_sync(g_virtual_input);return count;
}static DEVICE_ATTR(test_input, S_IRUGO | S_IWUSR, NULL, input_test_store);static int register_input_device_for_jack(void)
{int err;/* 分配input_dev */g_virtual_input = input_allocate_device();/* 设置 *//* 2.1 能产生哪类事件 */set_bit(EV_SYN, g_virtual_input->evbit);set_bit(EV_SW, g_virtual_input->evbit);/* 2.2 能产生这类事件中的哪些 *//* headset = 听筒 + MIC = SW_HEADPHONE_INSERT + SW_MICROPHONE_INSERT*    同时上报 SW_HEADPHONE_INSERT 和 SW_MICROPHONE_INSERT, 就表示headset*    为了简化, 对于android系统只上报SW_MICROPHONE_INSERT也表示headset*/set_bit(SW_HEADPHONE_INSERT, g_virtual_input->swbit);set_bit(SW_MICROPHONE_INSERT, g_virtual_input->swbit);set_bit(SW_LINEOUT_INSERT, g_virtual_input->swbit);/* 2.3 这些事件的范围 */g_virtual_input->name = "alsa_switch"; /* 不重要 *//* 注册 */err = input_register_device(g_virtual_input);if (err) {input_free_device(g_virtual_input);	printk("input_register_device for virtual jack err!\n");return err;}/* 创建/sys/class/input/inputX/test_input文件*   可以执行类似下面的命令来模拟耳麦的动作:  *       触发上报headset插入: echo 4 1 > /sys/class/input/inputX/test_input  *       触发上报headset取下: echo 4 0 > /sys/class/input/inputX/test_input  */err = device_create_file(&g_virtual_input->dev, &dev_attr_test_input);if (err) {printk("device_create_file for test_input err!\n");input_unregister_device(g_virtual_input);input_free_device(g_virtual_input); return err;}return 0;
}static void unregister_input_device_for_jack(void)
{device_remove_file(&g_virtual_input->dev, &dev_attr_test_input);input_unregister_device(g_virtual_input);input_free_device(g_virtual_input);	
}/**************************************************************************************************************/static struct switch_dev g_virtual_switch;static ssize_t state_test_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{long val;val = simple_strtol(buf, NULL, 0);printk("emulate to report swtich state: 0x%lx\n", val);switch_set_state(&g_virtual_switch, val);return count;
}static DEVICE_ATTR(test_state, S_IRUGO | S_IWUSR, NULL, state_test_store);static int register_switch_device_for_jack(void)
{int err;g_virtual_switch.name = "h2w";err = switch_dev_register(&g_virtual_switch);if (err) {printk("switch_dev_register h2w err!\n");return err;}/* 创建/sys/class/switch/h2w/test_state文件*   可以执行类似下面的命令来模拟耳麦的动作:  *       触发上报headset插入: echo 1 > /sys/class/switch/h2w/test_state*       触发上报headset取下: echo 0 > /sys/class/switch/h2w/test_state*/err = device_create_file(g_virtual_switch.dev, &dev_attr_test_state);if (err) {printk("device_create_file test err!\n");switch_dev_unregister(&g_virtual_switch);return err;}return 0;
}static void unregister_switch_device_for_jack(void)
{device_remove_file(g_virtual_switch.dev, &dev_attr_test_state);switch_dev_unregister(&g_virtual_switch);
}/**************************************************************************************************************/static int __init virtual_jack_init(void)
{int err;err = register_input_device_for_jack();err = register_switch_device_for_jack();return 0;
}static void __exit virtual_jack_exit(void)
{unregister_input_device_for_jack();unregister_switch_device_for_jack();
}module_init(virtual_jack_init);
module_exit(virtual_jack_exit);MODULE_AUTHOR("weidongshan@qq.com");
MODULE_DESCRIPTION("Virutal jack driver for sound card");
MODULE_LICENSE("GPL");

/* 创建/sys/class/switch/h2w/test_state文件
* 可以执行类似下面的命令来模拟耳麦的动作:
* 触发上报headset插入: echo 1 > /sys/class/switch/h2w/test_state
* 触发上报headset取下: echo 0 > /sys/class/switch/h2w/test_state
*/

/* 创建/sys/class/input/inputX/test_input文件
* 可以执行类似下面的命令来模拟耳麦的动作:
* 触发上报headset插入: echo 4 1 > /sys/class/input/inputX/test_input
* 触发上报headset取下: echo 4 0 > /sys/class/input/inputX/test_input
*/

下面说一下编写switch dev驱动的流程:
在这里插入图片描述
1.分配switch dev
2.设置switch dev
3.注册
4.硬件触发
代码简化如下:

static struct switch_dev g_virtual_switch;
/*戴米安耳机的拔插*/
g_virtual_switch.name = "h2w";
err = switch_dev_register(&g_virtual_switch);
/*硬件触发,状态设置,中断上报*/
switch_set_state(&g_virtual_switch, val);

下面是switch_set_state与输入子系统能够上报事件的一些对比:
在这里插入图片描述
前面提到Switch State通过网络上报事件,那么我们来分析一下:

void switch_set_state(struct switch_dev *sdev, int state)kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE);return kobject_uevent_env(kobj, action, NULL);/*通过网络发送数据*/retval = netlink_broadcast_filtered(uevent_sock, skb,0, 1, GFP_KERNEL,kobj_bcast_filter,kobj);/*sbin/hotplug APP*/retval = call_usermodehelper_exec(info, UMH_NO_WAIT);

如何把程序编写到内就不讲解了,下小节我们开始做实验。


http://www.ppmy.cn/news/380318.html

相关文章

8.5.3耳麦拔插事件调用流程分析

目录 回顾 input系统方法 回顾 在前面的小节中,我们编写了一个驱动程序,模拟耳机的插拔事件,其可以上报耳机的拔插事件,并且修改了android的源代码,可以根据耳机的拔插事件,在状态栏上现实或者消除耳麦的图标,这节视频我们讲解耳麦插拔事件导致的程序调用流程。 …

耳麦有杂音(电流声)的解决方法

耳麦有杂音&#xff08;电流声&#xff09;的解决方法 耳麦有杂音&#xff08;电流声&#xff09;主要原因&#xff1a; 1&#xff0c;电脑没有及时清理&#xff0c;堆积系统垃圾太多&#xff0c;电脑反映缓慢&#xff0c;应及时清理电脑的系统垃圾和杀毒。2&#xff0c;耳麦损…

Linux教程——Linux cd命令:切换目录 + Linux pwd命令:显示当前路径

Linux cd命令&#xff1a;切换目录 cd 命令&#xff0c;是 Change Directory 的缩写&#xff0c;用来切换工作目录。 Linux 命令按照来源方式&#xff0c;可分为两种&#xff0c;分别是 Shell 内置命令和外部命令。所谓 Shell 内置命令&#xff0c;就是 Shell 自带的命令&…

屋大维和王莽,同时同路不同命的双雄

汉朝与罗马&#xff0c;虽然他们相隔万里分布在欧亚大陆东西两端&#xff0c;但他们几乎同时成为世界性文明&#xff0c;分别都是当时世界上东西方最强大的所在。公元元年前后&#xff0c;这两个庞然大物内部都发生了一次巨变&#xff0c;罗马由共和制变为了元首制。而汉朝也由…

【Java注解】如何正确使用注解提高程序模块化和扩展性

I. Java 注解基础 Java 注解背景 Java 注解的出现是为了解决Java语言的不足之处。在 Java 语言中&#xff0c;类的成员只包括字段和方法&#xff0c;并且类是 Java 语言中最小的单位&#xff0c;而其他的语言&#xff08;如 C&#xff09;都支持宏定义。宏定义可以将功能与元…

【taro react】---- 解决H5接入uni-app版本的IM

1. 问题 由于项目开发比较紧张&#xff0c;腾讯 IM 的接入就使用了 TUIKit 含UI集成方案&#xff0c;遇到的问题&#xff0c;uni-app的UI本来就是一个单独的项目&#xff0c;需要集成到现有的 Taro React 中&#xff0c;就只能作为一个独立的项目&#xff0c;不跳转时不影响原有…

研一,有点迷茫。

作者&#xff1a;阿秀 校招八股文学习网站&#xff1a;https://interviewguide.cn 这是阿秀的第「277」篇原创 小伙伴们大家好&#xff0c;我是阿秀。 最近回答了不少大一大二研一在读的学习圈中学弟学妹的咨询问题&#xff0c;基本都是计算机学习、进度、疑惑等等相关的问题&a…

ping局域网里面全部的ip

for /L %i IN (1,1,254) DO ping -w 2 -n 1 192.168.1.%i |find /i “TTL” 你懂的&#xff0c;真的很好用哦。