文章目录

  • 耳机驱动注册流程
  • 耳机插入时accdet驱动调用
平台 os版本 内核
MT6765 Android 9.0 kernel-4.9

耳机驱动注册流程

耳机驱动的主要功能是 检测耳机的插拔,检测耳机是否带有mic,以及耳机上按键功能的设置 等。

入口函数所在文件:
./kernel-4.9/drivers/misc/mediatek/accdet/accdet_drv.c
非常的简单直接,在入口函数里调用platform_driver_register注册platform dirver

module_init(accdet_mod_init);static int accdet_mod_init(void)
{int ret = 0;ACCDET_DEBUG_DRV("[Accdet]accdet_mod_init begin!\n");ret = platform_driver_register(&accdet_driver);if (ret)ACCDET_DEBUG_DRV("[Accdet]platform_driver_register error:(%d)\n", ret);elseACCDET_DEBUG_DRV("[Accdet]platform_driver_register done!\n");ACCDET_DEBUG_DRV("[Accdet]accdet_mod_init done!\n");return ret;}

平台driver对应的结构体所在文件:
./kernel-4.9/drivers/misc/mediatek/accdet/accdet_drv.c

const struct of_device_id accdet_of_match[] = {...... /* 省略部分代码 */{ .compatible = "mediatek,pmic-accdet", },...... /* 省略部分代码 */{},
};static struct platform_driver accdet_driver = {.probe = accdet_probe,/* .suspend = accdet_suspend, *//* .resume = accdet_resume, */.remove = accdet_remove,.driver = {.name = "Accdet_Driver",
#ifdef CONFIG_PM.pm = &accdet_pm_ops,
#endif.of_match_table = accdet_of_match,},
};

of_match_table./kernel-4.9/arch/arm/boot/dts/mt6765.dts文件中的

accdet: accdet {compatible = "mediatek,pmic-accdet";
};

compatible中的字符串匹配成功后,会调用到相应的probe函数。

probe函数所在文件:
./kernel-4.9/drivers/misc/mediatek/accdet/accdet_drv.c

static int accdet_probe(struct platform_device *dev)
{return mt_accdet_probe(dev);
}

accdet_probe函数只是对mt_accdet_probe函数做的一层封装,真正的probe函数是mt_accdet_probe函数。

函数所在文件:
./kernel-4.9/drivers/misc/mediatek/accdet/mt6357/accdet.c
耳机的字符设备驱动程序的设备文件的主次设备号的分配以及创建都是在这里面完成的。

int mt_accdet_probe(struct platform_device *dev)
{int ret;struct platform_driver accdet_driver_hal = accdet_driver_func();pr_info("%s() begin!\n", __func__);/* register char device number, Create normal device for auido use *//* 不指定主设备号,而是通过内核分配主设备号,获取的 major = 245 */ret = alloc_chrdev_region(&accdet_devno, 0, 1, ACCDET_DEVNAME);if (ret) {pr_notice("%s alloc_chrdev_reg fail,ret:%d!\n", __func__, ret);goto err_chrdevregion;}/* init cdev, and add it to system *//********************************************************* cdev_alloc函数使用kzalloc申请了内存并且内部把申请到的* 内存初始化********************************************************/accdet_cdev = cdev_alloc();accdet_cdev->owner = THIS_MODULE;/****************************************************** 只是字符设备驱动框架上需要由file_operation结构体,实际上* accdet_get_fops里面的open,ioctl函数都是空函数 *****************************************************/accdet_cdev->ops = accdet_get_fops();ret = cdev_add(accdet_cdev, accdet_devno, 1);if (ret) {pr_notice("%s cdev_add fail.ret:%d\n", __func__, ret);goto err_cdev_add;}/* create class in sysfs, "sys/class/", so udev in userspace can create*device node, when device_create is called*/accdet_class = class_create(THIS_MODULE, ACCDET_DEVNAME);if (!accdet_class) {ret = -1;pr_notice("%s class_create fail.\n", __func__);goto err_class_create;}/* create device under /dev node* if we want auto creat device node, we must call this*/accdet_device = device_create(accdet_class, NULL, accdet_devno,NULL, ACCDET_DEVNAME);if (!accdet_device) {ret = -1;pr_notice("%s device_create fail.\n", __func__);goto err_device_create;}/* Create input device*/accdet_input_dev = input_allocate_device();if (!accdet_input_dev) {ret = -ENOMEM;pr_notice("%s input_allocate_device fail.\n", __func__);goto err_input_alloc;}/* 设置按键类事件 */__set_bit(EV_KEY, accdet_input_dev->evbit);/* 设置播放暂停功能按键事件 */__set_bit(KEY_PLAYPAUSE, accdet_input_dev->keybit);/* 设置音量-功能按键事件 */__set_bit(KEY_VOLUMEDOWN, accdet_input_dev->keybit);/* 设置音量+功能按键事件 */__set_bit(KEY_VOLUMEUP, accdet_input_dev->keybit);__set_bit(KEY_VOICECOMMAND, accdet_input_dev->keybit);__set_bit(EV_SW, accdet_input_dev->evbit);/* 设置耳机插入事件 */__set_bit(SW_HEADPHONE_INSERT, accdet_input_dev->swbit);/* 设置麦克风插入事件 */__set_bit(SW_MICROPHONE_INSERT, accdet_input_dev->swbit);__set_bit(SW_JACK_PHYSICAL_INSERT, accdet_input_dev->swbit);__set_bit(SW_LINEOUT_INSERT, accdet_input_dev->swbit);accdet_input_dev->id.bustype = BUS_HOST;accdet_input_dev->name = "ACCDET";/* 注册input设备 */ret = input_register_device(accdet_input_dev);if (ret) {pr_notice("%s input_register_device fail.ret:%d\n", __func__,ret);goto err_input_reg;}ret = accdet_create_attr(&accdet_driver_hal.driver);if (ret) {pr_notice("%s create_attr fail, ret = %d\n", __func__, ret);goto err_create_attr;}/* init the timer to disable micbias. *//* 创建并初始化一个定时器 */init_timer(&micbias_timer);/* MICBIAS_DISABLE_TIMER 等于 (6 * HZ) *//* 通过定时器每 6s 自动关闭 micbias,达到省电目的,因为中断会唤醒使能 */micbias_timer.expires = jiffies + MICBIAS_DISABLE_TIMER;micbias_timer.function = &dis_micbias_timerhandler;micbias_timer.data = 0;/* set the timer ensure accdet can be init even audio never call */init_timer(&accdet_init_timer);accdet_init_timer.expires = jiffies + ACCDET_INIT_WAIT_TIMER;accdet_init_timer.function = &delay_init_timerhandler;accdet_init_timer.data = 0;/* wake lock */accdet_irq_lock = wakeup_source_register("accdet_irq_lock");accdet_timer_lock = wakeup_source_register("accdet_timer_lock");/* Create workqueue *//********************************************************** 创建一个名为“accdet”的工作队列,用来处理ACCDET模块的按键识别* 流程,它将根据PMIC的状态是否有耳机插入,以及插入的耳机类型和* 按键的类型,如果有按键操作,会通过input子系统上报按键事件。*  * 它的queue_work是在accdet_irq_handle中执行的*********************************************************/accdet_workqueue = create_singlethread_workqueue("accdet");/* 初始化工作work_struct,指定工作函数 */INIT_WORK(&accdet_work, accdet_work_callback);if (!accdet_workqueue) {ret = -1;pr_notice("%s create accdet workqueue fail.\n", __func__);goto err_create_attr;}/* register pmic interrupt *//* 注册耳机中断,使用的是带有pmic前缀的中断函数,说明中断属于PMIC端的中断 */pmic_register_interrupt_callback(INT_ACCDET, accdet_int_handler);
/* kernel中配置CONFIG_ACCDET_EINT_IRQ=n */
#ifdef CONFIG_ACCDET_EINT_IRQ
/* kernel中配置CONFIG_ACCDET_SUPPORT_EINT0 =n */
#ifdef CONFIG_ACCDET_SUPPORT_EINT0 pmic_register_interrupt_callback(INT_ACCDET_EINT0,accdet_eint_handler);
#elif defined CONFIG_ACCDET_SUPPORT_EINT1pmic_register_interrupt_callback(INT_ACCDET_EINT1,accdet_eint_handler);
#elif defined CONFIG_ACCDET_BI_EINTpmic_register_interrupt_callback(INT_ACCDET_EINT0,accdet_eint_handler);pmic_register_interrupt_callback(INT_ACCDET_EINT1,accdet_eint_handler);
#endif
#endif/* 从dts里面获取耳机的一些参数设置 */ret = accdet_get_dts_data();if (ret) {atomic_set(&accdet_first, 0);pr_notice("%s accdet_get_dts_data err!\n", __func__);goto err;}dis_micbias_workqueue = create_singlethread_workqueue("dismicQueue");INIT_WORK(&dis_micbias_work, dis_micbias_work_callback);if (!dis_micbias_workqueue) {ret = -1;pr_notice("%s create dis micbias workqueue fail.\n", __func__);goto err;}/* 因为使用是ACCDEGT+EINT的模式检测耳机的插拔,所以这里也创建了一个工作队列 */eint_workqueue = create_singlethread_workqueue("accdet_eint");INIT_WORK(&eint_work, eint_work_callback);if (!eint_workqueue) {ret = -1;pr_notice("%s create eint workqueue fail.\n", __func__);goto err_create_workqueue;}/* kernel中配置CONFIG_ACCDET_EINT=y */
#ifdef CONFIG_ACCDET_EINT/* 外部中断的设置 */ret = ext_eint_setup(dev);if (ret) {pr_notice("%s ap eint setup fail.ret:%d\n", __func__, ret);goto err_eint_setup;}
#endifatomic_set(&accdet_first, 1);/* 修改定时器定时时长 */mod_timer(&accdet_init_timer, (jiffies + ACCDET_INIT_WAIT_TIMER));accdet_get_efuse();pr_info("%s done!\n", __func__);return 0;#ifdef CONFIG_ACCDET_EINT
err_eint_setup:destroy_workqueue(eint_workqueue);
#endiferr_create_workqueue:destroy_workqueue(dis_micbias_workqueue);
err:destroy_workqueue(accdet_workqueue);
err_create_attr:input_unregister_device(accdet_input_dev);
err_input_reg:input_free_device(accdet_input_dev);
err_input_alloc:device_del(accdet_device);
err_device_create:class_destroy(accdet_class);
err_class_create:cdev_del(accdet_cdev);
err_cdev_add:unregister_chrdev_region(accdet_devno, 1);
err_chrdevregion:pr_notice("%s error. now exit.!\n", __func__);return ret;
}

在probe函数里面做了相当多的工作:

  • 创建设备文件
  • 分配设置注册input_dev结构体
  • 创建并使用定时器
  • 设置wakeup_lock避免系统休眠
  • 创建工作队列
  • 注册pmic中断
  • 从dts获取accdet的相关data
  • 配置accdet的gpio中断引脚并配置中断
  • 获取accdet相关的efuse

基本上所有的初始化工作都在mt_accdet_probe这个函数中完成了。


accdet_get_dts_dataext_eint_setup两个函数中都会从dts里面获取ACCDET的一些硬件资源,比如耳机插拔的延时设置,耳机模式的设置,mic的模式设置,中断引脚的设置等。

平台资源所在文件:
./kernel-4.9/arch/arm64/boot/dts/mediatek/x022_k65v1_64_bsp.dts

/* accdet start */
&accdet {accdet-mic-vol = <6>;headset-mode-setting = <0x500 0x500 1 0x1f0 0x800 0x800 0x20 0x44>;accdet-plugout-debounce = <1>;accdet-mic-mode = <1>;headset-eint-level-pol = <8>;headset-three-key-threshold = <0 80 220 400>;headset-three-key-threshold-CDD = <0 121 192 600>;headset-four-key-threshold = <0 58 121 192 400>;pinctrl-names = "default", "state_eint_as_int";pinctrl-0 = <&accdet_pins_default>;pinctrl-1 = <&accdet_pins_eint_as_int>;status = "okay";
};
&pio {accdet_pins_default: accdetdefault {};accdet_pins_eint_as_int: accdeteint@0 {pins_cmd_dat {pinmux = <PINMUX_GPIO19__FUNC_GPIO19>;slew-rate = <0>;bias-disable;};};
};
/* accdet end */

平台资源获取的函数所在文件:
./kernel-4.9/drivers/misc/mediatek/accdet/mt6357/accdet.c

static int accdet_get_dts_data(void)
{int ret;struct device_node *node = NULL;int pwm_deb[8];
#ifdef CONFIG_FOUR_KEY_HEADSETint four_key[5];
#elseint three_key[4];
#endifpr_debug("%s\n", __func__);node = of_find_matching_node(node, accdet_of_match);if (!node) {pr_notice("%s can't find compatible dts node\n", __func__);return -1;}#if defined(CONFIG_MOISTURE_EXT_SUPPORT) || defined(CONFIG_MOISTURE_INT_SUPPORT)of_property_read_u32(node, "moisture-water-r", &water_r);
#ifdef CONFIG_MOISTURE_EXT_SUPPORTof_property_read_u32(node, "moisture-external-r", &moisture_ext_r);pr_info("accdet Moisture_EXT support water_r=%d, moisture_ext_r=%d\n",water_r, moisture_ext_r);
#endif
#ifdef CONFIG_MOISTURE_INT_SUPPORTof_property_read_u32(node, "moisture-internal-r", &moisture_int_r);pr_info("accdet Moisture_INT support water_r=%d, moisture_int_r=%d\n",water_r, moisture_int_r);
#endif
#endifof_property_read_u32(node, "accdet-mic-vol", &accdet_dts.mic_vol);of_property_read_u32(node, "accdet-plugout-debounce",&accdet_dts.plugout_deb);of_property_read_u32(node, "accdet-mic-mode", &accdet_dts.mic_mode);of_property_read_u32(node, "headset-eint-level-pol",&accdet_dts.eint_pol);pr_info("accdet mic_vol=%d, plugout_deb=%d mic_mode=%d eint_pol=%d\n",accdet_dts.mic_vol, accdet_dts.plugout_deb,accdet_dts.mic_mode, accdet_dts.eint_pol);#ifdef CONFIG_FOUR_KEY_HEADSETret = of_property_read_u32_array(node, "headset-four-key-threshold",four_key, ARRAY_SIZE(four_key));if (!ret)memcpy(&accdet_dts.four_key, four_key+1,sizeof(struct four_key_threshold));elsepr_info("accdet get 4-key-thrsh fail\n");pr_info("accdet key thresh mid = %d, voice = %d, up = %d, dwn = %d\n",accdet_dts.four_key.mid, accdet_dts.four_key.voice,accdet_dts.four_key.up, accdet_dts.four_key.down);
#else
#ifdef CONFIG_HEADSET_TRI_KEY_CDDret = of_property_read_u32_array(node,"headset-three-key-threshold-CDD", three_key,ARRAY_SIZE(three_key));
#elseret = of_property_read_u32_array(node, "headset-three-key-threshold",three_key, ARRAY_SIZE(three_key));
#endifif (!ret)memcpy(&accdet_dts.three_key, three_key+1,sizeof(struct three_key_threshold));elsepr_info("accdet get 3-key-thrsh fail\n");pr_info("accdet key thresh mid = %d, up = %d, down = %d\n",accdet_dts.three_key.mid, accdet_dts.three_key.up,accdet_dts.three_key.down);
#endifret = of_property_read_u32_array(node, "headset-mode-setting", pwm_deb,ARRAY_SIZE(pwm_deb));/* debounce8(auxadc debounce) is default, needn't get from dts */if (!ret)memcpy(&accdet_dts.pwm_deb, pwm_deb, sizeof(pwm_deb));elsepr_info("accdet get pwm-debounce setting fail\n");/* for discharge:0xB00 about 86ms */button_press_debounce = (accdet_dts.pwm_deb.debounce0 >> 1);cust_pwm_deb = &accdet_dts.pwm_deb;pr_info("accdet pwm_width=0x%x, thresh=0x%x, fall=0x%x, rise=0x%x\n",cust_pwm_deb->pwm_width, cust_pwm_deb->pwm_thresh,cust_pwm_deb->fall_delay, cust_pwm_deb->rise_delay);pr_info("accdet deb0=0x%x, deb1=0x%x, deb3=0x%x, deb4=0x%x\n",cust_pwm_deb->debounce0, cust_pwm_deb->debounce1,cust_pwm_deb->debounce3, cust_pwm_deb->debounce4);return 0;
}

中断引脚配置与中断注册函数所在的文件:
./kernel-4.9/drivers/misc/mediatek/accdet/mt6357/accdet.c

static inline int ext_eint_setup(struct platform_device *platform_device)
{int ret = 0;u32 ints[4] = { 0 };struct device_node *node = NULL;struct pinctrl_state *pins_default = NULL;pr_info("accdet %s()\n", __func__);accdet_pinctrl = devm_pinctrl_get(&platform_device->dev);if (IS_ERR(accdet_pinctrl)) {ret = PTR_ERR(accdet_pinctrl);dev_notice(&platform_device->dev, "get accdet_pinctrl fail.\n");return ret;}pins_default = pinctrl_lookup_state(accdet_pinctrl, "default");if (IS_ERR(pins_default)) {ret = PTR_ERR(pins_default);dev_notice(&platform_device->dev, "lookup deflt pinctrl fail\n");}pins_eint = pinctrl_lookup_state(accdet_pinctrl, "state_eint_as_int");if (IS_ERR(pins_eint)) {ret = PTR_ERR(pins_eint);dev_notice(&platform_device->dev, "lookup eint pinctrl fail\n");return ret;}pinctrl_select_state(accdet_pinctrl, pins_eint);node = of_find_matching_node(node, accdet_of_match);if (!node) {pr_notice("accdet %s can't find compatible node\n", __func__);return -1;}gpiopin = of_get_named_gpio(node, "deb-gpios", 0);ret = of_property_read_u32(node, "debounce", &gpio_headset_deb);if (ret < 0) {pr_notice("accdet %s gpiodebounce not found,ret:%d\n",__func__, ret);return ret;}gpio_set_debounce(gpiopin, gpio_headset_deb);accdet_irq = irq_of_parse_and_map(node, 0);ret = of_property_read_u32_array(node, "interrupts", ints,ARRAY_SIZE(ints));if (ret) {pr_notice("accdet %s interrupts not found,ret:%d\n",__func__, ret);return ret;}accdet_eint_type = ints[1];pr_info("accdet set gpio EINT, gpiopin=%d, accdet_eint_type=%d\n",gpiopin, accdet_eint_type);ret = request_irq(accdet_irq, ex_eint_handler, IRQF_TRIGGER_NONE,"accdet-eint", NULL);if (ret) {pr_notice("accdet %s request_irq fail, ret:%d.\n", __func__,ret);return ret;}pr_info("accdet set gpio EINT finished, irq=%d, gpio_headset_deb=%d\n",accdet_irq, gpio_headset_deb);return 0;
}

耳机插入时accdet驱动调用

中断是在mt_accdet_probe函数中注册的。
函数所在文件:
./kernel-4.9/drivers/misc/mediatek/accdet/mt6357/accdet.c

int mt_accdet_probe(struct platform_device *dev)
{... /* 省略部分代码 *//* register pmic interrupt *//* INT_ACCDET 是PMIC中对应的中断好 */pmic_register_interrupt_callback(INT_ACCDET, accdet_int_handler);... /* 省略部分代码 */
}

当插入耳机, AP中断使能 MICBIAS 之后,会走 accdet 检测,PMIC会产生中断,调用中断函数触发中断会调用到accdet_int_handler中断处理函数。
函数所在文件:
./kernel-4.9/drivers/misc/mediatek/accdet/mt6357/accdet.c

static void accdet_int_handler(void)
{pr_debug("%s()\n", __func__);accdet_irq_handle();
}

我们可以知道真正的中断处理函数是accdet_irq_handle
函数所在文件:
./kernel-4.9/drivers/misc/mediatek/accdet/mt6357/accdet.c

static void accdet_irq_handle(void)
{u32 eintID = 0;u32 irq_status;
#if defined(CONFIG_MOISTURE_INT_SUPPORT) || defined(CONFIG_MOISTURE_EXT_SUPPORT)unsigned int moisture_vol = 0;
#endif
#ifdef CONFIG_ACCDET_EINT_IRQeintID = get_triggered_eint();
#endifirq_status = pmic_read(ACCDET_IRQ_STS);if ((irq_status & ACCDET_IRQ_B0) && (eintID == 0)) {pr_info("%s() IRQ_STS = 0x%x, IRQ triggered\n", __func__,irq_status);clear_accdet_int();/* 执行的是名为"accdet"的工作队列 */accdet_queue_work();clear_accdet_int_check();
/* 在kernel中 CONFIG_ACCDET_EINT_IRQ=n */
#ifdef CONFIG_ACCDET_EINT_IRQ } else if (eintID != NO_PMIC_EINT) {pr_info("%s() IRQ_STS = 0x%x, pmic eint-%s triggered.\n",__func__, irq_status,(eintID == PMIC_EINT0)?"0":((eintID == PMIC_EINT1)?"1":"BI"));#if defined(CONFIG_MOISTURE_INT_SUPPORT) || defined(CONFIG_MOISTURE_EXT_SUPPORT)if (cur_eint_state == EINT_PIN_MOISTURE_DETECED) {pr_info("%s Moisture plug out detectecd\n", __func__);eint_polarity_reverse(eintID);cur_eint_state = EINT_PIN_PLUG_OUT;clear_accdet_eint(eintID);clear_accdet_eint_check(eintID);return;}if (cur_eint_state == EINT_PIN_PLUG_OUT) {pr_info("%s now check moisture\n", __func__);moisture_vol = moisture_detect();if (moisture_vol > moisture_vm) {eint_polarity_reverse(eintID);cur_eint_state = EINT_PIN_MOISTURE_DETECED;clear_accdet_eint(eintID);clear_accdet_eint_check(eintID);pr_info("%s Moisture plug in detectecd!\n",__func__);return;}pr_info("%s check moisture done,not water.\n",__func__);}
#endifeint_polarity_reverse(eintID);clear_accdet_eint(eintID);clear_accdet_eint_check(eintID);pmic_eint_queue_work(eintID);
#endif} elsepr_info("%s no interrupt detected!\n", __func__);
}

因为CONFIG_ACCDET_EINT_IRQ配置为n,所以这里仅仅需要执行accdet_queue_work()启动中断的下半部。

static void accdet_queue_work(void)
{int ret;if (accdet_status == MIC_BIAS)cali_voltage = accdet_get_auxadc(1);ret = queue_work(accdet_workqueue, &accdet_work);if (!ret)pr_info("queue work accdet_work return:%d!\n", ret);
}

audio驱动之耳机相关推荐

  1. Waveform Audio 驱动(Wavedev2)之:WAV API模拟

    Waveform Audio  驱动(Wavedev2)之:WAV API模拟 Waveform 驱动对Windows Mobile来说是一个非常重要的驱动,控制着所有有关声音的操作,包括喇叭.耳机. ...

  2. MTK 驱动(60)---Audio驱动开发之音频链路

    Audio驱动开发之音频链路 [元器件说明] 本文中使用的 Codec 芯片为 ALC5677. [音频链路模型] 一个常见的音频链路如 图1 所示,包含 音频输入.ADC.DSP.DAC.音频输出 ...

  3. AUDIO驱动点检表

    AUDIO驱动点检表 备注:以下都以MT6753,ANDROID 5.1版本为基础. 1.驱动配置部分 1.1 耳机部分 配置文件: accdet_custom_def.h 耳机MIC模式配置: 默认 ...

  4. Waveform Audio 驱动(Wavedev2)之:WAV 驱动解析

    Waveform Audio 驱动(Wavedev2)之:WAV 驱动解析 上篇文章中,我们模拟了WAV API.现在进入我们正在要解析的Wave 驱动的架构.我们了解一个驱动的时候,先不去看具体跟硬 ...

  5. audio驱动之codec和codec_dai

    平台 os版本 内核 MT6765 Android 9.0 kernel-4.9 在嵌入式设备中,codec的作用可以简单的分为4种: 对PCM等信号进行D/A转换,把数字的隐僻信号转换为模拟信号. ...

  6. win7(windows7旗舰版)声卡High Definition Audio驱动 (安装失败)解决方法

    win7(windows7旗舰版)声卡High Definition Audio驱动 (安装失败)解决方案 前几天装了一下windows7体验一下,结果声卡驱动安装有问题,这电脑没声音我可没法活啊. ...

  7. audio驱动之cpu_dai

    平台 os版本 内核 MT6765 Android 9.0 kernel-4.9 audio驱动相关结构体 注释 snd_soc_component 当底层驱动注册platform.codec+cod ...

  8. 在MTK平台配置一个支持smartPA的audio驱动

    文章目录 smartPA概述 smartPA AW87319概述 smartPA AW87319功能特性 在kernel中添加对smartPA的支持 1. 在配置文件中添加对smartPA的支持 2. ...

  9. Linux Audio驱动系列(技巧篇) - tingmix调试抓Log

    By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎订阅! 你的喜欢就是我写作的动力! 目录 ...

  10. Android Switch驱动的耳机检测

    在 Android 中添加了一个 switch 驱动,用于监测一些开关的变化,例如:HDMI.耳机的插拔检测之类的. 驱动源码存在内核源码的 drivers/switch 中,目录下有两个主要文件:s ...

最新文章

  1. python线程池及其原理和使用
  2. python处理数据的优势-【Python数据分析基础】: 数据缺失值处理
  3. 直播预告丨深耕用户价值,实战保险业数字化升级
  4. 史上最快消息内核——ZeroMQ
  5. python 随机排序_Python 如何随机打乱列表(List)排序
  6. 两个向量之间的夹角公式_向量的内积
  7. mybatis-01
  8. 中油即时通信电脑版_一文看懂云视频会议与即时聊天软件的差别
  9. Android基础之AutoCompleteTextView的使用
  10. FISCO BCOS Solidity 使用Table合约CRUD接口 智能合约例子
  11. 3、检验程序模块化指标---模块化系数-----labview宝典
  12. 在线小说网站的设计与实现(附源码)
  13. 人若不知足,永远不幸福
  14. AD7606(并行8080方式)的STM32F103ZET6配置
  15. 量子计算机采用超导技术吗,新发现的超导体材料可能是量子计算机的硅
  16. CS224W图机器学习笔记8-图神经网络三大应用
  17. 浏览器表单自动填充问题【兼容性解决方案】
  18. 数据结构与算法常见笔试题
  19. 相机技术--监控摄像机焦距与视角(视场大小)的具体选择
  20. bilibili直播间利用python爬虫自动发送弹幕

热门文章

  1. vdi linux桌面,ubuntu VDI ( Ulteo Open Virtual Desktop
  2. 荆棘遍地,鲜花满开(随笔二)
  3. 如何重命名mysql数据库_如何重命名MySQL数据库?
  4. 《阿里云前端技术周刊》第二期
  5. 银湖联手博通欲收购东芝芯片业务 出价180亿美元
  6. 将List集合用字符串,逗号隔开进行拼接
  7. 魔兽争霸dota内外网p2p联机玩游戏-不需要对战平台的联机
  8. linux下目录压缩,Linux下 目录 压缩 解压缩 打包
  9. 闲鱼:Thread.sleep(0) 到底有什么用?我:有点懵~
  10. 火狐老是跳出提示“Firefox正在安装组件,以便播放此页面上......”