This article is based on Android 4.4. For more information, see "4.2". The mechanism is the same. The details may vary. Here we mainly use 4.4.
Android headset plugging can be implemented through two mechanisms:
1. InputEvent
2. UEvent
UEvent is the default plug-in and plug-in mechanism of the Android system, so the final code here is implemented based on UEvent. For the InputEvent mechanism, I just looked at it and didn't implement it in detail. Therefore, it cannot be guaranteed to be correct, if you are looking for a solution, you can simply move to the UEvent mode.
1. Working Principle of headset Detection
First, let's look at the working principle of the headset detection. General earphone detection includes general earphone detection and earphone detection with mic. These two kinds of earphones are collectively referred to as Headset. For headphones without mic, they are generally referred to as Headphone.
For Headset device insertion detection, Jack is generally done through the Headset socket. The general principle is to use a Headset socket with a mechanical structure to connect the detection pin to the GPIO interrupt, when the earphone is plugged in, the metal of the earphone plug will touch the detection pin, which changes the level of the detection pin and causes interruption. In this way, you can read the GPIO value in the interrupt processing function to determine whether the headset is inserted or unplugged.
For whether the Headset has mic detection, the micbias current function attached to codec is required. For details, refer to my next article.
2. Two Methods of Switching
As mentioned above, Android provides two solutions by default, so there must be two ways to switch between them. This provides the configuration name config_useDevInputEventForAudioJack for global search of Android source code, you can see it in frameworks/base/core/res/values/config. in xml, the default value is false, that is, the InputEvent method is not used. In addition, related settings are also found in the vendor-related folders of the source code package, as shown below:
/Android/4.4/device/asus/flo/overlay/frameworks/base/core/res/values/config. xml
False
/Android/4.4/device/samsung/manta/overlay/frameworks/base/core/res/values/config. xml
True
/Android/4.4/device/asus/deb/overlay/frameworks/base/core/res/values/config. xml
False
/Android/4.4/device/lge/hammerhead/overlay/frameworks/base/core/res/values/config. xml
True
/Android/4.4/device/lge/mako/overlay/frameworks/base/core/res/values/config. xml
True
We can see that some manufacturers use the InputEvent Method for headset detection. The specific modification to this variable is either under device or frameworks. It may be better under device.
3. InputEvent
1) general mechanism of the Android Upper Layer
The general mechanism of InputEvent can be searched for articles on the Internet. I am not particularly clear about the specific process. Here I will give a rough description.
InputEvent is mainly used in InputManagerService. java. In the InputManagerService constructor, use the following function,
MUseDevInputEventForAudioJack = context. getResources (). getBoolean (R. bool. config_useDevInputEventForAudioJack );
Determine whether the current use of InputEvent for plug-in and plug-in detection.
After Android gets the InputEvent, it calls the policyswitch function in InputManagerService. java and then transfers it to the policywiredaccessorychanged function in the WiredAccessoryManager. java file. The subsequent process will be the same as that of UEvent.
2) mechanism of the Kernel layer
In the Kernel layer, InputEvent plug-in and plug-in is implemented through input_report_key/input_report_switch. In actual use, ASOC has encapsulated the corresponding Jack interface functions for us, it can be used as long as it complies with the specifications. The following lists several common interface functions.
Int snd_soc_jack_new (structsnd_soc_codec * codec, const char * id, int type, struct snd_soc_jack * jack)
Generate a New jack object and define the detected type, that is, the device type that may be inserted. It is generally defined as SND_JACK_HEADSET. You can also add SND_JACK_LINEOUT and SND_JACK_AVOUT according to the supported types of interfaces.
Snd_jack_new is called in this function. In snd_jack_new, we can see that the input device is allocated when input_allocate_device () is called, and the input event can be generated later.
Int snd_soc_jack_add_pins (structsnd_soc_jack * jack, int count, struct snd_soc_jack_pin * pins)
Add the previously defined pins to dapm widgets to facilitate unified management of dapm. This step is not necessarily related to InputEvent and can be called. It is mainly because you can define the headset outlet as widgets and add it to dapm for power-saving management.
Void snd_soc_jack_report (structsnd_soc_jack * jack, int status, int mask)
Report jack plugging status, mainly to complete the following two tasks:
a) update the status of the dapm pin added by snd_soc_jack_add_pins Based on the insertion and unplugging status to manage the power-on and power-off operations.
? B) Call snd_jack_report and report the input event to the upper layer through input_report_key/input_report_switch.
Based on the above functions, you can use the following method to implement the InputEvent-based headset plugging Detection:
A) snd_soc_jack_new: Create a jack object
B) add snd_soc_jack_add_pins to dapm wikis.
C) request the headset plugging interruption through request irq. In the interrupt processing function, determine whether the headset is inserted or unplugged through the detection line level, and read the codec register to determine whether it is headset or headphone.
D) Call snd_soc_jack_report based on the judgment result to send InputEvent
In addition, ASOC also provides an encapsulated function to implement the above c) and d) steps:
Int snd_soc_jack_add_gpios (struct snd_soc_jack * jack, int count, struct snd_soc_jack_gpio * gpios)
This function applies for GPIO and GPIO-related interruptions through the standard GPIO driver, and provides a unified interrupt processing function to report events. This function is only applicable when the headset is disconnected to gpio and the gpio driver is a Linux Standard driver and does not support mic detection. Therefore, it is not recommended.
4. UEvent
The UEvent mechanism is relatively simple. It is based on the switch driver. The switch driver will create a plug-in directory/sys/devices/virtual/switch/h2w on Android, there is a device node named state in this directory. The driver updates the state value to notify the upper-layer headphones of Android to change the status.
1) Android upper layer mechanism
For the UEvent mechanism, the Android upper layer is implemented in WiredAccessoryManager. java.
In this file, the WiredAccessoryObserver class is inherited from UEventObserver. In makeObservedUEventList, add the event to the UEvent system:
If (! MUseDevInputEventForAudioJack ){
Uei = new UEventInfo (NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC );
......
......
}
We can see that the UEvent event is added only when InputEvent is not used. NAME_H2W is the name of the switch driver corresponding to headphone. BIT_HEADSET and BIT_HEADSET_NO_MIC are the two values of the state node, indicating that there are mic and no mic headphones respectively.
When a UEvent event arrives, the overloaded onUEvent function in the WiredAccessoryObserver class will be called back to call updateStateLocked (devPath, name, state ), the value of state is obtained through the/sys/devices/virtual/switch/h2w/state node.
Finally, the program will go to the setDeviceStateLocked function for processing. In setDeviceStateLocked, set the device according to the state value, call mAudioManager. setWiredDeviceConnectionState, and enter AudioPolicyManagerBase: setDeviceConnectionState.
2) mechanism of the Kernel layer
As mentioned above, the UEvent-based headset detection mechanism needs to implement a switchdriver, which will create a directory for the headset plugging detection/sys/devices/virtual/switch/h2w, there is a device node named state in this directory. The switch driver updates the state value to notify the upper-layer headphones of Android to change the status.
The Directory of the switch driver is in the drivers/staging/android/switch directory of Linux kernel. You can see from the directory name that this driver is specially generated for Android. There are two existing files in the switch directory. switch_class.c is the internal implementation of the switch driver. It provides some APIs required by the switch driver. switch_gpio.c is an example, it implements a switch driver Based on GPIO interrupt.
In addition, there are the same files in the drivers/switch directory. The difference is that the locations of the nodes generated in Android are different, if you want to follow the switch driver under the drivers/switch directory, you need to change WiredAccessoryManager. java file.
The following describes how to add a switch driver. It is easy to add a switch driver. You can follow switch_gpio.c by taking the following steps:
Upload a) create a platform driver in the drivers/staging/android/switch Directory, which contains a global variable struct switch_dev sdev, that is, the switch device to be registered.
B) call it in the probe function of platformdriver.Switch_dev_registerRegister the previous sdev to the system.
Int switch_dev_register (struct switch_dev * sdev)
C) apply for the interrupt processing function for earphone detection. For earphone plugging, the user's insertion/removal speed may cause multiple interruptions, so it is generally to implement a delayed working queue in the interrupt processing function, that is, INIT_DELAYED_WORK, perform actual judgment in the callback function of the queue.
D) when the interruption occursSwitch_set_stateSet the value of the state node. This value must be consistent with that defined in the WiredAccessoryManager. java file. For details, see the definitions of BIT_HEADSET and BIT_HEADSET_NO_MIC. Currently, the value 0 indicates no earphones are inserted. The value 1 indicates a headset with Mic and the value 2 indicates a headset without Mic.
Void switch_set_state (struct switch_dev * sdev, int state)
Let's take a further look at the switch_set_state function. In this function, kobject_uevent_env/kobject_uevent is called. These two functions are the core functions that kernel notifies user space through uevent.