这个手机做device, audio accessory是Host.
以高通msm8x26(USB2.0) Lolliop android 5.0/5.1为例
1 代码
kernel/drivers/usb/gadget/f_accessory.c,f_audio_source.c
services/usb/java/com/android/server/usb/UsbDeviceManager.java
hardware/libhardware/modules/usbaudio/audio_hw.c
2 android_setup的调用栈
handle_IRQ
generic_handle_irq
handle_fasteoi_irq
handle_irq_event
handle_irq_event_percpu
msm_udc_irq
isr_tr_complete_handler
udc->driver->setup(&udc->gadget,&req);
android_setup android.c
value = acc_ctrlrequest(cdev, c);
value = composite_setup(gadget, c);
schedule_work(&dev->work);
android_work()
3 连接过程
大致分5步
3.1 CDP charger detection
charger检测过程中的状态转换过程
USB_CHG_STATE_UNDEFINED
USB_CHG_STATE_WAIT_FOR_DCD
USB_CHG_STATE_DCD_DONE
USB_CHG_STATE_PRIMARY_DONE
USB_CHG_STATE_SECONDARY_DONE
typical log:usbin-valid triggered: 1host_mode: 0 (usbin插入中断处理函数)
msm_otg f9a55000.usb:USB exited from low power mode
msm_otg f9a55000.usb: chg_type =USB_CDP_CHARGER
msm_otg f9a55000.usb:Availcurr from USB =1500
msm_hsusbmsm_hsusb:CI13XXX_CONTROLLER_RESET_EVENT received
msm_hsusbmsm_hsusb:CI13XXX_CONTROLLER_CONNECT_EVENT received
msm_hsusb msm_hsusb : reset (可能两次)android_work: android_work: did not senduevent (0 0 (null))
3.3 第一次尝试枚举
GetDescriptor (Device)
Reset
SetAddress
GetDescriptor(Device/Configuration)
此时Host得到的通常是Device的Configuration为MTP的回应
Typical log
android_usb gadget: [COM]composite_setup:value=0,bRequestType=0x80,bRequest=0x6,w_value=0x100,w_length=0x40
android_work: android_work: sent ueventUSB_STATE=CONNECTED
msm_hsusbmsm_hsusb: reset
android_work: android_work: sent ueventUSB_STATE=DISCONNECTED
isr_tr_complete_handlerUSB_REQ_SET_ADDRESS
android_usb gadget: [COM]composite_setup:value=0,bRequestType=0x80,bRequest=0x6,w_value=0x100,w_length=0x12
android_usb gadget: [COM]composite_setup:value=0,bRequestType=0x80,bRequest=0x6,w_value=0x200,w_length=0x9
android_usb gadget: [COM]composite_setup:value=0,bRequestType=0x80,bRequest=0x6,w_value=0x200,w_length=0x27
android_work: android_work: sent ueventUSB_STATE=CONNECTED
然后host开始一些accessory的ctrl request命令
typical log
代码实现在
Kernel/drivers/usb/gadget/f_accessory.c
定义在
kernel/include/linux/usb/f_accessory.h
if (b_requestType ==(USB_DIR_OUT | USB_TYPE_VENDOR)) {
if(b_request ==ACCESSORY_START) {
dev->start_requested = 1;
schedule_delayed_work(
&dev->start_work,…)
}else if (b_request ==ACCESSORY_SET_AUDIO_MODE &&
w_index == 0&&w_length == 0) {
dev->audio_mode =w_value;
value= 0;
...static void acc_start_work(structwork_struct *data)
{
char*envp[2] = {"ACCESSORY=START", NULL };
kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE,envp);
}
设置USB Mode to audio_source
frameworks/base/…/usb/UsbDeviceManager.java
private final UEventObservermUEventObserver = newUEventObserver() {
} else if ("START".equals(accessory)) {
if (DEBUG) Slog.d(TAG,"got accessory start");
startAccessoryMode();
private void startAccessoryMode() {
if (enableAccessory &&enableAudio) {
functions = UsbManager.USB_FUNCTION_ACCESSORY +","
+ UsbManager.USB_FUNCTION_AUDIO_SOURCE;
} else if (enableAccessory) {
functions = UsbManager.USB_FUNCTION_ACCESSORY;
} else if (enableAudio) {
functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE;
}
if (functions != null) {
mAccessoryModeRequestTime =SystemClock.elapsedRealtime();
setCurrentFunctions(functions,false);
}
send MSG_SET_CURRENT_FUNCTIONS
setEnabledFunctions(functions,makeDefault)
setUsbConfig("none")
setUsbConfig(functions)
init.usb.rc
# audio accessory configuration
on property:sys.usb.config=audio_source
write /sys/class/android_usb/android0/enable0
write /sys/class/android_usb/android0/idVendor18d1
write /sys/class/android_usb/android0/idProduct2d02
write /sys/class/android_usb/android0/functions${sys.usb.config}
write /sys/class/android_usb/android0/enable1
setpropsys.usb.state ${sys.usb.config}
typical log:
android_usb gadget:usb_remove_config #1 'fe8050c8.android_usb'/ec008900
android_usb gadget:unbind function 'mtp'/c3d2ab00
android_usb gadget:unbindconfig'fe8050c8.android_usb'/ec008900
enable_store disablemtp
android_usb gadget:usb_add_config addingconfig #1'fe8050c8.android_usb'/ec008900
android_usb gadget:usb_add_function adding 'audio_source'/c0e70460 toconfig'fe8050c8.android_usb'/ec008900
android_usb gadget:cfg 1/ec008900speeds: high full
android_usb gadget: interface 0 =audio_source/c0e70460
msm_hsusbmsm_hsusb: suspend
msm_hsusb msm_hsusb :CI13XXX_CONTROLLER_SUSPEND_EVENT receivedandroid_work: android_work: did not senduevent (1 1 (null))
3.4 Reset
msm_hsusbmsm_hsusb: reset (可能重复两次)
msm_hsusbmsm_hsusb:CI13XXX_CONTROLLER_RESUME_EVENT received
android_work: android_work: sent ueventUSB_STATE=DISCONNECTED
3.5 第二次枚举
android_work: android_work: sent ueventUSB_STATE=CONNECTED
msm_hsusbmsm_hsusb: reset
android_work : android_work : sent uevent USB_STATE=DISCONNECTEDandroid_work: android_work: sent ueventUSB_STATE=CONNECTED
android_usb gadget:set_config high-speedconfig #1:fe8050c8.android_usb
android_work: android_work: sent ueventUSB_STATE=CONFIGURED
UsbDeviceManager: updateAudioSourceFunction enabled=true
UsbDeviceManager: MSG_UPDATE_STATE updateAudioSourceFunction
if state=CONFIGURED
enable=true
send Intent AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG
frameworks/base/media/java/android/media/AudioService.java
outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
setWiredDeviceConnectionState(outDevice, state, params);
sendMsg MSG_SET_WIRED_DEVICE_CONNECTION_STATE
onSetWiredDeviceConnectionState
handleDeviceConnection()
AudioSystem.setDeviceConnectionState() (AudioSystem.java->AudioSystem.cpp)
AudioPolicyIntefaceImpl: setDeviceConnectionState()
AudioPolicyManager::setDeviceConnectionState()
AudioPolicyManager::setDeviceConnectionStateInt()
AudioPolicyManager::setDeviceConnectionStateInt()
AudioPolicyManager::checkOutputsForDevice()
mpClientInterface->openOutput() frameworks/av/services/audiopolicy/AudioPolicyClientImpl.cpp
af->openOutput()
frameworks/av/services/audioflinger/AudioFlinger.cpp
AudioFlinger::openOutput
AudioFlinger::openOutput_l()
hwDevHal->open_output_stream()
adev_open_output_stream()
hardware/libhardware/modules/usbaudio/audio_hw.c
adev->hw_device.open_output_stream = adev_open_output_stream;
随后是alsa_device_proxy: proxy_prepare()
usb_audio_hw.c out_set_parameters
如果开始播放音乐
usb_audio_hw.c里的out_write() 被调用
AudioFlinger: MixerThread::threadLoop_write Threads.cpp
AudioFlinger::PlaybackThread::threadLoop_write()
ssize_tframesWritten = mNormalSink->write()
bytesWritten = mOutput->stream->write()
out_write() in usbaudio/audio_hw.c
hardware/libhardware/modules/usbaudio/audio_hw.c
out->stream.write = out_write;
out_write usb_audio_hw
start_output_stream
proxy_open alsa_device_proxy
pcm_open qcom/audio/legacy/libalsa-intf/alsa_pcm.c
open
kernel/drivers/usb/gadget/f_audio_source.c
audio_pcm_open
随后是
audio_pcm_open(),audio_pcm_hw_params(), audio_pcm_prepare()
audio_pcm_playback_trigger cmd=1system/core/include/system/audio.h
audio_devices_t;
AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000,
frameworks/base/media/java/android/media/AudioSystem.java
public static final intDEVICE_OUT_USB_ACCESSORY = 0x2000;
5. Debug方法