diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..57f813c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +out +out/* diff --git a/Makefile b/Makefile index cb755549..1876675d 100755 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ ############same as android############### #make $(MIUI_PRODUCT) to buid device recovery.img, support as following; MIUI_PRODUCTS := crespo ville sensation vivo saga maguro honor shooteru \ - lu6200 p1 d1 finder note2 ef65l ef40s ef39s + lu6200 p1 d1 finder note2 ef65l ef40s ef39s mione_plus #crespo: Samsung Nexus S #ville: HTC One S #sensation: HTC pyramid(G14) diff --git a/bionic b/bionic new file mode 160000 index 00000000..f42cbba2 --- /dev/null +++ b/bionic @@ -0,0 +1 @@ +Subproject commit f42cbba2d408c59c595a3685aaabcd0b9bbf4547 diff --git a/hardware/broadcom/wlan b/hardware/broadcom/wlan new file mode 160000 index 00000000..6863a0b9 --- /dev/null +++ b/hardware/broadcom/wlan @@ -0,0 +1 @@ +Subproject commit 6863a0b90384a0fcb2d6280923e942242293f1c0 diff --git a/hardware/cm b/hardware/cm new file mode 160000 index 00000000..08c587e5 --- /dev/null +++ b/hardware/cm @@ -0,0 +1 @@ +Subproject commit 08c587e50c40e8b8fa9d4d7ce28d25d212bdc548 diff --git a/hardware/invensense b/hardware/invensense new file mode 160000 index 00000000..33ce91b3 --- /dev/null +++ b/hardware/invensense @@ -0,0 +1 @@ +Subproject commit 33ce91b37062fa63af192f5643de93f3beebe854 diff --git a/hardware/libhardware b/hardware/libhardware new file mode 160000 index 00000000..c41a16b2 --- /dev/null +++ b/hardware/libhardware @@ -0,0 +1 @@ +Subproject commit c41a16b2333418e0925b9b413fc4406e77954af4 diff --git a/hardware/libhardware_legacy/Android.mk b/hardware/libhardware_legacy/Android.mk new file mode 100644 index 00000000..90f6b5c3 --- /dev/null +++ b/hardware/libhardware_legacy/Android.mk @@ -0,0 +1,54 @@ +# Copyright 2006 The Android Open Source Project + +# Setting LOCAL_PATH will mess up all-subdir-makefiles, so do it beforehand. +legacy_modules := power uevent vibrator wifi qemu qemu_tracing + +SAVE_MAKEFILES := $(call all-named-subdir-makefiles,$(legacy_modules)) +LEGACY_AUDIO_MAKEFILES := $(call all-named-subdir-makefiles,audio) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SHARED_LIBRARIES := libcutils libwpa_client + +LOCAL_INCLUDES += $(LOCAL_PATH) + +ifdef USES_TI_MAC80211 +LOCAL_STATIC_LIBRARIES := libnl_2 +LOCAL_C_INCLUDES += external/libnl-headers +endif + +LOCAL_CFLAGS += -DQEMU_HARDWARE +QEMU_HARDWARE := true + +LOCAL_SHARED_LIBRARIES += libdl + +include $(SAVE_MAKEFILES) + +LOCAL_MODULE:= libhardware_legacy + +include $(BUILD_SHARED_LIBRARY) + +# static library for librpc +include $(CLEAR_VARS) + +LOCAL_MODULE:= libpower + +LOCAL_SRC_FILES += power/power.c + +include $(BUILD_STATIC_LIBRARY) + +# shared library for various HALs +include $(CLEAR_VARS) + +LOCAL_MODULE := libpower + +LOCAL_SRC_FILES := power/power.c + +LOCAL_SHARED_LIBRARIES := libcutils + +include $(BUILD_SHARED_LIBRARY) + +# legacy_audio builds it's own set of libraries that aren't linked into +# hardware_legacy +include $(LEGACY_AUDIO_MAKEFILES) diff --git a/hardware/libhardware_legacy/CleanSpec.mk b/hardware/libhardware_legacy/CleanSpec.mk new file mode 100644 index 00000000..56193a9e --- /dev/null +++ b/hardware/libhardware_legacy/CleanSpec.mk @@ -0,0 +1,51 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhardware_legacy_intermediates/) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhardware_legacy_intermediates/) \ No newline at end of file diff --git a/hardware/libhardware_legacy/MODULE_LICENSE_APACHE2 b/hardware/libhardware_legacy/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b diff --git a/hardware/libhardware_legacy/NOTICE b/hardware/libhardware_legacy/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/hardware/libhardware_legacy/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/hardware/libhardware_legacy/audio/A2dpAudioInterface.cpp b/hardware/libhardware_legacy/audio/A2dpAudioInterface.cpp new file mode 100644 index 00000000..9359ec3f --- /dev/null +++ b/hardware/libhardware_legacy/audio/A2dpAudioInterface.cpp @@ -0,0 +1,499 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +//#define LOG_NDEBUG 0 +#define LOG_TAG "A2dpAudioInterface" +#include +#include + +#include "A2dpAudioInterface.h" +#include "audio/liba2dp.h" +#include + + +namespace android_audio_legacy { + +static const char *sA2dpWakeLock = "A2dpOutputStream"; +#define MAX_WRITE_RETRIES 5 + +// ---------------------------------------------------------------------------- + +//AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface() +//{ +// AudioHardwareInterface* hw = 0; +// +// hw = AudioHardwareInterface::create(); +// ALOGD("new A2dpAudioInterface(hw: %p)", hw); +// hw = new A2dpAudioInterface(hw); +// return hw; +//} + +A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) : + mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false) +{ +} + +A2dpAudioInterface::~A2dpAudioInterface() +{ + closeOutputStream((AudioStreamOut *)mOutput); + delete mHardwareInterface; +} + +status_t A2dpAudioInterface::initCheck() +{ + if (mHardwareInterface == 0) return NO_INIT; + return mHardwareInterface->initCheck(); +} + +AudioStreamOut* A2dpAudioInterface::openOutputStream( + uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status) +{ + if (!audio_is_a2dp_device(devices)) { + ALOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices); + return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status); + } + + status_t err = 0; + + // only one output stream allowed + if (mOutput) { + if (status) + *status = -1; + return NULL; + } + + // create new output stream + A2dpAudioStreamOut* out = new A2dpAudioStreamOut(); + if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) { + mOutput = out; + mOutput->setBluetoothEnabled(mBluetoothEnabled); + mOutput->setSuspended(mSuspended); + } else { + delete out; + } + + if (status) + *status = err; + return mOutput; +} + +void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) { + if (mOutput == 0 || mOutput != out) { + mHardwareInterface->closeOutputStream(out); + } + else { + delete mOutput; + mOutput = 0; + } +} + + +AudioStreamIn* A2dpAudioInterface::openInputStream( + uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status, + AudioSystem::audio_in_acoustics acoustics) +{ + return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); +} + +void A2dpAudioInterface::closeInputStream(AudioStreamIn* in) +{ + return mHardwareInterface->closeInputStream(in); +} + +status_t A2dpAudioInterface::setMode(int mode) +{ + return mHardwareInterface->setMode(mode); +} + +status_t A2dpAudioInterface::setMicMute(bool state) +{ + return mHardwareInterface->setMicMute(state); +} + +status_t A2dpAudioInterface::getMicMute(bool* state) +{ + return mHardwareInterface->getMicMute(state); +} + +status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs) +{ + AudioParameter param = AudioParameter(keyValuePairs); + String8 value; + String8 key; + status_t status = NO_ERROR; + + ALOGV("setParameters() %s", keyValuePairs.string()); + + key = "bluetooth_enabled"; + if (param.get(key, value) == NO_ERROR) { + mBluetoothEnabled = (value == "true"); + if (mOutput) { + mOutput->setBluetoothEnabled(mBluetoothEnabled); + } + param.remove(key); + } + key = String8("A2dpSuspended"); + if (param.get(key, value) == NO_ERROR) { + mSuspended = (value == "true"); + if (mOutput) { + mOutput->setSuspended(mSuspended); + } + param.remove(key); + } + + if (param.size()) { + status_t hwStatus = mHardwareInterface->setParameters(param.toString()); + if (status == NO_ERROR) { + status = hwStatus; + } + } + + return status; +} + +String8 A2dpAudioInterface::getParameters(const String8& keys) +{ + AudioParameter param = AudioParameter(keys); + AudioParameter a2dpParam = AudioParameter(); + String8 value; + String8 key; + + key = "bluetooth_enabled"; + if (param.get(key, value) == NO_ERROR) { + value = mBluetoothEnabled ? "true" : "false"; + a2dpParam.add(key, value); + param.remove(key); + } + key = "A2dpSuspended"; + if (param.get(key, value) == NO_ERROR) { + value = mSuspended ? "true" : "false"; + a2dpParam.add(key, value); + param.remove(key); + } + + String8 keyValuePairs = a2dpParam.toString(); + + if (param.size()) { + if (keyValuePairs != "") { + keyValuePairs += ";"; + } + keyValuePairs += mHardwareInterface->getParameters(param.toString()); + } + + ALOGV("getParameters() %s", keyValuePairs.string()); + return keyValuePairs; +} + +size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) +{ + return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount); +} + +status_t A2dpAudioInterface::setVoiceVolume(float v) +{ + return mHardwareInterface->setVoiceVolume(v); +} + +status_t A2dpAudioInterface::setMasterVolume(float v) +{ + return mHardwareInterface->setMasterVolume(v); +} + +status_t A2dpAudioInterface::dump(int fd, const Vector& args) +{ + return mHardwareInterface->dumpState(fd, args); +} + +// ---------------------------------------------------------------------------- + +A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() : + mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL), + // assume BT enabled to start, this is safe because its only the + // enabled->disabled transition we are worried about + mBluetoothEnabled(true), mDevice(0), mClosing(false), mSuspended(false) +{ + // use any address by default + strcpy(mA2dpAddress, "00:00:00:00:00:00"); + init(); +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::set( + uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate) +{ + int lFormat = pFormat ? *pFormat : 0; + uint32_t lChannels = pChannels ? *pChannels : 0; + uint32_t lRate = pRate ? *pRate : 0; + + ALOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate); + + // fix up defaults + if (lFormat == 0) lFormat = format(); + if (lChannels == 0) lChannels = channels(); + if (lRate == 0) lRate = sampleRate(); + + // check values + if ((lFormat != format()) || + (lChannels != channels()) || + (lRate != sampleRate())){ + if (pFormat) *pFormat = format(); + if (pChannels) *pChannels = channels(); + if (pRate) *pRate = sampleRate(); + return BAD_VALUE; + } + + if (pFormat) *pFormat = lFormat; + if (pChannels) *pChannels = lChannels; + if (pRate) *pRate = lRate; + + mDevice = device; + mBufferDurationUs = ((bufferSize() * 1000 )/ frameSize() / sampleRate()) * 1000; + return NO_ERROR; +} + +A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut() +{ + ALOGV("A2dpAudioStreamOut destructor"); + close(); + ALOGV("A2dpAudioStreamOut destructor returning from close()"); +} + +ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes) +{ + status_t status = -1; + { + Mutex::Autolock lock(mLock); + + size_t remaining = bytes; + + if (!mBluetoothEnabled || mClosing || mSuspended) { + ALOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \ + mBluetoothEnabled %d, mClosing %d, mSuspended %d", + mBluetoothEnabled, mClosing, mSuspended); + goto Error; + } + + if (mStandby) { + acquire_wake_lock (PARTIAL_WAKE_LOCK, sA2dpWakeLock); + mStandby = false; + mLastWriteTime = systemTime(); + } + + status = init(); + if (status < 0) + goto Error; + + int retries = MAX_WRITE_RETRIES; + while (remaining > 0 && retries) { + status = a2dp_write(mData, buffer, remaining); + if (status < 0) { + ALOGE("a2dp_write failed err: %d\n", status); + goto Error; + } + if (status == 0) { + retries--; + } + remaining -= status; + buffer = (char *)buffer + status; + } + + // if A2DP sink runs abnormally fast, sleep a little so that audioflinger mixer thread + // does no spin and starve other threads. + // NOTE: It is likely that the A2DP headset is being disconnected + nsecs_t now = systemTime(); + if ((uint32_t)ns2us(now - mLastWriteTime) < (mBufferDurationUs >> 2)) { + ALOGV("A2DP sink runs too fast"); + usleep(mBufferDurationUs - (uint32_t)ns2us(now - mLastWriteTime)); + } + mLastWriteTime = now; + return bytes; + + } +Error: + + standby(); + + // Simulate audio output timing in case of error + usleep(mBufferDurationUs); + + return status; +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::init() +{ + if (!mData) { + status_t status = a2dp_init(44100, 2, &mData); + if (status < 0) { + ALOGE("a2dp_init failed err: %d\n", status); + mData = NULL; + return status; + } + a2dp_set_sink(mData, mA2dpAddress); + } + + return 0; +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::standby() +{ + Mutex::Autolock lock(mLock); + return standby_l(); +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::standby_l() +{ + int result = NO_ERROR; + + if (!mStandby) { + ALOGV_IF(mClosing || !mBluetoothEnabled, "Standby skip stop: closing %d enabled %d", + mClosing, mBluetoothEnabled); + if (!mClosing && mBluetoothEnabled) { + result = a2dp_stop(mData); + } + release_wake_lock(sA2dpWakeLock); + mStandby = true; + } + + return result; +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs) +{ + AudioParameter param = AudioParameter(keyValuePairs); + String8 value; + String8 key = String8("a2dp_sink_address"); + status_t status = NO_ERROR; + int device; + ALOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string()); + + if (param.get(key, value) == NO_ERROR) { + if (value.length() != strlen("00:00:00:00:00:00")) { + status = BAD_VALUE; + } else { + setAddress(value.string()); + } + param.remove(key); + } + key = String8("closing"); + if (param.get(key, value) == NO_ERROR) { + mClosing = (value == "true"); + if (mClosing) { + standby(); + } + param.remove(key); + } + key = AudioParameter::keyRouting; + if (param.getInt(key, device) == NO_ERROR) { + if (audio_is_a2dp_device(device)) { + mDevice = device; + status = NO_ERROR; + } else { + status = BAD_VALUE; + } + param.remove(key); + } + + if (param.size()) { + status = BAD_VALUE; + } + return status; +} + +String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys) +{ + AudioParameter param = AudioParameter(keys); + String8 value; + String8 key = String8("a2dp_sink_address"); + + if (param.get(key, value) == NO_ERROR) { + value = mA2dpAddress; + param.add(key, value); + } + key = AudioParameter::keyRouting; + if (param.get(key, value) == NO_ERROR) { + param.addInt(key, (int)mDevice); + } + + ALOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string()); + return param.toString(); +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address) +{ + Mutex::Autolock lock(mLock); + + if (strlen(address) != strlen("00:00:00:00:00:00")) + return -EINVAL; + + strcpy(mA2dpAddress, address); + if (mData) + a2dp_set_sink(mData, mA2dpAddress); + + return NO_ERROR; +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enabled) +{ + ALOGD("setBluetoothEnabled %d", enabled); + + Mutex::Autolock lock(mLock); + + mBluetoothEnabled = enabled; + if (!enabled) { + return close_l(); + } + return NO_ERROR; +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff) +{ + ALOGV("setSuspended %d", onOff); + mSuspended = onOff; + standby(); + return NO_ERROR; +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::close() +{ + Mutex::Autolock lock(mLock); + ALOGV("A2dpAudioStreamOut::close() calling close_l()"); + return close_l(); +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l() +{ + standby_l(); + if (mData) { + ALOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)"); + a2dp_cleanup(mData); + mData = NULL; + } + return NO_ERROR; +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector& args) +{ + return NO_ERROR; +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::getRenderPosition(uint32_t *driverFrames) +{ + //TODO: enable when supported by driver + return INVALID_OPERATION; +} + +}; // namespace android diff --git a/hardware/libhardware_legacy/audio/A2dpAudioInterface.h b/hardware/libhardware_legacy/audio/A2dpAudioInterface.h new file mode 100644 index 00000000..8fe97455 --- /dev/null +++ b/hardware/libhardware_legacy/audio/A2dpAudioInterface.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef A2DP_AUDIO_HARDWARE_H +#define A2DP_AUDIO_HARDWARE_H + +#include +#include + +#include + +#include + + +namespace android_audio_legacy { + using android::Mutex; + +class A2dpAudioInterface : public AudioHardwareBase +{ + class A2dpAudioStreamOut; + +public: + A2dpAudioInterface(AudioHardwareInterface* hw); + virtual ~A2dpAudioInterface(); + virtual status_t initCheck(); + + virtual status_t setVoiceVolume(float volume); + virtual status_t setMasterVolume(float volume); + + virtual status_t setMode(int mode); + + // mic mute + virtual status_t setMicMute(bool state); + virtual status_t getMicMute(bool* state); + + virtual status_t setParameters(const String8& keyValuePairs); + virtual String8 getParameters(const String8& keys); + + virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount); + + // create I/O streams + virtual AudioStreamOut* openOutputStream( + uint32_t devices, + int *format=0, + uint32_t *channels=0, + uint32_t *sampleRate=0, + status_t *status=0); + virtual void closeOutputStream(AudioStreamOut* out); + + virtual AudioStreamIn* openInputStream( + uint32_t devices, + int *format, + uint32_t *channels, + uint32_t *sampleRate, + status_t *status, + AudioSystem::audio_in_acoustics acoustics); + virtual void closeInputStream(AudioStreamIn* in); +// static AudioHardwareInterface* createA2dpInterface(); + +protected: + virtual status_t dump(int fd, const Vector& args); + +private: + class A2dpAudioStreamOut : public AudioStreamOut { + public: + A2dpAudioStreamOut(); + virtual ~A2dpAudioStreamOut(); + status_t set(uint32_t device, + int *pFormat, + uint32_t *pChannels, + uint32_t *pRate); + virtual uint32_t sampleRate() const { return 44100; } + // SBC codec wants a multiple of 512 + virtual size_t bufferSize() const { return 512 * 20; } + virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; } + virtual int format() const { return AudioSystem::PCM_16_BIT; } + virtual uint32_t latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; } + virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; } + virtual ssize_t write(const void* buffer, size_t bytes); + status_t standby(); + virtual status_t dump(int fd, const Vector& args); + virtual status_t setParameters(const String8& keyValuePairs); + virtual String8 getParameters(const String8& keys); + virtual status_t getRenderPosition(uint32_t *dspFrames); + + private: + friend class A2dpAudioInterface; + status_t init(); + status_t close(); + status_t close_l(); + status_t setAddress(const char* address); + status_t setBluetoothEnabled(bool enabled); + status_t setSuspended(bool onOff); + status_t standby_l(); + + private: + int mFd; + bool mStandby; + int mStartCount; + int mRetryCount; + char mA2dpAddress[20]; + void* mData; + Mutex mLock; + bool mBluetoothEnabled; + uint32_t mDevice; + bool mClosing; + bool mSuspended; + nsecs_t mLastWriteTime; + uint32_t mBufferDurationUs; + }; + + friend class A2dpAudioStreamOut; + + A2dpAudioStreamOut* mOutput; + AudioHardwareInterface *mHardwareInterface; + char mA2dpAddress[20]; + bool mBluetoothEnabled; + bool mSuspended; +}; + + +// ---------------------------------------------------------------------------- + +}; // namespace android + +#endif // A2DP_AUDIO_HARDWARE_H diff --git a/hardware/libhardware_legacy/audio/Android.mk b/hardware/libhardware_legacy/audio/Android.mk new file mode 100644 index 00000000..a69b9cd9 --- /dev/null +++ b/hardware/libhardware_legacy/audio/Android.mk @@ -0,0 +1,80 @@ +# Copyright 2011 The Android Open Source Project + +#AUDIO_POLICY_TEST := true +#ENABLE_AUDIO_DUMP := true + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + AudioHardwareInterface.cpp \ + audio_hw_hal.cpp + +LOCAL_MODULE := libaudiohw_legacy +LOCAL_MODULE_TAGS := optional +LOCAL_STATIC_LIBRARIES := libmedia_helper + +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + AudioPolicyManagerBase.cpp \ + AudioPolicyCompatClient.cpp \ + audio_policy_hal.cpp + +ifeq ($(AUDIO_POLICY_TEST),true) + LOCAL_CFLAGS += -DAUDIO_POLICY_TEST +endif + +LOCAL_STATIC_LIBRARIES := libmedia_helper +LOCAL_MODULE := libaudiopolicy_legacy +LOCAL_MODULE_TAGS := optional + +include $(BUILD_STATIC_LIBRARY) + +# The default audio policy, for now still implemented on top of legacy +# policy code +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + AudioPolicyManagerDefault.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils + +LOCAL_STATIC_LIBRARIES := \ + libmedia_helper + +LOCAL_WHOLE_STATIC_LIBRARIES := \ + libaudiopolicy_legacy + +LOCAL_MODULE := audio_policy.default +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) + +#ifeq ($(ENABLE_AUDIO_DUMP),true) +# LOCAL_SRC_FILES += AudioDumpInterface.cpp +# LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP +#endif +# +#ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true) +# LOCAL_CFLAGS += -D GENERIC_AUDIO +#endif + +#ifeq ($(BOARD_HAVE_BLUETOOTH),true) +# LOCAL_SRC_FILES += A2dpAudioInterface.cpp +# LOCAL_SHARED_LIBRARIES += liba2dp +# LOCAL_C_INCLUDES += $(call include-path-for, bluez) +# +# LOCAL_CFLAGS += \ +# -DWITH_BLUETOOTH \ +#endif +# +#include $(BUILD_SHARED_LIBRARY) + +# AudioHardwareGeneric.cpp \ +# AudioHardwareStub.cpp \ diff --git a/hardware/libhardware_legacy/audio/AudioDumpInterface.cpp b/hardware/libhardware_legacy/audio/AudioDumpInterface.cpp new file mode 100644 index 00000000..62fdbd68 --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioDumpInterface.cpp @@ -0,0 +1,573 @@ +/* //device/servers/AudioFlinger/AudioDumpInterface.cpp +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "AudioFlingerDump" +//#define LOG_NDEBUG 0 + +#include +#include +#include + +#include +#include + +#include "AudioDumpInterface.h" + +namespace android { + +// ---------------------------------------------------------------------------- + +AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw) + : mPolicyCommands(String8("")), mFileName(String8("")) +{ + if(hw == 0) { + ALOGE("Dump construct hw = 0"); + } + mFinalInterface = hw; + ALOGV("Constructor %p, mFinalInterface %p", this, mFinalInterface); +} + + +AudioDumpInterface::~AudioDumpInterface() +{ + for (size_t i = 0; i < mOutputs.size(); i++) { + closeOutputStream((AudioStreamOut *)mOutputs[i]); + } + + for (size_t i = 0; i < mInputs.size(); i++) { + closeInputStream((AudioStreamIn *)mInputs[i]); + } + + if(mFinalInterface) delete mFinalInterface; +} + + +AudioStreamOut* AudioDumpInterface::openOutputStream( + uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status) +{ + AudioStreamOut* outFinal = NULL; + int lFormat = AudioSystem::PCM_16_BIT; + uint32_t lChannels = AudioSystem::CHANNEL_OUT_STEREO; + uint32_t lRate = 44100; + + + outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status); + if (outFinal != 0) { + lFormat = outFinal->format(); + lChannels = outFinal->channels(); + lRate = outFinal->sampleRate(); + } else { + if (format != 0) { + if (*format != 0) { + lFormat = *format; + } else { + *format = lFormat; + } + } + if (channels != 0) { + if (*channels != 0) { + lChannels = *channels; + } else { + *channels = lChannels; + } + } + if (sampleRate != 0) { + if (*sampleRate != 0) { + lRate = *sampleRate; + } else { + *sampleRate = lRate; + } + } + if (status) *status = NO_ERROR; + } + ALOGV("openOutputStream(), outFinal %p", outFinal); + + AudioStreamOutDump *dumOutput = new AudioStreamOutDump(this, mOutputs.size(), outFinal, + devices, lFormat, lChannels, lRate); + mOutputs.add(dumOutput); + + return dumOutput; +} + +void AudioDumpInterface::closeOutputStream(AudioStreamOut* out) +{ + AudioStreamOutDump *dumpOut = (AudioStreamOutDump *)out; + + if (mOutputs.indexOf(dumpOut) < 0) { + ALOGW("Attempt to close invalid output stream"); + return; + } + + ALOGV("closeOutputStream() output %p", out); + + dumpOut->standby(); + if (dumpOut->finalStream() != NULL) { + mFinalInterface->closeOutputStream(dumpOut->finalStream()); + } + + mOutputs.remove(dumpOut); + delete dumpOut; +} + +AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format, uint32_t *channels, + uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics) +{ + AudioStreamIn* inFinal = NULL; + int lFormat = AudioSystem::PCM_16_BIT; + uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO; + uint32_t lRate = 8000; + + inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); + if (inFinal != 0) { + lFormat = inFinal->format(); + lChannels = inFinal->channels(); + lRate = inFinal->sampleRate(); + } else { + if (format != 0) { + if (*format != 0) { + lFormat = *format; + } else { + *format = lFormat; + } + } + if (channels != 0) { + if (*channels != 0) { + lChannels = *channels; + } else { + *channels = lChannels; + } + } + if (sampleRate != 0) { + if (*sampleRate != 0) { + lRate = *sampleRate; + } else { + *sampleRate = lRate; + } + } + if (status) *status = NO_ERROR; + } + ALOGV("openInputStream(), inFinal %p", inFinal); + + AudioStreamInDump *dumInput = new AudioStreamInDump(this, mInputs.size(), inFinal, + devices, lFormat, lChannels, lRate); + mInputs.add(dumInput); + + return dumInput; +} +void AudioDumpInterface::closeInputStream(AudioStreamIn* in) +{ + AudioStreamInDump *dumpIn = (AudioStreamInDump *)in; + + if (mInputs.indexOf(dumpIn) < 0) { + ALOGW("Attempt to close invalid input stream"); + return; + } + dumpIn->standby(); + if (dumpIn->finalStream() != NULL) { + mFinalInterface->closeInputStream(dumpIn->finalStream()); + } + + mInputs.remove(dumpIn); + delete dumpIn; +} + + +status_t AudioDumpInterface::setParameters(const String8& keyValuePairs) +{ + AudioParameter param = AudioParameter(keyValuePairs); + String8 value; + int valueInt; + ALOGV("setParameters %s", keyValuePairs.string()); + + if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) { + mFileName = value; + param.remove(String8("test_cmd_file_name")); + } + if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) { + Mutex::Autolock _l(mLock); + param.remove(String8("test_cmd_policy")); + mPolicyCommands = param.toString(); + ALOGV("test_cmd_policy command %s written", mPolicyCommands.string()); + return NO_ERROR; + } + + if (mFinalInterface != 0 ) return mFinalInterface->setParameters(keyValuePairs); + return NO_ERROR; +} + +String8 AudioDumpInterface::getParameters(const String8& keys) +{ + AudioParameter param = AudioParameter(keys); + AudioParameter response; + String8 value; + +// ALOGV("getParameters %s", keys.string()); + if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) { + Mutex::Autolock _l(mLock); + if (mPolicyCommands.length() != 0) { + response = AudioParameter(mPolicyCommands); + response.addInt(String8("test_cmd_policy"), 1); + } else { + response.addInt(String8("test_cmd_policy"), 0); + } + param.remove(String8("test_cmd_policy")); +// ALOGV("test_cmd_policy command %s read", mPolicyCommands.string()); + } + + if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) { + response.add(String8("test_cmd_file_name"), mFileName); + param.remove(String8("test_cmd_file_name")); + } + + String8 keyValuePairs = response.toString(); + + if (param.size() && mFinalInterface != 0 ) { + keyValuePairs += ";"; + keyValuePairs += mFinalInterface->getParameters(param.toString()); + } + + return keyValuePairs; +} + +status_t AudioDumpInterface::setMode(int mode) +{ + return mFinalInterface->setMode(mode); +} + +size_t AudioDumpInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) +{ + return mFinalInterface->getInputBufferSize(sampleRate, format, channelCount); +} + +// ---------------------------------------------------------------------------- + +AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface, + int id, + AudioStreamOut* finalStream, + uint32_t devices, + int format, + uint32_t channels, + uint32_t sampleRate) + : mInterface(interface), mId(id), + mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices), + mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0) +{ + ALOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream); +} + + +AudioStreamOutDump::~AudioStreamOutDump() +{ + ALOGV("AudioStreamOutDump destructor"); + Close(); +} + +ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes) +{ + ssize_t ret; + + if (mFinalStream) { + ret = mFinalStream->write(buffer, bytes); + } else { + usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000); + ret = bytes; + } + if(!mFile) { + if (mInterface->fileName() != "") { + char name[255]; + sprintf(name, "%s_out_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); + mFile = fopen(name, "wb"); + ALOGV("Opening dump file %s, fh %p", name, mFile); + } + } + if (mFile) { + fwrite(buffer, bytes, 1, mFile); + } + return ret; +} + +status_t AudioStreamOutDump::standby() +{ + ALOGV("AudioStreamOutDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream); + + Close(); + if (mFinalStream != 0 ) return mFinalStream->standby(); + return NO_ERROR; +} + +uint32_t AudioStreamOutDump::sampleRate() const +{ + if (mFinalStream != 0 ) return mFinalStream->sampleRate(); + return mSampleRate; +} + +size_t AudioStreamOutDump::bufferSize() const +{ + if (mFinalStream != 0 ) return mFinalStream->bufferSize(); + return mBufferSize; +} + +uint32_t AudioStreamOutDump::channels() const +{ + if (mFinalStream != 0 ) return mFinalStream->channels(); + return mChannels; +} +int AudioStreamOutDump::format() const +{ + if (mFinalStream != 0 ) return mFinalStream->format(); + return mFormat; +} +uint32_t AudioStreamOutDump::latency() const +{ + if (mFinalStream != 0 ) return mFinalStream->latency(); + return 0; +} +status_t AudioStreamOutDump::setVolume(float left, float right) +{ + if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right); + return NO_ERROR; +} +status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs) +{ + ALOGV("AudioStreamOutDump::setParameters %s", keyValuePairs.string()); + + if (mFinalStream != 0 ) { + return mFinalStream->setParameters(keyValuePairs); + } + + AudioParameter param = AudioParameter(keyValuePairs); + String8 value; + int valueInt; + status_t status = NO_ERROR; + + if (param.getInt(String8("set_id"), valueInt) == NO_ERROR) { + mId = valueInt; + } + + if (param.getInt(String8("format"), valueInt) == NO_ERROR) { + if (mFile == 0) { + mFormat = valueInt; + } else { + status = INVALID_OPERATION; + } + } + if (param.getInt(String8("channels"), valueInt) == NO_ERROR) { + if (valueInt == AudioSystem::CHANNEL_OUT_STEREO || valueInt == AudioSystem::CHANNEL_OUT_MONO) { + mChannels = valueInt; + } else { + status = BAD_VALUE; + } + } + if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) { + if (valueInt > 0 && valueInt <= 48000) { + if (mFile == 0) { + mSampleRate = valueInt; + } else { + status = INVALID_OPERATION; + } + } else { + status = BAD_VALUE; + } + } + return status; +} + +String8 AudioStreamOutDump::getParameters(const String8& keys) +{ + if (mFinalStream != 0 ) return mFinalStream->getParameters(keys); + + AudioParameter param = AudioParameter(keys); + return param.toString(); +} + +status_t AudioStreamOutDump::dump(int fd, const Vector& args) +{ + if (mFinalStream != 0 ) return mFinalStream->dump(fd, args); + return NO_ERROR; +} + +void AudioStreamOutDump::Close() +{ + if(mFile) { + fclose(mFile); + mFile = 0; + } +} + +status_t AudioStreamOutDump::getRenderPosition(uint32_t *dspFrames) +{ + if (mFinalStream != 0 ) return mFinalStream->getRenderPosition(dspFrames); + return INVALID_OPERATION; +} + +// ---------------------------------------------------------------------------- + +AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface, + int id, + AudioStreamIn* finalStream, + uint32_t devices, + int format, + uint32_t channels, + uint32_t sampleRate) + : mInterface(interface), mId(id), + mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices), + mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0) +{ + ALOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream); +} + + +AudioStreamInDump::~AudioStreamInDump() +{ + Close(); +} + +ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes) +{ + ssize_t ret; + + if (mFinalStream) { + ret = mFinalStream->read(buffer, bytes); + if(!mFile) { + if (mInterface->fileName() != "") { + char name[255]; + sprintf(name, "%s_in_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); + mFile = fopen(name, "wb"); + ALOGV("Opening input dump file %s, fh %p", name, mFile); + } + } + if (mFile) { + fwrite(buffer, bytes, 1, mFile); + } + } else { + usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000); + ret = bytes; + if(!mFile) { + char name[255]; + strcpy(name, "/sdcard/music/sine440"); + if (channels() == AudioSystem::CHANNEL_IN_MONO) { + strcat(name, "_mo"); + } else { + strcat(name, "_st"); + } + if (format() == AudioSystem::PCM_16_BIT) { + strcat(name, "_16b"); + } else { + strcat(name, "_8b"); + } + if (sampleRate() < 16000) { + strcat(name, "_8k"); + } else if (sampleRate() < 32000) { + strcat(name, "_22k"); + } else if (sampleRate() < 48000) { + strcat(name, "_44k"); + } else { + strcat(name, "_48k"); + } + strcat(name, ".wav"); + mFile = fopen(name, "rb"); + ALOGV("Opening input read file %s, fh %p", name, mFile); + if (mFile) { + fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); + } + } + if (mFile) { + ssize_t bytesRead = fread(buffer, bytes, 1, mFile); + if (bytesRead >=0 && bytesRead < bytes) { + fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); + fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mFile); + } + } + } + + return ret; +} + +status_t AudioStreamInDump::standby() +{ + ALOGV("AudioStreamInDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream); + + Close(); + if (mFinalStream != 0 ) return mFinalStream->standby(); + return NO_ERROR; +} + +status_t AudioStreamInDump::setGain(float gain) +{ + if (mFinalStream != 0 ) return mFinalStream->setGain(gain); + return NO_ERROR; +} + +uint32_t AudioStreamInDump::sampleRate() const +{ + if (mFinalStream != 0 ) return mFinalStream->sampleRate(); + return mSampleRate; +} + +size_t AudioStreamInDump::bufferSize() const +{ + if (mFinalStream != 0 ) return mFinalStream->bufferSize(); + return mBufferSize; +} + +uint32_t AudioStreamInDump::channels() const +{ + if (mFinalStream != 0 ) return mFinalStream->channels(); + return mChannels; +} + +int AudioStreamInDump::format() const +{ + if (mFinalStream != 0 ) return mFinalStream->format(); + return mFormat; +} + +status_t AudioStreamInDump::setParameters(const String8& keyValuePairs) +{ + ALOGV("AudioStreamInDump::setParameters()"); + if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs); + return NO_ERROR; +} + +String8 AudioStreamInDump::getParameters(const String8& keys) +{ + if (mFinalStream != 0 ) return mFinalStream->getParameters(keys); + + AudioParameter param = AudioParameter(keys); + return param.toString(); +} + +unsigned int AudioStreamInDump::getInputFramesLost() const +{ + if (mFinalStream != 0 ) return mFinalStream->getInputFramesLost(); + return 0; +} + +status_t AudioStreamInDump::dump(int fd, const Vector& args) +{ + if (mFinalStream != 0 ) return mFinalStream->dump(fd, args); + return NO_ERROR; +} + +void AudioStreamInDump::Close() +{ + if(mFile) { + fclose(mFile); + mFile = 0; + } +} +}; // namespace android diff --git a/hardware/libhardware_legacy/audio/AudioDumpInterface.h b/hardware/libhardware_legacy/audio/AudioDumpInterface.h new file mode 100644 index 00000000..814ce5f7 --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioDumpInterface.h @@ -0,0 +1,170 @@ +/* //device/servers/AudioFlinger/AudioDumpInterface.h +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef ANDROID_AUDIO_DUMP_INTERFACE_H +#define ANDROID_AUDIO_DUMP_INTERFACE_H + +#include +#include +#include +#include + +#include + +namespace android { + +#define AUDIO_DUMP_WAVE_HDR_SIZE 44 + +class AudioDumpInterface; + +class AudioStreamOutDump : public AudioStreamOut { +public: + AudioStreamOutDump(AudioDumpInterface *interface, + int id, + AudioStreamOut* finalStream, + uint32_t devices, + int format, + uint32_t channels, + uint32_t sampleRate); + ~AudioStreamOutDump(); + + virtual ssize_t write(const void* buffer, size_t bytes); + virtual uint32_t sampleRate() const; + virtual size_t bufferSize() const; + virtual uint32_t channels() const; + virtual int format() const; + virtual uint32_t latency() const; + virtual status_t setVolume(float left, float right); + virtual status_t standby(); + virtual status_t setParameters(const String8& keyValuePairs); + virtual String8 getParameters(const String8& keys); + virtual status_t dump(int fd, const Vector& args); + void Close(void); + AudioStreamOut* finalStream() { return mFinalStream; } + uint32_t device() { return mDevice; } + int getId() { return mId; } + virtual status_t getRenderPosition(uint32_t *dspFrames); + +private: + AudioDumpInterface *mInterface; + int mId; + uint32_t mSampleRate; // + uint32_t mFormat; // + uint32_t mChannels; // output configuration + uint32_t mLatency; // + uint32_t mDevice; // current device this output is routed to + size_t mBufferSize; + AudioStreamOut *mFinalStream; + FILE *mFile; // output file + int mFileCount; +}; + +class AudioStreamInDump : public AudioStreamIn { +public: + AudioStreamInDump(AudioDumpInterface *interface, + int id, + AudioStreamIn* finalStream, + uint32_t devices, + int format, + uint32_t channels, + uint32_t sampleRate); + ~AudioStreamInDump(); + + virtual uint32_t sampleRate() const; + virtual size_t bufferSize() const; + virtual uint32_t channels() const; + virtual int format() const; + + virtual status_t setGain(float gain); + virtual ssize_t read(void* buffer, ssize_t bytes); + virtual status_t standby(); + virtual status_t setParameters(const String8& keyValuePairs); + virtual String8 getParameters(const String8& keys); + virtual unsigned int getInputFramesLost() const; + virtual status_t dump(int fd, const Vector& args); + void Close(void); + AudioStreamIn* finalStream() { return mFinalStream; } + uint32_t device() { return mDevice; } + +private: + AudioDumpInterface *mInterface; + int mId; + uint32_t mSampleRate; // + uint32_t mFormat; // + uint32_t mChannels; // output configuration + uint32_t mDevice; // current device this output is routed to + size_t mBufferSize; + AudioStreamIn *mFinalStream; + FILE *mFile; // output file + int mFileCount; +}; + +class AudioDumpInterface : public AudioHardwareBase +{ + +public: + AudioDumpInterface(AudioHardwareInterface* hw); + virtual AudioStreamOut* openOutputStream( + uint32_t devices, + int *format=0, + uint32_t *channels=0, + uint32_t *sampleRate=0, + status_t *status=0); + virtual void closeOutputStream(AudioStreamOut* out); + + virtual ~AudioDumpInterface(); + + virtual status_t initCheck() + {return mFinalInterface->initCheck();} + virtual status_t setVoiceVolume(float volume) + {return mFinalInterface->setVoiceVolume(volume);} + virtual status_t setMasterVolume(float volume) + {return mFinalInterface->setMasterVolume(volume);} + + virtual status_t setMode(int mode); + + // mic mute + virtual status_t setMicMute(bool state) + {return mFinalInterface->setMicMute(state);} + virtual status_t getMicMute(bool* state) + {return mFinalInterface->getMicMute(state);} + + virtual status_t setParameters(const String8& keyValuePairs); + virtual String8 getParameters(const String8& keys); + + virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount); + + virtual AudioStreamIn* openInputStream(uint32_t devices, int *format, uint32_t *channels, + uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics); + virtual void closeInputStream(AudioStreamIn* in); + + virtual status_t dump(int fd, const Vector& args) { return mFinalInterface->dumpState(fd, args); } + + String8 fileName() const { return mFileName; } +protected: + + AudioHardwareInterface *mFinalInterface; + SortedVector mOutputs; + SortedVector mInputs; + Mutex mLock; + String8 mPolicyCommands; + String8 mFileName; +}; + +}; // namespace android + +#endif // ANDROID_AUDIO_DUMP_INTERFACE_H diff --git a/hardware/libhardware_legacy/audio/AudioHardwareGeneric.cpp b/hardware/libhardware_legacy/audio/AudioHardwareGeneric.cpp new file mode 100644 index 00000000..a2b00f8f --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioHardwareGeneric.cpp @@ -0,0 +1,413 @@ +/* +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "AudioHardware" +#include +#include + +#include "AudioHardwareGeneric.h" +#include + +#include + +namespace android_audio_legacy { + +// ---------------------------------------------------------------------------- + +static char const * const kAudioDeviceName = "/dev/eac"; + +// ---------------------------------------------------------------------------- + +AudioHardwareGeneric::AudioHardwareGeneric() + : mOutput(0), mInput(0), mFd(-1), mMicMute(false) +{ + mFd = ::open(kAudioDeviceName, O_RDWR); +} + +AudioHardwareGeneric::~AudioHardwareGeneric() +{ + if (mFd >= 0) ::close(mFd); + closeOutputStream((AudioStreamOut *)mOutput); + closeInputStream((AudioStreamIn *)mInput); +} + +status_t AudioHardwareGeneric::initCheck() +{ + if (mFd >= 0) { + if (::access(kAudioDeviceName, O_RDWR) == NO_ERROR) + return NO_ERROR; + } + return NO_INIT; +} + +AudioStreamOut* AudioHardwareGeneric::openOutputStream( + uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status) +{ + AutoMutex lock(mLock); + + // only one output stream allowed + if (mOutput) { + if (status) { + *status = INVALID_OPERATION; + } + return 0; + } + + // create new output stream + AudioStreamOutGeneric* out = new AudioStreamOutGeneric(); + status_t lStatus = out->set(this, mFd, devices, format, channels, sampleRate); + if (status) { + *status = lStatus; + } + if (lStatus == NO_ERROR) { + mOutput = out; + } else { + delete out; + } + return mOutput; +} + +void AudioHardwareGeneric::closeOutputStream(AudioStreamOut* out) { + if (mOutput && out == mOutput) { + delete mOutput; + mOutput = 0; + } +} + +AudioStreamIn* AudioHardwareGeneric::openInputStream( + uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, + status_t *status, AudioSystem::audio_in_acoustics acoustics) +{ + // check for valid input source + if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) { + return 0; + } + + AutoMutex lock(mLock); + + // only one input stream allowed + if (mInput) { + if (status) { + *status = INVALID_OPERATION; + } + return 0; + } + + // create new output stream + AudioStreamInGeneric* in = new AudioStreamInGeneric(); + status_t lStatus = in->set(this, mFd, devices, format, channels, sampleRate, acoustics); + if (status) { + *status = lStatus; + } + if (lStatus == NO_ERROR) { + mInput = in; + } else { + delete in; + } + return mInput; +} + +void AudioHardwareGeneric::closeInputStream(AudioStreamIn* in) { + if (mInput && in == mInput) { + delete mInput; + mInput = 0; + } +} + +status_t AudioHardwareGeneric::setVoiceVolume(float v) +{ + // Implement: set voice volume + return NO_ERROR; +} + +status_t AudioHardwareGeneric::setMasterVolume(float v) +{ + // Implement: set master volume + // return error - software mixer will handle it + return INVALID_OPERATION; +} + +status_t AudioHardwareGeneric::setMicMute(bool state) +{ + mMicMute = state; + return NO_ERROR; +} + +status_t AudioHardwareGeneric::getMicMute(bool* state) +{ + *state = mMicMute; + return NO_ERROR; +} + +status_t AudioHardwareGeneric::dumpInternals(int fd, const Vector& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + result.append("AudioHardwareGeneric::dumpInternals\n"); + snprintf(buffer, SIZE, "\tmFd: %d mMicMute: %s\n", mFd, mMicMute? "true": "false"); + result.append(buffer); + ::write(fd, result.string(), result.size()); + return NO_ERROR; +} + +status_t AudioHardwareGeneric::dump(int fd, const Vector& args) +{ + dumpInternals(fd, args); + if (mInput) { + mInput->dump(fd, args); + } + if (mOutput) { + mOutput->dump(fd, args); + } + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + +status_t AudioStreamOutGeneric::set( + AudioHardwareGeneric *hw, + int fd, + uint32_t devices, + int *pFormat, + uint32_t *pChannels, + uint32_t *pRate) +{ + int lFormat = pFormat ? *pFormat : 0; + uint32_t lChannels = pChannels ? *pChannels : 0; + uint32_t lRate = pRate ? *pRate : 0; + + // fix up defaults + if (lFormat == 0) lFormat = format(); + if (lChannels == 0) lChannels = channels(); + if (lRate == 0) lRate = sampleRate(); + + // check values + if ((lFormat != format()) || + (lChannels != channels()) || + (lRate != sampleRate())) { + if (pFormat) *pFormat = format(); + if (pChannels) *pChannels = channels(); + if (pRate) *pRate = sampleRate(); + return BAD_VALUE; + } + + if (pFormat) *pFormat = lFormat; + if (pChannels) *pChannels = lChannels; + if (pRate) *pRate = lRate; + + mAudioHardware = hw; + mFd = fd; + mDevice = devices; + return NO_ERROR; +} + +AudioStreamOutGeneric::~AudioStreamOutGeneric() +{ +} + +ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes) +{ + Mutex::Autolock _l(mLock); + return ssize_t(::write(mFd, buffer, bytes)); +} + +status_t AudioStreamOutGeneric::standby() +{ + // Implement: audio hardware to standby mode + return NO_ERROR; +} + +status_t AudioStreamOutGeneric::dump(int fd, const Vector& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + snprintf(buffer, SIZE, "AudioStreamOutGeneric::dump\n"); + result.append(buffer); + snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate()); + result.append(buffer); + snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize()); + result.append(buffer); + snprintf(buffer, SIZE, "\tchannels: %d\n", channels()); + result.append(buffer); + snprintf(buffer, SIZE, "\tformat: %d\n", format()); + result.append(buffer); + snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice); + result.append(buffer); + snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware); + result.append(buffer); + snprintf(buffer, SIZE, "\tmFd: %d\n", mFd); + result.append(buffer); + ::write(fd, result.string(), result.size()); + return NO_ERROR; +} + +status_t AudioStreamOutGeneric::setParameters(const String8& keyValuePairs) +{ + AudioParameter param = AudioParameter(keyValuePairs); + String8 key = String8(AudioParameter::keyRouting); + status_t status = NO_ERROR; + int device; + ALOGV("setParameters() %s", keyValuePairs.string()); + + if (param.getInt(key, device) == NO_ERROR) { + mDevice = device; + param.remove(key); + } + + if (param.size()) { + status = BAD_VALUE; + } + return status; +} + +String8 AudioStreamOutGeneric::getParameters(const String8& keys) +{ + AudioParameter param = AudioParameter(keys); + String8 value; + String8 key = String8(AudioParameter::keyRouting); + + if (param.get(key, value) == NO_ERROR) { + param.addInt(key, (int)mDevice); + } + + ALOGV("getParameters() %s", param.toString().string()); + return param.toString(); +} + +status_t AudioStreamOutGeneric::getRenderPosition(uint32_t *dspFrames) +{ + return INVALID_OPERATION; +} + +// ---------------------------------------------------------------------------- + +// record functions +status_t AudioStreamInGeneric::set( + AudioHardwareGeneric *hw, + int fd, + uint32_t devices, + int *pFormat, + uint32_t *pChannels, + uint32_t *pRate, + AudioSystem::audio_in_acoustics acoustics) +{ + if (pFormat == 0 || pChannels == 0 || pRate == 0) return BAD_VALUE; + ALOGV("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate); + // check values + if ((*pFormat != format()) || + (*pChannels != channels()) || + (*pRate != sampleRate())) { + ALOGE("Error opening input channel"); + *pFormat = format(); + *pChannels = channels(); + *pRate = sampleRate(); + return BAD_VALUE; + } + + mAudioHardware = hw; + mFd = fd; + mDevice = devices; + return NO_ERROR; +} + +AudioStreamInGeneric::~AudioStreamInGeneric() +{ +} + +ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes) +{ + AutoMutex lock(mLock); + if (mFd < 0) { + ALOGE("Attempt to read from unopened device"); + return NO_INIT; + } + return ::read(mFd, buffer, bytes); +} + +status_t AudioStreamInGeneric::dump(int fd, const Vector& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + snprintf(buffer, SIZE, "AudioStreamInGeneric::dump\n"); + result.append(buffer); + snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate()); + result.append(buffer); + snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize()); + result.append(buffer); + snprintf(buffer, SIZE, "\tchannels: %d\n", channels()); + result.append(buffer); + snprintf(buffer, SIZE, "\tformat: %d\n", format()); + result.append(buffer); + snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice); + result.append(buffer); + snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware); + result.append(buffer); + snprintf(buffer, SIZE, "\tmFd: %d\n", mFd); + result.append(buffer); + ::write(fd, result.string(), result.size()); + return NO_ERROR; +} + +status_t AudioStreamInGeneric::setParameters(const String8& keyValuePairs) +{ + AudioParameter param = AudioParameter(keyValuePairs); + String8 key = String8(AudioParameter::keyRouting); + status_t status = NO_ERROR; + int device; + ALOGV("setParameters() %s", keyValuePairs.string()); + + if (param.getInt(key, device) == NO_ERROR) { + mDevice = device; + param.remove(key); + } + + if (param.size()) { + status = BAD_VALUE; + } + return status; +} + +String8 AudioStreamInGeneric::getParameters(const String8& keys) +{ + AudioParameter param = AudioParameter(keys); + String8 value; + String8 key = String8(AudioParameter::keyRouting); + + if (param.get(key, value) == NO_ERROR) { + param.addInt(key, (int)mDevice); + } + + ALOGV("getParameters() %s", param.toString().string()); + return param.toString(); +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/hardware/libhardware_legacy/audio/AudioHardwareGeneric.h b/hardware/libhardware_legacy/audio/AudioHardwareGeneric.h new file mode 100644 index 00000000..7b41e95f --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioHardwareGeneric.h @@ -0,0 +1,154 @@ +/* +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef ANDROID_AUDIO_HARDWARE_GENERIC_H +#define ANDROID_AUDIO_HARDWARE_GENERIC_H + +#include +#include + +#include + +#include +#include + +namespace android_audio_legacy { + using android::Mutex; + using android::AutoMutex; + +// ---------------------------------------------------------------------------- + +class AudioHardwareGeneric; + +class AudioStreamOutGeneric : public AudioStreamOut { +public: + AudioStreamOutGeneric() : mAudioHardware(0), mFd(-1) {} + virtual ~AudioStreamOutGeneric(); + + virtual status_t set( + AudioHardwareGeneric *hw, + int mFd, + uint32_t devices, + int *pFormat, + uint32_t *pChannels, + uint32_t *pRate); + + virtual uint32_t sampleRate() const { return 44100; } + virtual size_t bufferSize() const { return 4096; } + virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; } + virtual int format() const { return AudioSystem::PCM_16_BIT; } + virtual uint32_t latency() const { return 20; } + virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; } + virtual ssize_t write(const void* buffer, size_t bytes); + virtual status_t standby(); + virtual status_t dump(int fd, const Vector& args); + virtual status_t setParameters(const String8& keyValuePairs); + virtual String8 getParameters(const String8& keys); + virtual status_t getRenderPosition(uint32_t *dspFrames); + +private: + AudioHardwareGeneric *mAudioHardware; + Mutex mLock; + int mFd; + uint32_t mDevice; +}; + +class AudioStreamInGeneric : public AudioStreamIn { +public: + AudioStreamInGeneric() : mAudioHardware(0), mFd(-1) {} + virtual ~AudioStreamInGeneric(); + + virtual status_t set( + AudioHardwareGeneric *hw, + int mFd, + uint32_t devices, + int *pFormat, + uint32_t *pChannels, + uint32_t *pRate, + AudioSystem::audio_in_acoustics acoustics); + + virtual uint32_t sampleRate() const { return 8000; } + virtual size_t bufferSize() const { return 320; } + virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; } + virtual int format() const { return AudioSystem::PCM_16_BIT; } + virtual status_t setGain(float gain) { return INVALID_OPERATION; } + virtual ssize_t read(void* buffer, ssize_t bytes); + virtual status_t dump(int fd, const Vector& args); + virtual status_t standby() { return NO_ERROR; } + virtual status_t setParameters(const String8& keyValuePairs); + virtual String8 getParameters(const String8& keys); + virtual unsigned int getInputFramesLost() const { return 0; } + +private: + AudioHardwareGeneric *mAudioHardware; + Mutex mLock; + int mFd; + uint32_t mDevice; +}; + + +class AudioHardwareGeneric : public AudioHardwareBase +{ +public: + AudioHardwareGeneric(); + virtual ~AudioHardwareGeneric(); + virtual status_t initCheck(); + virtual status_t setVoiceVolume(float volume); + virtual status_t setMasterVolume(float volume); + + // mic mute + virtual status_t setMicMute(bool state); + virtual status_t getMicMute(bool* state); + + // create I/O streams + virtual AudioStreamOut* openOutputStream( + uint32_t devices, + int *format=0, + uint32_t *channels=0, + uint32_t *sampleRate=0, + status_t *status=0); + virtual void closeOutputStream(AudioStreamOut* out); + + virtual AudioStreamIn* openInputStream( + uint32_t devices, + int *format, + uint32_t *channels, + uint32_t *sampleRate, + status_t *status, + AudioSystem::audio_in_acoustics acoustics); + virtual void closeInputStream(AudioStreamIn* in); + + void closeOutputStream(AudioStreamOutGeneric* out); + void closeInputStream(AudioStreamInGeneric* in); +protected: + virtual status_t dump(int fd, const Vector& args); + +private: + status_t dumpInternals(int fd, const Vector& args); + + Mutex mLock; + AudioStreamOutGeneric *mOutput; + AudioStreamInGeneric *mInput; + int mFd; + bool mMicMute; +}; + +// ---------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_AUDIO_HARDWARE_GENERIC_H diff --git a/hardware/libhardware_legacy/audio/AudioHardwareInterface.cpp b/hardware/libhardware_legacy/audio/AudioHardwareInterface.cpp new file mode 100644 index 00000000..0e109aa8 --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioHardwareInterface.cpp @@ -0,0 +1,155 @@ +/* +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include +#include +#include +//#define LOG_NDEBUG 0 + +#define LOG_TAG "AudioHardwareInterface" +#include +#include + +#include "AudioHardwareStub.h" +#include "AudioHardwareGeneric.h" + +#ifdef ENABLE_AUDIO_DUMP +#include "AudioDumpInterface.h" +#endif + + +// change to 1 to log routing calls +#define LOG_ROUTING_CALLS 1 + +namespace android_audio_legacy { + +#if LOG_ROUTING_CALLS +static const char* routingModeStrings[] = +{ + "OUT OF RANGE", + "INVALID", + "CURRENT", + "NORMAL", + "RINGTONE", + "IN_CALL", + "IN_COMMUNICATION" +}; + +static const char* routeNone = "NONE"; + +static const char* displayMode(int mode) +{ + if ((mode < AudioSystem::MODE_INVALID) || (mode >= AudioSystem::NUM_MODES)) + return routingModeStrings[0]; + return routingModeStrings[mode+3]; +} +#endif + +// ---------------------------------------------------------------------------- + +AudioHardwareInterface* AudioHardwareInterface::create() +{ + return NULL; +} + +AudioStreamOut::~AudioStreamOut() +{ +} + +// default implementation is unsupported +#ifndef ICS_AUDIO_BLOB +status_t AudioStreamOut::getNextWriteTimestamp(int64_t *timestamp) +{ + return INVALID_OPERATION; +} +#endif + +AudioStreamIn::~AudioStreamIn() {} + +AudioHardwareBase::AudioHardwareBase() +{ + mMode = 0; +} + +status_t AudioHardwareBase::setMode(int mode) +{ +#if LOG_ROUTING_CALLS + ALOGD("setMode(%s)", displayMode(mode)); +#endif + if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) + return BAD_VALUE; + if (mMode == mode) + return ALREADY_EXISTS; + mMode = mode; + return NO_ERROR; +} + +// default implementation +status_t AudioHardwareBase::setParameters(const String8& keyValuePairs) +{ + return NO_ERROR; +} + +// default implementation +String8 AudioHardwareBase::getParameters(const String8& keys) +{ + AudioParameter param = AudioParameter(keys); + return param.toString(); +} + +// default implementation +size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) +{ + if (sampleRate != 8000) { + ALOGW("getInputBufferSize bad sampling rate: %d", sampleRate); + return 0; + } + if (format != AudioSystem::PCM_16_BIT) { + ALOGW("getInputBufferSize bad format: %d", format); + return 0; + } + if (channelCount != 1) { + ALOGW("getInputBufferSize bad channel count: %d", channelCount); + return 0; + } + + return 320; +} + +// default implementation is unsupported +status_t AudioHardwareBase::getMasterVolume(float *volume) +{ + return INVALID_OPERATION; +} + +status_t AudioHardwareBase::dumpState(int fd, const Vector& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + snprintf(buffer, SIZE, "AudioHardwareBase::dumpState\n"); + result.append(buffer); + snprintf(buffer, SIZE, "\tmMode: %d\n", mMode); + result.append(buffer); + ::write(fd, result.string(), result.size()); + dump(fd, args); // Dump the state of the concrete child. + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/hardware/libhardware_legacy/audio/AudioHardwareStub.cpp b/hardware/libhardware_legacy/audio/AudioHardwareStub.cpp new file mode 100644 index 00000000..70a8309e --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioHardwareStub.cpp @@ -0,0 +1,209 @@ +/* //device/servers/AudioFlinger/AudioHardwareStub.cpp +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include +#include + +#include +#include +#include + +#include "AudioHardwareStub.h" +#include + +namespace android_audio_legacy { + +// ---------------------------------------------------------------------------- + +AudioHardwareStub::AudioHardwareStub() : mMicMute(false) +{ +} + +AudioHardwareStub::~AudioHardwareStub() +{ +} + +status_t AudioHardwareStub::initCheck() +{ + return NO_ERROR; +} + +AudioStreamOut* AudioHardwareStub::openOutputStream( + uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status) +{ + AudioStreamOutStub* out = new AudioStreamOutStub(); + status_t lStatus = out->set(format, channels, sampleRate); + if (status) { + *status = lStatus; + } + if (lStatus == NO_ERROR) + return out; + delete out; + return 0; +} + +void AudioHardwareStub::closeOutputStream(AudioStreamOut* out) +{ + delete out; +} + +AudioStreamIn* AudioHardwareStub::openInputStream( + uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, + status_t *status, AudioSystem::audio_in_acoustics acoustics) +{ + // check for valid input source + if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) { + return 0; + } + + AudioStreamInStub* in = new AudioStreamInStub(); + status_t lStatus = in->set(format, channels, sampleRate, acoustics); + if (status) { + *status = lStatus; + } + if (lStatus == NO_ERROR) + return in; + delete in; + return 0; +} + +void AudioHardwareStub::closeInputStream(AudioStreamIn* in) +{ + delete in; +} + +status_t AudioHardwareStub::setVoiceVolume(float volume) +{ + return NO_ERROR; +} + +status_t AudioHardwareStub::setMasterVolume(float volume) +{ + return NO_ERROR; +} + +status_t AudioHardwareStub::dumpInternals(int fd, const Vector& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + result.append("AudioHardwareStub::dumpInternals\n"); + snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false"); + result.append(buffer); + ::write(fd, result.string(), result.size()); + return NO_ERROR; +} + +status_t AudioHardwareStub::dump(int fd, const Vector& args) +{ + dumpInternals(fd, args); + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + +status_t AudioStreamOutStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate) +{ + if (pFormat) *pFormat = format(); + if (pChannels) *pChannels = channels(); + if (pRate) *pRate = sampleRate(); + + return NO_ERROR; +} + +ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes) +{ + // fake timing for audio output + usleep(bytes * 1000000 / sizeof(int16_t) / AudioSystem::popCount(channels()) / sampleRate()); + return bytes; +} + +status_t AudioStreamOutStub::standby() +{ + return NO_ERROR; +} + +status_t AudioStreamOutStub::dump(int fd, const Vector& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n"); + snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate()); + snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize()); + snprintf(buffer, SIZE, "\tchannels: %d\n", channels()); + snprintf(buffer, SIZE, "\tformat: %d\n", format()); + result.append(buffer); + ::write(fd, result.string(), result.size()); + return NO_ERROR; +} + +String8 AudioStreamOutStub::getParameters(const String8& keys) +{ + AudioParameter param = AudioParameter(keys); + return param.toString(); +} + +status_t AudioStreamOutStub::getRenderPosition(uint32_t *dspFrames) +{ + return INVALID_OPERATION; +} + +// ---------------------------------------------------------------------------- + +status_t AudioStreamInStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate, + AudioSystem::audio_in_acoustics acoustics) +{ + return NO_ERROR; +} + +ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes) +{ + // fake timing for audio input + usleep(bytes * 1000000 / sizeof(int16_t) / AudioSystem::popCount(channels()) / sampleRate()); + memset(buffer, 0, bytes); + return bytes; +} + +status_t AudioStreamInStub::dump(int fd, const Vector& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + snprintf(buffer, SIZE, "AudioStreamInStub::dump\n"); + result.append(buffer); + snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate()); + result.append(buffer); + snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize()); + result.append(buffer); + snprintf(buffer, SIZE, "\tchannels: %d\n", channels()); + result.append(buffer); + snprintf(buffer, SIZE, "\tformat: %d\n", format()); + result.append(buffer); + ::write(fd, result.string(), result.size()); + return NO_ERROR; +} + +String8 AudioStreamInStub::getParameters(const String8& keys) +{ + AudioParameter param = AudioParameter(keys); + return param.toString(); +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/hardware/libhardware_legacy/audio/AudioHardwareStub.h b/hardware/libhardware_legacy/audio/AudioHardwareStub.h new file mode 100644 index 00000000..0858f371 --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioHardwareStub.h @@ -0,0 +1,106 @@ +/* //device/servers/AudioFlinger/AudioHardwareStub.h +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef ANDROID_AUDIO_HARDWARE_STUB_H +#define ANDROID_AUDIO_HARDWARE_STUB_H + +#include +#include + +#include + +namespace android_audio_legacy { + +// ---------------------------------------------------------------------------- + +class AudioStreamOutStub : public AudioStreamOut { +public: + virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate); + virtual uint32_t sampleRate() const { return 44100; } + virtual size_t bufferSize() const { return 4096; } + virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; } + virtual int format() const { return AudioSystem::PCM_16_BIT; } + virtual uint32_t latency() const { return 0; } + virtual status_t setVolume(float left, float right) { return NO_ERROR; } + virtual ssize_t write(const void* buffer, size_t bytes); + virtual status_t standby(); + virtual status_t dump(int fd, const Vector& args); + virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;} + virtual String8 getParameters(const String8& keys); + virtual status_t getRenderPosition(uint32_t *dspFrames); +}; + +class AudioStreamInStub : public AudioStreamIn { +public: + virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics); + virtual uint32_t sampleRate() const { return 8000; } + virtual size_t bufferSize() const { return 320; } + virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; } + virtual int format() const { return AudioSystem::PCM_16_BIT; } + virtual status_t setGain(float gain) { return NO_ERROR; } + virtual ssize_t read(void* buffer, ssize_t bytes); + virtual status_t dump(int fd, const Vector& args); + virtual status_t standby() { return NO_ERROR; } + virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;} + virtual String8 getParameters(const String8& keys); + virtual unsigned int getInputFramesLost() const { return 0; } +}; + +class AudioHardwareStub : public AudioHardwareBase +{ +public: + AudioHardwareStub(); + virtual ~AudioHardwareStub(); + virtual status_t initCheck(); + virtual status_t setVoiceVolume(float volume); + virtual status_t setMasterVolume(float volume); + + // mic mute + virtual status_t setMicMute(bool state) { mMicMute = state; return NO_ERROR; } + virtual status_t getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; } + + // create I/O streams + virtual AudioStreamOut* openOutputStream( + uint32_t devices, + int *format=0, + uint32_t *channels=0, + uint32_t *sampleRate=0, + status_t *status=0); + virtual void closeOutputStream(AudioStreamOut* out); + + virtual AudioStreamIn* openInputStream( + uint32_t devices, + int *format, + uint32_t *channels, + uint32_t *sampleRate, + status_t *status, + AudioSystem::audio_in_acoustics acoustics); + virtual void closeInputStream(AudioStreamIn* in); + +protected: + virtual status_t dump(int fd, const Vector& args); + + bool mMicMute; +private: + status_t dumpInternals(int fd, const Vector& args); +}; + +// ---------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_AUDIO_HARDWARE_STUB_H diff --git a/hardware/libhardware_legacy/audio/AudioPolicyCompatClient.cpp b/hardware/libhardware_legacy/audio/AudioPolicyCompatClient.cpp new file mode 100644 index 00000000..bb0059c7 --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioPolicyCompatClient.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AudioPolicyCompatClient" +//#define LOG_NDEBUG 0 + +#include + +#include +#include +#include +#include + +#include + +#include "AudioPolicyCompatClient.h" + +namespace android_audio_legacy { + +audio_module_handle_t AudioPolicyCompatClient::loadHwModule(const char *moduleName) +{ + return mServiceOps->load_hw_module(mService, moduleName); +} + +audio_io_handle_t AudioPolicyCompatClient::openOutput(audio_module_handle_t module, + audio_devices_t *pDevices, + uint32_t *pSamplingRate, + audio_format_t *pFormat, + audio_channel_mask_t *pChannelMask, + uint32_t *pLatencyMs, + audio_output_flags_t flags) +{ + return mServiceOps->open_output_on_module(mService, module, pDevices, pSamplingRate, + pFormat, pChannelMask, pLatencyMs, + flags); +} + +audio_io_handle_t AudioPolicyCompatClient::openDuplicateOutput(audio_io_handle_t output1, + audio_io_handle_t output2) +{ + return mServiceOps->open_duplicate_output(mService, output1, output2); +} + +status_t AudioPolicyCompatClient::closeOutput(audio_io_handle_t output) +{ + return mServiceOps->close_output(mService, output); +} + +status_t AudioPolicyCompatClient::suspendOutput(audio_io_handle_t output) +{ + return mServiceOps->suspend_output(mService, output); +} + +status_t AudioPolicyCompatClient::restoreOutput(audio_io_handle_t output) +{ + return mServiceOps->restore_output(mService, output); +} + +audio_io_handle_t AudioPolicyCompatClient::openInput(audio_module_handle_t module, + audio_devices_t *pDevices, + uint32_t *pSamplingRate, + audio_format_t *pFormat, + audio_channel_mask_t *pChannelMask) +{ + return mServiceOps->open_input_on_module(mService, module, pDevices, + pSamplingRate, pFormat, pChannelMask); +} + +status_t AudioPolicyCompatClient::closeInput(audio_io_handle_t input) +{ + return mServiceOps->close_input(mService, input); +} + +status_t AudioPolicyCompatClient::setStreamOutput(AudioSystem::stream_type stream, + audio_io_handle_t output) +{ + return mServiceOps->set_stream_output(mService, (audio_stream_type_t)stream, + output); +} + +status_t AudioPolicyCompatClient::moveEffects(int session, audio_io_handle_t srcOutput, + audio_io_handle_t dstOutput) +{ + return mServiceOps->move_effects(mService, session, srcOutput, dstOutput); +} + +String8 AudioPolicyCompatClient::getParameters(audio_io_handle_t ioHandle, const String8& keys) +{ + char *str; + String8 out_str8; + + str = mServiceOps->get_parameters(mService, ioHandle, keys.string()); + out_str8 = String8(str); + free(str); + + return out_str8; +} + +void AudioPolicyCompatClient::setParameters(audio_io_handle_t ioHandle, + const String8& keyValuePairs, + int delayMs) +{ + mServiceOps->set_parameters(mService, ioHandle, keyValuePairs.string(), + delayMs); +} + +status_t AudioPolicyCompatClient::setStreamVolume( + AudioSystem::stream_type stream, + float volume, + audio_io_handle_t output, + int delayMs) +{ + return mServiceOps->set_stream_volume(mService, (audio_stream_type_t)stream, + volume, output, delayMs); +} + +#ifdef QCOM_FM_ENABLED +status_t AudioPolicyCompatClient::setFmVolume(float volume, + int delayMs) +{ + return mServiceOps->set_fm_volume(mService, volume, delayMs); +} +#endif + +status_t AudioPolicyCompatClient::startTone(ToneGenerator::tone_type tone, + AudioSystem::stream_type stream) +{ + return mServiceOps->start_tone(mService, + AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION, + (audio_stream_type_t)stream); +} + +status_t AudioPolicyCompatClient::stopTone() +{ + return mServiceOps->stop_tone(mService); +} + +status_t AudioPolicyCompatClient::setVoiceVolume(float volume, int delayMs) +{ + return mServiceOps->set_voice_volume(mService, volume, delayMs); +} + +}; // namespace android_audio_legacy diff --git a/hardware/libhardware_legacy/audio/AudioPolicyCompatClient.h b/hardware/libhardware_legacy/audio/AudioPolicyCompatClient.h new file mode 100644 index 00000000..d468126f --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioPolicyCompatClient.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AUDIOPOLICYCLIENTLEGACY_H +#define ANDROID_AUDIOPOLICYCLIENTLEGACY_H + +#include +#include +#include + +#include +#include + +/************************************/ +/* FOR BACKWARDS COMPATIBILITY ONLY */ +/************************************/ +namespace android_audio_legacy { + +class AudioPolicyCompatClient : public AudioPolicyClientInterface { +public: + AudioPolicyCompatClient(struct audio_policy_service_ops *serviceOps, + void *service) : + mServiceOps(serviceOps) , mService(service) {} + + virtual audio_module_handle_t loadHwModule(const char *moduleName); + + virtual audio_io_handle_t openOutput(audio_module_handle_t module, + audio_devices_t *pDevices, + uint32_t *pSamplingRate, + audio_format_t *pFormat, + audio_channel_mask_t *pChannelMask, + uint32_t *pLatencyMs, + audio_output_flags_t flags); + virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, + audio_io_handle_t output2); + virtual status_t closeOutput(audio_io_handle_t output); + virtual status_t suspendOutput(audio_io_handle_t output); + virtual status_t restoreOutput(audio_io_handle_t output); + virtual audio_io_handle_t openInput(audio_module_handle_t module, + audio_devices_t *pDevices, + uint32_t *pSamplingRate, + audio_format_t *pFormat, + audio_channel_mask_t *pChannelMask); + virtual status_t closeInput(audio_io_handle_t input); + virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output); + virtual status_t moveEffects(int session, + audio_io_handle_t srcOutput, + audio_io_handle_t dstOutput); + + virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys); + virtual void setParameters(audio_io_handle_t ioHandle, + const String8& keyValuePairs, + int delayMs = 0); + virtual status_t setStreamVolume(AudioSystem::stream_type stream, + float volume, + audio_io_handle_t output, + int delayMs = 0); +#ifdef QCOM_FM_ENABLED + virtual status_t setFmVolume(float volume, int delayMs = 0); +#endif + virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream); + virtual status_t stopTone(); + virtual status_t setVoiceVolume(float volume, int delayMs = 0); + +private: + struct audio_policy_service_ops* mServiceOps; + void* mService; +}; + +}; // namespace android_audio_legacy + +#endif // ANDROID_AUDIOPOLICYCLIENTLEGACY_H diff --git a/hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp b/hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp new file mode 100644 index 00000000..9c48d350 --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp @@ -0,0 +1,3885 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AudioPolicyManagerBase" +//#define LOG_NDEBUG 0 + +//#define VERY_VERBOSE_LOGGING +#ifdef VERY_VERBOSE_LOGGING +#define ALOGVV ALOGV +#else +#define ALOGVV(a...) do { } while(0) +#endif + +// A device mask for all audio input devices that are considered "virtual" when evaluating +// active inputs in getActiveInput() +#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX + +#include +#include +#include +#include +#include +#include + +namespace android_audio_legacy { + +// ---------------------------------------------------------------------------- +// AudioPolicyInterface implementation +// ---------------------------------------------------------------------------- + + +status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device, + AudioSystem::device_connection_state state, + const char *device_address) +{ + SortedVector outputs; + + ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); + + // connect/disconnect only 1 device at a time + if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE; + + if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) { + ALOGE("setDeviceConnectionState() invalid address: %s", device_address); + return BAD_VALUE; + } + + // handle output devices + if (audio_is_output_device(device)) { + + if (!mHasA2dp && audio_is_a2dp_device(device)) { + ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device); + return BAD_VALUE; + } + if (!mHasUsb && audio_is_usb_device(device)) { + ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device); + return BAD_VALUE; + } + if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) { + ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device); + return BAD_VALUE; + } + + // save a copy of the opened output descriptors before any output is opened or closed + // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies() + mPreviousOutputs = mOutputs; + switch (state) + { + // handle output device connection + case AudioSystem::DEVICE_STATE_AVAILABLE: + if (mAvailableOutputDevices & device) { + ALOGW("setDeviceConnectionState() device already connected: %x", device); + return INVALID_OPERATION; + } + ALOGV("setDeviceConnectionState() connecting device %x", device); + + if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) { + return INVALID_OPERATION; + } + ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs", + outputs.size()); + // register new device as available + mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device); + + if (!outputs.isEmpty()) { + String8 paramStr; + if (mHasA2dp && audio_is_a2dp_device(device)) { + // handle A2DP device connection + AudioParameter param; + param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address)); + paramStr = param.toString(); + mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); + mA2dpSuspended = false; + } else if (audio_is_bluetooth_sco_device(device)) { + // handle SCO device connection + mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); + } else if (mHasUsb && audio_is_usb_device(device)) { + // handle USB device connection + mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN); + paramStr = mUsbCardAndDevice; + } + // not currently handling multiple simultaneous submixes: ignoring remote submix + // case and address + if (!paramStr.isEmpty()) { + for (size_t i = 0; i < outputs.size(); i++) { + mpClientInterface->setParameters(outputs[i], paramStr); + } + } + } + break; + // handle output device disconnection + case AudioSystem::DEVICE_STATE_UNAVAILABLE: { + if (!(mAvailableOutputDevices & device)) { + ALOGW("setDeviceConnectionState() device not connected: %x", device); + return INVALID_OPERATION; + } + + ALOGV("setDeviceConnectionState() disconnecting device %x", device); + // remove device from available output devices + mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device); + + checkOutputsForDevice(device, state, outputs); + if (mHasA2dp && audio_is_a2dp_device(device)) { + // handle A2DP device disconnection + mA2dpDeviceAddress = ""; + mA2dpSuspended = false; + } else if (audio_is_bluetooth_sco_device(device)) { + // handle SCO device disconnection + mScoDeviceAddress = ""; + } else if (mHasUsb && audio_is_usb_device(device)) { + // handle USB device disconnection + mUsbCardAndDevice = ""; + } + // not currently handling multiple simultaneous submixes: ignoring remote submix + // case and address + } break; + + default: + ALOGE("setDeviceConnectionState() invalid state: %x", state); + return BAD_VALUE; + } + + checkA2dpSuspend(); + checkOutputForAllStrategies(); + // outputs must be closed after checkOutputForAllStrategies() is executed + if (!outputs.isEmpty()) { + for (size_t i = 0; i < outputs.size(); i++) { + // close unused outputs after device disconnection or direct outputs that have been + // opened by checkOutputsForDevice() to query dynamic parameters + if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) || + (mOutputs.valueFor(outputs[i])->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { + closeOutput(outputs[i]); + } + } + } + + updateDevicesAndOutputs(); + for (size_t i = 0; i < mOutputs.size(); i++) { + // do not force device change on duplicated output because if device is 0, it will + // also force a device 0 for the two outputs it is duplicated to which may override + // a valid device selection on those outputs. + setOutputDevice(mOutputs.keyAt(i), + getNewDevice(mOutputs.keyAt(i), true /*fromCache*/), + !mOutputs.valueAt(i)->isDuplicated(), + 0); + } + + if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) { + device = AUDIO_DEVICE_IN_WIRED_HEADSET; + } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO || + device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET || + device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) { + device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; + } else { + return NO_ERROR; + } + } + // handle input devices + if (audio_is_input_device(device)) { + + switch (state) + { + // handle input device connection + case AudioSystem::DEVICE_STATE_AVAILABLE: { + if (mAvailableInputDevices & device) { + ALOGW("setDeviceConnectionState() device already connected: %d", device); + return INVALID_OPERATION; + } + mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN); + } + break; + + // handle input device disconnection + case AudioSystem::DEVICE_STATE_UNAVAILABLE: { + if (!(mAvailableInputDevices & device)) { + ALOGW("setDeviceConnectionState() device not connected: %d", device); + return INVALID_OPERATION; + } + mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device); + } break; + + default: + ALOGE("setDeviceConnectionState() invalid state: %x", state); + return BAD_VALUE; + } + + audio_io_handle_t activeInput = getActiveInput(); + if (activeInput != 0) { + AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); + audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); + if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { + ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d", + inputDesc->mDevice, newDevice, activeInput); + inputDesc->mDevice = newDevice; + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); + mpClientInterface->setParameters(activeInput, param.toString()); + } + } + + return NO_ERROR; + } + + ALOGW("setDeviceConnectionState() invalid device: %x", device); + return BAD_VALUE; +} + +AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(audio_devices_t device, + const char *device_address) +{ + AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE; + String8 address = String8(device_address); + if (audio_is_output_device(device)) { + if (device & mAvailableOutputDevices) { + if (audio_is_a2dp_device(device) && + (!mHasA2dp || (address != "" && mA2dpDeviceAddress != address))) { + return state; + } + if (audio_is_bluetooth_sco_device(device) && + address != "" && mScoDeviceAddress != address) { + return state; + } + if (audio_is_usb_device(device) && + (!mHasUsb || (address != "" && mUsbCardAndDevice != address))) { + ALOGE("getDeviceConnectionState() invalid device: %x", device); + return state; + } + if (audio_is_remote_submix_device((audio_devices_t)device) && !mHasRemoteSubmix) { + return state; + } + state = AudioSystem::DEVICE_STATE_AVAILABLE; + } + } else if (audio_is_input_device(device)) { + if (device & mAvailableInputDevices) { + state = AudioSystem::DEVICE_STATE_AVAILABLE; + } + } + + return state; +} + +void AudioPolicyManagerBase::setPhoneState(int state) +{ + ALOGV("setPhoneState() state %d", state); + audio_devices_t newDevice = AUDIO_DEVICE_NONE; + if (state < 0 || state >= AudioSystem::NUM_MODES) { + ALOGW("setPhoneState() invalid state %d", state); + return; + } + + if (state == mPhoneState ) { + ALOGW("setPhoneState() setting same state %d", state); + return; + } + + // if leaving call state, handle special case of active streams + // pertaining to sonification strategy see handleIncallSonification() + if (isInCall()) { + ALOGV("setPhoneState() in call state management: new state is %d", state); + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + handleIncallSonification(stream, false, true); + } + } + + // store previous phone state for management of sonification strategy below + int oldState = mPhoneState; + mPhoneState = state; + bool force = false; + + // are we entering or starting a call + if (!isStateInCall(oldState) && isStateInCall(state)) { + ALOGV(" Entering call in setPhoneState()"); + // force routing command to audio hardware when starting a call + // even if no device change is needed + force = true; + } else if (isStateInCall(oldState) && !isStateInCall(state)) { + ALOGV(" Exiting call in setPhoneState()"); + // force routing command to audio hardware when exiting a call + // even if no device change is needed + force = true; + } else if (isStateInCall(state) && (state != oldState)) { + ALOGV(" Switching between telephony and VoIP in setPhoneState()"); + // force routing command to audio hardware when switching between telephony and VoIP + // even if no device change is needed + force = true; + } + + // check for device and output changes triggered by new phone state + newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/); + checkA2dpSuspend(); + checkOutputForAllStrategies(); + updateDevicesAndOutputs(); + + AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput); + + // force routing command to audio hardware when ending call + // even if no device change is needed + if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) { + newDevice = hwOutputDesc->device(); + } + + // when changing from ring tone to in call mode, mute the ringing tone + // immediately and delay the route change to avoid sending the ring tone + // tail into the earpiece or headset. + int delayMs = 0; + if (isStateInCall(state) && oldState == AudioSystem::MODE_RINGTONE) { + // delay the device change command by twice the output latency to have some margin + // and be sure that audio buffers not yet affected by the mute are out when + // we actually apply the route change + delayMs = hwOutputDesc->mLatency*2; + setStreamMute(AudioSystem::RING, true, mPrimaryOutput); + } + + if (isStateInCall(state)) { + for (size_t i = 0; i < mOutputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueAt(i); + //take the biggest latency for all outputs + if (delayMs < (int)desc->mLatency*2) { + delayMs = desc->mLatency*2; + } + //mute STRATEGY_MEDIA on all outputs + if (desc->strategyRefCount(STRATEGY_MEDIA) != 0) { + setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i)); + setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS, + getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/)); + } + } + } + + // change routing is necessary + setOutputDevice(mPrimaryOutput, newDevice, force, delayMs); + + // if entering in call state, handle special case of active streams + // pertaining to sonification strategy see handleIncallSonification() + if (isStateInCall(state)) { + ALOGV("setPhoneState() in call state management: new state is %d", state); + // unmute the ringing tone after a sufficient delay if it was muted before + // setting output device above + if (oldState == AudioSystem::MODE_RINGTONE) { + setStreamMute(AudioSystem::RING, false, mPrimaryOutput, MUTE_TIME_MS); + } + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + handleIncallSonification(stream, true, true); + } + } + + // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE + if (state == AudioSystem::MODE_RINGTONE && + isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) { + mLimitRingtoneVolume = true; + } else { + mLimitRingtoneVolume = false; + } +} + +void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) +{ + ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); + + bool forceVolumeReeval = false; + switch(usage) { + case AudioSystem::FOR_COMMUNICATION: + if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO && + config != AudioSystem::FORCE_NONE) { + ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config); + return; + } + forceVolumeReeval = true; + mForceUse[usage] = config; + break; + case AudioSystem::FOR_MEDIA: + if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP && + config != AudioSystem::FORCE_WIRED_ACCESSORY && + config != AudioSystem::FORCE_ANALOG_DOCK && + config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE && + config != AudioSystem::FORCE_NO_BT_A2DP) { + ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config); + return; + } + mForceUse[usage] = config; + break; + case AudioSystem::FOR_RECORD: + if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY && + config != AudioSystem::FORCE_NONE) { + ALOGW("setForceUse() invalid config %d for FOR_RECORD", config); + return; + } + mForceUse[usage] = config; + break; + case AudioSystem::FOR_DOCK: + if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK && + config != AudioSystem::FORCE_BT_DESK_DOCK && + config != AudioSystem::FORCE_WIRED_ACCESSORY && + config != AudioSystem::FORCE_ANALOG_DOCK && + config != AudioSystem::FORCE_DIGITAL_DOCK) { + ALOGW("setForceUse() invalid config %d for FOR_DOCK", config); + } + forceVolumeReeval = true; + mForceUse[usage] = config; + break; + case AudioSystem::FOR_SYSTEM: + if (config != AudioSystem::FORCE_NONE && + config != AudioSystem::FORCE_SYSTEM_ENFORCED) { + ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config); + } + forceVolumeReeval = true; + mForceUse[usage] = config; + break; + default: + ALOGW("setForceUse() invalid usage %d", usage); + break; + } + + // check for device and output changes triggered by new force usage + checkA2dpSuspend(); + checkOutputForAllStrategies(); + updateDevicesAndOutputs(); + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_io_handle_t output = mOutputs.keyAt(i); + audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/); + setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); + if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) { + applyStreamVolumes(output, newDevice, 0, true); + } + } + + audio_io_handle_t activeInput = getActiveInput(); + if (activeInput != 0) { + AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); + audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); + if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { + ALOGV("setForceUse() changing device from %x to %x for input %d", + inputDesc->mDevice, newDevice, activeInput); + inputDesc->mDevice = newDevice; + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); + mpClientInterface->setParameters(activeInput, param.toString()); + } + } + +} + +AudioSystem::forced_config AudioPolicyManagerBase::getForceUse(AudioSystem::force_use usage) +{ + return mForceUse[usage]; +} + +void AudioPolicyManagerBase::setSystemProperty(const char* property, const char* value) +{ + ALOGV("setSystemProperty() property %s, value %s", property, value); +} + +AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getProfileForDirectOutput( + audio_devices_t device, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + audio_output_flags_t flags) +{ + for (size_t i = 0; i < mHwModules.size(); i++) { + if (mHwModules[i]->mHandle == 0) { + continue; + } + for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { + IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; + if (profile->isCompatibleProfile(device, samplingRate, format, + channelMask, +#ifdef QCOM_HARDWARE + (audio_output_flags_t)(flags|AUDIO_OUTPUT_FLAG_DIRECT))) +#else + AUDIO_OUTPUT_FLAG_DIRECT)) +#endif + { + if (mAvailableOutputDevices & profile->mSupportedDevices) { + return mHwModules[i]->mOutputProfiles[j]; + } + } + } + } + return 0; +} + +audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + AudioSystem::output_flags flags) +{ + audio_io_handle_t output = 0; + uint32_t latency = 0; + routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); + audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/); + ALOGV("getOutput() stream %d, samplingRate %d, format %d, channelMask %x, flags %x", + stream, samplingRate, format, channelMask, flags); + +#ifdef AUDIO_POLICY_TEST + if (mCurOutput != 0) { + ALOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelMask %x, mDirectOutput %d", + mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput); + + if (mTestOutputs[mCurOutput] == 0) { + ALOGV("getOutput() opening test output"); + AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL); + outputDesc->mDevice = mTestDevice; + outputDesc->mSamplingRate = mTestSamplingRate; + outputDesc->mFormat = mTestFormat; + outputDesc->mChannelMask = mTestChannels; + outputDesc->mLatency = mTestLatencyMs; + outputDesc->mFlags = (audio_output_flags_t)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0); + outputDesc->mRefCount[stream] = 0; + mTestOutputs[mCurOutput] = mpClientInterface->openOutput(0, &outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannelMask, + &outputDesc->mLatency, + outputDesc->mFlags); + if (mTestOutputs[mCurOutput]) { + AudioParameter outputCmd = AudioParameter(); + outputCmd.addInt(String8("set_id"),mCurOutput); + mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString()); + addOutput(mTestOutputs[mCurOutput], outputDesc); + } + } + return mTestOutputs[mCurOutput]; + } +#endif //AUDIO_POLICY_TEST + + IOProfile *profile = getProfileForDirectOutput(device, + samplingRate, + format, + channelMask, + (audio_output_flags_t)flags); + + if (profile != NULL) { + + ALOGV("getOutput() opening direct output device %x", device); + + AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(profile); + outputDesc->mDevice = device; + outputDesc->mSamplingRate = samplingRate; + outputDesc->mFormat = (audio_format_t)format; + outputDesc->mChannelMask = (audio_channel_mask_t)channelMask; + outputDesc->mLatency = 0; + outputDesc->mFlags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);; + outputDesc->mRefCount[stream] = 0; + outputDesc->mStopTime[stream] = 0; + output = mpClientInterface->openOutput(profile->mModule->mHandle, + &outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannelMask, + &outputDesc->mLatency, + outputDesc->mFlags); + + // only accept an output with the requested parameters + if (output == 0 || + (samplingRate != 0 && samplingRate != outputDesc->mSamplingRate) || + (format != 0 && format != outputDesc->mFormat) || + (channelMask != 0 && channelMask != outputDesc->mChannelMask)) { + ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d," + "format %d %d, channelMask %04x %04x", output, samplingRate, + outputDesc->mSamplingRate, format, outputDesc->mFormat, channelMask, + outputDesc->mChannelMask); + if (output != 0) { + mpClientInterface->closeOutput(output); + } + delete outputDesc; + return 0; + } + addOutput(output, outputDesc); + ALOGV("getOutput() returns direct output %d", output); + return output; + } + + // ignoring channel mask due to downmix capability in mixer + + // open a non direct output + + // get which output is suitable for the specified stream. The actual routing change will happen + // when startOutput() will be called + SortedVector outputs = getOutputsForDevice(device, mOutputs); + + output = selectOutput(outputs, flags); + + ALOGW_IF((output ==0), "getOutput() could not find output for stream %d, samplingRate %d," + "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags); + + ALOGV("getOutput() returns output %d", output); + + return output; +} + +audio_io_handle_t AudioPolicyManagerBase::selectOutput(const SortedVector& outputs, + AudioSystem::output_flags flags) +{ + // select one output among several that provide a path to a particular device or set of + // devices (the list was previously build by getOutputsForDevice()). + // The priority is as follows: + // 1: the output with the highest number of requested policy flags + // 2: the primary output + // 3: the first output in the list + + if (outputs.size() == 0) { + return 0; + } + if (outputs.size() == 1) { + return outputs[0]; + } + + int maxCommonFlags = 0; + audio_io_handle_t outputFlags = 0; + audio_io_handle_t outputPrimary = 0; + + for (size_t i = 0; i < outputs.size(); i++) { + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(outputs[i]); + if (!outputDesc->isDuplicated()) { + int commonFlags = (int)AudioSystem::popCount(outputDesc->mProfile->mFlags & flags); + if (commonFlags > maxCommonFlags) { + outputFlags = outputs[i]; + maxCommonFlags = commonFlags; + ALOGV("selectOutput() commonFlags for output %d, %04x", outputs[i], commonFlags); + } + if (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) { + outputPrimary = outputs[i]; + } + } + } + + if (outputFlags != 0) { + return outputFlags; + } + if (outputPrimary != 0) { + return outputPrimary; + } + + return outputs[0]; +} + +status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) +{ + ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + ALOGW("startOutput() unknow output %d", output); + return BAD_VALUE; + } + + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + + // increment usage count for this stream on the requested output: + // NOTE that the usage count is the same for duplicated output and hardware output which is + // necessary for a correct control of hardware output routing by startOutput() and stopOutput() + outputDesc->changeRefCount(stream, 1); + + if (outputDesc->mRefCount[stream] == 1) { + audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/); + routing_strategy strategy = getStrategy(stream); + bool shouldWait = (strategy == STRATEGY_SONIFICATION) || + (strategy == STRATEGY_SONIFICATION_RESPECTFUL); + uint32_t waitMs = 0; + bool force = false; + for (size_t i = 0; i < mOutputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueAt(i); + if (desc != outputDesc) { + // force a device change if any other output is managed by the same hw + // module and has a current device selection that differs from selected device. + // In this case, the audio HAL must receive the new device selection so that it can + // change the device currently selected by the other active output. + if (outputDesc->sharesHwModuleWith(desc) && + desc->device() != newDevice) { + force = true; + } + // wait for audio on other active outputs to be presented when starting + // a notification so that audio focus effect can propagate. + uint32_t latency = desc->latency(); + if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) { + waitMs = latency; + } + } + } + uint32_t muteWaitMs = setOutputDevice(output, newDevice, force); + + // handle special case for sonification while in call + if (isInCall()) { + handleIncallSonification(stream, true, false); + } + + // apply volume rules for current stream and device if necessary + checkAndSetVolume(stream, + mStreams[stream].getVolumeIndex(newDevice), + output, + newDevice); + + // update the outputs if starting an output with a stream that can affect notification + // routing + handleNotificationRoutingForStream(stream); + if (waitMs > muteWaitMs) { + usleep((waitMs - muteWaitMs) * 2 * 1000); + } + } + return NO_ERROR; +} + + +status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) +{ + ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + ALOGW("stopOutput() unknow output %d", output); + return BAD_VALUE; + } + + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + + // handle special case for sonification while in call + if (isInCall()) { + handleIncallSonification(stream, false, false); + } + + if (outputDesc->mRefCount[stream] > 0) { + // decrement usage count of this stream on the output + outputDesc->changeRefCount(stream, -1); + // store time at which the stream was stopped - see isStreamActive() + if (outputDesc->mRefCount[stream] == 0) { + outputDesc->mStopTime[stream] = systemTime(); + audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/); + // delay the device switch by twice the latency because stopOutput() is executed when + // the track stop() command is received and at that time the audio track buffer can + // still contain data that needs to be drained. The latency only covers the audio HAL + // and kernel buffers. Also the latency does not always include additional delay in the + // audio path (audio DSP, CODEC ...) + setOutputDevice(output, newDevice, false, outputDesc->mLatency*2); + + // force restoring the device selection on other active outputs if it differs from the + // one being selected for this output + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_io_handle_t curOutput = mOutputs.keyAt(i); + AudioOutputDescriptor *desc = mOutputs.valueAt(i); + if (curOutput != output && + desc->refCount() != 0 && + outputDesc->sharesHwModuleWith(desc) && + newDevice != desc->device()) { + setOutputDevice(curOutput, + getNewDevice(curOutput, false /*fromCache*/), + true, + outputDesc->mLatency*2); + } + } + // update the outputs if stopping one with a stream that can affect notification routing + handleNotificationRoutingForStream(stream); + } + return NO_ERROR; + } else { + ALOGW("stopOutput() refcount is already 0 for output %d", output); + return INVALID_OPERATION; + } +} + +void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output) +{ + ALOGV("releaseOutput() %d", output); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + ALOGW("releaseOutput() releasing unknown output %d", output); + return; + } + +#ifdef AUDIO_POLICY_TEST + int testIndex = testOutputIndex(output); + if (testIndex != 0) { + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + if (outputDesc->refCount() == 0) { + mpClientInterface->closeOutput(output); + delete mOutputs.valueAt(index); + mOutputs.removeItem(output); + mTestOutputs[testIndex] = 0; + } + return; + } +#endif //AUDIO_POLICY_TEST + + if (mOutputs.valueAt(index)->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) { + mpClientInterface->closeOutput(output); + delete mOutputs.valueAt(index); + mOutputs.removeItem(output); + mPreviousOutputs = mOutputs; + } + +} + +audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + AudioSystem::audio_in_acoustics acoustics) +{ + audio_io_handle_t input = 0; + audio_devices_t device = getDeviceForInputSource(inputSource); + + ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x", + inputSource, samplingRate, format, channelMask, acoustics); + + if (device == AUDIO_DEVICE_NONE) { + ALOGW("getInput() could not find device for inputSource %d", inputSource); + return 0; + } + + // adapt channel selection to input source + switch(inputSource) { + case AUDIO_SOURCE_VOICE_UPLINK: + channelMask = AudioSystem::CHANNEL_IN_VOICE_UPLINK; + break; + case AUDIO_SOURCE_VOICE_DOWNLINK: + channelMask = AudioSystem::CHANNEL_IN_VOICE_DNLINK; + break; + case AUDIO_SOURCE_VOICE_CALL: + channelMask = (AudioSystem::CHANNEL_IN_VOICE_UPLINK | AudioSystem::CHANNEL_IN_VOICE_DNLINK); + break; + default: + break; + } + + IOProfile *profile = getInputProfile(device, + samplingRate, + format, + channelMask); + if (profile == NULL) { + ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d," + "channelMask %04x", + device, samplingRate, format, channelMask); + return 0; + } + + if (profile->mModule->mHandle == 0) { + ALOGE("getInput(): HW module %s not opened", profile->mModule->mName); + return 0; + } + + AudioInputDescriptor *inputDesc = new AudioInputDescriptor(profile); + + inputDesc->mInputSource = inputSource; + inputDesc->mDevice = device; + inputDesc->mSamplingRate = samplingRate; + inputDesc->mFormat = (audio_format_t)format; + inputDesc->mChannelMask = (audio_channel_mask_t)channelMask; + inputDesc->mRefCount = 0; + input = mpClientInterface->openInput(profile->mModule->mHandle, + &inputDesc->mDevice, + &inputDesc->mSamplingRate, + &inputDesc->mFormat, + &inputDesc->mChannelMask); + + // only accept input with the exact requested set of parameters + if (input == 0 || + (samplingRate != inputDesc->mSamplingRate) || + (format != inputDesc->mFormat) || + (channelMask != inputDesc->mChannelMask)) { + ALOGV("getInput() failed opening input: samplingRate %d, format %d, channelMask %d", + samplingRate, format, channelMask); + if (input != 0) { + mpClientInterface->closeInput(input); + } + delete inputDesc; + return 0; + } + mInputs.add(input, inputDesc); + return input; +} + +status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input) +{ + ALOGV("startInput() input %d", input); + ssize_t index = mInputs.indexOfKey(input); + if (index < 0) { + ALOGW("startInput() unknow input %d", input); + return BAD_VALUE; + } + AudioInputDescriptor *inputDesc = mInputs.valueAt(index); + +#ifdef AUDIO_POLICY_TEST + if (mTestInput == 0) +#endif //AUDIO_POLICY_TEST + { + // refuse 2 active AudioRecord clients at the same time + if (getActiveInput() != 0) { + ALOGW("startInput() input %d failed: other input already started", input); + return INVALID_OPERATION; + } + } + + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice); + + param.addInt(String8(AudioParameter::keyInputSource), (int)inputDesc->mInputSource); + ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource); + + mpClientInterface->setParameters(input, param.toString()); + + inputDesc->mRefCount = 1; + return NO_ERROR; +} + +status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input) +{ + ALOGV("stopInput() input %d", input); + ssize_t index = mInputs.indexOfKey(input); + if (index < 0) { + ALOGW("stopInput() unknow input %d", input); + return BAD_VALUE; + } + AudioInputDescriptor *inputDesc = mInputs.valueAt(index); + + if (inputDesc->mRefCount == 0) { + ALOGW("stopInput() input %d already stopped", input); + return INVALID_OPERATION; + } else { + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), 0); + mpClientInterface->setParameters(input, param.toString()); + inputDesc->mRefCount = 0; + return NO_ERROR; + } +} + +void AudioPolicyManagerBase::releaseInput(audio_io_handle_t input) +{ + ALOGV("releaseInput() %d", input); + ssize_t index = mInputs.indexOfKey(input); + if (index < 0) { + ALOGW("releaseInput() releasing unknown input %d", input); + return; + } + mpClientInterface->closeInput(input); + delete mInputs.valueAt(index); + mInputs.removeItem(input); + ALOGV("releaseInput() exit"); +} + +void AudioPolicyManagerBase::initStreamVolume(AudioSystem::stream_type stream, + int indexMin, + int indexMax) +{ + ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax); + if (indexMin < 0 || indexMin >= indexMax) { + ALOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d", stream , indexMin, indexMax); + return; + } + mStreams[stream].mIndexMin = indexMin; + mStreams[stream].mIndexMax = indexMax; +} + +status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type stream, + int index, + audio_devices_t device) +{ + + if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) { + return BAD_VALUE; + } + if (!audio_is_output_device(device)) { + return BAD_VALUE; + } + + // Force max volume if stream cannot be muted + if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax; + + ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d", + stream, device, index); + + // if device is AUDIO_DEVICE_OUT_DEFAULT set default value and + // clear all device specific values + if (device == AUDIO_DEVICE_OUT_DEFAULT) { + mStreams[stream].mIndexCur.clear(); + } + mStreams[stream].mIndexCur.add(device, index); + + // compute and apply stream volume on all outputs according to connected device + status_t status = NO_ERROR; + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_devices_t curDevice = + getDeviceForVolume(mOutputs.valueAt(i)->device()); +#ifndef ICS_AUDIO_BLOB + if (device == curDevice) +#endif + { + status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice); + if (volStatus != NO_ERROR) { + status = volStatus; + } + } + } + return status; +} + +status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type stream, + int *index, + audio_devices_t device) +{ + if (index == NULL) { + return BAD_VALUE; + } +#ifndef ICS_AUDIO_BLOB + if (!audio_is_output_device(device)) { + return BAD_VALUE; + } + // if device is AUDIO_DEVICE_OUT_DEFAULT, return volume for device corresponding to + // the strategy the stream belongs to. + if (device == AUDIO_DEVICE_OUT_DEFAULT) { + device = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/); + } + device = getDeviceForVolume(device); + + *index = mStreams[stream].getVolumeIndex(device); +#else + *index = mStreams[stream].mIndexCur.valueAt(0); +#endif + ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index); + return NO_ERROR; +} + +audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(const effect_descriptor_t *desc) +{ + ALOGV("getOutputForEffect()"); + // apply simple rule where global effects are attached to the same output as MUSIC streams + + routing_strategy strategy = getStrategy(AudioSystem::MUSIC); + audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/); + SortedVector dstOutputs = getOutputsForDevice(device, mOutputs); + int outIdx = 0; + for (size_t i = 0; i < dstOutputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueFor(dstOutputs[i]); + if (desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { + outIdx = i; + } + } + return dstOutputs[outIdx]; +} + +status_t AudioPolicyManagerBase::registerEffect(const effect_descriptor_t *desc, + audio_io_handle_t io, + uint32_t strategy, + int session, + int id) +{ + ssize_t index = mOutputs.indexOfKey(io); + if (index < 0) { + index = mInputs.indexOfKey(io); + if (index < 0) { + ALOGW("registerEffect() unknown io %d", io); + return INVALID_OPERATION; + } + } + + if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) { + ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB", + desc->name, desc->memoryUsage); + return INVALID_OPERATION; + } + mTotalEffectsMemory += desc->memoryUsage; + ALOGV("registerEffect() effect %s, io %d, strategy %d session %d id %d", + desc->name, io, strategy, session, id); + ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory); + + EffectDescriptor *pDesc = new EffectDescriptor(); + memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t)); + pDesc->mIo = io; + pDesc->mStrategy = (routing_strategy)strategy; + pDesc->mSession = session; + pDesc->mEnabled = false; + + mEffects.add(id, pDesc); + + return NO_ERROR; +} + +status_t AudioPolicyManagerBase::unregisterEffect(int id) +{ + ssize_t index = mEffects.indexOfKey(id); + if (index < 0) { + ALOGW("unregisterEffect() unknown effect ID %d", id); + return INVALID_OPERATION; + } + + EffectDescriptor *pDesc = mEffects.valueAt(index); + + setEffectEnabled(pDesc, false); + + if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) { + ALOGW("unregisterEffect() memory %d too big for total %d", + pDesc->mDesc.memoryUsage, mTotalEffectsMemory); + pDesc->mDesc.memoryUsage = mTotalEffectsMemory; + } + mTotalEffectsMemory -= pDesc->mDesc.memoryUsage; + ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d", + pDesc->mDesc.name, id, pDesc->mDesc.memoryUsage, mTotalEffectsMemory); + + mEffects.removeItem(id); + delete pDesc; + + return NO_ERROR; +} + +status_t AudioPolicyManagerBase::setEffectEnabled(int id, bool enabled) +{ + ssize_t index = mEffects.indexOfKey(id); + if (index < 0) { + ALOGW("unregisterEffect() unknown effect ID %d", id); + return INVALID_OPERATION; + } + + return setEffectEnabled(mEffects.valueAt(index), enabled); +} + +status_t AudioPolicyManagerBase::setEffectEnabled(EffectDescriptor *pDesc, bool enabled) +{ + if (enabled == pDesc->mEnabled) { + ALOGV("setEffectEnabled(%s) effect already %s", + enabled?"true":"false", enabled?"enabled":"disabled"); + return INVALID_OPERATION; + } + + if (enabled) { + if (mTotalEffectsCpuLoad + pDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) { + ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS", + pDesc->mDesc.name, (float)pDesc->mDesc.cpuLoad/10); + return INVALID_OPERATION; + } + mTotalEffectsCpuLoad += pDesc->mDesc.cpuLoad; + ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad); + } else { + if (mTotalEffectsCpuLoad < pDesc->mDesc.cpuLoad) { + ALOGW("setEffectEnabled(false) CPU load %d too high for total %d", + pDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad); + pDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad; + } + mTotalEffectsCpuLoad -= pDesc->mDesc.cpuLoad; + ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad); + } + pDesc->mEnabled = enabled; + return NO_ERROR; +} + +bool AudioPolicyManagerBase::isStreamActive(int stream, uint32_t inPastMs) const +{ + nsecs_t sysTime = systemTime(); + for (size_t i = 0; i < mOutputs.size(); i++) { + if (mOutputs.valueAt(i)->mRefCount[stream] != 0 || + ns2ms(sysTime - mOutputs.valueAt(i)->mStopTime[stream]) < inPastMs) { + return true; + } + } + return false; +} + +bool AudioPolicyManagerBase::isSourceActive(audio_source_t source) const +{ + for (size_t i = 0; i < mInputs.size(); i++) { + const AudioInputDescriptor * inputDescriptor = mInputs.valueAt(i); + if ((inputDescriptor->mInputSource == (int) source) + && (inputDescriptor->mRefCount > 0)) { + return true; + } + } + return false; +} + + + +status_t AudioPolicyManagerBase::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this); + result.append(buffer); + + snprintf(buffer, SIZE, " Primary Output: %d\n", mPrimaryOutput); + result.append(buffer); + snprintf(buffer, SIZE, " A2DP device address: %s\n", mA2dpDeviceAddress.string()); + result.append(buffer); + snprintf(buffer, SIZE, " SCO device address: %s\n", mScoDeviceAddress.string()); + result.append(buffer); + snprintf(buffer, SIZE, " USB audio ALSA %s\n", mUsbCardAndDevice.string()); + result.append(buffer); + snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices); + result.append(buffer); + snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices); + result.append(buffer); + snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState); + result.append(buffer); + snprintf(buffer, SIZE, " Force use for communications %d\n", mForceUse[AudioSystem::FOR_COMMUNICATION]); + result.append(buffer); + snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AudioSystem::FOR_MEDIA]); + result.append(buffer); + snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AudioSystem::FOR_RECORD]); + result.append(buffer); + snprintf(buffer, SIZE, " Force use for dock %d\n", mForceUse[AudioSystem::FOR_DOCK]); + result.append(buffer); + snprintf(buffer, SIZE, " Force use for system %d\n", mForceUse[AudioSystem::FOR_SYSTEM]); + result.append(buffer); + write(fd, result.string(), result.size()); + + + snprintf(buffer, SIZE, "\nHW Modules dump:\n"); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < mHwModules.size(); i++) { + snprintf(buffer, SIZE, "- HW Module %d:\n", i + 1); + write(fd, buffer, strlen(buffer)); + mHwModules[i]->dump(fd); + } + + snprintf(buffer, SIZE, "\nOutputs dump:\n"); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < mOutputs.size(); i++) { + snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i)); + write(fd, buffer, strlen(buffer)); + mOutputs.valueAt(i)->dump(fd); + } + + snprintf(buffer, SIZE, "\nInputs dump:\n"); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < mInputs.size(); i++) { + snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i)); + write(fd, buffer, strlen(buffer)); + mInputs.valueAt(i)->dump(fd); + } + + snprintf(buffer, SIZE, "\nStreams dump:\n"); + write(fd, buffer, strlen(buffer)); + snprintf(buffer, SIZE, + " Stream Can be muted Index Min Index Max Index Cur [device : index]...\n"); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { + snprintf(buffer, SIZE, " %02d ", i); + write(fd, buffer, strlen(buffer)); + mStreams[i].dump(fd); + } + + snprintf(buffer, SIZE, "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB\n", + (float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory); + write(fd, buffer, strlen(buffer)); + + snprintf(buffer, SIZE, "Registered effects:\n"); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < mEffects.size(); i++) { + snprintf(buffer, SIZE, "- Effect %d dump:\n", mEffects.keyAt(i)); + write(fd, buffer, strlen(buffer)); + mEffects.valueAt(i)->dump(fd); + } + + + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- +// AudioPolicyManagerBase +// ---------------------------------------------------------------------------- + +AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface) + : +#ifdef AUDIO_POLICY_TEST + Thread(false), +#endif //AUDIO_POLICY_TEST + mPrimaryOutput((audio_io_handle_t)0), + mAvailableOutputDevices(AUDIO_DEVICE_NONE), + mPhoneState(AudioSystem::MODE_NORMAL), + mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f), + mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0), + mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false) +{ + mpClientInterface = clientInterface; + + for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) { + mForceUse[i] = AudioSystem::FORCE_NONE; + } + + initializeVolumeCurves(); + + mA2dpDeviceAddress = String8(""); + mScoDeviceAddress = String8(""); + mUsbCardAndDevice = String8(""); + + if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) { + if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) { + ALOGE("could not load audio policy configuration file, setting defaults"); + defaultAudioPolicyConfig(); + } + } + + // open all output streams needed to access attached devices + for (size_t i = 0; i < mHwModules.size(); i++) { + mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName); + if (mHwModules[i]->mHandle == 0) { + ALOGW("could not open HW module %s", mHwModules[i]->mName); + continue; + } + // open all output streams needed to access attached devices + for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) + { + const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j]; +#ifdef QCOM_HARDWARE + if ( (outProfile->mSupportedDevices & mAttachedOutputDevices) && + !(outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) ) +#else + if (outProfile->mSupportedDevices & mAttachedOutputDevices) +#endif + { + AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile); + outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice & + outProfile->mSupportedDevices); + audio_io_handle_t output = mpClientInterface->openOutput( + outProfile->mModule->mHandle, + &outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannelMask, + &outputDesc->mLatency, + outputDesc->mFlags); + if (output == 0) { + delete outputDesc; + } else { + mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | + (outProfile->mSupportedDevices & mAttachedOutputDevices)); + if (mPrimaryOutput == 0 && + outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) { + mPrimaryOutput = output; + } + addOutput(output, outputDesc); + setOutputDevice(output, + (audio_devices_t)(mDefaultOutputDevice & + outProfile->mSupportedDevices), + true); + } + } + } + } + + ALOGE_IF((mAttachedOutputDevices & ~mAvailableOutputDevices), + "Not output found for attached devices %08x", + (mAttachedOutputDevices & ~mAvailableOutputDevices)); + + ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output"); + + updateDevicesAndOutputs(); + +#ifdef AUDIO_POLICY_TEST + if (mPrimaryOutput != 0) { + AudioParameter outputCmd = AudioParameter(); + outputCmd.addInt(String8("set_id"), 0); + mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString()); + + mTestDevice = AUDIO_DEVICE_OUT_SPEAKER; + mTestSamplingRate = 44100; + mTestFormat = AudioSystem::PCM_16_BIT; + mTestChannels = AudioSystem::CHANNEL_OUT_STEREO; + mTestLatencyMs = 0; + mCurOutput = 0; + mDirectOutput = false; + for (int i = 0; i < NUM_TEST_OUTPUTS; i++) { + mTestOutputs[i] = 0; + } + + const size_t SIZE = 256; + char buffer[SIZE]; + snprintf(buffer, SIZE, "AudioPolicyManagerTest"); + run(buffer, ANDROID_PRIORITY_AUDIO); + } +#endif //AUDIO_POLICY_TEST +} + +AudioPolicyManagerBase::~AudioPolicyManagerBase() +{ +#ifdef AUDIO_POLICY_TEST + exit(); +#endif //AUDIO_POLICY_TEST + for (size_t i = 0; i < mOutputs.size(); i++) { + mpClientInterface->closeOutput(mOutputs.keyAt(i)); + delete mOutputs.valueAt(i); + } + for (size_t i = 0; i < mInputs.size(); i++) { + mpClientInterface->closeInput(mInputs.keyAt(i)); + delete mInputs.valueAt(i); + } + for (size_t i = 0; i < mHwModules.size(); i++) { + delete mHwModules[i]; + } +} + +status_t AudioPolicyManagerBase::initCheck() +{ + return (mPrimaryOutput == 0) ? NO_INIT : NO_ERROR; +} + +#ifdef AUDIO_POLICY_TEST +bool AudioPolicyManagerBase::threadLoop() +{ + ALOGV("entering threadLoop()"); + while (!exitPending()) + { + String8 command; + int valueInt; + String8 value; + + Mutex::Autolock _l(mLock); + mWaitWorkCV.waitRelative(mLock, milliseconds(50)); + + command = mpClientInterface->getParameters(0, String8("test_cmd_policy")); + AudioParameter param = AudioParameter(command); + + if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR && + valueInt != 0) { + ALOGV("Test command %s received", command.string()); + String8 target; + if (param.get(String8("target"), target) != NO_ERROR) { + target = "Manager"; + } + if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) { + param.remove(String8("test_cmd_policy_output")); + mCurOutput = valueInt; + } + if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) { + param.remove(String8("test_cmd_policy_direct")); + if (value == "false") { + mDirectOutput = false; + } else if (value == "true") { + mDirectOutput = true; + } + } + if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) { + param.remove(String8("test_cmd_policy_input")); + mTestInput = valueInt; + } + + if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) { + param.remove(String8("test_cmd_policy_format")); + int format = AudioSystem::INVALID_FORMAT; + if (value == "PCM 16 bits") { + format = AudioSystem::PCM_16_BIT; + } else if (value == "PCM 8 bits") { + format = AudioSystem::PCM_8_BIT; + } else if (value == "Compressed MP3") { + format = AudioSystem::MP3; + } + if (format != AudioSystem::INVALID_FORMAT) { + if (target == "Manager") { + mTestFormat = format; + } else if (mTestOutputs[mCurOutput] != 0) { + AudioParameter outputParam = AudioParameter(); + outputParam.addInt(String8("format"), format); + mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); + } + } + } + if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) { + param.remove(String8("test_cmd_policy_channels")); + int channels = 0; + + if (value == "Channels Stereo") { + channels = AudioSystem::CHANNEL_OUT_STEREO; + } else if (value == "Channels Mono") { + channels = AudioSystem::CHANNEL_OUT_MONO; + } + if (channels != 0) { + if (target == "Manager") { + mTestChannels = channels; + } else if (mTestOutputs[mCurOutput] != 0) { + AudioParameter outputParam = AudioParameter(); + outputParam.addInt(String8("channels"), channels); + mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); + } + } + } + if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) { + param.remove(String8("test_cmd_policy_sampleRate")); + if (valueInt >= 0 && valueInt <= 96000) { + int samplingRate = valueInt; + if (target == "Manager") { + mTestSamplingRate = samplingRate; + } else if (mTestOutputs[mCurOutput] != 0) { + AudioParameter outputParam = AudioParameter(); + outputParam.addInt(String8("sampling_rate"), samplingRate); + mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); + } + } + } + + if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) { + param.remove(String8("test_cmd_policy_reopen")); + + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput); + mpClientInterface->closeOutput(mPrimaryOutput); + + audio_module_handle_t moduleHandle = outputDesc->mModule->mHandle; + + delete mOutputs.valueFor(mPrimaryOutput); + mOutputs.removeItem(mPrimaryOutput); + + AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL); + outputDesc->mDevice = AUDIO_DEVICE_OUT_SPEAKER; + mPrimaryOutput = mpClientInterface->openOutput(moduleHandle, + &outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannelMask, + &outputDesc->mLatency, + outputDesc->mFlags); + if (mPrimaryOutput == 0) { + ALOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d", + outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannelMask); + } else { + AudioParameter outputCmd = AudioParameter(); + outputCmd.addInt(String8("set_id"), 0); + mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString()); + addOutput(mPrimaryOutput, outputDesc); + } + } + + + mpClientInterface->setParameters(0, String8("test_cmd_policy=")); + } + } + return false; +} + +void AudioPolicyManagerBase::exit() +{ + { + AutoMutex _l(mLock); + requestExit(); + mWaitWorkCV.signal(); + } + requestExitAndWait(); +} + +int AudioPolicyManagerBase::testOutputIndex(audio_io_handle_t output) +{ + for (int i = 0; i < NUM_TEST_OUTPUTS; i++) { + if (output == mTestOutputs[i]) return i; + } + return 0; +} +#endif //AUDIO_POLICY_TEST + +// --- + +void AudioPolicyManagerBase::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc) +{ + outputDesc->mId = id; + mOutputs.add(id, outputDesc); +} + + +status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device, + AudioSystem::device_connection_state state, + SortedVector& outputs) +{ + AudioOutputDescriptor *desc; + + if (state == AudioSystem::DEVICE_STATE_AVAILABLE) { + // first list already open outputs that can be routed to this device + for (size_t i = 0; i < mOutputs.size(); i++) { + desc = mOutputs.valueAt(i); + if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices & device)) { + ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i)); + outputs.add(mOutputs.keyAt(i)); + } + } + // then look for output profiles that can be routed to this device + SortedVector profiles; + for (size_t i = 0; i < mHwModules.size(); i++) + { + if (mHwModules[i]->mHandle == 0) { + continue; + } + for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) + { + if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices & device) { + ALOGV("checkOutputsForDevice(): adding profile %d from module %d", j, i); + profiles.add(mHwModules[i]->mOutputProfiles[j]); + } + } + } + + if (profiles.isEmpty() && outputs.isEmpty()) { + ALOGW("checkOutputsForDevice(): No output available for device %04x", device); + return BAD_VALUE; + } + + // open outputs for matching profiles if needed. Direct outputs are also opened to + // query for dynamic parameters and will be closed later by setDeviceConnectionState() + for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) { + IOProfile *profile = profiles[profile_index]; + + // nothing to do if one output is already opened for this profile + size_t j; + for (j = 0; j < mOutputs.size(); j++) { + desc = mOutputs.valueAt(j); + if (!desc->isDuplicated() && desc->mProfile == profile) { + break; + } + } + if (j != mOutputs.size()) { + continue; + } + + ALOGV("opening output for device %08x", device); + desc = new AudioOutputDescriptor(profile); + desc->mDevice = device; + audio_io_handle_t output = 0; +#ifdef QCOM_HARDWARE + if (!(desc->mFlags & AUDIO_OUTPUT_FLAG_LPA || desc->mFlags & AUDIO_OUTPUT_FLAG_TUNNEL || + desc->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX)) { +#endif + output = mpClientInterface->openOutput(profile->mModule->mHandle, + &desc->mDevice, + &desc->mSamplingRate, + &desc->mFormat, + &desc->mChannelMask, + &desc->mLatency, + desc->mFlags); +#ifdef QCOM_HARDWARE + } +#endif + if (output != 0) { + if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { + String8 reply; + char *value; + if (profile->mSamplingRates[0] == 0) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)); + ALOGV("checkOutputsForDevice() direct output sup sampling rates %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadSamplingRates(value + 1, profile); + } + } + if (profile->mFormats[0] == 0) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS)); + ALOGV("checkOutputsForDevice() direct output sup formats %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadFormats(value + 1, profile); + } + } + if (profile->mChannelMasks[0] == 0) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS)); + ALOGV("checkOutputsForDevice() direct output sup channel masks %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadOutChannels(value + 1, profile); + } + } + if (((profile->mSamplingRates[0] == 0) && + (profile->mSamplingRates.size() < 2)) || + ((profile->mFormats[0] == 0) && + (profile->mFormats.size() < 2)) || + ((profile->mFormats[0] == 0) && + (profile->mChannelMasks.size() < 2))) { + ALOGW("checkOutputsForDevice() direct output missing param"); + mpClientInterface->closeOutput(output); + output = 0; + } else { + addOutput(output, desc); + } + } else { + audio_io_handle_t duplicatedOutput = 0; + // add output descriptor + addOutput(output, desc); + // set initial stream volume for device + applyStreamVolumes(output, device, 0, true); + + //TODO: configure audio effect output stage here + + // open a duplicating output thread for the new output and the primary output + duplicatedOutput = mpClientInterface->openDuplicateOutput(output, + mPrimaryOutput); + if (duplicatedOutput != 0) { + // add duplicated output descriptor + AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL); + dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput); + dupOutputDesc->mOutput2 = mOutputs.valueFor(output); + dupOutputDesc->mSamplingRate = desc->mSamplingRate; + dupOutputDesc->mFormat = desc->mFormat; + dupOutputDesc->mChannelMask = desc->mChannelMask; + dupOutputDesc->mLatency = desc->mLatency; + addOutput(duplicatedOutput, dupOutputDesc); + applyStreamVolumes(duplicatedOutput, device, 0, true); + } else { + ALOGW("checkOutputsForDevice() could not open dup output for %d and %d", + mPrimaryOutput, output); + mpClientInterface->closeOutput(output); + mOutputs.removeItem(output); + output = 0; + } + } + } + if (output == 0) { + ALOGW("checkOutputsForDevice() could not open output for device %x", device); + delete desc; + profiles.removeAt(profile_index); + profile_index--; + } else { + outputs.add(output); + ALOGV("checkOutputsForDevice(): adding output %d", output); + } + } + + if (profiles.isEmpty()) { + ALOGW("checkOutputsForDevice(): No output available for device %04x", device); + return BAD_VALUE; + } + } else { + // check if one opened output is not needed any more after disconnecting one device + for (size_t i = 0; i < mOutputs.size(); i++) { + desc = mOutputs.valueAt(i); + if (!desc->isDuplicated() && + !(desc->mProfile->mSupportedDevices & mAvailableOutputDevices)) { + ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i)); + outputs.add(mOutputs.keyAt(i)); + } + } + for (size_t i = 0; i < mHwModules.size(); i++) + { + if (mHwModules[i]->mHandle == 0) { + continue; + } + for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) + { + IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; + if ((profile->mSupportedDevices & device) && + (profile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { + ALOGV("checkOutputsForDevice(): clearing direct output profile %d on module %d", + j, i); + if (profile->mSamplingRates[0] == 0) { + profile->mSamplingRates.clear(); + profile->mSamplingRates.add(0); + } + if (profile->mFormats[0] == 0) { + profile->mFormats.clear(); + profile->mFormats.add((audio_format_t)0); + } + if (profile->mChannelMasks[0] == 0) { + profile->mChannelMasks.clear(); + profile->mChannelMasks.add((audio_channel_mask_t)0); + } + } + } + } + } + return NO_ERROR; +} + +void AudioPolicyManagerBase::closeOutput(audio_io_handle_t output) +{ + ALOGV("closeOutput(%d)", output); + + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + if (outputDesc == NULL) { + ALOGW("closeOutput() unknown output %d", output); + return; + } + + // look for duplicated outputs connected to the output being removed. + for (size_t i = 0; i < mOutputs.size(); i++) { + AudioOutputDescriptor *dupOutputDesc = mOutputs.valueAt(i); + if (dupOutputDesc->isDuplicated() && + (dupOutputDesc->mOutput1 == outputDesc || + dupOutputDesc->mOutput2 == outputDesc)) { + AudioOutputDescriptor *outputDesc2; + if (dupOutputDesc->mOutput1 == outputDesc) { + outputDesc2 = dupOutputDesc->mOutput2; + } else { + outputDesc2 = dupOutputDesc->mOutput1; + } + // As all active tracks on duplicated output will be deleted, + // and as they were also referenced on the other output, the reference + // count for their stream type must be adjusted accordingly on + // the other output. + for (int j = 0; j < (int)AudioSystem::NUM_STREAM_TYPES; j++) { + int refCount = dupOutputDesc->mRefCount[j]; + outputDesc2->changeRefCount((AudioSystem::stream_type)j,-refCount); + } + audio_io_handle_t duplicatedOutput = mOutputs.keyAt(i); + ALOGV("closeOutput() closing also duplicated output %d", duplicatedOutput); + + mpClientInterface->closeOutput(duplicatedOutput); + delete mOutputs.valueFor(duplicatedOutput); + mOutputs.removeItem(duplicatedOutput); + } + } + + AudioParameter param; + param.add(String8("closing"), String8("true")); + mpClientInterface->setParameters(output, param.toString()); + + mpClientInterface->closeOutput(output); + delete mOutputs.valueFor(output); + mOutputs.removeItem(output); +} + +SortedVector AudioPolicyManagerBase::getOutputsForDevice(audio_devices_t device, + DefaultKeyedVector openOutputs) +{ + SortedVector outputs; + + ALOGVV("getOutputsForDevice() device %04x", device); + for (size_t i = 0; i < openOutputs.size(); i++) { + ALOGVV("output %d isDuplicated=%d device=%04x", + i, openOutputs.valueAt(i)->isDuplicated(), openOutputs.valueAt(i)->supportedDevices()); + if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) { + ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i)); + outputs.add(openOutputs.keyAt(i)); + } + } + return outputs; +} + +bool AudioPolicyManagerBase::vectorsEqual(SortedVector& outputs1, + SortedVector& outputs2) +{ + if (outputs1.size() != outputs2.size()) { + return false; + } + for (size_t i = 0; i < outputs1.size(); i++) { + if (outputs1[i] != outputs2[i]) { + return false; + } + } + return true; +} + +void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy) +{ + audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/); + audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/); + SortedVector srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs); + SortedVector dstOutputs = getOutputsForDevice(newDevice, mOutputs); + + if (!vectorsEqual(srcOutputs,dstOutputs)) { + ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d", + strategy, srcOutputs[0], dstOutputs[0]); + // mute strategy while moving tracks from one output to another + for (size_t i = 0; i < srcOutputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueFor(srcOutputs[i]); + if (desc->strategyRefCount(strategy) != 0) { + setStrategyMute(strategy, true, srcOutputs[i]); + setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice); + } + } + + // Move effects associated to this strategy from previous output to new output + if (strategy == STRATEGY_MEDIA) { + int outIdx = 0; + for (size_t i = 0; i < dstOutputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueFor(dstOutputs[i]); + if (desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { + outIdx = i; + } + } + SortedVector moved; + for (size_t i = 0; i < mEffects.size(); i++) { + EffectDescriptor *desc = mEffects.valueAt(i); + if (desc->mSession == AUDIO_SESSION_OUTPUT_MIX && + desc->mIo != dstOutputs[outIdx]) { + if (moved.indexOf(desc->mIo) < 0) { + ALOGV("checkOutputForStrategy() moving effect %d to output %d", + mEffects.keyAt(i), dstOutputs[outIdx]); + mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, desc->mIo, + dstOutputs[outIdx]); + moved.add(desc->mIo); + } + desc->mIo = dstOutputs[outIdx]; + } + } + } + // Move tracks associated to this strategy from previous output to new output + for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { + if (getStrategy((AudioSystem::stream_type)i) == strategy) { + //FIXME see fixme on name change + mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, + dstOutputs[0] /* ignored */); + } + } + } +} + +void AudioPolicyManagerBase::checkOutputForAllStrategies() +{ + checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE); + checkOutputForStrategy(STRATEGY_PHONE); + checkOutputForStrategy(STRATEGY_SONIFICATION); + checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); + checkOutputForStrategy(STRATEGY_MEDIA); + checkOutputForStrategy(STRATEGY_DTMF); +} + +audio_io_handle_t AudioPolicyManagerBase::getA2dpOutput() +{ + if (!mHasA2dp) { + return 0; + } + + for (size_t i = 0; i < mOutputs.size(); i++) { + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i); + if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) { + return mOutputs.keyAt(i); + } + } + + return 0; +} + +void AudioPolicyManagerBase::checkA2dpSuspend() +{ + if (!mHasA2dp) { + return; + } + audio_io_handle_t a2dpOutput = getA2dpOutput(); + if (a2dpOutput == 0) { + return; + } + + // suspend A2DP output if: + // (NOT already suspended) && + // ((SCO device is connected && + // (forced usage for communication || for record is SCO))) || + // (phone state is ringing || in call) + // + // restore A2DP output if: + // (Already suspended) && + // ((SCO device is NOT connected || + // (forced usage NOT for communication && NOT for record is SCO))) && + // (phone state is NOT ringing && NOT in call) + // + if (mA2dpSuspended) { + if (((mScoDeviceAddress == "") || + ((mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO) && + (mForceUse[AudioSystem::FOR_RECORD] != AudioSystem::FORCE_BT_SCO))) && + ((mPhoneState != AudioSystem::MODE_IN_CALL) && + (mPhoneState != AudioSystem::MODE_RINGTONE))) { + + mpClientInterface->restoreOutput(a2dpOutput); + mA2dpSuspended = false; + } + } else { + if (((mScoDeviceAddress != "") && + ((mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || + (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO))) || + ((mPhoneState == AudioSystem::MODE_IN_CALL) || + (mPhoneState == AudioSystem::MODE_RINGTONE))) { + + mpClientInterface->suspendOutput(a2dpOutput); + mA2dpSuspended = true; + } + } +} + +audio_devices_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache) +{ + audio_devices_t device = AUDIO_DEVICE_NONE; + + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + // check the following by order of priority to request a routing change if necessary: + // 1: the strategy enforced audible is active on the output: + // use device for strategy enforced audible + // 2: we are in call or the strategy phone is active on the output: + // use device for strategy phone + // 3: the strategy sonification is active on the output: + // use device for strategy sonification + // 4: the strategy "respectful" sonification is active on the output: + // use device for strategy "respectful" sonification + // 5: the strategy media is active on the output: + // use device for strategy media + // 6: the strategy DTMF is active on the output: + // use device for strategy DTMF + if (outputDesc->isUsedByStrategy(STRATEGY_ENFORCED_AUDIBLE)) { + device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); + } else if (isInCall() || + outputDesc->isUsedByStrategy(STRATEGY_PHONE)) { + device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); + } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)){ + device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); + } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION_RESPECTFUL)) { + device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache); + } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) { + device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); + } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) { + device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); + } + + ALOGV("getNewDevice() selected device %x", device); + return device; +} + +uint32_t AudioPolicyManagerBase::getStrategyForStream(AudioSystem::stream_type stream) { + return (uint32_t)getStrategy(stream); +} + +audio_devices_t AudioPolicyManagerBase::getDevicesForStream(AudioSystem::stream_type stream) { + audio_devices_t devices; + // By checking the range of stream before calling getStrategy, we avoid + // getStrategy's behavior for invalid streams. getStrategy would do a ALOGE + // and then return STRATEGY_MEDIA, but we want to return the empty set. + if (stream < (AudioSystem::stream_type) 0 || stream >= AudioSystem::NUM_STREAM_TYPES) { + devices = AUDIO_DEVICE_NONE; + } else { + AudioPolicyManagerBase::routing_strategy strategy = getStrategy(stream); + devices = getDeviceForStrategy(strategy, true /*fromCache*/); + } + return devices; +} + +AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy( + AudioSystem::stream_type stream) { + // stream to strategy mapping + switch (stream) { + case AudioSystem::VOICE_CALL: + case AudioSystem::BLUETOOTH_SCO: + return STRATEGY_PHONE; + case AudioSystem::RING: + case AudioSystem::ALARM: + return STRATEGY_SONIFICATION; + case AudioSystem::NOTIFICATION: + return STRATEGY_SONIFICATION_RESPECTFUL; + case AudioSystem::DTMF: + return STRATEGY_DTMF; + default: + ALOGE("unknown stream type"); + case AudioSystem::SYSTEM: + // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs + // while key clicks are played produces a poor result + case AudioSystem::TTS: + case AudioSystem::MUSIC: +#ifdef QCOM_FM_ENABLED + case AudioSystem::FM: +#endif + return STRATEGY_MEDIA; + case AudioSystem::ENFORCED_AUDIBLE: + return STRATEGY_ENFORCED_AUDIBLE; + } +} + +void AudioPolicyManagerBase::handleNotificationRoutingForStream(AudioSystem::stream_type stream) { + switch(stream) { + case AudioSystem::MUSIC: + checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); + updateDevicesAndOutputs(); + break; + default: + break; + } +} + +audio_devices_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, + bool fromCache) +{ + uint32_t device = AUDIO_DEVICE_NONE; + + if (fromCache) { + ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x", + strategy, mDeviceForStrategy[strategy]); + return mDeviceForStrategy[strategy]; + } + + switch (strategy) { + + case STRATEGY_SONIFICATION_RESPECTFUL: + if (isInCall()) { + device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); + } else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { + // while media is playing (or has recently played), use the same device + device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/); + } else { + // when media is not playing anymore, fall back on the sonification behavior + device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); + } + + break; + + case STRATEGY_DTMF: + if (!isInCall()) { + // when off call, DTMF strategy follows the same rules as MEDIA strategy + device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/); + break; + } + // when in call, DTMF and PHONE strategies follow the same rules + // FALL THROUGH + + case STRATEGY_PHONE: + // for phone strategy, we first consider the forced use and then the available devices by order + // of priority + switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) { + case AudioSystem::FORCE_BT_SCO: + if (!isInCall() || strategy != STRATEGY_DTMF) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT; + if (device) break; + } + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO; + if (device) break; + // if SCO device is requested but no SCO device is available, fall back to default case + // FALL THROUGH + + default: // FORCE_NONE + // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP + if (mHasA2dp && !isInCall() && + (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && + (getA2dpOutput() != 0) && !mA2dpSuspended) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + if (device) break; + } + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET; + if (device) break; + if (mPhoneState != AudioSystem::MODE_IN_CALL) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + if (device) break; + } + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE; + if (device) break; + device = mDefaultOutputDevice; + if (device == AUDIO_DEVICE_NONE) { + ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE"); + } + break; + + case AudioSystem::FORCE_SPEAKER: + // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to + // A2DP speaker when forcing to speaker output + if (mHasA2dp && !isInCall() && + (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && + (getA2dpOutput() != 0) && !mA2dpSuspended) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + if (device) break; + } + if (mPhoneState != AudioSystem::MODE_IN_CALL) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + if (device) break; + } + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; + if (device) break; + device = mDefaultOutputDevice; + if (device == AUDIO_DEVICE_NONE) { + ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER"); + } + break; + } + break; + + case STRATEGY_SONIFICATION: + + // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by + // handleIncallSonification(). + if (isInCall()) { + device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/); + break; + } + // FALL THROUGH + + case STRATEGY_ENFORCED_AUDIBLE: + // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION + // except: + // - when in call where it doesn't default to STRATEGY_PHONE behavior + // - in countries where not enforced in which case it follows STRATEGY_MEDIA + + if ((strategy == STRATEGY_SONIFICATION) || + (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) { + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; + if (device == AUDIO_DEVICE_NONE) { + ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION"); + } + } + // The second device used for sonification is the same as the device used by media strategy + // FALL THROUGH + + case STRATEGY_MEDIA: { + uint32_t device2 = AUDIO_DEVICE_NONE; + if (strategy != STRATEGY_SONIFICATION) { + // no sonification on remote submix (e.g. WFD) + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + } + if ((device2 == AUDIO_DEVICE_NONE) && + mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && + (getA2dpOutput() != 0) && !mA2dpSuspended) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + } + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + } + if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) { + // no sonification on aux digital (e.g. HDMI) + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; + } + if ((device2 == AUDIO_DEVICE_NONE) && + (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; + } + + // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or + // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise + device |= device2; + if (device) break; + device = mDefaultOutputDevice; + if (device == AUDIO_DEVICE_NONE) { + ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA"); + } + } break; + + default: + ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy); + break; + } + + ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device); + return device; +} + +void AudioPolicyManagerBase::updateDevicesAndOutputs() +{ + for (int i = 0; i < NUM_STRATEGIES; i++) { + mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/); + } + mPreviousOutputs = mOutputs; +} + +uint32_t AudioPolicyManagerBase::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc, + audio_devices_t prevDevice, + uint32_t delayMs) +{ + // mute/unmute strategies using an incompatible device combination + // if muting, wait for the audio in pcm buffer to be drained before proceeding + // if unmuting, unmute only after the specified delay + if (outputDesc->isDuplicated()) { + return 0; + } + + uint32_t muteWaitMs = 0; + audio_devices_t device = outputDesc->device(); + bool shouldMute = (outputDesc->refCount() != 0) && + (AudioSystem::popCount(device) >= 2); + // temporary mute output if device selection changes to avoid volume bursts due to + // different per device volumes + bool tempMute = (outputDesc->refCount() != 0) && (device != prevDevice); + + for (size_t i = 0; i < NUM_STRATEGIES; i++) { + audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/); + bool mute = shouldMute && (curDevice & device) && (curDevice != device); + bool doMute = false; + + if (mute && !outputDesc->mStrategyMutedByDevice[i]) { + doMute = true; + outputDesc->mStrategyMutedByDevice[i] = true; + } else if (!mute && outputDesc->mStrategyMutedByDevice[i]){ + doMute = true; + outputDesc->mStrategyMutedByDevice[i] = false; + } + if (doMute || tempMute) { + for (size_t j = 0; j < mOutputs.size(); j++) { + AudioOutputDescriptor *desc = mOutputs.valueAt(j); + if ((desc->supportedDevices() & outputDesc->supportedDevices()) + == AUDIO_DEVICE_NONE) { + continue; + } + audio_io_handle_t curOutput = mOutputs.keyAt(j); + ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x) on output %d", + mute ? "muting" : "unmuting", i, curDevice, curOutput); + setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs); + if (desc->strategyRefCount((routing_strategy)i) != 0) { + if (tempMute) { + setStrategyMute((routing_strategy)i, true, curOutput); + setStrategyMute((routing_strategy)i, false, curOutput, +#ifdef QCOM_HARDWARE + desc->latency() * 4, +#else + desc->latency() * 2, +#endif + device); + } + if (tempMute || mute) { + if (muteWaitMs < desc->latency()) { + muteWaitMs = desc->latency(); + } + } + } + } + } + } + + // FIXME: should not need to double latency if volume could be applied immediately by the + // audioflinger mixer. We must account for the delay between now and the next time + // the audioflinger thread for this output will process a buffer (which corresponds to + // one buffer size, usually 1/2 or 1/4 of the latency). + muteWaitMs *= 2; + // wait for the PCM output buffers to empty before proceeding with the rest of the command + if (muteWaitMs > delayMs) { + muteWaitMs -= delayMs; + usleep(muteWaitMs * 1000); + return muteWaitMs; + } + return 0; +} + +uint32_t AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, + audio_devices_t device, + bool force, + int delayMs) +{ + ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs); + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + AudioParameter param; + uint32_t muteWaitMs = 0; + + if (outputDesc->isDuplicated()) { + muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs); + muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs); + return muteWaitMs; + } + // filter devices according to output selected + device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices); + + audio_devices_t prevDevice = outputDesc->mDevice; + + ALOGV("setOutputDevice() prevDevice %04x", prevDevice); + + if (device != AUDIO_DEVICE_NONE) { + outputDesc->mDevice = device; + } + muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs); + + // Do not change the routing if: + // - the requested device is AUDIO_DEVICE_NONE + // - the requested device is the same as current device and force is not specified. + // Doing this check here allows the caller to call setOutputDevice() without conditions + if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) { + ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output); + return muteWaitMs; + } + + ALOGV("setOutputDevice() changing device"); + // do the routing + param.addInt(String8(AudioParameter::keyRouting), (int)device); + mpClientInterface->setParameters(output, param.toString(), delayMs); + + // update stream volumes according to new device + applyStreamVolumes(output, device, delayMs); + + return muteWaitMs; +} + +AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getInputProfile(audio_devices_t device, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask) +{ + // Choose an input profile based on the requested capture parameters: select the first available + // profile supporting all requested parameters. + + for (size_t i = 0; i < mHwModules.size(); i++) + { + if (mHwModules[i]->mHandle == 0) { + continue; + } + for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++) + { + IOProfile *profile = mHwModules[i]->mInputProfiles[j]; + if (profile->isCompatibleProfile(device, samplingRate, format, + channelMask,(audio_output_flags_t)0)) { + return profile; + } + } + } + return NULL; +} + +audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource) +{ + uint32_t device = AUDIO_DEVICE_NONE; + + switch(inputSource) { + case AUDIO_SOURCE_DEFAULT: + case AUDIO_SOURCE_MIC: + case AUDIO_SOURCE_VOICE_RECOGNITION: + case AUDIO_SOURCE_VOICE_COMMUNICATION: + if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO && + mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { + device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; + } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) { + device = AUDIO_DEVICE_IN_WIRED_HEADSET; + } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) { + device = AUDIO_DEVICE_IN_BUILTIN_MIC; + } + break; + case AUDIO_SOURCE_CAMCORDER: + if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) { + device = AUDIO_DEVICE_IN_BACK_MIC; + } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) { + device = AUDIO_DEVICE_IN_BUILTIN_MIC; + } + break; + case AUDIO_SOURCE_VOICE_UPLINK: + case AUDIO_SOURCE_VOICE_DOWNLINK: + case AUDIO_SOURCE_VOICE_CALL: + if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) { + device = AUDIO_DEVICE_IN_VOICE_CALL; + } + break; + case AUDIO_SOURCE_REMOTE_SUBMIX: + if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { + device = AUDIO_DEVICE_IN_REMOTE_SUBMIX; + } + break; + default: + ALOGW("getDeviceForInputSource() invalid input source %d", inputSource); + break; + } + ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device); + return device; +} + +bool AudioPolicyManagerBase::isVirtualInputDevice(audio_devices_t device) +{ + if ((device & AUDIO_DEVICE_BIT_IN) != 0) { + device &= ~AUDIO_DEVICE_BIT_IN; + if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0)) + return true; + } + return false; +} + +audio_io_handle_t AudioPolicyManagerBase::getActiveInput(bool ignoreVirtualInputs) +{ + for (size_t i = 0; i < mInputs.size(); i++) { + const AudioInputDescriptor * input_descriptor = mInputs.valueAt(i); + if ((input_descriptor->mRefCount > 0) + && (!ignoreVirtualInputs || !isVirtualInputDevice(input_descriptor->mDevice))) { + return mInputs.keyAt(i); + } + } + return 0; +} + + +audio_devices_t AudioPolicyManagerBase::getDeviceForVolume(audio_devices_t device) +{ + if (device == AUDIO_DEVICE_NONE) { + // this happens when forcing a route update and no track is active on an output. + // In this case the returned category is not important. + device = AUDIO_DEVICE_OUT_SPEAKER; + } else if (AudioSystem::popCount(device) > 1) { + // Multiple device selection is either: + // - speaker + one other device: give priority to speaker in this case. + // - one A2DP device + another device: happens with duplicated output. In this case + // retain the device on the A2DP output as the other must not correspond to an active + // selection if not the speaker. + if (device & AUDIO_DEVICE_OUT_SPEAKER) { + device = AUDIO_DEVICE_OUT_SPEAKER; + } else { + device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP); + } + } + + ALOGW_IF(AudioSystem::popCount(device) != 1, + "getDeviceForVolume() invalid device combination: %08x", + device); + + return device; +} + +AudioPolicyManagerBase::device_category AudioPolicyManagerBase::getDeviceCategory(audio_devices_t device) +{ + switch(getDeviceForVolume(device)) { + case AUDIO_DEVICE_OUT_EARPIECE: + return DEVICE_CATEGORY_EARPIECE; + case AUDIO_DEVICE_OUT_WIRED_HEADSET: + case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: + case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP: + case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: +#if defined(QCOM_FM_ENABLED) || defined(STE_FM) + case AUDIO_DEVICE_OUT_FM: +#endif + return DEVICE_CATEGORY_HEADSET; + case AUDIO_DEVICE_OUT_SPEAKER: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: + case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: + case AUDIO_DEVICE_OUT_AUX_DIGITAL: + case AUDIO_DEVICE_OUT_USB_ACCESSORY: + case AUDIO_DEVICE_OUT_USB_DEVICE: + case AUDIO_DEVICE_OUT_REMOTE_SUBMIX: + default: + return DEVICE_CATEGORY_SPEAKER; + } +} + +float AudioPolicyManagerBase::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, + int indexInUi) +{ + device_category deviceCategory = getDeviceCategory(device); + const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory]; + + // the volume index in the UI is relative to the min and max volume indices for this stream type + int nbSteps = 1 + curve[VOLMAX].mIndex - + curve[VOLMIN].mIndex; + int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) / + (streamDesc.mIndexMax - streamDesc.mIndexMin); + + // find what part of the curve this index volume belongs to, or if it's out of bounds + int segment = 0; + if (volIdx < curve[VOLMIN].mIndex) { // out of bounds + return 0.0f; + } else if (volIdx < curve[VOLKNEE1].mIndex) { + segment = 0; + } else if (volIdx < curve[VOLKNEE2].mIndex) { + segment = 1; + } else if (volIdx <= curve[VOLMAX].mIndex) { + segment = 2; + } else { // out of bounds + return 1.0f; + } + + // linear interpolation in the attenuation table in dB + float decibels = curve[segment].mDBAttenuation + + ((float)(volIdx - curve[segment].mIndex)) * + ( (curve[segment+1].mDBAttenuation - + curve[segment].mDBAttenuation) / + ((float)(curve[segment+1].mIndex - + curve[segment].mIndex)) ); + + float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 ) + + ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f", + curve[segment].mIndex, volIdx, + curve[segment+1].mIndex, + curve[segment].mDBAttenuation, + decibels, + curve[segment+1].mDBAttenuation, + amplification); + + return amplification; +} + +const AudioPolicyManagerBase::VolumeCurvePoint + AudioPolicyManagerBase::sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT] = { + {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f} +}; + +const AudioPolicyManagerBase::VolumeCurvePoint + AudioPolicyManagerBase::sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = { + {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f} +}; + +const AudioPolicyManagerBase::VolumeCurvePoint + AudioPolicyManagerBase::sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = { + {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f} +}; + +const AudioPolicyManagerBase::VolumeCurvePoint + AudioPolicyManagerBase::sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT] = { + {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f} +}; + +// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks +// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets (See AudioService.java). +// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset. +const AudioPolicyManagerBase::VolumeCurvePoint + AudioPolicyManagerBase::sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = { + {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f} +}; + +const AudioPolicyManagerBase::VolumeCurvePoint + AudioPolicyManagerBase::sHeadsetSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = { + {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f} +}; + +const AudioPolicyManagerBase::VolumeCurvePoint + AudioPolicyManagerBase::sDefaultVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT] = { + {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f} +}; + +const AudioPolicyManagerBase::VolumeCurvePoint + AudioPolicyManagerBase::sSpeakerVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT] = { + {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f} +}; + +const AudioPolicyManagerBase::VolumeCurvePoint + *AudioPolicyManagerBase::sVolumeProfiles[AUDIO_STREAM_CNT] + [AudioPolicyManagerBase::DEVICE_CATEGORY_CNT] = { + { // AUDIO_STREAM_VOICE_CALL + sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET + sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultVoiceVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, + { // AUDIO_STREAM_SYSTEM + sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET + sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, + { // AUDIO_STREAM_RING + sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET + sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, + { // AUDIO_STREAM_MUSIC + sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET + sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, + { // AUDIO_STREAM_ALARM + sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET + sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, + { // AUDIO_STREAM_NOTIFICATION + sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET + sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, + { // AUDIO_STREAM_BLUETOOTH_SCO + sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET + sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultVoiceVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, + { // AUDIO_STREAM_ENFORCED_AUDIBLE + sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET + sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, + { // AUDIO_STREAM_DTMF + sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET + sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, + { // AUDIO_STREAM_TTS + sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET + sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, +#ifdef QCOM_FM_ENABLED + { // AUDIO_STREAM_FM + sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET + sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, +#endif + +}; + +void AudioPolicyManagerBase::initializeVolumeCurves() +{ + for (int i = 0; i < AUDIO_STREAM_CNT; i++) { + for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) { + mStreams[i].mVolumeCurve[j] = + sVolumeProfiles[i][j]; + } + } +} + +float AudioPolicyManagerBase::computeVolume(int stream, + int index, + audio_io_handle_t output, + audio_devices_t device) +{ + float volume = 1.0; + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + StreamDescriptor &streamDesc = mStreams[stream]; + + if (device == AUDIO_DEVICE_NONE) { + device = outputDesc->device(); + } + + // if volume is not 0 (not muted), force media volume to max on digital output + if (stream == AudioSystem::MUSIC && + index != mStreams[stream].mIndexMin && + (device == AUDIO_DEVICE_OUT_AUX_DIGITAL || + device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET || + device == AUDIO_DEVICE_OUT_USB_ACCESSORY || + device == AUDIO_DEVICE_OUT_USB_DEVICE)) { + return 1.0; + } + + volume = volIndexToAmpl(device, streamDesc, index); + + // if a headset is connected, apply the following rules to ring tones and notifications + // to avoid sound level bursts in user's ears: + // - always attenuate ring tones and notifications volume by 6dB + // - if music is playing, always limit the volume to current music volume, + // with a minimum threshold at -36dB so that notification is always perceived. + const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream); + if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + AUDIO_DEVICE_OUT_WIRED_HEADSET | + AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) && + ((stream_strategy == STRATEGY_SONIFICATION) + || (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL) + || (stream == AudioSystem::SYSTEM) + || ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) && + (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) && + streamDesc.mCanBeMuted) { + volume *= SONIFICATION_HEADSET_VOLUME_FACTOR; + // when the phone is ringing we must consider that music could have been paused just before + // by the music application and behave as if music was active if the last music track was + // just stopped + if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) || + mLimitRingtoneVolume) { + audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/); + float musicVol = computeVolume(AudioSystem::MUSIC, + mStreams[AudioSystem::MUSIC].getVolumeIndex(musicDevice), + output, + musicDevice); + float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ? + musicVol : SONIFICATION_HEADSET_VOLUME_MIN; + if (volume > minVol) { + volume = minVol; + ALOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol); + } + } + } + + return volume; +} + +status_t AudioPolicyManagerBase::checkAndSetVolume(int stream, + int index, + audio_io_handle_t output, + audio_devices_t device, + int delayMs, + bool force) +{ + + // do not change actual stream volume if the stream is muted + if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) { + ALOGVV("checkAndSetVolume() stream %d muted count %d", + stream, mOutputs.valueFor(output)->mMuteCount[stream]); + return NO_ERROR; + } + + // do not change in call volume if bluetooth is connected and vice versa + if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || + (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) { + ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm", + stream, mForceUse[AudioSystem::FOR_COMMUNICATION]); + return INVALID_OPERATION; + } + + float volume = computeVolume(stream, index, output, device); + // We actually change the volume if: + // - the float value returned by computeVolume() changed + // - the force flag is set + if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || + force) { + mOutputs.valueFor(output)->mCurVolume[stream] = volume; + ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs); + // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is + // enabled + if (stream == AudioSystem::BLUETOOTH_SCO) { + mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs); + } + mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); + } + + if (stream == AudioSystem::VOICE_CALL || + stream == AudioSystem::BLUETOOTH_SCO) { + float voiceVolume; + // Force voice volume to max for bluetooth SCO as volume is managed by the headset + if (stream == AudioSystem::VOICE_CALL) { + voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; + } else { + voiceVolume = 1.0; + } + + if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) { + mpClientInterface->setVoiceVolume(voiceVolume, delayMs); + mLastVoiceVolume = voiceVolume; + } + } + + return NO_ERROR; +} + +void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output, + audio_devices_t device, + int delayMs, + bool force) +{ + ALOGVV("applyStreamVolumes() for output %d and device %x", output, device); + + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + checkAndSetVolume(stream, + mStreams[stream].getVolumeIndex(device), + output, + device, + delayMs, + force); + } +} + +void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy, + bool on, + audio_io_handle_t output, + int delayMs, + audio_devices_t device) +{ + ALOGVV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output); + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + if (getStrategy((AudioSystem::stream_type)stream) == strategy) { + setStreamMute(stream, on, output, delayMs, device); + } + } +} + +void AudioPolicyManagerBase::setStreamMute(int stream, + bool on, + audio_io_handle_t output, + int delayMs, + audio_devices_t device) +{ + StreamDescriptor &streamDesc = mStreams[stream]; + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + if (device == AUDIO_DEVICE_NONE) { + device = outputDesc->device(); + } + + ALOGVV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d device %04x", + stream, on, output, outputDesc->mMuteCount[stream], device); + + if (on) { + if (outputDesc->mMuteCount[stream] == 0) { + if (streamDesc.mCanBeMuted && + ((stream != AudioSystem::ENFORCED_AUDIBLE) || + (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) { + checkAndSetVolume(stream, 0, output, device, delayMs); + } + } + // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored + outputDesc->mMuteCount[stream]++; + } else { + if (outputDesc->mMuteCount[stream] == 0) { + ALOGV("setStreamMute() unmuting non muted stream!"); + return; + } + if (--outputDesc->mMuteCount[stream] == 0) { + checkAndSetVolume(stream, + streamDesc.getVolumeIndex(device), + output, + device, + delayMs); + } + } +} + +void AudioPolicyManagerBase::handleIncallSonification(int stream, bool starting, bool stateChange) +{ + // if the stream pertains to sonification strategy and we are in call we must + // mute the stream if it is low visibility. If it is high visibility, we must play a tone + // in the device used for phone strategy and play the tone if the selected device does not + // interfere with the device used for phone strategy + // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as + // many times as there are active tracks on the output + const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream); + if ((stream_strategy == STRATEGY_SONIFICATION) || + ((stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL))) { + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput); + ALOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d", + stream, starting, outputDesc->mDevice, stateChange); + if (outputDesc->mRefCount[stream]) { + int muteCount = 1; + if (stateChange) { + muteCount = outputDesc->mRefCount[stream]; + } + if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) { + ALOGV("handleIncallSonification() low visibility, muteCount %d", muteCount); + for (int i = 0; i < muteCount; i++) { + setStreamMute(stream, starting, mPrimaryOutput); + } + } else { + ALOGV("handleIncallSonification() high visibility"); + if (outputDesc->device() & + getDeviceForStrategy(STRATEGY_PHONE, true /*fromCache*/)) { + ALOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount); + for (int i = 0; i < muteCount; i++) { + setStreamMute(stream, starting, mPrimaryOutput); + } + } + if (starting) { + mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL); + } else { + mpClientInterface->stopTone(); + } + } + } + } +} + +bool AudioPolicyManagerBase::isInCall() +{ + return isStateInCall(mPhoneState); +} + +bool AudioPolicyManagerBase::isStateInCall(int state) { + return ((state == AudioSystem::MODE_IN_CALL) || + (state == AudioSystem::MODE_IN_COMMUNICATION)); +} + +bool AudioPolicyManagerBase::needsDirectOuput(audio_stream_type_t stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + audio_devices_t device) +{ + return ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || + (format != 0 && !AudioSystem::isLinearPCM(format))); +} + +uint32_t AudioPolicyManagerBase::getMaxEffectsCpuLoad() +{ + return MAX_EFFECTS_CPU_LOAD; +} + +uint32_t AudioPolicyManagerBase::getMaxEffectsMemory() +{ + return MAX_EFFECTS_MEMORY; +} + +// --- AudioOutputDescriptor class implementation + +AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor( + const IOProfile *profile) + : mId(0), mSamplingRate(0), mFormat((audio_format_t)0), + mChannelMask((audio_channel_mask_t)0), mLatency(0), + mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), + mOutput1(0), mOutput2(0), mProfile(profile) +{ + // clear usage count for all stream types + for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { + mRefCount[i] = 0; + mCurVolume[i] = -1.0; + mMuteCount[i] = 0; + mStopTime[i] = 0; + } + for (int i = 0; i < NUM_STRATEGIES; i++) { + mStrategyMutedByDevice[i] = false; + } + if (profile != NULL) { + mSamplingRate = profile->mSamplingRates[0]; + mFormat = profile->mFormats[0]; + mChannelMask = profile->mChannelMasks[0]; + mFlags = profile->mFlags; + } +} + +audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::device() +{ + if (isDuplicated()) { + return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice); + } else { + return mDevice; + } +} + +uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::latency() +{ + if (isDuplicated()) { + return (mOutput1->mLatency > mOutput2->mLatency) ? mOutput1->mLatency : mOutput2->mLatency; + } else { + return mLatency; + } +} + +bool AudioPolicyManagerBase::AudioOutputDescriptor::sharesHwModuleWith( + const AudioOutputDescriptor *outputDesc) +{ + if (isDuplicated()) { + return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc); + } else if (outputDesc->isDuplicated()){ + return sharesHwModuleWith(outputDesc->mOutput1) || sharesHwModuleWith(outputDesc->mOutput2); + } else { + return (mProfile->mModule == outputDesc->mProfile->mModule); + } +} + +void AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta) +{ + // forward usage count change to attached outputs + if (isDuplicated()) { + mOutput1->changeRefCount(stream, delta); + mOutput2->changeRefCount(stream, delta); + } + if ((delta + (int)mRefCount[stream]) < 0) { + ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]); + mRefCount[stream] = 0; + return; + } + mRefCount[stream] += delta; + ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]); +} + +uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::refCount() +{ + uint32_t refcount = 0; + for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { + refcount += mRefCount[i]; + } + return refcount; +} + +uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::strategyRefCount(routing_strategy strategy) +{ + uint32_t refCount = 0; + for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { + if (getStrategy((AudioSystem::stream_type)i) == strategy) { + refCount += mRefCount[i]; + } + } + return refCount; +} + +audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::supportedDevices() +{ + if (isDuplicated()) { + return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices()); + } else { + return mProfile->mSupportedDevices ; + } +} + +bool AudioPolicyManagerBase::AudioOutputDescriptor::isActive(uint32_t inPastMs) const +{ + nsecs_t sysTime = systemTime(); + for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { + if (mRefCount[i] != 0 || + ns2ms(sysTime - mStopTime[i]) < inPastMs) { + return true; + } + } + return false; +} + +status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate); + result.append(buffer); + snprintf(buffer, SIZE, " Format: %d\n", mFormat); + result.append(buffer); + snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask); + result.append(buffer); + snprintf(buffer, SIZE, " Latency: %d\n", mLatency); + result.append(buffer); + snprintf(buffer, SIZE, " Flags %08x\n", mFlags); + result.append(buffer); + snprintf(buffer, SIZE, " Devices %08x\n", device()); + result.append(buffer); + snprintf(buffer, SIZE, " Stream volume refCount muteCount\n"); + result.append(buffer); + for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { + snprintf(buffer, SIZE, " %02d %.03f %02d %02d\n", i, mCurVolume[i], mRefCount[i], mMuteCount[i]); + result.append(buffer); + } + write(fd, result.string(), result.size()); + + return NO_ERROR; +} + +// --- AudioInputDescriptor class implementation + +AudioPolicyManagerBase::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile) + : mSamplingRate(0), mFormat((audio_format_t)0), mChannelMask((audio_channel_mask_t)0), + mDevice(AUDIO_DEVICE_NONE), mRefCount(0), + mInputSource(0), mProfile(profile) +{ +} + +status_t AudioPolicyManagerBase::AudioInputDescriptor::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate); + result.append(buffer); + snprintf(buffer, SIZE, " Format: %d\n", mFormat); + result.append(buffer); + snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask); + result.append(buffer); + snprintf(buffer, SIZE, " Devices %08x\n", mDevice); + result.append(buffer); + snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount); + result.append(buffer); + write(fd, result.string(), result.size()); + + return NO_ERROR; +} + +// --- StreamDescriptor class implementation + +AudioPolicyManagerBase::StreamDescriptor::StreamDescriptor() + : mIndexMin(0), mIndexMax(1), mCanBeMuted(true) +{ + mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0); +} + +int AudioPolicyManagerBase::StreamDescriptor::getVolumeIndex(audio_devices_t device) +{ + device = AudioPolicyManagerBase::getDeviceForVolume(device); + // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT + if (mIndexCur.indexOfKey(device) < 0) { + device = AUDIO_DEVICE_OUT_DEFAULT; + } + return mIndexCur.valueFor(device); +} + +void AudioPolicyManagerBase::StreamDescriptor::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, "%s %02d %02d ", + mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax); + result.append(buffer); + for (size_t i = 0; i < mIndexCur.size(); i++) { + snprintf(buffer, SIZE, "%04x : %02d, ", + mIndexCur.keyAt(i), + mIndexCur.valueAt(i)); + result.append(buffer); + } + result.append("\n"); + + write(fd, result.string(), result.size()); +} + +// --- EffectDescriptor class implementation + +status_t AudioPolicyManagerBase::EffectDescriptor::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, " I/O: %d\n", mIo); + result.append(buffer); + snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy); + result.append(buffer); + snprintf(buffer, SIZE, " Session: %d\n", mSession); + result.append(buffer); + snprintf(buffer, SIZE, " Name: %s\n", mDesc.name); + result.append(buffer); + snprintf(buffer, SIZE, " %s\n", mEnabled ? "Enabled" : "Disabled"); + result.append(buffer); + write(fd, result.string(), result.size()); + + return NO_ERROR; +} + +// --- IOProfile class implementation + +AudioPolicyManagerBase::HwModule::HwModule(const char *name) + : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)), mHandle(0) +{ +} + +AudioPolicyManagerBase::HwModule::~HwModule() +{ + for (size_t i = 0; i < mOutputProfiles.size(); i++) { + delete mOutputProfiles[i]; + } + for (size_t i = 0; i < mInputProfiles.size(); i++) { + delete mInputProfiles[i]; + } + free((void *)mName); +} + +void AudioPolicyManagerBase::HwModule::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, " - name: %s\n", mName); + result.append(buffer); + snprintf(buffer, SIZE, " - handle: %d\n", mHandle); + result.append(buffer); + write(fd, result.string(), result.size()); + if (mOutputProfiles.size()) { + write(fd, " - outputs:\n", sizeof(" - outputs:\n")); + for (size_t i = 0; i < mOutputProfiles.size(); i++) { + snprintf(buffer, SIZE, " output %d:\n", i); + write(fd, buffer, strlen(buffer)); + mOutputProfiles[i]->dump(fd); + } + } + if (mInputProfiles.size()) { + write(fd, " - inputs:\n", sizeof(" - inputs:\n")); + for (size_t i = 0; i < mInputProfiles.size(); i++) { + snprintf(buffer, SIZE, " input %d:\n", i); + write(fd, buffer, strlen(buffer)); + mInputProfiles[i]->dump(fd); + } + } +} + +AudioPolicyManagerBase::IOProfile::IOProfile(HwModule *module) + : mFlags((audio_output_flags_t)0), mModule(module) +{ +} + +AudioPolicyManagerBase::IOProfile::~IOProfile() +{ +} + +// checks if the IO profile is compatible with specified parameters. By convention a value of 0 +// means a parameter is don't care +bool AudioPolicyManagerBase::IOProfile::isCompatibleProfile(audio_devices_t device, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + audio_output_flags_t flags) const +{ + if ((mSupportedDevices & device) != device) { + return false; + } + if ((mFlags & flags) != flags) { + return false; + } + if (samplingRate != 0) { + size_t i; + for (i = 0; i < mSamplingRates.size(); i++) + { + if (mSamplingRates[i] == samplingRate) { + break; + } + } + if (i == mSamplingRates.size()) { + return false; + } + } + if (format != 0) { + size_t i; + for (i = 0; i < mFormats.size(); i++) + { + if (mFormats[i] == format) { + break; + } + } + if (i == mFormats.size()) { + return false; + } + } + if (channelMask != 0) { + size_t i; + for (i = 0; i < mChannelMasks.size(); i++) + { + if (mChannelMasks[i] == channelMask) { + break; + } + } + if (i == mChannelMasks.size()) { + return false; + } + } + return true; +} + +void AudioPolicyManagerBase::IOProfile::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, " - sampling rates: "); + result.append(buffer); + for (size_t i = 0; i < mSamplingRates.size(); i++) { + snprintf(buffer, SIZE, "%d", mSamplingRates[i]); + result.append(buffer); + result.append(i == (mSamplingRates.size() - 1) ? "\n" : ", "); + } + + snprintf(buffer, SIZE, " - channel masks: "); + result.append(buffer); + for (size_t i = 0; i < mChannelMasks.size(); i++) { + snprintf(buffer, SIZE, "%04x", mChannelMasks[i]); + result.append(buffer); + result.append(i == (mChannelMasks.size() - 1) ? "\n" : ", "); + } + + snprintf(buffer, SIZE, " - formats: "); + result.append(buffer); + for (size_t i = 0; i < mFormats.size(); i++) { + snprintf(buffer, SIZE, "%d", mFormats[i]); + result.append(buffer); + result.append(i == (mFormats.size() - 1) ? "\n" : ", "); + } + + snprintf(buffer, SIZE, " - devices: %04x\n", mSupportedDevices); + result.append(buffer); + snprintf(buffer, SIZE, " - flags: %04x\n", mFlags); + result.append(buffer); + + write(fd, result.string(), result.size()); +} + +// --- audio_policy.conf file parsing + +struct StringToEnum { + const char *name; + uint32_t value; +}; + +#define STRING_TO_ENUM(string) { #string, string } +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +const struct StringToEnum sDeviceNameToEnumTable[] = { + STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE), +#ifdef QCOM_HARDWARE + STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANC_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANC_HEADPHONE), +#endif + STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_SCO), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY), +#if defined(QCOM_FM_ENABLED) || defined(STE_FM) + STRING_TO_ENUM(AUDIO_DEVICE_OUT_FM), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_FM_TX), +#endif + STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB), +#ifdef QCOM_HARDWARE + STRING_TO_ENUM(AUDIO_DEVICE_OUT_PROXY), +#endif + STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX), + STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC), + STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET), +#ifdef QCOM_HARDWARE + STRING_TO_ENUM(AUDIO_DEVICE_IN_ANC_HEADSET), +#endif + STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL), +#if defined(QCOM_FM_ENABLED) || defined(STE_FM) + STRING_TO_ENUM(AUDIO_DEVICE_IN_FM_RX), + STRING_TO_ENUM(AUDIO_DEVICE_IN_FM_RX_A2DP), +#endif + STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL), + STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC), + STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX), + STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET), + STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY), +#ifdef QCOM_HARDWARE + STRING_TO_ENUM(AUDIO_DEVICE_IN_PROXY), + STRING_TO_ENUM(AUDIO_DEVICE_IN_COMMUNICATION), +#endif +}; + +const struct StringToEnum sFlagNameToEnumTable[] = { + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER), +#ifdef QCOM_HARDWARE + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_LPA), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_TUNNEL), +#endif +}; + +const struct StringToEnum sFormatNameToEnumTable[] = { + STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT), + STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT), + STRING_TO_ENUM(AUDIO_FORMAT_MP3), + STRING_TO_ENUM(AUDIO_FORMAT_AAC), + STRING_TO_ENUM(AUDIO_FORMAT_VORBIS), +#ifdef QCOM_HARDWARE + STRING_TO_ENUM(AUDIO_FORMAT_AC3), + STRING_TO_ENUM(AUDIO_FORMAT_EAC3), + STRING_TO_ENUM(AUDIO_FORMAT_DTS), + STRING_TO_ENUM(AUDIO_FORMAT_DTS_LBR), + STRING_TO_ENUM(AUDIO_FORMAT_WMA), + STRING_TO_ENUM(AUDIO_FORMAT_WMA_PRO), + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADIF), + STRING_TO_ENUM(AUDIO_FORMAT_AMR_NB), + STRING_TO_ENUM(AUDIO_FORMAT_AMR_WB), + STRING_TO_ENUM(AUDIO_FORMAT_AMR_WB_PLUS), + STRING_TO_ENUM(AUDIO_FORMAT_EVRC), + STRING_TO_ENUM(AUDIO_FORMAT_EVRCB), + STRING_TO_ENUM(AUDIO_FORMAT_EVRCWB), + STRING_TO_ENUM(AUDIO_FORMAT_QCELP), + STRING_TO_ENUM(AUDIO_FORMAT_MP2), +#endif +}; + +const struct StringToEnum sOutChannelsNameToEnumTable[] = { + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), +#ifdef QCOM_HARDWARE + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_2POINT1), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_SURROUND), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_PENTA), +#endif + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), +#ifdef QCOM_HARDWARE + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_6POINT1), +#endif + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), +}; + +const struct StringToEnum sInChannelsNameToEnumTable[] = { + STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO), + STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO), +#ifdef QCOM_HARDWARE + STRING_TO_ENUM(AUDIO_CHANNEL_IN_5POINT1), + STRING_TO_ENUM(AUDIO_CHANNEL_IN_VOICE_CALL_MONO), + STRING_TO_ENUM(AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO), + STRING_TO_ENUM(AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO), +#endif +}; + + +uint32_t AudioPolicyManagerBase::stringToEnum(const struct StringToEnum *table, + size_t size, + const char *name) +{ + for (size_t i = 0; i < size; i++) { + if (strcmp(table[i].name, name) == 0) { + ALOGV("stringToEnum() found %s", table[i].name); + return table[i].value; + } + } + return 0; +} + +audio_output_flags_t AudioPolicyManagerBase::parseFlagNames(char *name) +{ + uint32_t flag = 0; + + // it is OK to cast name to non const here as we are not going to use it after + // strtok() modifies it + char *flagName = strtok(name, "|"); + while (flagName != NULL) { + if (strlen(flagName) != 0) { + flag |= stringToEnum(sFlagNameToEnumTable, + ARRAY_SIZE(sFlagNameToEnumTable), + flagName); + } + flagName = strtok(NULL, "|"); + } + return (audio_output_flags_t)flag; +} + +audio_devices_t AudioPolicyManagerBase::parseDeviceNames(char *name) +{ + uint32_t device = 0; + + char *devName = strtok(name, "|"); + while (devName != NULL) { + if (strlen(devName) != 0) { + device |= stringToEnum(sDeviceNameToEnumTable, + ARRAY_SIZE(sDeviceNameToEnumTable), + devName); + } + devName = strtok(NULL, "|"); + } + return device; +} + +void AudioPolicyManagerBase::loadSamplingRates(char *name, IOProfile *profile) +{ + char *str = strtok(name, "|"); + + // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling + // rates should be read from the output stream after it is opened for the first time + if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { + profile->mSamplingRates.add(0); + return; + } + + while (str != NULL) { + uint32_t rate = atoi(str); + if (rate != 0) { + ALOGV("loadSamplingRates() adding rate %d", rate); + profile->mSamplingRates.add(rate); + } + str = strtok(NULL, "|"); + } + return; +} + +void AudioPolicyManagerBase::loadFormats(char *name, IOProfile *profile) +{ + char *str = strtok(name, "|"); + + // by convention, "0' in the first entry in mFormats indicates the supported formats + // should be read from the output stream after it is opened for the first time + if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { + profile->mFormats.add((audio_format_t)0); + return; + } + + while (str != NULL) { + audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable, + ARRAY_SIZE(sFormatNameToEnumTable), + str); + if (format != 0) { + profile->mFormats.add(format); + } + str = strtok(NULL, "|"); + } + return; +} + +void AudioPolicyManagerBase::loadInChannels(char *name, IOProfile *profile) +{ + const char *str = strtok(name, "|"); + + ALOGV("loadInChannels() %s", name); + + if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { + profile->mChannelMasks.add((audio_channel_mask_t)0); + return; + } + + while (str != NULL) { + audio_channel_mask_t channelMask = + (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable, + ARRAY_SIZE(sInChannelsNameToEnumTable), + str); + if (channelMask != 0) { + ALOGV("loadInChannels() adding channelMask %04x", channelMask); + profile->mChannelMasks.add(channelMask); + } + str = strtok(NULL, "|"); + } + return; +} + +void AudioPolicyManagerBase::loadOutChannels(char *name, IOProfile *profile) +{ + const char *str = strtok(name, "|"); + + ALOGV("loadOutChannels() %s", name); + + // by convention, "0' in the first entry in mChannelMasks indicates the supported channel + // masks should be read from the output stream after it is opened for the first time + if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { + profile->mChannelMasks.add((audio_channel_mask_t)0); + return; + } + + while (str != NULL) { + audio_channel_mask_t channelMask = + (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable, + ARRAY_SIZE(sOutChannelsNameToEnumTable), + str); + if (channelMask != 0) { + profile->mChannelMasks.add(channelMask); + } + str = strtok(NULL, "|"); + } + return; +} + +status_t AudioPolicyManagerBase::loadInput(cnode *root, HwModule *module) +{ + cnode *node = root->first_child; + + IOProfile *profile = new IOProfile(module); + + while (node) { + if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) { + loadSamplingRates((char *)node->value, profile); + } else if (strcmp(node->name, FORMATS_TAG) == 0) { + loadFormats((char *)node->value, profile); + } else if (strcmp(node->name, CHANNELS_TAG) == 0) { + loadInChannels((char *)node->value, profile); + } else if (strcmp(node->name, DEVICES_TAG) == 0) { + profile->mSupportedDevices = parseDeviceNames((char *)node->value); + } + node = node->next; + } + ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE, + "loadInput() invalid supported devices"); + ALOGW_IF(profile->mChannelMasks.size() == 0, + "loadInput() invalid supported channel masks"); + ALOGW_IF(profile->mSamplingRates.size() == 0, + "loadInput() invalid supported sampling rates"); + ALOGW_IF(profile->mFormats.size() == 0, + "loadInput() invalid supported formats"); + if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) && + (profile->mChannelMasks.size() != 0) && + (profile->mSamplingRates.size() != 0) && + (profile->mFormats.size() != 0)) { + + ALOGV("loadInput() adding input mSupportedDevices %04x", profile->mSupportedDevices); + + module->mInputProfiles.add(profile); + return NO_ERROR; + } else { + delete profile; + return BAD_VALUE; + } +} + +status_t AudioPolicyManagerBase::loadOutput(cnode *root, HwModule *module) +{ + cnode *node = root->first_child; + + IOProfile *profile = new IOProfile(module); + + while (node) { + if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) { + loadSamplingRates((char *)node->value, profile); + } else if (strcmp(node->name, FORMATS_TAG) == 0) { + loadFormats((char *)node->value, profile); + } else if (strcmp(node->name, CHANNELS_TAG) == 0) { + loadOutChannels((char *)node->value, profile); + } else if (strcmp(node->name, DEVICES_TAG) == 0) { + profile->mSupportedDevices = parseDeviceNames((char *)node->value); + } else if (strcmp(node->name, FLAGS_TAG) == 0) { + profile->mFlags = parseFlagNames((char *)node->value); + } + node = node->next; + } + ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE, + "loadOutput() invalid supported devices"); + ALOGW_IF(profile->mChannelMasks.size() == 0, + "loadOutput() invalid supported channel masks"); + ALOGW_IF(profile->mSamplingRates.size() == 0, + "loadOutput() invalid supported sampling rates"); + ALOGW_IF(profile->mFormats.size() == 0, + "loadOutput() invalid supported formats"); + if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) && + (profile->mChannelMasks.size() != 0) && + (profile->mSamplingRates.size() != 0) && + (profile->mFormats.size() != 0)) { + + ALOGV("loadOutput() adding output mSupportedDevices %04x, mFlags %04x", + profile->mSupportedDevices, profile->mFlags); + + module->mOutputProfiles.add(profile); + return NO_ERROR; + } else { + delete profile; + return BAD_VALUE; + } +} + +void AudioPolicyManagerBase::loadHwModule(cnode *root) +{ + cnode *node = config_find(root, OUTPUTS_TAG); + status_t status = NAME_NOT_FOUND; + + HwModule *module = new HwModule(root->name); + + if (node != NULL) { + if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_A2DP) == 0) { + mHasA2dp = true; + } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_USB) == 0) { + mHasUsb = true; + } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) { + mHasRemoteSubmix = true; + } + + node = node->first_child; + while (node) { + ALOGV("loadHwModule() loading output %s", node->name); + status_t tmpStatus = loadOutput(node, module); + if (status == NAME_NOT_FOUND || status == NO_ERROR) { + status = tmpStatus; + } + node = node->next; + } + } + node = config_find(root, INPUTS_TAG); + if (node != NULL) { + node = node->first_child; + while (node) { + ALOGV("loadHwModule() loading input %s", node->name); + status_t tmpStatus = loadInput(node, module); + if (status == NAME_NOT_FOUND || status == NO_ERROR) { + status = tmpStatus; + } + node = node->next; + } + } + if (status == NO_ERROR) { + mHwModules.add(module); + } else { + delete module; + } +} + +void AudioPolicyManagerBase::loadHwModules(cnode *root) +{ + cnode *node = config_find(root, AUDIO_HW_MODULE_TAG); + if (node == NULL) { + return; + } + + node = node->first_child; + while (node) { + ALOGV("loadHwModules() loading module %s", node->name); + loadHwModule(node); + node = node->next; + } +} + +void AudioPolicyManagerBase::loadGlobalConfig(cnode *root) +{ + cnode *node = config_find(root, GLOBAL_CONFIG_TAG); + if (node == NULL) { + return; + } + node = node->first_child; + while (node) { + if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) { + mAttachedOutputDevices = parseDeviceNames((char *)node->value); + ALOGW_IF(mAttachedOutputDevices == AUDIO_DEVICE_NONE, + "loadGlobalConfig() no attached output devices"); + ALOGV("loadGlobalConfig() mAttachedOutputDevices %04x", mAttachedOutputDevices); + } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) { + mDefaultOutputDevice = (audio_devices_t)stringToEnum(sDeviceNameToEnumTable, + ARRAY_SIZE(sDeviceNameToEnumTable), + (char *)node->value); + ALOGW_IF(mDefaultOutputDevice == AUDIO_DEVICE_NONE, + "loadGlobalConfig() default device not specified"); + ALOGV("loadGlobalConfig() mDefaultOutputDevice %04x", mDefaultOutputDevice); + } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) { + mAvailableInputDevices = parseDeviceNames((char *)node->value) & ~AUDIO_DEVICE_BIT_IN; + ALOGV("loadGlobalConfig() mAvailableInputDevices %04x", mAvailableInputDevices); + } + node = node->next; + } +} + +status_t AudioPolicyManagerBase::loadAudioPolicyConfig(const char *path) +{ + cnode *root; + char *data; + + data = (char *)load_file(path, NULL); + if (data == NULL) { + return -ENODEV; + } + root = config_node("", ""); + config_load(root, data); + + loadGlobalConfig(root); + loadHwModules(root); + + config_free(root); + free(root); + free(data); + + ALOGI("loadAudioPolicyConfig() loaded %s\n", path); + + return NO_ERROR; +} + +void AudioPolicyManagerBase::defaultAudioPolicyConfig(void) +{ + HwModule *module; + IOProfile *profile; + + mDefaultOutputDevice = AUDIO_DEVICE_OUT_SPEAKER; + mAttachedOutputDevices = AUDIO_DEVICE_OUT_SPEAKER; + mAvailableInputDevices = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN; + + module = new HwModule("primary"); + + profile = new IOProfile(module); + profile->mSamplingRates.add(44100); + profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT); + profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO); + profile->mSupportedDevices = AUDIO_DEVICE_OUT_SPEAKER; + profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY; + module->mOutputProfiles.add(profile); + + profile = new IOProfile(module); + profile->mSamplingRates.add(8000); + profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT); + profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO); + profile->mSupportedDevices = AUDIO_DEVICE_IN_BUILTIN_MIC; + module->mInputProfiles.add(profile); + + mHwModules.add(module); +} + +}; // namespace android diff --git a/hardware/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp b/hardware/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp new file mode 100644 index 00000000..90836382 --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AudioPolicyManagerDefault" +//#define LOG_NDEBUG 0 + +#include "AudioPolicyManagerDefault.h" + +namespace android_audio_legacy { + +extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) +{ + return new AudioPolicyManagerDefault(clientInterface); +} + +extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface) +{ + delete interface; +} + +}; // namespace android diff --git a/hardware/libhardware_legacy/audio/AudioPolicyManagerDefault.h b/hardware/libhardware_legacy/audio/AudioPolicyManagerDefault.h new file mode 100644 index 00000000..03079769 --- /dev/null +++ b/hardware/libhardware_legacy/audio/AudioPolicyManagerDefault.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include + +#include + +namespace android_audio_legacy { + +class AudioPolicyManagerDefault: public AudioPolicyManagerBase +{ + +public: + AudioPolicyManagerDefault(AudioPolicyClientInterface *clientInterface) + : AudioPolicyManagerBase(clientInterface) {} + + virtual ~AudioPolicyManagerDefault() {} + +}; +}; diff --git a/hardware/libhardware_legacy/audio/audio_hw_hal.cpp b/hardware/libhardware_legacy/audio/audio_hw_hal.cpp new file mode 100644 index 00000000..e43140fd --- /dev/null +++ b/hardware/libhardware_legacy/audio/audio_hw_hal.cpp @@ -0,0 +1,751 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "legacy_audio_hw_hal" +//#define LOG_NDEBUG 0 + +#include + +#include +#include +#include + +#include +#include + +namespace android_audio_legacy { + +extern "C" { + +struct legacy_audio_module { + struct audio_module module; +}; + +struct legacy_audio_device { + struct audio_hw_device device; + + struct AudioHardwareInterface *hwif; +}; + +struct legacy_stream_out { + struct audio_stream_out stream; + + AudioStreamOut *legacy_out; +}; + +struct legacy_stream_in { + struct audio_stream_in stream; + + AudioStreamIn *legacy_in; +}; + + +enum { + HAL_API_REV_1_0, + HAL_API_REV_2_0, + HAL_API_REV_NUM +} hal_api_rev; + +static uint32_t audio_device_conv_table[][HAL_API_REV_NUM] = +{ + /* output devices */ + { AudioSystem::DEVICE_OUT_EARPIECE, AUDIO_DEVICE_OUT_EARPIECE }, + { AudioSystem::DEVICE_OUT_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER }, + { AudioSystem::DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADSET }, + { AudioSystem::DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADPHONE }, + { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, AUDIO_DEVICE_OUT_BLUETOOTH_SCO }, + { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET }, + { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT }, + { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP }, + { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES }, + { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER }, + { AudioSystem::DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_AUX_DIGITAL }, + { AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET }, + { AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET }, + { AudioSystem::DEVICE_OUT_DEFAULT, AUDIO_DEVICE_OUT_DEFAULT }, + /* input devices */ + { AudioSystem::DEVICE_IN_COMMUNICATION, AUDIO_DEVICE_IN_COMMUNICATION }, + { AudioSystem::DEVICE_IN_AMBIENT, AUDIO_DEVICE_IN_AMBIENT }, + { AudioSystem::DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC }, + { AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET }, + { AudioSystem::DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET }, + { AudioSystem::DEVICE_IN_AUX_DIGITAL, AUDIO_DEVICE_IN_AUX_DIGITAL }, + { AudioSystem::DEVICE_IN_VOICE_CALL, AUDIO_DEVICE_IN_VOICE_CALL }, + { AudioSystem::DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BACK_MIC }, + { AudioSystem::DEVICE_IN_DEFAULT, AUDIO_DEVICE_IN_DEFAULT }, +}; + +static uint32_t convert_audio_device(uint32_t from_device, int from_rev, int to_rev) +{ + const uint32_t k_num_devices = sizeof(audio_device_conv_table)/sizeof(uint32_t)/HAL_API_REV_NUM; + uint32_t to_device = AUDIO_DEVICE_NONE; + uint32_t in_bit = 0; + + if (from_rev != HAL_API_REV_1_0) { + in_bit = from_device & AUDIO_DEVICE_BIT_IN; + from_device &= ~AUDIO_DEVICE_BIT_IN; + } + + while (from_device) { + uint32_t i = 31 - __builtin_clz(from_device); + uint32_t cur_device = (1 << i) | in_bit; + + for (i = 0; i < k_num_devices; i++) { + if (audio_device_conv_table[i][from_rev] == cur_device) { + to_device |= audio_device_conv_table[i][to_rev]; + break; + } + } + from_device &= ~cur_device; + } + return to_device; +} + + +/** audio_stream_out implementation **/ +static uint32_t out_get_sample_rate(const struct audio_stream *stream) +{ + const struct legacy_stream_out *out = + reinterpret_cast(stream); + return out->legacy_out->sampleRate(); +} + +static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + struct legacy_stream_out *out = + reinterpret_cast(stream); + + ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); + /* TODO: implement this */ + return 0; +} + +static size_t out_get_buffer_size(const struct audio_stream *stream) +{ + const struct legacy_stream_out *out = + reinterpret_cast(stream); + return out->legacy_out->bufferSize(); +} + +static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) +{ + const struct legacy_stream_out *out = + reinterpret_cast(stream); + return (audio_channel_mask_t) out->legacy_out->channels(); +} + +static audio_format_t out_get_format(const struct audio_stream *stream) +{ + const struct legacy_stream_out *out = + reinterpret_cast(stream); + // legacy API, don't change return type + return (audio_format_t) out->legacy_out->format(); +} + +static int out_set_format(struct audio_stream *stream, audio_format_t format) +{ + struct legacy_stream_out *out = + reinterpret_cast(stream); + ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); + /* TODO: implement me */ + return 0; +} + +static int out_standby(struct audio_stream *stream) +{ + struct legacy_stream_out *out = + reinterpret_cast(stream); + return out->legacy_out->standby(); +} + +static int out_dump(const struct audio_stream *stream, int fd) +{ + const struct legacy_stream_out *out = + reinterpret_cast(stream); + Vector args; + return out->legacy_out->dump(fd, args); +} + +static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + struct legacy_stream_out *out = + reinterpret_cast(stream); + int val; + String8 s8 = String8(kvpairs); + AudioParameter parms = AudioParameter(String8(kvpairs)); + + if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) { + val = convert_audio_device(val, HAL_API_REV_2_0, HAL_API_REV_1_0); + parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING)); + parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val); + s8 = parms.toString(); + } + + return out->legacy_out->setParameters(s8); +} + +static char * out_get_parameters(const struct audio_stream *stream, const char *keys) +{ + const struct legacy_stream_out *out = + reinterpret_cast(stream); + String8 s8; + int val; + + s8 = out->legacy_out->getParameters(String8(keys)); + + AudioParameter parms = AudioParameter(s8); + if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) { + val = convert_audio_device(val, HAL_API_REV_1_0, HAL_API_REV_2_0); + parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING)); + parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val); + s8 = parms.toString(); + } + + return strdup(s8.string()); +} + +static uint32_t out_get_latency(const struct audio_stream_out *stream) +{ + const struct legacy_stream_out *out = + reinterpret_cast(stream); + return out->legacy_out->latency(); +} + +static int out_set_volume(struct audio_stream_out *stream, float left, + float right) +{ + struct legacy_stream_out *out = + reinterpret_cast(stream); + return out->legacy_out->setVolume(left, right); +} + +static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, + size_t bytes) +{ + struct legacy_stream_out *out = + reinterpret_cast(stream); + return out->legacy_out->write(buffer, bytes); +} + +static int out_get_render_position(const struct audio_stream_out *stream, + uint32_t *dsp_frames) +{ + const struct legacy_stream_out *out = + reinterpret_cast(stream); + return out->legacy_out->getRenderPosition(dsp_frames); +} + +#ifndef ICS_AUDIO_BLOB +static int out_get_next_write_timestamp(const struct audio_stream_out *stream, + int64_t *timestamp) +{ + const struct legacy_stream_out *out = + reinterpret_cast(stream); + return out->legacy_out->getNextWriteTimestamp(timestamp); +} +#endif + +static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +/** audio_stream_in implementation **/ +static uint32_t in_get_sample_rate(const struct audio_stream *stream) +{ + const struct legacy_stream_in *in = + reinterpret_cast(stream); + return in->legacy_in->sampleRate(); +} + +static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + struct legacy_stream_in *in = + reinterpret_cast(stream); + + ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); + /* TODO: implement this */ + return 0; +} + +static size_t in_get_buffer_size(const struct audio_stream *stream) +{ + const struct legacy_stream_in *in = + reinterpret_cast(stream); + return in->legacy_in->bufferSize(); +} + +static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) +{ + const struct legacy_stream_in *in = + reinterpret_cast(stream); + return (audio_channel_mask_t) in->legacy_in->channels(); +} + +static audio_format_t in_get_format(const struct audio_stream *stream) +{ + const struct legacy_stream_in *in = + reinterpret_cast(stream); + // legacy API, don't change return type + return (audio_format_t) in->legacy_in->format(); +} + +static int in_set_format(struct audio_stream *stream, audio_format_t format) +{ + struct legacy_stream_in *in = + reinterpret_cast(stream); + ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); + /* TODO: implement me */ + return 0; +} + +static int in_standby(struct audio_stream *stream) +{ + struct legacy_stream_in *in = reinterpret_cast(stream); + return in->legacy_in->standby(); +} + +static int in_dump(const struct audio_stream *stream, int fd) +{ + const struct legacy_stream_in *in = + reinterpret_cast(stream); + Vector args; + return in->legacy_in->dump(fd, args); +} + +static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + struct legacy_stream_in *in = + reinterpret_cast(stream); + int val; + AudioParameter parms = AudioParameter(String8(kvpairs)); + String8 s8 = String8(kvpairs); + + if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) { + val = convert_audio_device(val, HAL_API_REV_2_0, HAL_API_REV_1_0); + parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING)); + parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val); + s8 = parms.toString(); + } + + return in->legacy_in->setParameters(s8); +} + +static char * in_get_parameters(const struct audio_stream *stream, + const char *keys) +{ + const struct legacy_stream_in *in = + reinterpret_cast(stream); + String8 s8; + int val; + + s8 = in->legacy_in->getParameters(String8(keys)); + + AudioParameter parms = AudioParameter(s8); + if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) { + val = convert_audio_device(val, HAL_API_REV_1_0, HAL_API_REV_2_0); + parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING)); + parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val); + s8 = parms.toString(); + } + + return strdup(s8.string()); +} + +static int in_set_gain(struct audio_stream_in *stream, float gain) +{ + struct legacy_stream_in *in = + reinterpret_cast(stream); + return in->legacy_in->setGain(gain); +} + +static ssize_t in_read(struct audio_stream_in *stream, void* buffer, + size_t bytes) +{ + struct legacy_stream_in *in = + reinterpret_cast(stream); + return in->legacy_in->read(buffer, bytes); +} + +static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) +{ + struct legacy_stream_in *in = + reinterpret_cast(stream); + return in->legacy_in->getInputFramesLost(); +} + +static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + const struct legacy_stream_in *in = + reinterpret_cast(stream); + return in->legacy_in->addAudioEffect(effect); +} + +static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + const struct legacy_stream_in *in = + reinterpret_cast(stream); + return in->legacy_in->removeAudioEffect(effect); +} + +/** audio_hw_device implementation **/ +static inline struct legacy_audio_device * to_ladev(struct audio_hw_device *dev) +{ + return reinterpret_cast(dev); +} + +static inline const struct legacy_audio_device * to_cladev(const struct audio_hw_device *dev) +{ + return reinterpret_cast(dev); +} + +static int adev_init_check(const struct audio_hw_device *dev) +{ + const struct legacy_audio_device *ladev = to_cladev(dev); + + return ladev->hwif->initCheck(); +} + +static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) +{ + struct legacy_audio_device *ladev = to_ladev(dev); + return ladev->hwif->setVoiceVolume(volume); +} + +static int adev_set_master_volume(struct audio_hw_device *dev, float volume) +{ + struct legacy_audio_device *ladev = to_ladev(dev); + return ladev->hwif->setMasterVolume(volume); +} + +#ifndef ICS_AUDIO_BLOB +static int adev_get_master_volume(struct audio_hw_device *dev, float* volume) +{ + struct legacy_audio_device *ladev = to_ladev(dev); + return ladev->hwif->getMasterVolume(volume); +} +#endif + +static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) +{ + struct legacy_audio_device *ladev = to_ladev(dev); + // as this is the legacy API, don't change it to use audio_mode_t instead of int + return ladev->hwif->setMode((int) mode); +} + +static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) +{ + struct legacy_audio_device *ladev = to_ladev(dev); + return ladev->hwif->setMicMute(state); +} + +static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) +{ + const struct legacy_audio_device *ladev = to_cladev(dev); + return ladev->hwif->getMicMute(state); +} + +static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) +{ + struct legacy_audio_device *ladev = to_ladev(dev); + return ladev->hwif->setParameters(String8(kvpairs)); +} + +static char * adev_get_parameters(const struct audio_hw_device *dev, + const char *keys) +{ + const struct legacy_audio_device *ladev = to_cladev(dev); + String8 s8; + + s8 = ladev->hwif->getParameters(String8(keys)); + return strdup(s8.string()); +} + +#ifndef ICS_AUDIO_BLOB +static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, + const struct audio_config *config) +{ + const struct legacy_audio_device *ladev = to_cladev(dev); + return ladev->hwif->getInputBufferSize(config->sample_rate, (int) config->format, + popcount(config->channel_mask)); +} +#else +static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, + uint32_t sample_rate, int format, + int channel_count) +{ + const struct legacy_audio_device *ladev = to_cladev(dev); + return ladev->hwif->getInputBufferSize(sample_rate, format, channel_count); +} +#endif + +#ifndef ICS_AUDIO_BLOB +static int adev_open_output_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config, + struct audio_stream_out **stream_out) +#else +static int adev_open_output_stream(struct audio_hw_device *dev, + uint32_t devices, + int *format, + uint32_t *channels, + uint32_t *sample_rate, + struct audio_stream_out **stream_out) +#endif +{ + struct legacy_audio_device *ladev = to_ladev(dev); + status_t status; + struct legacy_stream_out *out; + int ret; + + out = (struct legacy_stream_out *)calloc(1, sizeof(*out)); + if (!out) + return -ENOMEM; + + devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0); + +#ifndef ICS_AUDIO_BLOB + out->legacy_out = ladev->hwif->openOutputStream(devices, (int *) &config->format, + &config->channel_mask, + &config->sample_rate, &status); +#else + out->legacy_out = ladev->hwif->openOutputStream(devices, format, channels, + sample_rate, &status); +#endif + + if (!out->legacy_out) { + ret = status; + goto err_open; + } + + out->stream.common.get_sample_rate = out_get_sample_rate; + out->stream.common.set_sample_rate = out_set_sample_rate; + out->stream.common.get_buffer_size = out_get_buffer_size; + out->stream.common.get_channels = out_get_channels; + out->stream.common.get_format = out_get_format; + out->stream.common.set_format = out_set_format; + out->stream.common.standby = out_standby; + out->stream.common.dump = out_dump; + out->stream.common.set_parameters = out_set_parameters; + out->stream.common.get_parameters = out_get_parameters; + out->stream.common.add_audio_effect = out_add_audio_effect; + out->stream.common.remove_audio_effect = out_remove_audio_effect; + out->stream.get_latency = out_get_latency; + out->stream.set_volume = out_set_volume; + out->stream.write = out_write; + out->stream.get_render_position = out_get_render_position; +#ifndef ICS_AUDIO_BLOB + out->stream.get_next_write_timestamp = out_get_next_write_timestamp; +#endif + + *stream_out = &out->stream; + return 0; + +err_open: + free(out); + *stream_out = NULL; + return ret; +} + +static void adev_close_output_stream(struct audio_hw_device *dev, + struct audio_stream_out* stream) +{ + struct legacy_audio_device *ladev = to_ladev(dev); + struct legacy_stream_out *out = reinterpret_cast(stream); + + ladev->hwif->closeOutputStream(out->legacy_out); + free(out); +} + +/** This method creates and opens the audio hardware input stream */ +static int adev_open_input_stream(struct audio_hw_device *dev, +#ifndef ICS_AUDIO_BLOB + audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config, +#else + uint32_t devices, int *format, + uint32_t *channels, uint32_t *sample_rate, + audio_in_acoustics_t acoustics, +#endif + struct audio_stream_in **stream_in) +{ + struct legacy_audio_device *ladev = to_ladev(dev); + status_t status; + struct legacy_stream_in *in; + int ret; + + in = (struct legacy_stream_in *)calloc(1, sizeof(*in)); + if (!in) + return -ENOMEM; + + devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0); + +#ifndef ICS_AUDIO_BLOB + in->legacy_in = ladev->hwif->openInputStream(devices, (int *) &config->format, + &config->channel_mask, &config->sample_rate, + &status, (AudioSystem::audio_in_acoustics)0); +#else + in->legacy_in = ladev->hwif->openInputStream(devices, format, channels, + sample_rate, &status, + (AudioSystem::audio_in_acoustics)acoustics); +#endif + if (!in->legacy_in) { + ret = status; + goto err_open; + } + + in->stream.common.get_sample_rate = in_get_sample_rate; + in->stream.common.set_sample_rate = in_set_sample_rate; + in->stream.common.get_buffer_size = in_get_buffer_size; + in->stream.common.get_channels = in_get_channels; + in->stream.common.get_format = in_get_format; + in->stream.common.set_format = in_set_format; + in->stream.common.standby = in_standby; + in->stream.common.dump = in_dump; + in->stream.common.set_parameters = in_set_parameters; + in->stream.common.get_parameters = in_get_parameters; + in->stream.common.add_audio_effect = in_add_audio_effect; + in->stream.common.remove_audio_effect = in_remove_audio_effect; + in->stream.set_gain = in_set_gain; + in->stream.read = in_read; + in->stream.get_input_frames_lost = in_get_input_frames_lost; + + *stream_in = &in->stream; + return 0; + +err_open: + free(in); + *stream_in = NULL; + return ret; +} + +static void adev_close_input_stream(struct audio_hw_device *dev, + struct audio_stream_in *stream) +{ + struct legacy_audio_device *ladev = to_ladev(dev); + struct legacy_stream_in *in = + reinterpret_cast(stream); + + ladev->hwif->closeInputStream(in->legacy_in); + free(in); +} + +static int adev_dump(const struct audio_hw_device *dev, int fd) +{ + const struct legacy_audio_device *ladev = to_cladev(dev); + Vector args; + + return ladev->hwif->dumpState(fd, args); +} + +static int legacy_adev_close(hw_device_t* device) +{ + struct audio_hw_device *hwdev = + reinterpret_cast(device); + struct legacy_audio_device *ladev = to_ladev(hwdev); + + if (!ladev) + return 0; + + if (ladev->hwif) + delete ladev->hwif; + + free(ladev); + return 0; +} + +static int legacy_adev_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + struct legacy_audio_device *ladev; + int ret; + + if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) + return -EINVAL; + + ladev = (struct legacy_audio_device *)calloc(1, sizeof(*ladev)); + if (!ladev) + return -ENOMEM; + + ladev->device.common.tag = HARDWARE_DEVICE_TAG; + ladev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; + ladev->device.common.module = const_cast(module); + ladev->device.common.close = legacy_adev_close; + + ladev->device.init_check = adev_init_check; + ladev->device.set_voice_volume = adev_set_voice_volume; + ladev->device.set_master_volume = adev_set_master_volume; +#ifndef ICS_AUDIO_BLOB + ladev->device.get_master_volume = adev_get_master_volume; +#endif + ladev->device.set_mode = adev_set_mode; + ladev->device.set_mic_mute = adev_set_mic_mute; + ladev->device.get_mic_mute = adev_get_mic_mute; + ladev->device.set_parameters = adev_set_parameters; + ladev->device.get_parameters = adev_get_parameters; + ladev->device.get_input_buffer_size = adev_get_input_buffer_size; + ladev->device.open_output_stream = adev_open_output_stream; + ladev->device.open_input_stream = adev_open_input_stream; + ladev->device.close_output_stream = adev_close_output_stream; + ladev->device.close_input_stream = adev_close_input_stream; + ladev->device.dump = adev_dump; + + ladev->hwif = createAudioHardware(); + if (!ladev->hwif) { + ret = -EIO; + goto err_create_audio_hw; + } + + *device = &ladev->device.common; + + return 0; + +err_create_audio_hw: + free(ladev); + return ret; +} + +static struct hw_module_methods_t legacy_audio_module_methods = { + open: legacy_adev_open +}; + +struct legacy_audio_module HAL_MODULE_INFO_SYM = { + module: { + common: { + tag: HARDWARE_MODULE_TAG, + module_api_version: AUDIO_MODULE_API_VERSION_0_1, + hal_api_version: HARDWARE_HAL_API_VERSION, + id: AUDIO_HARDWARE_MODULE_ID, + name: "LEGACY Audio HW HAL", + author: "The Android Open Source Project", + methods: &legacy_audio_module_methods, + dso : NULL, + reserved : {0}, + }, + }, +}; + +}; // extern "C" + +}; // namespace android_audio_legacy diff --git a/hardware/libhardware_legacy/audio/audio_policy.conf b/hardware/libhardware_legacy/audio/audio_policy.conf new file mode 100644 index 00000000..d4e78448 --- /dev/null +++ b/hardware/libhardware_legacy/audio/audio_policy.conf @@ -0,0 +1,46 @@ +# +# Audio policy configuration for generic device builds (goldfish audio HAL - emulator) +# + +# Global configuration section: lists input and output devices always present on the device +# as well as the output device selected by default. +# Devices are designated by a string that corresponds to the enum in audio.h + +global_configuration { + attached_output_devices AUDIO_DEVICE_OUT_SPEAKER + default_output_device AUDIO_DEVICE_OUT_SPEAKER + attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC +} + +# audio hardware module section: contains descriptors for all audio hw modules present on the +# device. Each hw module node is named after the corresponding hw module library base name. +# For instance, "primary" corresponds to audio.primary..so. +# The "primary" module is mandatory and must include at least one output with +# AUDIO_OUTPUT_FLAG_PRIMARY flag. +# Each module descriptor contains one or more output profile descriptors and zero or more +# input profile descriptors. Each profile lists all the parameters supported by a given output +# or input stream category. +# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding +# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n". + +audio_hw_modules { + primary { + outputs { + primary { + sampling_rates 44100 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_SPEAKER + flags AUDIO_OUTPUT_FLAG_PRIMARY + } + } + inputs { + primary { + sampling_rates 8000|16000 + channel_masks AUDIO_CHANNEL_IN_MONO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_IN_BUILTIN_MIC + } + } + } +} diff --git a/hardware/libhardware_legacy/audio/audio_policy_hal.cpp b/hardware/libhardware_legacy/audio/audio_policy_hal.cpp new file mode 100644 index 00000000..99b37bf7 --- /dev/null +++ b/hardware/libhardware_legacy/audio/audio_policy_hal.cpp @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "legacy_audio_policy_hal" +//#define LOG_NDEBUG 0 + +#include + +#include +#include +#include +#include + +#include +#include + +#include "AudioPolicyCompatClient.h" + +namespace android_audio_legacy { + +extern "C" { + +struct legacy_ap_module { + struct audio_policy_module module; +}; + +struct legacy_ap_device { + struct audio_policy_device device; +}; + +struct legacy_audio_policy { + struct audio_policy policy; + + void *service; + struct audio_policy_service_ops *aps_ops; + AudioPolicyCompatClient *service_client; + AudioPolicyInterface *apm; +}; + +static inline struct legacy_audio_policy * to_lap(struct audio_policy *pol) +{ + return reinterpret_cast(pol); +} + +static inline const struct legacy_audio_policy * to_clap(const struct audio_policy *pol) +{ + return reinterpret_cast(pol); +} + + +static int ap_set_device_connection_state(struct audio_policy *pol, + audio_devices_t device, + audio_policy_dev_state_t state, + const char *device_address) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->setDeviceConnectionState( + (AudioSystem::audio_devices)device, + (AudioSystem::device_connection_state)state, + device_address); +} + +static audio_policy_dev_state_t ap_get_device_connection_state( + const struct audio_policy *pol, + audio_devices_t device, + const char *device_address) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return (audio_policy_dev_state_t)lap->apm->getDeviceConnectionState( + (AudioSystem::audio_devices)device, + device_address); +} + +static void ap_set_phone_state(struct audio_policy *pol, audio_mode_t state) +{ + struct legacy_audio_policy *lap = to_lap(pol); + // as this is the legacy API, don't change it to use audio_mode_t instead of int + lap->apm->setPhoneState((int) state); +} + + /* indicate a change in ringer mode */ +static void ap_set_ringer_mode(struct audio_policy *pol, uint32_t mode, + uint32_t mask) +{ + // deprecated, never called +} + + /* force using a specific device category for the specified usage */ +static void ap_set_force_use(struct audio_policy *pol, + audio_policy_force_use_t usage, + audio_policy_forced_cfg_t config) +{ + struct legacy_audio_policy *lap = to_lap(pol); + lap->apm->setForceUse((AudioSystem::force_use)usage, + (AudioSystem::forced_config)config); +} + + /* retreive current device category forced for a given usage */ +static audio_policy_forced_cfg_t ap_get_force_use( + const struct audio_policy *pol, + audio_policy_force_use_t usage) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return (audio_policy_forced_cfg_t)lap->apm->getForceUse( + (AudioSystem::force_use)usage); +} + +/* if can_mute is true, then audio streams that are marked ENFORCED_AUDIBLE + * can still be muted. */ +static void ap_set_can_mute_enforced_audible(struct audio_policy *pol, + bool can_mute) +{ + struct legacy_audio_policy *lap = to_lap(pol); + lap->apm->setSystemProperty("ro.camera.sound.forced", can_mute ? "0" : "1"); +} + +static int ap_init_check(const struct audio_policy *pol) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return lap->apm->initCheck(); +} + +static audio_io_handle_t ap_get_output(struct audio_policy *pol, + audio_stream_type_t stream, + uint32_t sampling_rate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags) +{ + struct legacy_audio_policy *lap = to_lap(pol); + + ALOGV("%s: tid %d", __func__, gettid()); + return lap->apm->getOutput((AudioSystem::stream_type)stream, + sampling_rate, (int) format, channelMask, + (AudioSystem::output_flags)flags); +} + +static int ap_start_output(struct audio_policy *pol, audio_io_handle_t output, + audio_stream_type_t stream, int session) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->startOutput(output, (AudioSystem::stream_type)stream, + session); +} + +static int ap_stop_output(struct audio_policy *pol, audio_io_handle_t output, + audio_stream_type_t stream, int session) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->stopOutput(output, (AudioSystem::stream_type)stream, + session); +} + +static void ap_release_output(struct audio_policy *pol, + audio_io_handle_t output) +{ + struct legacy_audio_policy *lap = to_lap(pol); + lap->apm->releaseOutput(output); +} + +static audio_io_handle_t ap_get_input(struct audio_policy *pol, audio_source_t inputSource, + uint32_t sampling_rate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_in_acoustics_t acoustics) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->getInput((int) inputSource, sampling_rate, (int) format, channelMask, + (AudioSystem::audio_in_acoustics)acoustics); +} + +static int ap_start_input(struct audio_policy *pol, audio_io_handle_t input) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->startInput(input); +} + +static int ap_stop_input(struct audio_policy *pol, audio_io_handle_t input) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->stopInput(input); +} + +static void ap_release_input(struct audio_policy *pol, audio_io_handle_t input) +{ + struct legacy_audio_policy *lap = to_lap(pol); + lap->apm->releaseInput(input); +} + +static void ap_init_stream_volume(struct audio_policy *pol, + audio_stream_type_t stream, int index_min, + int index_max) +{ + struct legacy_audio_policy *lap = to_lap(pol); + lap->apm->initStreamVolume((AudioSystem::stream_type)stream, index_min, + index_max); +} + +static int ap_set_stream_volume_index(struct audio_policy *pol, + audio_stream_type_t stream, + int index) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream, + index, + AUDIO_DEVICE_OUT_DEFAULT); +} + +static int ap_get_stream_volume_index(const struct audio_policy *pol, + audio_stream_type_t stream, + int *index) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return lap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream, + index, + AUDIO_DEVICE_OUT_DEFAULT); +} + +static int ap_set_stream_volume_index_for_device(struct audio_policy *pol, + audio_stream_type_t stream, + int index, + audio_devices_t device) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream, + index, + device); +} + +static int ap_get_stream_volume_index_for_device(const struct audio_policy *pol, + audio_stream_type_t stream, + int *index, + audio_devices_t device) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return lap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream, + index, + device); +} + +static uint32_t ap_get_strategy_for_stream(const struct audio_policy *pol, + audio_stream_type_t stream) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return lap->apm->getStrategyForStream((AudioSystem::stream_type)stream); +} + +static audio_devices_t ap_get_devices_for_stream(const struct audio_policy *pol, + audio_stream_type_t stream) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return lap->apm->getDevicesForStream((AudioSystem::stream_type)stream); +} + +static audio_io_handle_t ap_get_output_for_effect(struct audio_policy *pol, + const struct effect_descriptor_s *desc) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->getOutputForEffect(desc); +} + +static int ap_register_effect(struct audio_policy *pol, + const struct effect_descriptor_s *desc, + audio_io_handle_t io, + uint32_t strategy, + int session, + int id) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->registerEffect(desc, io, strategy, session, id); +} + +static int ap_unregister_effect(struct audio_policy *pol, int id) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->unregisterEffect(id); +} + +static int ap_set_effect_enabled(struct audio_policy *pol, int id, bool enabled) +{ + struct legacy_audio_policy *lap = to_lap(pol); + return lap->apm->setEffectEnabled(id, enabled); +} + +static bool ap_is_stream_active(const struct audio_policy *pol, audio_stream_type_t stream, + uint32_t in_past_ms) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return lap->apm->isStreamActive((int) stream, in_past_ms); +} + +static bool ap_is_source_active(const struct audio_policy *pol, audio_source_t source) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return lap->apm->isSourceActive(source); +} + +static int ap_dump(const struct audio_policy *pol, int fd) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return lap->apm->dump(fd); +} + +static int create_legacy_ap(const struct audio_policy_device *device, + struct audio_policy_service_ops *aps_ops, + void *service, + struct audio_policy **ap) +{ + struct legacy_audio_policy *lap; + int ret; + + if (!service || !aps_ops) + return -EINVAL; + + lap = (struct legacy_audio_policy *)calloc(1, sizeof(*lap)); + if (!lap) + return -ENOMEM; + + lap->policy.set_device_connection_state = ap_set_device_connection_state; + lap->policy.get_device_connection_state = ap_get_device_connection_state; + lap->policy.set_phone_state = ap_set_phone_state; + lap->policy.set_ringer_mode = ap_set_ringer_mode; + lap->policy.set_force_use = ap_set_force_use; + lap->policy.get_force_use = ap_get_force_use; + lap->policy.set_can_mute_enforced_audible = + ap_set_can_mute_enforced_audible; + lap->policy.init_check = ap_init_check; + lap->policy.get_output = ap_get_output; + lap->policy.start_output = ap_start_output; + lap->policy.stop_output = ap_stop_output; + lap->policy.release_output = ap_release_output; + lap->policy.get_input = ap_get_input; + lap->policy.start_input = ap_start_input; + lap->policy.stop_input = ap_stop_input; + lap->policy.release_input = ap_release_input; + lap->policy.init_stream_volume = ap_init_stream_volume; + lap->policy.set_stream_volume_index = ap_set_stream_volume_index; + lap->policy.get_stream_volume_index = ap_get_stream_volume_index; +#ifndef ICS_AUDIO_BLOB + lap->policy.set_stream_volume_index_for_device = ap_set_stream_volume_index_for_device; + lap->policy.get_stream_volume_index_for_device = ap_get_stream_volume_index_for_device; +#endif + lap->policy.get_strategy_for_stream = ap_get_strategy_for_stream; + lap->policy.get_devices_for_stream = ap_get_devices_for_stream; + lap->policy.get_output_for_effect = ap_get_output_for_effect; + lap->policy.register_effect = ap_register_effect; + lap->policy.unregister_effect = ap_unregister_effect; + lap->policy.set_effect_enabled = ap_set_effect_enabled; + lap->policy.is_stream_active = ap_is_stream_active; + lap->policy.is_source_active = ap_is_source_active; + lap->policy.dump = ap_dump; + + lap->service = service; + lap->aps_ops = aps_ops; + lap->service_client = + new AudioPolicyCompatClient(aps_ops, service); + if (!lap->service_client) { + ret = -ENOMEM; + goto err_new_compat_client; + } + + lap->apm = createAudioPolicyManager(lap->service_client); + if (!lap->apm) { + ret = -ENOMEM; + goto err_create_apm; + } + + *ap = &lap->policy; + return 0; + +err_create_apm: + delete lap->service_client; +err_new_compat_client: + free(lap); + *ap = NULL; + return ret; +} + +static int destroy_legacy_ap(const struct audio_policy_device *ap_dev, + struct audio_policy *ap) +{ + struct legacy_audio_policy *lap = to_lap(ap); + + if (!lap) + return 0; + + if (lap->apm) + destroyAudioPolicyManager(lap->apm); + if (lap->service_client) + delete lap->service_client; + free(lap); + return 0; +} + +static int legacy_ap_dev_close(hw_device_t* device) +{ + if (device) + free(device); + return 0; +} + +static int legacy_ap_dev_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + struct legacy_ap_device *dev; + + if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0) + return -EINVAL; + + dev = (struct legacy_ap_device *)calloc(1, sizeof(*dev)); + if (!dev) + return -ENOMEM; + + dev->device.common.tag = HARDWARE_DEVICE_TAG; + dev->device.common.version = 0; + dev->device.common.module = const_cast(module); + dev->device.common.close = legacy_ap_dev_close; + dev->device.create_audio_policy = create_legacy_ap; + dev->device.destroy_audio_policy = destroy_legacy_ap; + + *device = &dev->device.common; + + return 0; +} + +static struct hw_module_methods_t legacy_ap_module_methods = { + open: legacy_ap_dev_open +}; + +struct legacy_ap_module HAL_MODULE_INFO_SYM = { + module: { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: AUDIO_POLICY_HARDWARE_MODULE_ID, + name: "LEGACY Audio Policy HAL", + author: "The Android Open Source Project", + methods: &legacy_ap_module_methods, + dso : NULL, + reserved : {0}, + }, + }, +}; + +}; // extern "C" + +}; // namespace android_audio_legacy diff --git a/hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareBase.h b/hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareBase.h new file mode 100644 index 00000000..eac40dc1 --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareBase.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AUDIO_HARDWARE_BASE_H +#define ANDROID_AUDIO_HARDWARE_BASE_H + +#include + +#include + +namespace android_audio_legacy { + +// ---------------------------------------------------------------------------- + +/** + * AudioHardwareBase is a convenient base class used for implementing the + * AudioHardwareInterface interface. + */ +class AudioHardwareBase : public AudioHardwareInterface +{ +public: + AudioHardwareBase(); + virtual ~AudioHardwareBase() { } + + /** + * setMode is called when the audio mode changes. NORMAL mode is for + * standard audio playback, RINGTONE when a ringtone is playing, IN_CALL + * when a telephony call is in progress, IN_COMMUNICATION when a VoIP call is in progress. + */ + virtual status_t setMode(int mode); + + virtual status_t setParameters(const String8& keyValuePairs); + virtual String8 getParameters(const String8& keys); + + virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount); + virtual status_t getMasterVolume(float *volume); + + /**This method dumps the state of the audio hardware */ + virtual status_t dumpState(int fd, const Vector& args); + +protected: + /** returns true if the given mode maps to a telephony or VoIP call is in progress */ + virtual bool isModeInCall(int mode) + { return ((mode == AudioSystem::MODE_IN_CALL) + || (mode == AudioSystem::MODE_IN_COMMUNICATION)); }; + /** returns true if a telephony or VoIP call is in progress */ + virtual bool isInCall() { return isModeInCall(mMode); }; + int mMode; +}; + +}; // namespace android + +#endif // ANDROID_AUDIO_HARDWARE_BASE_H diff --git a/hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h b/hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h new file mode 100644 index 00000000..a456bafe --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AUDIO_HARDWARE_INTERFACE_H +#define ANDROID_AUDIO_HARDWARE_INTERFACE_H + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace android_audio_legacy { + using android::Vector; + using android::String16; + using android::String8; + +// ---------------------------------------------------------------------------- + +/** + * AudioStreamOut is the abstraction interface for the audio output hardware. + * + * It provides information about various properties of the audio output hardware driver. + */ +class AudioStreamOut { +public: + virtual ~AudioStreamOut() = 0; + + /** return audio sampling rate in hz - eg. 44100 */ + virtual uint32_t sampleRate() const = 0; + + /** returns size of output buffer - eg. 4800 */ + virtual size_t bufferSize() const = 0; + + /** + * returns the output channel mask + */ + virtual uint32_t channels() const = 0; + + /** + * return audio format in 8bit or 16bit PCM format - + * eg. AudioSystem:PCM_16_BIT + */ + virtual int format() const = 0; + + /** + * return the frame size (number of bytes per sample). + */ + uint32_t frameSize() const { return popcount(channels())*((format()==AUDIO_FORMAT_PCM_16_BIT)?sizeof(int16_t):sizeof(int8_t)); } + + /** + * return the audio hardware driver latency in milli seconds. + */ + virtual uint32_t latency() const = 0; + + /** + * Use this method in situations where audio mixing is done in the + * hardware. This method serves as a direct interface with hardware, + * allowing you to directly set the volume as apposed to via the framework. + * This method might produce multiple PCM outputs or hardware accelerated + * codecs, such as MP3 or AAC. + */ + virtual status_t setVolume(float left, float right) = 0; + + /** write audio buffer to driver. Returns number of bytes written */ + virtual ssize_t write(const void* buffer, size_t bytes) = 0; + + /** + * Put the audio hardware output into standby mode. Returns + * status based on include/utils/Errors.h + */ + virtual status_t standby() = 0; + + /** dump the state of the audio output device */ + virtual status_t dump(int fd, const Vector& args) = 0; + + // set/get audio output parameters. The function accepts a list of parameters + // key value pairs in the form: key1=value1;key2=value2;... + // Some keys are reserved for standard parameters (See AudioParameter class). + // If the implementation does not accept a parameter change while the output is + // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION. + // The audio flinger will put the output in standby and then change the parameter value. + virtual status_t setParameters(const String8& keyValuePairs) = 0; + virtual String8 getParameters(const String8& keys) = 0; + + // return the number of audio frames written by the audio dsp to DAC since + // the output has exited standby + virtual status_t getRenderPosition(uint32_t *dspFrames) = 0; + + /** + * get the local time at which the next write to the audio driver will be + * presented + */ +#ifndef ICS_AUDIO_BLOB + virtual status_t getNextWriteTimestamp(int64_t *timestamp); +#ifdef QCOM_HARDWARE + virtual status_t start() {return INVALID_OPERATION;} + virtual status_t pause() {return INVALID_OPERATION;} + virtual status_t flush() {return INVALID_OPERATION;} + virtual status_t stop() {return INVALID_OPERATION;} + virtual int setObserver(void *observer) {return INVALID_OPERATION;} + virtual status_t getBufferInfo(buf_info **buf) {return INVALID_OPERATION;} + virtual status_t isBufferAvailable(int *isAvail) { + *isAvail = true; + return NO_ERROR; + } +#endif +#endif + +}; + +/** + * AudioStreamIn is the abstraction interface for the audio input hardware. + * + * It defines the various properties of the audio hardware input driver. + */ +class AudioStreamIn { +public: + virtual ~AudioStreamIn() = 0; + + /** return audio sampling rate in hz - eg. 44100 */ + virtual uint32_t sampleRate() const = 0; + + /** return the input buffer size allowed by audio driver */ + virtual size_t bufferSize() const = 0; + + /** return input channel mask */ + virtual uint32_t channels() const = 0; + + /** + * return audio format in 8bit or 16bit PCM format - + * eg. AudioSystem:PCM_16_BIT + */ + virtual int format() const = 0; + + /** + * return the frame size (number of bytes per sample). + */ + uint32_t frameSize() const { return AudioSystem::popCount(channels())*((format()==AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(int8_t)); } + + /** set the input gain for the audio driver. This method is for + * for future use */ + virtual status_t setGain(float gain) = 0; + + /** read audio buffer in from audio driver */ + virtual ssize_t read(void* buffer, ssize_t bytes) = 0; + + /** dump the state of the audio input device */ + virtual status_t dump(int fd, const Vector& args) = 0; + + /** + * Put the audio hardware input into standby mode. Returns + * status based on include/utils/Errors.h + */ + virtual status_t standby() = 0; + + // set/get audio input parameters. The function accepts a list of parameters + // key value pairs in the form: key1=value1;key2=value2;... + // Some keys are reserved for standard parameters (See AudioParameter class). + // If the implementation does not accept a parameter change while the output is + // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION. + // The audio flinger will put the input in standby and then change the parameter value. + virtual status_t setParameters(const String8& keyValuePairs) = 0; + virtual String8 getParameters(const String8& keys) = 0; + + + // Return the number of input frames lost in the audio driver since the last call of this function. + // Audio driver is expected to reset the value to 0 and restart counting upon returning the current value by this function call. + // Such loss typically occurs when the user space process is blocked longer than the capacity of audio driver buffers. + // Unit: the number of input audio frames + virtual unsigned int getInputFramesLost() const = 0; + + virtual status_t addAudioEffect(effect_handle_t effect) = 0; + virtual status_t removeAudioEffect(effect_handle_t effect) = 0; +}; + +/** + * AudioHardwareInterface.h defines the interface to the audio hardware abstraction layer. + * + * The interface supports setting and getting parameters, selecting audio routing + * paths, and defining input and output streams. + * + * AudioFlinger initializes the audio hardware and immediately opens an output stream. + * You can set Audio routing to output to handset, speaker, Bluetooth, or a headset. + * + * The audio input stream is initialized when AudioFlinger is called to carry out + * a record operation. + */ +class AudioHardwareInterface +{ +public: + virtual ~AudioHardwareInterface() {} + + /** + * check to see if the audio hardware interface has been initialized. + * return status based on values defined in include/utils/Errors.h + */ + virtual status_t initCheck() = 0; + + /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */ + virtual status_t setVoiceVolume(float volume) = 0; + +#ifdef QCOM_FM_ENABLED + /** set the fm volume. Range is between 0.0 and 1.0 */ + virtual status_t setFmVolume(float volume) { return 0; } +#endif + + /** + * set the audio volume for all audio activities other than voice call. + * Range between 0.0 and 1.0. If any value other than NO_ERROR is returned, + * the software mixer will emulate this capability. + */ + virtual status_t setMasterVolume(float volume) = 0; + + /** + * Get the current master volume value for the HAL, if the HAL supports + * master volume control. AudioFlinger will query this value from the + * primary audio HAL when the service starts and use the value for setting + * the initial master volume across all HALs. + */ + virtual status_t getMasterVolume(float *volume) = 0; + + /** + * setMode is called when the audio mode changes. NORMAL mode is for + * standard audio playback, RINGTONE when a ringtone is playing, and IN_CALL + * when a call is in progress. + */ + virtual status_t setMode(int mode) = 0; + + // mic mute + virtual status_t setMicMute(bool state) = 0; + virtual status_t getMicMute(bool* state) = 0; + + // set/get global audio parameters + virtual status_t setParameters(const String8& keyValuePairs) = 0; + virtual String8 getParameters(const String8& keys) = 0; + + // Returns audio input buffer size according to parameters passed or 0 if one of the + // parameters is not supported + virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0; + + /** This method creates and opens the audio hardware output stream */ + virtual AudioStreamOut* openOutputStream( + uint32_t devices, + int *format=0, + uint32_t *channels=0, + uint32_t *sampleRate=0, + status_t *status=0) = 0; + virtual void closeOutputStream(AudioStreamOut* out) = 0; + + /** This method creates and opens the audio hardware input stream */ + virtual AudioStreamIn* openInputStream( + uint32_t devices, + int *format, + uint32_t *channels, + uint32_t *sampleRate, + status_t *status, + AudioSystem::audio_in_acoustics acoustics) = 0; + virtual void closeInputStream(AudioStreamIn* in) = 0; + + /**This method dumps the state of the audio hardware */ + virtual status_t dumpState(int fd, const Vector& args) = 0; + + static AudioHardwareInterface* create(); + +protected: + + virtual status_t dump(int fd, const Vector& args) = 0; +}; + +// ---------------------------------------------------------------------------- + +extern "C" AudioHardwareInterface* createAudioHardware(void); + +}; // namespace android + +#endif // ANDROID_AUDIO_HARDWARE_INTERFACE_H diff --git a/hardware/libhardware_legacy/include/hardware_legacy/AudioPolicyInterface.h b/hardware/libhardware_legacy/include/hardware_legacy/AudioPolicyInterface.h new file mode 100644 index 00000000..b0f4c392 --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/AudioPolicyInterface.h @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AUDIOPOLICYINTERFACE_H +#define ANDROID_AUDIOPOLICYINTERFACE_H + +#include +#include +#include + +#include + +namespace android_audio_legacy { + using android::Vector; + using android::String8; + using android::ToneGenerator; + +// ---------------------------------------------------------------------------- + +// The AudioPolicyInterface and AudioPolicyClientInterface classes define the communication interfaces +// between the platform specific audio policy manager and Android generic audio policy manager. +// The platform specific audio policy manager must implement methods of the AudioPolicyInterface class. +// This implementation makes use of the AudioPolicyClientInterface to control the activity and +// configuration of audio input and output streams. +// +// The platform specific audio policy manager is in charge of the audio routing and volume control +// policies for a given platform. +// The main roles of this module are: +// - keep track of current system state (removable device connections, phone state, user requests...). +// System state changes and user actions are notified to audio policy manager with methods of the AudioPolicyInterface. +// - process getOutput() queries received when AudioTrack objects are created: Those queries +// return a handler on an output that has been selected, configured and opened by the audio policy manager and that +// must be used by the AudioTrack when registering to the AudioFlinger with the createTrack() method. +// When the AudioTrack object is released, a putOutput() query is received and the audio policy manager can decide +// to close or reconfigure the output depending on other streams using this output and current system state. +// - similarly process getInput() and putInput() queries received from AudioRecord objects and configure audio inputs. +// - process volume control requests: the stream volume is converted from an index value (received from UI) to a float value +// applicable to each output as a function of platform specific settings and current output route (destination device). It +// also make sure that streams are not muted if not allowed (e.g. camera shutter sound in some countries). +// +// The platform specific audio policy manager is provided as a shared library by platform vendors (as for libaudio.so) +// and is linked with libaudioflinger.so + + +// Audio Policy Manager Interface +class AudioPolicyInterface +{ + +public: + virtual ~AudioPolicyInterface() {} + // + // configuration functions + // + + // indicate a change in device connection status + virtual status_t setDeviceConnectionState(audio_devices_t device, + AudioSystem::device_connection_state state, + const char *device_address) = 0; + // retrieve a device connection status + virtual AudioSystem::device_connection_state getDeviceConnectionState(audio_devices_t device, + const char *device_address) = 0; + // indicate a change in phone state. Valid phones states are defined by AudioSystem::audio_mode + virtual void setPhoneState(int state) = 0; + // force using a specific device category for the specified usage + virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) = 0; + // retrieve current device category forced for a given usage + virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage) = 0; + // set a system property (e.g. camera sound always audible) + virtual void setSystemProperty(const char* property, const char* value) = 0; + // check proper initialization + virtual status_t initCheck() = 0; + + // + // Audio routing query functions + // + + // request an output appropriate for playback of the supplied stream type and parameters + virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream, + uint32_t samplingRate = 0, + uint32_t format = AudioSystem::FORMAT_DEFAULT, + uint32_t channels = 0, + AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT) = 0; + // indicates to the audio policy manager that the output starts being used by corresponding stream. + virtual status_t startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0) = 0; + // indicates to the audio policy manager that the output stops being used by corresponding stream. + virtual status_t stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0) = 0; + // releases the output. + virtual void releaseOutput(audio_io_handle_t output) = 0; + + // request an input appropriate for record from the supplied device with supplied parameters. + virtual audio_io_handle_t getInput(int inputSource, + uint32_t samplingRate = 0, + uint32_t Format = AudioSystem::FORMAT_DEFAULT, + uint32_t channels = 0, + AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0) = 0; + // indicates to the audio policy manager that the input starts being used. + virtual status_t startInput(audio_io_handle_t input) = 0; + // indicates to the audio policy manager that the input stops being used. + virtual status_t stopInput(audio_io_handle_t input) = 0; + // releases the input. + virtual void releaseInput(audio_io_handle_t input) = 0; + + // + // volume control functions + // + + // initialises stream volume conversion parameters by specifying volume index range. + virtual void initStreamVolume(AudioSystem::stream_type stream, + int indexMin, + int indexMax) = 0; + + // sets the new stream volume at a level corresponding to the supplied index for the + // supplied device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means + // setting volume for all devices + virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, + int index, + audio_devices_t device) = 0; + + // retrieve current volume index for the specified stream and the + // specified device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means + // querying the volume of the active device. + virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, + int *index, + audio_devices_t device) = 0; + + // return the strategy corresponding to a given stream type + virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream) = 0; + + // return the enabled output devices for the given stream type + virtual audio_devices_t getDevicesForStream(AudioSystem::stream_type stream) = 0; + + // Audio effect management + virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc) = 0; + virtual status_t registerEffect(const effect_descriptor_t *desc, + audio_io_handle_t io, + uint32_t strategy, + int session, + int id) = 0; + virtual status_t unregisterEffect(int id) = 0; + virtual status_t setEffectEnabled(int id, bool enabled) = 0; + + virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const = 0; + virtual bool isSourceActive(audio_source_t source) const = 0; + + //dump state + virtual status_t dump(int fd) = 0; +}; + + +// Audio Policy client Interface +class AudioPolicyClientInterface +{ +public: + virtual ~AudioPolicyClientInterface() {} + + // + // Audio HW module functions + // + + // loads a HW module. + virtual audio_module_handle_t loadHwModule(const char *name) = 0; + + // + // Audio output Control functions + // + + // opens an audio output with the requested parameters. The parameter values can indicate to use the default values + // in case the audio policy manager has no specific requirements for the output being opened. + // When the function returns, the parameter values reflect the actual values used by the audio hardware output stream. + // The audio policy manager can check if the proposed parameters are suitable or not and act accordingly. + virtual audio_io_handle_t openOutput(audio_module_handle_t module, + audio_devices_t *pDevices, + uint32_t *pSamplingRate, + audio_format_t *pFormat, + audio_channel_mask_t *pChannelMask, + uint32_t *pLatencyMs, + audio_output_flags_t flags) = 0; + // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by + // a special mixer thread in the AudioFlinger. + virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2) = 0; + // closes the output stream + virtual status_t closeOutput(audio_io_handle_t output) = 0; + // suspends the output. When an output is suspended, the corresponding audio hardware output stream is placed in + // standby and the AudioTracks attached to the mixer thread are still processed but the output mix is discarded. + virtual status_t suspendOutput(audio_io_handle_t output) = 0; + // restores a suspended output. + virtual status_t restoreOutput(audio_io_handle_t output) = 0; + + // + // Audio input Control functions + // + + // opens an audio input + virtual audio_io_handle_t openInput(audio_module_handle_t module, + audio_devices_t *pDevices, + uint32_t *pSamplingRate, + audio_format_t *pFormat, + audio_channel_mask_t *pChannelMask) = 0; + // closes an audio input + virtual status_t closeInput(audio_io_handle_t input) = 0; + // + // misc control functions + // + + // set a stream volume for a particular output. For the same user setting, a given stream type can have different volumes + // for each output (destination device) it is attached to. + virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs = 0) = 0; + + // FIXME ignores output, should be renamed to invalidateStreamOuput(stream) + // reroute a given stream type to the specified output + virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output) = 0; + + // function enabling to send proprietary informations directly from audio policy manager to audio hardware interface. + virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0) = 0; + // function enabling to receive proprietary informations directly from audio hardware interface to audio policy manager. + virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) = 0; + + // request the playback of a tone on the specified stream: used for instance to replace notification sounds when playing + // over a telephony device during a phone call. + virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream) = 0; + virtual status_t stopTone() = 0; + + // set down link audio volume. + virtual status_t setVoiceVolume(float volume, int delayMs = 0) = 0; + + // move effect to the specified output + virtual status_t moveEffects(int session, + audio_io_handle_t srcOutput, + audio_io_handle_t dstOutput) = 0; + +#ifdef QCOM_FM_ENABLED + // set FM volume. + virtual status_t setFmVolume(float volume, int delayMs = 0) { return 0; } +#endif + +}; + +extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface); +extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface); + + +}; // namespace android + +#endif // ANDROID_AUDIOPOLICYINTERFACE_H diff --git a/hardware/libhardware_legacy/include/hardware_legacy/AudioPolicyManagerBase.h b/hardware/libhardware_legacy/include/hardware_legacy/AudioPolicyManagerBase.h new file mode 100644 index 00000000..16c3b166 --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/AudioPolicyManagerBase.h @@ -0,0 +1,587 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace android_audio_legacy { + using android::KeyedVector; + using android::DefaultKeyedVector; + using android::SortedVector; + +// ---------------------------------------------------------------------------- + +#define MAX_DEVICE_ADDRESS_LEN 20 +// Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB +#define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5 +// Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB +#define SONIFICATION_HEADSET_VOLUME_MIN 0.016 +// Time in milliseconds during which we consider that music is still active after a music +// track was stopped - see computeVolume() +#define SONIFICATION_HEADSET_MUSIC_DELAY 5000 +// Time in milliseconds after media stopped playing during which we consider that the +// sonification should be as unobtrusive as during the time media was playing. +#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000 +// Time in milliseconds during witch some streams are muted while the audio path +// is switched +#define MUTE_TIME_MS 2000 + +#define NUM_TEST_OUTPUTS 5 + +#define NUM_VOL_CURVE_KNEES 2 + +// ---------------------------------------------------------------------------- +// AudioPolicyManagerBase implements audio policy manager behavior common to all platforms. +// Each platform must implement an AudioPolicyManager class derived from AudioPolicyManagerBase +// and override methods for which the platform specific behavior differs from the implementation +// in AudioPolicyManagerBase. Even if no specific behavior is required, the AudioPolicyManager +// class must be implemented as well as the class factory function createAudioPolicyManager() +// and provided in a shared library libaudiopolicy.so. +// ---------------------------------------------------------------------------- + +class AudioPolicyManagerBase: public AudioPolicyInterface +#ifdef AUDIO_POLICY_TEST + , public Thread +#endif //AUDIO_POLICY_TEST +{ + +public: + AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface); + virtual ~AudioPolicyManagerBase(); + + // AudioPolicyInterface + virtual status_t setDeviceConnectionState(audio_devices_t device, + AudioSystem::device_connection_state state, + const char *device_address); + virtual AudioSystem::device_connection_state getDeviceConnectionState(audio_devices_t device, + const char *device_address); + virtual void setPhoneState(int state); + virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config); + virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage); + virtual void setSystemProperty(const char* property, const char* value); + virtual status_t initCheck(); + virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream, + uint32_t samplingRate = 0, + uint32_t format = AudioSystem::FORMAT_DEFAULT, + uint32_t channels = 0, + AudioSystem::output_flags flags = + AudioSystem::OUTPUT_FLAG_INDIRECT); + virtual status_t startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); + virtual status_t stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); + virtual void releaseOutput(audio_io_handle_t output); + virtual audio_io_handle_t getInput(int inputSource, + uint32_t samplingRate, + uint32_t format, + uint32_t channels, + AudioSystem::audio_in_acoustics acoustics); + + // indicates to the audio policy manager that the input starts being used. + virtual status_t startInput(audio_io_handle_t input); + + // indicates to the audio policy manager that the input stops being used. + virtual status_t stopInput(audio_io_handle_t input); + virtual void releaseInput(audio_io_handle_t input); + virtual void initStreamVolume(AudioSystem::stream_type stream, + int indexMin, + int indexMax); + virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, + int index, + audio_devices_t device); + virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, + int *index, + audio_devices_t device); + + // return the strategy corresponding to a given stream type + virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream); + + // return the enabled output devices for the given stream type + virtual audio_devices_t getDevicesForStream(AudioSystem::stream_type stream); + + virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc); + virtual status_t registerEffect(const effect_descriptor_t *desc, + audio_io_handle_t io, + uint32_t strategy, + int session, + int id); + virtual status_t unregisterEffect(int id); + virtual status_t setEffectEnabled(int id, bool enabled); + + virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const; + virtual bool isSourceActive(audio_source_t source) const; + + virtual status_t dump(int fd); + +protected: + + enum routing_strategy { + STRATEGY_MEDIA, + STRATEGY_PHONE, + STRATEGY_SONIFICATION, + STRATEGY_SONIFICATION_RESPECTFUL, + STRATEGY_DTMF, + STRATEGY_ENFORCED_AUDIBLE, + NUM_STRATEGIES + }; + + // 4 points to define the volume attenuation curve, each characterized by the volume + // index (from 0 to 100) at which they apply, and the attenuation in dB at that index. + // we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl() + + enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4}; + + class VolumeCurvePoint + { + public: + int mIndex; + float mDBAttenuation; + }; + + // device categories used for volume curve management. + enum device_category { + DEVICE_CATEGORY_HEADSET, + DEVICE_CATEGORY_SPEAKER, + DEVICE_CATEGORY_EARPIECE, + DEVICE_CATEGORY_CNT + }; + + class IOProfile; + + class HwModule { + public: + HwModule(const char *name); + ~HwModule(); + + void dump(int fd); + + const char *const mName; // base name of the audio HW module (primary, a2dp ...) + audio_module_handle_t mHandle; + Vector mOutputProfiles; // output profiles exposed by this module + Vector mInputProfiles; // input profiles exposed by this module + }; + + // the IOProfile class describes the capabilities of an output or input stream. + // It is currently assumed that all combination of listed parameters are supported. + // It is used by the policy manager to determine if an output or input is suitable for + // a given use case, open/close it accordingly and connect/disconnect audio tracks + // to/from it. + class IOProfile + { + public: + IOProfile(HwModule *module); + ~IOProfile(); + + bool isCompatibleProfile(audio_devices_t device, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + audio_output_flags_t flags) const; + + void dump(int fd); + + // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats + // indicates the supported parameters should be read from the output stream + // after it is opened for the first time + Vector mSamplingRates; // supported sampling rates + Vector mChannelMasks; // supported channel masks + Vector mFormats; // supported audio formats + audio_devices_t mSupportedDevices; // supported devices (devices this output can be + // routed to) + audio_output_flags_t mFlags; // attribute flags (e.g primary output, + // direct output...). For outputs only. + HwModule *mModule; // audio HW module exposing this I/O stream + }; + + // default volume curve + static const VolumeCurvePoint sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT]; + // default volume curve for media strategy + static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT]; + // volume curve for media strategy on speakers + static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT]; + // volume curve for sonification strategy on speakers + static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT]; + static const VolumeCurvePoint sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT]; + static const VolumeCurvePoint sHeadsetSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT]; + static const VolumeCurvePoint sDefaultVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT]; + static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT]; + // default volume curves per stream and device category. See initializeVolumeCurves() + static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][DEVICE_CATEGORY_CNT]; + + // descriptor for audio outputs. Used to maintain current configuration of each opened audio output + // and keep track of the usage of this output by each audio stream type. + class AudioOutputDescriptor + { + public: + AudioOutputDescriptor(const IOProfile *profile); + + status_t dump(int fd); + + audio_devices_t device(); + void changeRefCount(AudioSystem::stream_type, int delta); + uint32_t refCount(); + uint32_t strategyRefCount(routing_strategy strategy); + bool isUsedByStrategy(routing_strategy strategy) { return (strategyRefCount(strategy) != 0);} + bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); } + audio_devices_t supportedDevices(); + uint32_t latency(); + bool sharesHwModuleWith(const AudioOutputDescriptor *outputDesc); + bool isActive(uint32_t inPastMs) const; + + audio_io_handle_t mId; // output handle + uint32_t mSamplingRate; // + audio_format_t mFormat; // + audio_channel_mask_t mChannelMask; // output configuration + uint32_t mLatency; // + audio_output_flags_t mFlags; // + audio_devices_t mDevice; // current device this output is routed to + uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using this output + nsecs_t mStopTime[AudioSystem::NUM_STREAM_TYPES]; + AudioOutputDescriptor *mOutput1; // used by duplicated outputs: first output + AudioOutputDescriptor *mOutput2; // used by duplicated outputs: second output + float mCurVolume[AudioSystem::NUM_STREAM_TYPES]; // current stream volume + int mMuteCount[AudioSystem::NUM_STREAM_TYPES]; // mute request counter + const IOProfile *mProfile; // I/O profile this output derives from + bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible + // device selection. See checkDeviceMuteStrategies() + }; + + // descriptor for audio inputs. Used to maintain current configuration of each opened audio input + // and keep track of the usage of this input. + class AudioInputDescriptor + { + public: + AudioInputDescriptor(const IOProfile *profile); + + status_t dump(int fd); + + uint32_t mSamplingRate; // + audio_format_t mFormat; // input configuration + audio_channel_mask_t mChannelMask; // + audio_devices_t mDevice; // current device this input is routed to + uint32_t mRefCount; // number of AudioRecord clients using this output + int mInputSource; // input source selected by application (mediarecorder.h) + const IOProfile *mProfile; // I/O profile this output derives from + }; + + // stream descriptor used for volume control + class StreamDescriptor + { + public: + StreamDescriptor(); + + int getVolumeIndex(audio_devices_t device); + void dump(int fd); + + int mIndexMin; // min volume index + int mIndexMax; // max volume index + KeyedVector mIndexCur; // current volume index per device + bool mCanBeMuted; // true is the stream can be muted + + const VolumeCurvePoint *mVolumeCurve[DEVICE_CATEGORY_CNT]; + }; + + // stream descriptor used for volume control + class EffectDescriptor + { + public: + + status_t dump(int fd); + + int mIo; // io the effect is attached to + routing_strategy mStrategy; // routing strategy the effect is associated to + int mSession; // audio session the effect is on + effect_descriptor_t mDesc; // effect descriptor + bool mEnabled; // enabled state: CPU load being used or not + }; + + void addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc); + + // return the strategy corresponding to a given stream type + static routing_strategy getStrategy(AudioSystem::stream_type stream); + + // return appropriate device for streams handled by the specified strategy according to current + // phone state, connected devices... + // if fromCache is true, the device is returned from mDeviceForStrategy[], + // otherwise it is determine by current state + // (device connected,phone state, force use, a2dp output...) + // This allows to: + // 1 speed up process when the state is stable (when starting or stopping an output) + // 2 access to either current device selection (fromCache == true) or + // "future" device selection (fromCache == false) when called from a context + // where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND + // before updateDevicesAndOutputs() is called. + virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, + bool fromCache); + + // change the route of the specified output. Returns the number of ms we have slept to + // allow new routing to take effect in certain cases. +#ifdef QCOM_HARDWARE + virtual uint32_t setOutputDevice(audio_io_handle_t output, +#else + uint32_t setOutputDevice(audio_io_handle_t output, +#endif + audio_devices_t device, + bool force = false, + int delayMs = 0); + + // select input device corresponding to requested audio source + virtual audio_devices_t getDeviceForInputSource(int inputSource); + + // return io handle of active input or 0 if no input is active + // Only considers inputs from physical devices (e.g. main mic, headset mic) when + // ignoreVirtualInputs is true. + audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true); + + // initialize volume curves for each strategy and device category + void initializeVolumeCurves(); + + // compute the actual volume for a given stream according to the requested index and a particular + // device + virtual float computeVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device); + + // check that volume change is permitted, compute and send new volume to audio hardware +#ifdef QCOM_HARDWARE + virtual status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false); +#else + status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false); +#endif + + // apply all stream volumes to the specified output and device + void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false); + + // Mute or unmute all streams handled by the specified strategy on the specified output + void setStrategyMute(routing_strategy strategy, + bool on, + audio_io_handle_t output, + int delayMs = 0, + audio_devices_t device = (audio_devices_t)0); + + // Mute or unmute the stream on the specified output +#ifdef QCOM_HARDWARE + virtual void setStreamMute(int stream, +#else + void setStreamMute(int stream, +#endif + bool on, + audio_io_handle_t output, + int delayMs = 0, + audio_devices_t device = (audio_devices_t)0); + + // handle special cases for sonification strategy while in call: mute streams or replace by + // a special tone in the device used for communication + void handleIncallSonification(int stream, bool starting, bool stateChange); + + // true if device is in a telephony or VoIP call + virtual bool isInCall(); + + // true if given state represents a device in a telephony or VoIP call + virtual bool isStateInCall(int state); + + // when a device is connected, checks if an open output can be routed + // to this device. If none is open, tries to open one of the available outputs. + // Returns an output suitable to this device or 0. + // when a device is disconnected, checks if an output is not used any more and + // returns its handle if any. + // transfers the audio tracks and effects from one output thread to another accordingly. + status_t checkOutputsForDevice(audio_devices_t device, + AudioSystem::device_connection_state state, + SortedVector& outputs); + + // close an output and its companion duplicating output. + void closeOutput(audio_io_handle_t output); + + // checks and if necessary changes outputs used for all strategies. + // must be called every time a condition that affects the output choice for a given strategy + // changes: connected device, phone state, force use... + // Must be called before updateDevicesAndOutputs() + void checkOutputForStrategy(routing_strategy strategy); + + // Same as checkOutputForStrategy() but for a all strategies in order of priority + void checkOutputForAllStrategies(); + + // manages A2DP output suspend/restore according to phone state and BT SCO usage + void checkA2dpSuspend(); + + // returns the A2DP output handle if it is open or 0 otherwise + audio_io_handle_t getA2dpOutput(); + + // selects the most appropriate device on output for current state + // must be called every time a condition that affects the device choice for a given output is + // changed: connected device, phone state, force use, output start, output stop.. + // see getDeviceForStrategy() for the use of fromCache parameter + + audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache); + // updates cache of device used by all strategies (mDeviceForStrategy[]) + // must be called every time a condition that affects the device choice for a given strategy is + // changed: connected device, phone state, force use... + // cached values are used by getDeviceForStrategy() if parameter fromCache is true. + // Must be called after checkOutputForAllStrategies() + + void updateDevicesAndOutputs(); + + // true if current platform requires a specific output to be opened for this particular + // set of parameters. This function is called by getOutput() and is implemented by platform + // specific audio policy manager. + virtual bool needsDirectOuput(audio_stream_type_t stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + audio_devices_t device); + + virtual uint32_t getMaxEffectsCpuLoad(); + virtual uint32_t getMaxEffectsMemory(); +#ifdef AUDIO_POLICY_TEST + virtual bool threadLoop(); + void exit(); + int testOutputIndex(audio_io_handle_t output); +#endif //AUDIO_POLICY_TEST + + status_t setEffectEnabled(EffectDescriptor *pDesc, bool enabled); + + // returns the category the device belongs to with regard to volume curve management + static device_category getDeviceCategory(audio_devices_t device); + + // extract one device relevant for volume control from multiple device selection + static audio_devices_t getDeviceForVolume(audio_devices_t device); + + SortedVector getOutputsForDevice(audio_devices_t device, + DefaultKeyedVector openOutputs); + bool vectorsEqual(SortedVector& outputs1, + SortedVector& outputs2); + + // mute/unmute strategies using an incompatible device combination + // if muting, wait for the audio in pcm buffer to be drained before proceeding + // if unmuting, unmute only after the specified delay + // Returns the number of ms waited + uint32_t checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc, + audio_devices_t prevDevice, + uint32_t delayMs); + + audio_io_handle_t selectOutput(const SortedVector& outputs, + AudioSystem::output_flags flags); + IOProfile *getInputProfile(audio_devices_t device, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask); +#ifdef QCOM_HARDWARE + virtual IOProfile *getProfileForDirectOutput(audio_devices_t device, +#else + IOProfile *getProfileForDirectOutput(audio_devices_t device, +#endif + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + audio_output_flags_t flags); + // + // Audio policy configuration file parsing (audio_policy.conf) + // + static uint32_t stringToEnum(const struct StringToEnum *table, + size_t size, + const char *name); + static audio_output_flags_t parseFlagNames(char *name); + static audio_devices_t parseDeviceNames(char *name); + void loadSamplingRates(char *name, IOProfile *profile); + void loadFormats(char *name, IOProfile *profile); + void loadOutChannels(char *name, IOProfile *profile); + void loadInChannels(char *name, IOProfile *profile); + status_t loadOutput(cnode *root, HwModule *module); + status_t loadInput(cnode *root, HwModule *module); + void loadHwModule(cnode *root); + void loadHwModules(cnode *root); + void loadGlobalConfig(cnode *root); + status_t loadAudioPolicyConfig(const char *path); + void defaultAudioPolicyConfig(void); + + + AudioPolicyClientInterface *mpClientInterface; // audio policy client interface + audio_io_handle_t mPrimaryOutput; // primary output handle + // list of descriptors for outputs currently opened + DefaultKeyedVector mOutputs; + // copy of mOutputs before setDeviceConnectionState() opens new outputs + // reset to mOutputs when updateDevicesAndOutputs() is called. + DefaultKeyedVector mPreviousOutputs; + DefaultKeyedVector mInputs; // list of input descriptors + audio_devices_t mAvailableOutputDevices; // bit field of all available output devices + audio_devices_t mAvailableInputDevices; // bit field of all available input devices + // without AUDIO_DEVICE_BIT_IN to allow direct bit + // field comparisons + int mPhoneState; // current phone state + AudioSystem::forced_config mForceUse[AudioSystem::NUM_FORCE_USE]; // current forced use configuration + + StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES]; // stream descriptors for volume control + String8 mA2dpDeviceAddress; // A2DP device MAC address + String8 mScoDeviceAddress; // SCO device MAC address + String8 mUsbCardAndDevice; // USB audio ALSA card and device numbers: + // card=;device=<> + bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected + audio_devices_t mDeviceForStrategy[NUM_STRATEGIES]; + float mLastVoiceVolume; // last voice volume value sent to audio HAL + + // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units + static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000; + // Maximum memory allocated to audio effects in KB + static const uint32_t MAX_EFFECTS_MEMORY = 512; + uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects + uint32_t mTotalEffectsMemory; // current memory used by effects + KeyedVector mEffects; // list of registered audio effects + bool mA2dpSuspended; // true if A2DP output is suspended + bool mHasA2dp; // true on platforms with support for bluetooth A2DP + bool mHasUsb; // true on platforms with support for USB audio + bool mHasRemoteSubmix; // true on platforms with support for remote presentation of a submix + audio_devices_t mAttachedOutputDevices; // output devices always available on the platform + audio_devices_t mDefaultOutputDevice; // output device selected by default at boot time + // (must be in mAttachedOutputDevices) + + Vector mHwModules; + +#ifdef AUDIO_POLICY_TEST + Mutex mLock; + Condition mWaitWorkCV; + + int mCurOutput; + bool mDirectOutput; + audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS]; + int mTestInput; + uint32_t mTestDevice; + uint32_t mTestSamplingRate; + uint32_t mTestFormat; + uint32_t mTestChannels; + uint32_t mTestLatencyMs; +#endif //AUDIO_POLICY_TEST + +private: + static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, + int indexInUi); + // updates device caching and output for streams that can influence the + // routing of notifications + void handleNotificationRoutingForStream(AudioSystem::stream_type stream); + static bool isVirtualInputDevice(audio_devices_t device); +}; + +}; diff --git a/hardware/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h b/hardware/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h new file mode 100644 index 00000000..762b6bee --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AUDIOSYSTEM_LEGACY_H_ +#define ANDROID_AUDIOSYSTEM_LEGACY_H_ + +#include +#include + +#include +#include + +namespace android_audio_legacy { + +using android::status_t; +using android::AudioParameter; + +enum { + OK = android::OK, + NO_ERROR = android::NO_ERROR, + + UNKNOWN_ERROR = android::UNKNOWN_ERROR, + + NO_MEMORY = android::NO_MEMORY, + INVALID_OPERATION = android::INVALID_OPERATION, + BAD_VALUE = android::BAD_VALUE, + BAD_TYPE = android::BAD_TYPE, + NAME_NOT_FOUND = android::NAME_NOT_FOUND, + PERMISSION_DENIED = android::PERMISSION_DENIED, + NO_INIT = android::NO_INIT, + ALREADY_EXISTS = android::ALREADY_EXISTS, + DEAD_OBJECT = android::DEAD_OBJECT, + FAILED_TRANSACTION = android::FAILED_TRANSACTION, + JPARKS_BROKE_IT = android::JPARKS_BROKE_IT, + BAD_INDEX = android::BAD_INDEX, + NOT_ENOUGH_DATA = android::NOT_ENOUGH_DATA, + WOULD_BLOCK = android::WOULD_BLOCK, + TIMED_OUT = android::TIMED_OUT, + UNKNOWN_TRANSACTION = android::UNKNOWN_TRANSACTION, +}; + +enum audio_source { + AUDIO_SOURCE_DEFAULT = 0, + AUDIO_SOURCE_MIC = 1, + AUDIO_SOURCE_VOICE_UPLINK = 2, + AUDIO_SOURCE_VOICE_DOWNLINK = 3, + AUDIO_SOURCE_VOICE_CALL = 4, + AUDIO_SOURCE_CAMCORDER = 5, + AUDIO_SOURCE_VOICE_RECOGNITION = 6, + AUDIO_SOURCE_VOICE_COMMUNICATION = 7, + AUDIO_SOURCE_REMOTE_SUBMIX = 8, +#if defined(QCOM_FM_ENABLED) || defined(STE_FM) + AUDIO_SOURCE_FM_RX = 9, + AUDIO_SOURCE_FM_RX_A2DP = 10, + AUDIO_SOURCE_MAX = AUDIO_SOURCE_FM_RX_A2DP, +#else + AUDIO_SOURCE_MAX = AUDIO_SOURCE_REMOTE_SUBMIX, +#endif + AUDIO_SOURCE_LIST_END // must be last - used to validate audio source type +}; + +class AudioSystem { +public: +#if 1 + enum stream_type { + DEFAULT =-1, + VOICE_CALL = 0, + SYSTEM = 1, + RING = 2, + MUSIC = 3, + ALARM = 4, + NOTIFICATION = 5, + BLUETOOTH_SCO = 6, + ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker + DTMF = 8, + TTS = 9, +#ifdef QCOM_FM_ENABLED + FM = 10, +#endif + NUM_STREAM_TYPES + }; + + // Audio sub formats (see AudioSystem::audio_format). + enum pcm_sub_format { + PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility + PCM_SUB_8_BIT = 0x2, // must be 2 for backward compatibility + }; + + enum audio_sessions { + SESSION_OUTPUT_STAGE = AUDIO_SESSION_OUTPUT_STAGE, + SESSION_OUTPUT_MIX = AUDIO_SESSION_OUTPUT_MIX, + }; + + // MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to specify + // bit rate, stereo mode, version... + enum mp3_sub_format { + //TODO + }; + + // AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient or octet aligned, + // encoding mode for recording... + enum amr_sub_format { + //TODO + }; + + // AAC sub format field definition: specify profile or bitrate for recording... + enum aac_sub_format { + //TODO + }; + + // VORBIS sub format field definition: specify quality for recording... + enum vorbis_sub_format { + //TODO + }; + + // Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24 bits). + // The main format indicates the main codec type. The sub format field indicates options and parameters + // for each format. The sub format is mainly used for record to indicate for instance the requested bitrate + // or profile. It can also be used for certain formats to give informations not present in the encoded + // audio stream (e.g. octet alignement for AMR). + enum audio_format { + INVALID_FORMAT = -1, + FORMAT_DEFAULT = 0, + PCM = 0x00000000, // must be 0 for backward compatibility + MP3 = 0x01000000, + AMR_NB = 0x02000000, + AMR_WB = 0x03000000, + AAC = 0x04000000, + HE_AAC_V1 = 0x05000000, + HE_AAC_V2 = 0x06000000, + VORBIS = 0x07000000, + EVRC = 0x08000000, + QCELP = 0x09000000, + MAIN_FORMAT_MASK = 0xFF000000, + SUB_FORMAT_MASK = 0x00FFFFFF, + // Aliases + PCM_16_BIT = (PCM|PCM_SUB_16_BIT), + PCM_8_BIT = (PCM|PCM_SUB_8_BIT) + }; + + enum audio_channels { + // output channels + CHANNEL_OUT_FRONT_LEFT = 0x1, + CHANNEL_OUT_FRONT_RIGHT = 0x2, + CHANNEL_OUT_FRONT_CENTER = 0x4, + CHANNEL_OUT_LOW_FREQUENCY = 0x8, + CHANNEL_OUT_BACK_LEFT = 0x10, + CHANNEL_OUT_BACK_RIGHT = 0x20, + CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40, + CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80, + CHANNEL_OUT_BACK_CENTER = 0x100, + CHANNEL_OUT_SIDE_LEFT = 0x200, + CHANNEL_OUT_SIDE_RIGHT = 0x400, + CHANNEL_OUT_TOP_CENTER = 0x800, + CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000, + CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000, + CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000, + CHANNEL_OUT_TOP_BACK_LEFT = 0x8000, + CHANNEL_OUT_TOP_BACK_CENTER = 0x10000, + CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000, + + CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT, + CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT), + CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | + CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT), + CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | + CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER), + CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | + CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | + CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT), + // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1 + CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | + CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | + CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT | + CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT), + CHANNEL_OUT_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | + CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | + CHANNEL_OUT_BACK_RIGHT | CHANNEL_OUT_FRONT_LEFT_OF_CENTER | + CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER | + CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT | CHANNEL_OUT_TOP_CENTER | + CHANNEL_OUT_TOP_FRONT_LEFT | CHANNEL_OUT_TOP_FRONT_CENTER | + CHANNEL_OUT_TOP_FRONT_RIGHT | CHANNEL_OUT_TOP_BACK_LEFT | + CHANNEL_OUT_TOP_BACK_CENTER | CHANNEL_OUT_TOP_BACK_RIGHT), + + // input channels + CHANNEL_IN_LEFT = 0x4, + CHANNEL_IN_RIGHT = 0x8, + CHANNEL_IN_FRONT = 0x10, + CHANNEL_IN_BACK = 0x20, + CHANNEL_IN_LEFT_PROCESSED = 0x40, + CHANNEL_IN_RIGHT_PROCESSED = 0x80, + CHANNEL_IN_FRONT_PROCESSED = 0x100, + CHANNEL_IN_BACK_PROCESSED = 0x200, + CHANNEL_IN_PRESSURE = 0x400, + CHANNEL_IN_X_AXIS = 0x800, + CHANNEL_IN_Y_AXIS = 0x1000, + CHANNEL_IN_Z_AXIS = 0x2000, + CHANNEL_IN_VOICE_UPLINK = 0x4000, + CHANNEL_IN_VOICE_DNLINK = 0x8000, + CHANNEL_IN_MONO = CHANNEL_IN_FRONT, + CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT), + CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK| + CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED | CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED| + CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS | CHANNEL_IN_Z_AXIS | + CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK) + }; + + enum audio_mode { + MODE_INVALID = -2, + MODE_CURRENT = -1, + MODE_NORMAL = 0, + MODE_RINGTONE, + MODE_IN_CALL, + MODE_IN_COMMUNICATION, + NUM_MODES // not a valid entry, denotes end-of-list + }; + + enum audio_in_acoustics { + AGC_ENABLE = 0x0001, + AGC_DISABLE = 0, + NS_ENABLE = 0x0002, + NS_DISABLE = 0, + TX_IIR_ENABLE = 0x0004, + TX_DISABLE = 0 + }; + + // DO NOT USE: the "audio_devices" enumeration below is obsolete, use type "audio_devices_t" and + // audio device enumeration from system/audio.h instead. + enum audio_devices { + // output devices + DEVICE_OUT_EARPIECE = 0x1, + DEVICE_OUT_SPEAKER = 0x2, + DEVICE_OUT_WIRED_HEADSET = 0x4, + DEVICE_OUT_WIRED_HEADPHONE = 0x8, + DEVICE_OUT_BLUETOOTH_SCO = 0x10, + DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, + DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, + DEVICE_OUT_BLUETOOTH_A2DP = 0x80, + DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, + DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, + DEVICE_OUT_AUX_DIGITAL = 0x400, + DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800, + DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000, +#ifdef QCOM_HARDWARE + DEVICE_OUT_USB_ACCESSORY = 0x2000, + DEVICE_OUT_USB_DEVICE = 0x4000, +#endif +#if defined(QCOM_FM_ENABLED) || defined(STE_FM) + DEVICE_OUT_FM = 0x8000, + DEVICE_OUT_FM_TX = 0x10000, +#endif +#ifdef QCOM_HARDWARE + DEVICE_OUT_ANC_HEADSET = 0x20000, + DEVICE_OUT_ANC_HEADPHONE = 0x40000, + DEVICE_OUT_PROXY = 0x80000, + DEVICE_OUT_DEFAULT = DEVICE_OUT_SPEAKER, +#else + DEVICE_OUT_DEFAULT = 0x8000, +#endif + DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET | + DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET | + DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | + DEVICE_OUT_ANLG_DOCK_HEADSET | DEVICE_OUT_DGTL_DOCK_HEADSET | +#ifdef QCOM_HARDWARE + DEVICE_OUT_USB_ACCESSORY | DEVICE_OUT_USB_DEVICE | + DEVICE_OUT_ANC_HEADSET | DEVICE_OUT_ANC_HEADPHONE | + DEVICE_OUT_PROXY | +#endif +#if defined(QCOM_FM_ENABLED) || defined(STE_FM) + DEVICE_OUT_FM | DEVICE_OUT_FM_TX | +#endif + DEVICE_OUT_DEFAULT), + DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), +#ifdef QCOM_HARDWARE + DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY | DEVICE_OUT_USB_DEVICE), + + // input devices + DEVICE_IN_COMMUNICATION = 0x100000, + DEVICE_IN_AMBIENT = 0x200000, + DEVICE_IN_BUILTIN_MIC = 0x400000, + DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x800000, + DEVICE_IN_WIRED_HEADSET = 0x1000000, + DEVICE_IN_AUX_DIGITAL = 0x2000000, + DEVICE_IN_VOICE_CALL = 0x4000000, + DEVICE_IN_BACK_MIC = 0x8000000, + DEVICE_IN_ANC_HEADSET = 0x10000000, +#else + // input devices + DEVICE_IN_COMMUNICATION = 0x10000, + DEVICE_IN_AMBIENT = 0x20000, + DEVICE_IN_BUILTIN_MIC = 0x40000, + DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000, + DEVICE_IN_WIRED_HEADSET = 0x100000, + DEVICE_IN_AUX_DIGITAL = 0x200000, + DEVICE_IN_VOICE_CALL = 0x400000, + DEVICE_IN_BACK_MIC = 0x800000, + DEVICE_IN_DEFAULT = 0x80000000, +#endif +#if defined(QCOM_FM_ENABLED) || defined(STE_FM) + DEVICE_IN_FM_RX = 0x20000000, + DEVICE_IN_FM_RX_A2DP = 0x40000000, +#endif +#ifdef QCOM_HARDWARE + DEVICE_IN_DEFAULT = DEVICE_IN_BUILTIN_MIC, + DEVICE_IN_ANLG_DOCK_HEADSET = 0x80000000, + DEVICE_IN_PROXY = DEVICE_IN_ANLG_DOCK_HEADSET, +#endif + + DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC | + DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL | + DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC | +#ifdef QCOM_HARDWARE + DEVICE_IN_ANC_HEADSET | DEVICE_IN_PROXY | DEVICE_IN_ANLG_DOCK_HEADSET | +#endif +#if defined(QCOM_FM_ENABLED) || defined(STE_FM) + DEVICE_IN_FM_RX | DEVICE_IN_FM_RX_A2DP | +#endif + DEVICE_IN_DEFAULT) + }; + + // request to open a direct output with getOutput() (by opposition to sharing an output with other AudioTracks) + enum output_flags { + OUTPUT_FLAG_INDIRECT = 0x0, + OUTPUT_FLAG_DIRECT = 0x1 + }; + + // device categories used for setForceUse() + enum forced_config { + FORCE_NONE, + FORCE_SPEAKER, + FORCE_HEADPHONES, + FORCE_BT_SCO, + FORCE_BT_A2DP, + FORCE_WIRED_ACCESSORY, + FORCE_BT_CAR_DOCK, + FORCE_BT_DESK_DOCK, + FORCE_ANALOG_DOCK, + FORCE_DIGITAL_DOCK, + FORCE_NO_BT_A2DP, + FORCE_SYSTEM_ENFORCED, + NUM_FORCE_CONFIG, + FORCE_DEFAULT = FORCE_NONE + }; + + // usages used for setForceUse() + enum force_use { + FOR_COMMUNICATION, + FOR_MEDIA, + FOR_RECORD, + FOR_DOCK, + FOR_SYSTEM, + NUM_FORCE_USE + }; + + // + // AudioPolicyService interface + // + + // device connection states used for setDeviceConnectionState() + enum device_connection_state { + DEVICE_STATE_UNAVAILABLE, + DEVICE_STATE_AVAILABLE, + NUM_DEVICE_STATES + }; + +#endif + + static uint32_t popCount(uint32_t u) { + return popcount(u); + } + +#if 1 + static bool isOutputDevice(audio_devices device) { + if ((popcount(device) == 1) && ((device & ~DEVICE_OUT_ALL) == 0)) + return true; + else + return false; + } + static bool isInputDevice(audio_devices device) { + if ((popcount(device) == 1) && ((device & ~DEVICE_IN_ALL) == 0)) + return true; + else + return false; + } + static bool isA2dpDevice(audio_devices device) { + return audio_is_a2dp_device((audio_devices_t)device); + } + static bool isBluetoothScoDevice(audio_devices device) { + return audio_is_bluetooth_sco_device((audio_devices_t)device); + } + static bool isLowVisibility(stream_type stream) { + return audio_is_low_visibility((audio_stream_type_t)stream); + } + static bool isValidFormat(uint32_t format) { + return audio_is_valid_format((audio_format_t) format); + } + static bool isLinearPCM(uint32_t format) { + return audio_is_linear_pcm((audio_format_t) format); + } + static bool isOutputChannel(uint32_t channel) { + return audio_is_output_channel(channel); + } + static bool isInputChannel(uint32_t channel) { + return audio_is_input_channel(channel); + } + +#endif +}; + +}; // namespace android + +#endif // ANDROID_AUDIOSYSTEM_LEGACY_H_ diff --git a/hardware/libhardware_legacy/include/hardware_legacy/IMountService.h b/hardware/libhardware_legacy/include/hardware_legacy/IMountService.h new file mode 100644 index 00000000..257319c8 --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/IMountService.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +#ifndef ANDROID_HARDWARE_IMOUNTSERVICE_H +#define ANDROID_HARDWARE_IMOUNTSERVICE_H + +#include +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class IMountService : public IInterface +{ +public: + static const int OperationSucceeded = 0; + static const int OperationFailedInternalError = -1; + static const int OperationFailedNoMedia = -2; + static const int OperationFailedMediaBlank = -3; + static const int OperationFailedMediaCorrupt = -4; + static const int OperationFailedVolumeNotMounted = -5; + + +public: + DECLARE_META_INTERFACE(MountService); + + virtual void getShareMethodList() = 0; + virtual bool getShareMethodAvailable(String16 method) = 0; + virtual int shareVolume(String16 path, String16 method) = 0; + virtual int unshareVolume(String16 path, String16 method) = 0; + virtual bool getVolumeShared(String16 path, String16 method) = 0; + virtual int mountVolume(String16 path) = 0; + virtual int unmountVolume(String16 path) = 0; + virtual int formatVolume(String16 path) = 0; + virtual String16 getVolumeState(String16 mountPoint) = 0; + virtual int createSecureContainer(String16 id, int sizeMb, String16 fstype, String16 key, int ownerUid) = 0; + virtual int finalizeSecureContainer(String16 id) = 0; + virtual int destroySecureContainer(String16 id) = 0; + virtual int mountSecureContainer(String16 id, String16 key, int ownerUid) = 0; + virtual int unmountSecureContainer(String16 id) = 0; + virtual int renameSecureContainer(String16 oldId, String16 newId) = 0; + virtual String16 getSecureContainerPath(String16 id) = 0; + virtual void getSecureContainerList() = 0; + virtual void shutdown() = 0; +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_HARDWARE_IMOUNTSERVICE_H diff --git a/hardware/libhardware_legacy/include/hardware_legacy/audio_policy_conf.h b/hardware/libhardware_legacy/include/hardware_legacy/audio_policy_conf.h new file mode 100644 index 00000000..fa58c36a --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/audio_policy_conf.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef ANDROID_AUDIO_POLICY_CONF_H +#define ANDROID_AUDIO_POLICY_CONF_H + + +///////////////////////////////////////////////// +// Definitions for audio policy configuration file (audio_policy.conf) +///////////////////////////////////////////////// + +#define AUDIO_HARDWARE_MODULE_ID_MAX_LEN 32 + +#define AUDIO_POLICY_CONFIG_FILE "/system/etc/audio_policy.conf" +#define AUDIO_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_policy.conf" + +// global configuration +#define GLOBAL_CONFIG_TAG "global_configuration" + +#define ATTACHED_OUTPUT_DEVICES_TAG "attached_output_devices" +#define DEFAULT_OUTPUT_DEVICE_TAG "default_output_device" +#define ATTACHED_INPUT_DEVICES_TAG "attached_input_devices" + +// hw modules descriptions +#define AUDIO_HW_MODULE_TAG "audio_hw_modules" + +#define OUTPUTS_TAG "outputs" +#define INPUTS_TAG "inputs" + +#define SAMPLING_RATES_TAG "sampling_rates" +#define FORMATS_TAG "formats" +#define CHANNELS_TAG "channel_masks" +#define DEVICES_TAG "devices" +#define FLAGS_TAG "flags" + +#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and + // "formats" in outputs descriptors indicating that supported + // values should be queried after opening the output. + +#endif // ANDROID_AUDIO_POLICY_CONF_H diff --git a/hardware/libhardware_legacy/include/hardware_legacy/power.h b/hardware/libhardware_legacy/include/hardware_legacy/power.h new file mode 100644 index 00000000..604e0ed8 --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/power.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _HARDWARE_POWER_H +#define _HARDWARE_POWER_H + +#include + +#if __cplusplus +extern "C" { +#endif + +enum { + PARTIAL_WAKE_LOCK = 1, // the cpu stays on, but the screen is off + FULL_WAKE_LOCK = 2 // the screen is also on +}; + +// while you have a lock held, the device will stay on at least at the +// level you request. +int acquire_wake_lock(int lock, const char* id); +int release_wake_lock(const char* id); + + +#if __cplusplus +} // extern "C" +#endif + +#endif // _HARDWARE_POWER_H diff --git a/hardware/libhardware_legacy/include/hardware_legacy/qemu_tracing.h b/hardware/libhardware_legacy/include/hardware_legacy/qemu_tracing.h new file mode 100644 index 00000000..645a0be9 --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/qemu_tracing.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _HARDWARE_QEMU_TRACING_H +#define _HARDWARE_QEMU_TRACING_H + +#if __cplusplus +extern "C" { +#endif + +int qemu_start_tracing(); +int qemu_stop_tracing(); +int qemu_add_mapping(unsigned int addr, const char *name); +int qemu_remove_mapping(unsigned int addr); + +#if __cplusplus +} // extern "C" +#endif + +#endif // _HARDWARE_QEMU_TRACING_H diff --git a/hardware/libhardware_legacy/include/hardware_legacy/uevent.h b/hardware/libhardware_legacy/include/hardware_legacy/uevent.h new file mode 100644 index 00000000..bedfff57 --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/uevent.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _HARDWARE_UEVENT_H +#define _HARDWARE_UEVENT_H + +#if __cplusplus +extern "C" { +#endif + +int uevent_init(); +int uevent_get_fd(); +int uevent_next_event(char* buffer, int buffer_length); +int uevent_add_native_handler(void (*handler)(void *data, const char *msg, int msg_len), + void *handler_data); +int uevent_remove_native_handler(void (*handler)(void *data, const char *msg, int msg_len)); + +#if __cplusplus +} // extern "C" +#endif + +#endif // _HARDWARE_UEVENT_H diff --git a/hardware/libhardware_legacy/include/hardware_legacy/vibrator.h b/hardware/libhardware_legacy/include/hardware_legacy/vibrator.h new file mode 100644 index 00000000..7994f623 --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/vibrator.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _HARDWARE_VIBRATOR_H +#define _HARDWARE_VIBRATOR_H + +#if __cplusplus +extern "C" { +#endif + +/** + * Return whether the device has a vibrator. + * + * @return 1 if a vibrator exists, 0 if it doesn't. + */ +int vibrator_exists(); + +/** + * Turn on vibrator + * + * @param timeout_ms number of milliseconds to vibrate + * + * @return 0 if successful, -1 if error + */ +int vibrator_on(int timeout_ms); + +/** + * Turn off vibrator + * + * @return 0 if successful, -1 if error + */ +int vibrator_off(); + +#if __cplusplus +} // extern "C" +#endif + +#endif // _HARDWARE_VIBRATOR_H diff --git a/hardware/libhardware_legacy/include/hardware_legacy/wifi.h b/hardware/libhardware_legacy/include/hardware_legacy/wifi.h new file mode 100644 index 00000000..1233730d --- /dev/null +++ b/hardware/libhardware_legacy/include/hardware_legacy/wifi.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _WIFI_H +#define _WIFI_H + +#if __cplusplus +extern "C" { +#endif + +/** + * Load the Wi-Fi driver. + * + * @return 0 on success, < 0 on failure. + */ +int wifi_load_driver(); + +/** + * Unload the Wi-Fi driver. + * + * @return 0 on success, < 0 on failure. + */ +int wifi_unload_driver(); + +/** + * Check if the Wi-Fi driver is loaded. + * + * @return 0 on success, < 0 on failure. + */ +int is_wifi_driver_loaded(); + + +/** + * Start supplicant. + * + * @return 0 on success, < 0 on failure. + */ +int wifi_start_supplicant(int p2pSupported); + +/** + * Stop supplicant. + * + * @return 0 on success, < 0 on failure. + */ +int wifi_stop_supplicant(int p2pSupported); + +/** + * Open a connection to supplicant on interface + * + * @return 0 on success, < 0 on failure. + */ +int wifi_connect_to_supplicant(const char *ifname); + +/** + * Close connection to supplicant on interface + * + * @return 0 on success, < 0 on failure. + */ +void wifi_close_supplicant_connection(const char *ifname); + +/** + * wifi_wait_for_event() performs a blocking call to + * get a Wi-Fi event and returns a string representing + * a Wi-Fi event when it occurs. + * + * @param iface is the interface on which event is received + * @param buf is the buffer that receives the event + * @param len is the maximum length of the buffer + * + * @returns number of bytes in buffer, 0 if no + * event (for instance, no connection), and less than 0 + * if there is an error. + */ +int wifi_wait_for_event(const char *iface, char *buf, size_t len); + +/** + * wifi_command() issues a command to the Wi-Fi driver. + * + * Android extends the standard commands listed at + * /link http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html + * to include support for sending commands to the driver: + * + * See wifi/java/android/net/wifi/WifiNative.java for the details of + * driver commands that are supported + * + * @param iface is the interface on which command is sent + * @param command is the string command + * @param reply is a buffer to receive a reply string + * @param reply_len on entry, this is the maximum length of + * the reply buffer. On exit, the number of + * bytes in the reply buffer. + * + * @return 0 if successful, < 0 if an error. + */ +int wifi_command(const char *iface, const char *command, char *reply, size_t *reply_len); + +/** + * do_dhcp_request() issues a dhcp request and returns the acquired + * information. + * + * All IPV4 addresses/mask are in network byte order. + * + * @param ipaddr return the assigned IPV4 address + * @param gateway return the gateway being used + * @param mask return the IPV4 mask + * @param dns1 return the IPV4 address of a DNS server + * @param dns2 return the IPV4 address of a DNS server + * @param server return the IPV4 address of DHCP server + * @param lease return the length of lease in seconds. + * + * @return 0 if successful, < 0 if error. + */ +int do_dhcp_request(int *ipaddr, int *gateway, int *mask, + int *dns1, int *dns2, int *server, int *lease); + +/** + * Return the error string of the last do_dhcp_request(). + */ +const char *get_dhcp_error_string(); + +/** + * Return the path to requested firmware + */ +#define WIFI_GET_FW_PATH_STA 0 +#define WIFI_GET_FW_PATH_AP 1 +#define WIFI_GET_FW_PATH_P2P 2 +const char *wifi_get_fw_path(int fw_type); + +/** + * Change the path to firmware for the wlan driver + */ +int wifi_change_fw_path(const char *fwpath); + +/** + * Set the wifi mode (0 = normal, 1 = ap) + */ +int wifi_set_mode(int mode); + +/** + * Check and create if necessary initial entropy file + */ +#define WIFI_ENTROPY_FILE "/data/misc/wifi/entropy.bin" +int ensure_entropy_file_exists(); + +#if __cplusplus +}; // extern "C" +#endif + +#endif // _WIFI_H diff --git a/hardware/libhardware_legacy/nl80211.h b/hardware/libhardware_legacy/nl80211.h new file mode 100644 index 00000000..776b1343 --- /dev/null +++ b/hardware/libhardware_legacy/nl80211.h @@ -0,0 +1,3133 @@ +#ifndef __LINUX_NL80211_H +#define __LINUX_NL80211_H +/* + * 802.11 netlink interface public header + * + * Copyright 2006-2010 Johannes Berg + * Copyright 2008 Michael Wu + * Copyright 2008 Luis Carlos Cobo + * Copyright 2008 Michael Buesch + * Copyright 2008, 2009 Luis R. Rodriguez + * Copyright 2008 Jouni Malinen + * Copyright 2008 Colin McCabe + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include + +/** + * DOC: Station handling + * + * Stations are added per interface, but a special case exists with VLAN + * interfaces. When a station is bound to an AP interface, it may be moved + * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). + * The station is still assumed to belong to the AP interface it was added + * to. + * + * TODO: need more info? + */ + +/** + * DOC: Frame transmission/registration support + * + * Frame transmission and registration support exists to allow userspace + * management entities such as wpa_supplicant react to management frames + * that are not being handled by the kernel. This includes, for example, + * certain classes of action frames that cannot be handled in the kernel + * for various reasons. + * + * Frame registration is done on a per-interface basis and registrations + * cannot be removed other than by closing the socket. It is possible to + * specify a registration filter to register, for example, only for a + * certain type of action frame. In particular with action frames, those + * that userspace registers for will not be returned as unhandled by the + * driver, so that the registered application has to take responsibility + * for doing that. + * + * The type of frame that can be registered for is also dependent on the + * driver and interface type. The frame types are advertised in wiphy + * attributes so applications know what to expect. + * + * NOTE: When an interface changes type while registrations are active, + * these registrations are ignored until the interface type is + * changed again. This means that changing the interface type can + * lead to a situation that couldn't otherwise be produced, but + * any such registrations will be dormant in the sense that they + * will not be serviced, i.e. they will not receive any frames. + * + * Frame transmission allows userspace to send for example the required + * responses to action frames. It is subject to some sanity checking, + * but many frames can be transmitted. When a frame was transmitted, its + * status is indicated to the sending socket. + * + * For more technical details, see the corresponding command descriptions + * below. + */ + +/** + * DOC: Virtual interface / concurrency capabilities + * + * Some devices are able to operate with virtual MACs, they can have + * more than one virtual interface. The capability handling for this + * is a bit complex though, as there may be a number of restrictions + * on the types of concurrency that are supported. + * + * To start with, each device supports the interface types listed in + * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the + * types there no concurrency is implied. + * + * Once concurrency is desired, more attributes must be observed: + * To start with, since some interface types are purely managed in + * software, like the AP-VLAN type in mac80211 for example, there's + * an additional list of these, they can be added at any time and + * are only restricted by some semantic restrictions (e.g. AP-VLAN + * cannot be added without a corresponding AP interface). This list + * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute. + * + * Further, the list of supported combinations is exported. This is + * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically, + * it exports a list of "groups", and at any point in time the + * interfaces that are currently active must fall into any one of + * the advertised groups. Within each group, there are restrictions + * on the number of interfaces of different types that are supported + * and also the number of different channels, along with potentially + * some other restrictions. See &enum nl80211_if_combination_attrs. + * + * All together, these attributes define the concurrency of virtual + * interfaces that a given device supports. + */ + +/** + * enum nl80211_commands - supported nl80211 commands + * + * @NL80211_CMD_UNSPEC: unspecified command to catch errors + * + * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request + * to get a list of all present wiphys. + * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or + * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, + * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, + * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT, + * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, + * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD. + * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL + * instead, the support here is for backward compatibility only. + * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request + * or rename notification. Has attributes %NL80211_ATTR_WIPHY and + * %NL80211_ATTR_WIPHY_NAME. + * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes + * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME. + * + * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration; + * either a dump request on a %NL80211_ATTR_WIPHY or a specific get + * on an %NL80211_ATTR_IFINDEX is supported. + * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. + * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response + * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX, + * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also + * be sent from userspace to request creation of a new virtual interface, + * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and + * %NL80211_ATTR_IFNAME. + * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from + * userspace to request deletion of a virtual interface, then requires + * attribute %NL80211_ATTR_IFINDEX. + * + * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified + * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. + * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT, + * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD. + * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, + * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER, + * and %NL80211_ATTR_KEY_SEQ attributes. + * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX + * or %NL80211_ATTR_MAC. + * + * @NL80211_CMD_GET_BEACON: (not used) + * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface + * using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL + * attributes. For drivers that generate the beacon and probe responses + * internally, the following attributes must be provided: %NL80211_ATTR_IE, + * %NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP. + * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters + * are like for %NL80211_CMD_SET_BEACON, and additionally parameters that + * do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL, + * %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID, + * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, + * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, + * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, + * %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT. + * The channel to use can be set on the interface or be given using the + * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs. + * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP + * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface + * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP + * + * @NL80211_CMD_GET_STATION: Get station attributes for station identified by + * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_STATION: Set station attributes for station identified by + * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the + * the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC + * or, if no MAC address given, all stations, on the interface identified + * by %NL80211_ATTR_IFINDEX. + * + * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to + * destination %NL80211_ATTR_MAC on the interface identified by + * %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to + * destination %NL80211_ATTR_MAC on the interface identified by + * %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by + * %NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP. + * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by + * %NL80211_ATTR_MAC. + * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the + * the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC + * or, if no MAC address given, all mesh paths, on the interface identified + * by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by + * %NL80211_ATTR_IFINDEX. + * + * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set + * regulatory domain. + * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command + * after being queried by the kernel. CRDA replies by sending a regulatory + * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our + * current alpha2 if it found a match. It also provides + * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each + * regulatory rule is a nested set of attributes given by + * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and + * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by + * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and + * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP. + * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain + * to the specified ISO/IEC 3166-1 alpha2 country code. The core will + * store this as a valid request and then query userspace for it. + * + * @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the + * interface identified by %NL80211_ATTR_IFINDEX + * + * @NL80211_CMD_SET_MESH_CONFIG: Set mesh networking properties for the + * interface identified by %NL80211_ATTR_IFINDEX + * + * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The + * interface is identified with %NL80211_ATTR_IFINDEX and the management + * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be + * added to the end of the specified management frame is specified with + * %NL80211_ATTR_IE. If the command succeeds, the requested data will be + * added to all specified management frames generated by + * kernel/firmware/driver. + * Note: This command has been removed and it is only reserved at this + * point to avoid re-using existing command number. The functionality this + * command was planned for has been provided with cleaner design with the + * option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN, + * NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE, + * NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE. + * + * @NL80211_CMD_GET_SCAN: get scan results + * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters + * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the + * probe requests at CCK rate or not. + * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to + * NL80211_CMD_GET_SCAN and on the "scan" multicast group) + * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, + * partial scan results may be available + * + * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain + * intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL. + * Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS) + * are passed, they are used in the probe requests. For + * broadcast, a broadcast SSID must be passed (ie. an empty + * string). If no SSID is passed, no probe requests are sent and + * a passive scan is performed. %NL80211_ATTR_SCAN_FREQUENCIES, + * if passed, define which channels should be scanned; if not + * passed, all channels allowed for the current regulatory domain + * are used. Extra IEs can also be passed from the userspace by + * using the %NL80211_ATTR_IE attribute. + * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT + * if scheduled scan is not running. + * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan + * results available. + * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has + * stopped. The driver may issue this event at any time during a + * scheduled scan. One reason for stopping the scan is if the hardware + * does not support starting an association or a normal scan while running + * a scheduled scan. This event is also sent when the + * %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface + * is brought down while a scheduled scan was running. + * + * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation + * or noise level + * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to + * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) + * + * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC + * (for the BSSID) and %NL80211_ATTR_PMKID. + * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC + * (for the BSSID) and %NL80211_ATTR_PMKID. + * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries. + * + * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain + * has been changed and provides details of the request information + * that caused the change such as who initiated the regulatory request + * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx + * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if + * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or + * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain + * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is + * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on + * to (%NL80211_ATTR_REG_ALPHA2). + * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon + * has been found while world roaming thus enabling active scan or + * any mode of operation that initiates TX (beacons) on a channel + * where we would not have been able to do either before. As an example + * if you are world roaming (regulatory domain set to world or if your + * driver is using a custom world roaming regulatory domain) and while + * doing a passive scan on the 5 GHz band you find an AP there (if not + * on a DFS channel) you will now be able to actively scan for that AP + * or use AP mode on your card on that same channel. Note that this will + * never be used for channels 1-11 on the 2 GHz band as they are always + * enabled world wide. This beacon hint is only sent if your device had + * either disabled active scanning or beaconing on a channel. We send to + * userspace the wiphy on which we removed a restriction from + * (%NL80211_ATTR_WIPHY) and the channel on which this occurred + * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER) + * the beacon hint was processed. + * + * @NL80211_CMD_AUTHENTICATE: authentication request and notification. + * This command is used both as a command (request to authenticate) and + * as an event on the "mlme" multicast group indicating completion of the + * authentication process. + * When used as a command, %NL80211_ATTR_IFINDEX is used to identify the + * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and + * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify + * the SSID (mainly for association, but is included in authentication + * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used + * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE + * is used to specify the authentication type. %NL80211_ATTR_IE is used to + * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs) + * to be added to the frame. + * When used as an event, this reports reception of an Authentication + * frame in station and IBSS modes when the local MLME processed the + * frame, i.e., it was for the local STA and was received in correct + * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the + * MLME SAP interface (kernel providing MLME, userspace SME). The + * included %NL80211_ATTR_FRAME attribute contains the management frame + * (including both the header and frame body, but not FCS). This event is + * also used to indicate if the authentication attempt timed out. In that + * case the %NL80211_ATTR_FRAME attribute is replaced with a + * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which + * pending authentication timed out). + * @NL80211_CMD_ASSOCIATE: association request and notification; like + * NL80211_CMD_AUTHENTICATE but for Association and Reassociation + * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request, + * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives). + * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like + * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to + * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication + * primitives). + * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like + * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to + * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives). + * + * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael + * MIC (part of TKIP) failure; sent on the "mlme" multicast group; the + * event includes %NL80211_ATTR_MAC to describe the source MAC address of + * the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key + * type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and + * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this + * event matches with MLME-MICHAELMICFAILURE.indication() primitive + * + * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a + * FREQ attribute (for the initial frequency if no peer can be found) + * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those + * should be fixed rather than automatically determined. Can only be + * executed on a network interface that is UP, and fixed BSSID/FREQ + * may be rejected. Another optional parameter is the beacon interval, + * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not + * given defaults to 100 TU (102.4ms). + * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is + * determined by the network interface. + * + * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute + * to identify the device, and the TESTDATA blob attribute to pass through + * to the driver. + * + * @NL80211_CMD_CONNECT: connection request and notification; this command + * requests to connect to a specified network but without separating + * auth and assoc steps. For this, you need to specify the SSID in a + * %NL80211_ATTR_SSID attribute, and can optionally specify the association + * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC, + * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, + * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT. + * Background scan period can optionally be + * specified in %NL80211_ATTR_BG_SCAN_PERIOD, + * if not specified default background scan configuration + * in driver is used and if period value is 0, bg scan will be disabled. + * This attribute is ignored if driver does not support roam scan. + * It is also sent as an event, with the BSSID and response IEs when the + * connection is established or failed to be established. This can be + * determined by the STATUS_CODE attribute. + * @NL80211_CMD_ROAM: request that the card roam (currently not implemented), + * sent as an event when the card/driver roamed by itself. + * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify + * userspace that a connection was dropped by the AP or due to other + * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and + * %NL80211_ATTR_REASON_CODE attributes are used. + * + * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices + * associated with this wiphy must be down and will follow. + * + * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified + * channel for the specified amount of time. This can be used to do + * off-channel operations like transmit a Public Action frame and wait for + * a response while being associated to an AP on another channel. + * %NL80211_ATTR_IFINDEX is used to specify which interface (and thus + * radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the + * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be + * optionally used to specify additional channel parameters. + * %NL80211_ATTR_DURATION is used to specify the duration in milliseconds + * to remain on the channel. This command is also used as an event to + * notify when the requested duration starts (it may take a while for the + * driver to schedule this time due to other concurrent needs for the + * radio). + * When called, this operation returns a cookie (%NL80211_ATTR_COOKIE) + * that will be included with any events pertaining to this request; + * the cookie is also used to cancel the request. + * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a + * pending remain-on-channel duration if the desired operation has been + * completed prior to expiration of the originally requested duration. + * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the + * radio. The %NL80211_ATTR_COOKIE attribute must be given as well to + * uniquely identify the request. + * This command is also used as an event to notify when a requested + * remain-on-channel duration has expired. + * + * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX + * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface + * and @NL80211_ATTR_TX_RATES the set of allowed rates. + * + * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames + * (via @NL80211_CMD_FRAME) for processing in userspace. This command + * requires an interface index, a frame type attribute (optional for + * backward compatibility reasons, if not given assumes action frames) + * and a match attribute containing the first few bytes of the frame + * that should match, e.g. a single byte for only a category match or + * four bytes for vendor frames including the OUI. The registration + * cannot be dropped, but is removed automatically when the netlink + * socket is closed. Multiple registrations can be made. + * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for + * backward compatibility + * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This + * command is used both as a request to transmit a management frame and + * as an event indicating reception of a frame that was not processed in + * kernel code, but is for us (i.e., which may need to be processed in a + * user space application). %NL80211_ATTR_FRAME is used to specify the + * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and + * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on + * which channel the frame is to be transmitted or was received. If this + * channel is not the current channel (remain-on-channel or the + * operational channel) the device will switch to the given channel and + * transmit the frame, optionally waiting for a response for the time + * specified using %NL80211_ATTR_DURATION. When called, this operation + * returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the + * TX status event pertaining to the TX request. + * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the + * management frames at CCK rate or not in 2GHz band. + * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this + * command may be used with the corresponding cookie to cancel the wait + * time if it is known that it is no longer necessary. + * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility. + * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame + * transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies + * the TX command and %NL80211_ATTR_FRAME includes the contents of the + * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged + * the frame. + * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for + * backward compatibility. + * + * @NL80211_CMD_SET_POWER_SAVE: Set powersave, using %NL80211_ATTR_PS_STATE + * @NL80211_CMD_GET_POWER_SAVE: Get powersave status in %NL80211_ATTR_PS_STATE + * + * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command + * is used to configure connection quality monitoring notification trigger + * levels. + * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This + * command is used as an event to indicate the that a trigger level was + * reached. + * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ + * and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed + * by %NL80211_ATTR_IFINDEX) shall operate on. + * In case multiple channels are supported by the device, the mechanism + * with which it switches channels is implementation-defined. + * When a monitor interface is given, it can only switch channel while + * no other interfaces are operating to avoid disturbing the operation + * of any other interfaces, and other interfaces will again take + * precedence when they are used. + * + * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. + * + * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial + * mesh config parameters may be given. + * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the + * network is determined by the network interface. + * + * @NL80211_CMD_UNPROT_DEAUTHENTICATE: Unprotected deauthentication frame + * notification. This event is used to indicate that an unprotected + * deauthentication frame was dropped when MFP is in use. + * @NL80211_CMD_UNPROT_DISASSOCIATE: Unprotected disassociation frame + * notification. This event is used to indicate that an unprotected + * disassociation frame was dropped when MFP is in use. + * + * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a + * beacon or probe response from a compatible mesh peer. This is only + * sent while no station information (sta_info) exists for the new peer + * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On + * reception of this notification, userspace may decide to create a new + * station (@NL80211_CMD_NEW_STATION). To stop this notification from + * reoccurring, the userspace authentication daemon may want to create the + * new station with the AUTHENTICATED flag unset and maybe change it later + * depending on the authentication result. + * + * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings. + * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings. + * Since wireless is more complex than wired ethernet, it supports + * various triggers. These triggers can be configured through this + * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For + * more background information, see + * http://wireless.kernel.org/en/users/Documentation/WoWLAN. + * + * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver + * the necessary information for supporting GTK rekey offload. This + * feature is typically used during WoWLAN. The configuration data + * is contained in %NL80211_ATTR_REKEY_DATA (which is nested and + * contains the data in sub-attributes). After rekeying happened, + * this command may also be sent by the driver as an MLME event to + * inform userspace of the new replay counter. + * + * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace + * of PMKSA caching dandidates. + * + * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup). + * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. + * + * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP + * (or GO) interface (i.e. hostapd) to ask for unexpected frames to + * implement sending deauth to stations that send unexpected class 3 + * frames. Also used as the event sent by the kernel when such a frame + * is received. + * For the event, the %NL80211_ATTR_MAC attribute carries the TA and + * other attributes like the interface index are present. + * If used as the command it must have an interface index and you can + * only unsubscribe from the event by closing the socket. Subscription + * is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events. + * + * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the + * associated station identified by %NL80211_ATTR_MAC sent a 4addr frame + * and wasn't already in a 4-addr VLAN. The event will be sent similarly + * to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener. + * + * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface + * by sending a null data frame to it and reporting when the frame is + * acknowleged. This is used to allow timing out inactive clients. Uses + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a + * direct reply with an %NL80211_ATTR_COOKIE that is later used to match + * up the event with the request. The event includes the same data and + * has %NL80211_ATTR_ACK set if the frame was ACKed. + * + * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from + * other BSSes when any interfaces are in AP mode. This helps implement + * OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME + * messages. Note that per PHY only one application may register. + * + * @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether + * No Acknowledgement Policy should be applied. + * + * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels + * independently of the userspace SME, send this event indicating + * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with + * %NL80211_ATTR_WIPHY_CHANNEL_TYPE. + * + * @NL80211_CMD_SCAN_CANCEL: Stop currently running scan (both sw and hw). + * This operation will eventually invoke %NL80211_CMD_SCAN_ABORTED + * event, partial scan results will be available. Returns -ENOENT + * if scan is not running. + * + * @NL80211_CMD_IM_SCAN_RESULT: Intermediate scan result notification event, + * this event could be enabled with @NL80211_ATTR_IM_SCAN_RESULT + * flag during @NL80211_CMD_TRIGGER_SCAN. This event contains + * %NL80211_BSS_BSSID which is used to specify the BSSID of received + * scan result and %NL80211_BSS_SIGNAL_MBM to indicate signal strength. + * On reception of this notification, userspace may decide to stop earlier + * currently running scan with (@NL80211_CMD_SCAN_CANCEL). + * + * @NL80211_CMD_ROAMING_SUPPORT: A notify event used to alert userspace + * regarding changes in roaming support by the driver. If roaming is + * disabled (marked by the presence of @NL80211_ATTR_ROAMING_DISABLED flag) + * userspace should disable background scans and roaming attempts. + * + * @NL80211_CMD_MAX: highest used command number + * @__NL80211_CMD_AFTER_LAST: internal use + */ +enum nl80211_commands { +/* don't change the order or add anything between, this is ABI! */ + NL80211_CMD_UNSPEC, + + NL80211_CMD_GET_WIPHY, /* can dump */ + NL80211_CMD_SET_WIPHY, + NL80211_CMD_NEW_WIPHY, + NL80211_CMD_DEL_WIPHY, + + NL80211_CMD_GET_INTERFACE, /* can dump */ + NL80211_CMD_SET_INTERFACE, + NL80211_CMD_NEW_INTERFACE, + NL80211_CMD_DEL_INTERFACE, + + NL80211_CMD_GET_KEY, + NL80211_CMD_SET_KEY, + NL80211_CMD_NEW_KEY, + NL80211_CMD_DEL_KEY, + + NL80211_CMD_GET_BEACON, + NL80211_CMD_SET_BEACON, + NL80211_CMD_START_AP, + NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP, + NL80211_CMD_STOP_AP, + NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP, + + NL80211_CMD_GET_STATION, + NL80211_CMD_SET_STATION, + NL80211_CMD_NEW_STATION, + NL80211_CMD_DEL_STATION, + + NL80211_CMD_GET_MPATH, + NL80211_CMD_SET_MPATH, + NL80211_CMD_NEW_MPATH, + NL80211_CMD_DEL_MPATH, + + NL80211_CMD_SET_BSS, + + NL80211_CMD_SET_REG, + NL80211_CMD_REQ_SET_REG, + + NL80211_CMD_GET_MESH_CONFIG, + NL80211_CMD_SET_MESH_CONFIG, + + NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */, + + NL80211_CMD_GET_REG, + + NL80211_CMD_GET_SCAN, + NL80211_CMD_TRIGGER_SCAN, + NL80211_CMD_NEW_SCAN_RESULTS, + NL80211_CMD_SCAN_ABORTED, + + NL80211_CMD_REG_CHANGE, + + NL80211_CMD_AUTHENTICATE, + NL80211_CMD_ASSOCIATE, + NL80211_CMD_DEAUTHENTICATE, + NL80211_CMD_DISASSOCIATE, + + NL80211_CMD_MICHAEL_MIC_FAILURE, + + NL80211_CMD_REG_BEACON_HINT, + + NL80211_CMD_JOIN_IBSS, + NL80211_CMD_LEAVE_IBSS, + + NL80211_CMD_TESTMODE, + + NL80211_CMD_CONNECT, + NL80211_CMD_ROAM, + NL80211_CMD_DISCONNECT, + + NL80211_CMD_SET_WIPHY_NETNS, + + NL80211_CMD_GET_SURVEY, + NL80211_CMD_NEW_SURVEY_RESULTS, + + NL80211_CMD_SET_PMKSA, + NL80211_CMD_DEL_PMKSA, + NL80211_CMD_FLUSH_PMKSA, + + NL80211_CMD_REMAIN_ON_CHANNEL, + NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, + + NL80211_CMD_SET_TX_BITRATE_MASK, + + NL80211_CMD_REGISTER_FRAME, + NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME, + NL80211_CMD_FRAME, + NL80211_CMD_ACTION = NL80211_CMD_FRAME, + NL80211_CMD_FRAME_TX_STATUS, + NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS, + + NL80211_CMD_SET_POWER_SAVE, + NL80211_CMD_GET_POWER_SAVE, + + NL80211_CMD_SET_CQM, + NL80211_CMD_NOTIFY_CQM, + + NL80211_CMD_SET_CHANNEL, + NL80211_CMD_SET_WDS_PEER, + + NL80211_CMD_FRAME_WAIT_CANCEL, + + NL80211_CMD_JOIN_MESH, + NL80211_CMD_LEAVE_MESH, + + NL80211_CMD_UNPROT_DEAUTHENTICATE, + NL80211_CMD_UNPROT_DISASSOCIATE, + + NL80211_CMD_NEW_PEER_CANDIDATE, + + NL80211_CMD_GET_WOWLAN, + NL80211_CMD_SET_WOWLAN, + + NL80211_CMD_START_SCHED_SCAN, + NL80211_CMD_STOP_SCHED_SCAN, + NL80211_CMD_SCHED_SCAN_RESULTS, + NL80211_CMD_SCHED_SCAN_STOPPED, + + NL80211_CMD_SET_REKEY_OFFLOAD, + + NL80211_CMD_PMKSA_CANDIDATE, + + NL80211_CMD_TDLS_OPER, + NL80211_CMD_TDLS_MGMT, + + NL80211_CMD_UNEXPECTED_FRAME, + + NL80211_CMD_PROBE_CLIENT, + + NL80211_CMD_REGISTER_BEACONS, + + NL80211_CMD_UNEXPECTED_4ADDR_FRAME, + + NL80211_CMD_SET_NOACK_MAP, + + NL80211_CMD_CH_SWITCH_NOTIFY, + + /* leave some room for adding nl80211 commands for old kernels */ + NL80211_CMD_SCAN_CANCEL = NL80211_CMD_CH_SWITCH_NOTIFY + 10, + + NL80211_CMD_IM_SCAN_RESULT, + + NL80211_CMD_ROAMING_SUPPORT, + + NL80211_CMD_SET_PRIORITY, + NL80211_CMD_CANCEL_PRIORITY, + /* add new commands above here */ + + /* used to define NL80211_CMD_MAX below */ + __NL80211_CMD_AFTER_LAST, + NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 +}; + +/* + * Allow user space programs to use #ifdef on new commands by defining them + * here + */ +#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS +#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE +#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE +#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE +#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE +#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE +#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE +#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT + +#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS + +/* source-level API compatibility */ +#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG +#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG +#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE + +/** + * enum nl80211_attrs - nl80211 netlink attributes + * + * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors + * + * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf. + * /sys/class/ieee80211//index + * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) + * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz + * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ + * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): + * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including + * this attribute) + * NL80211_CHAN_HT20 = HT20 only + * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel + * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel + * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is + * less than or equal to the RTS threshold; allowed range: 1..255; + * dot11ShortRetryLimit; u8 + * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is + * greater than the RTS threshold; allowed range: 1..255; + * dot11ShortLongLimit; u8 + * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum + * length in octets for frames; allowed range: 256..8000, disable + * fragmentation with (u32)-1; dot11FragmentationThreshold; u32 + * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length + * larger than or equal to this use RTS/CTS handshake); allowed range: + * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32 + * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11 + * section 7.3.2.9; dot11CoverageClass; u8 + * + * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on + * @NL80211_ATTR_IFNAME: network interface name + * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype + * + * @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices + * that don't have a netdev (u64) + * + * @NL80211_ATTR_MAC: MAC address (various uses) + * + * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of + * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC + * keys + * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3) + * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 + * section 7.3.2.25.1, e.g. 0x000FAC04) + * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and + * CCMP keys, each six bytes in little endian + * @NL80211_ATTR_KEY_DEFAULT: Flag attribute indicating the key is default key + * @NL80211_ATTR_KEY_DEFAULT_MGMT: Flag attribute indicating the key is the + * default management key + * @NL80211_ATTR_CIPHER_SUITES_PAIRWISE: For crypto settings for connect or + * other commands, indicates which pairwise cipher suites are used + * @NL80211_ATTR_CIPHER_SUITE_GROUP: For crypto settings for connect or + * other commands, indicates which group cipher suite is used + * + * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU + * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing + * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE + * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE + * + * @NL80211_ATTR_STA_AID: Association ID for the station (u16) + * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of + * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2) + * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by + * IEEE 802.11 7.3.1.6 (u16). + * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported + * rates as defined by IEEE 802.11 7.3.2.2 but without the length + * restriction (at most %NL80211_MAX_SUPP_RATES). + * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station + * to, or the AP interface the station was originally added to to. + * @NL80211_ATTR_STA_INFO: information about a station, part of station info + * given for %NL80211_CMD_GET_STATION, nested attribute containing + * info as possible, see &enum nl80211_sta_info. + * + * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, + * consisting of a nested array. + * + * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). + * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link. + * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. + * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path + * info given for %NL80211_CMD_GET_MPATH, nested attribute described at + * &enum nl80211_mpath_info. + * + * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of + * &enum nl80211_mntr_flags. + * + * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the + * current regulatory domain should be set to or is already set to. + * For example, 'CR', for Costa Rica. This attribute is used by the kernel + * to query the CRDA to retrieve one regulatory domain. This attribute can + * also be used by userspace to query the kernel for the currently set + * regulatory domain. We chose an alpha2 as that is also used by the + * IEEE-802.11d country information element to identify a country. + * Users can also simply ask the wireless core to set regulatory domain + * to a specific alpha2. + * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory + * rules. + * + * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1) + * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled + * (u8, 0 or 1) + * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled + * (u8, 0 or 1) + * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic + * rates in format defined by IEEE 802.11 7.3.2.2 but without the length + * restriction (at most %NL80211_MAX_SUPP_RATES). + * + * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from + * association request when used with NL80211_CMD_NEW_STATION) + * + * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all + * supported interface types, each a flag attribute with the number + * of the interface mode. + * + * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for + * %NL80211_CMD_SET_MGMT_EXTRA_IE. + * + * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with + * %NL80211_CMD_SET_MGMT_EXTRA_IE). + * + * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with + * a single scan request, a wiphy attribute. + * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can + * scan with a single scheduled scan request, a wiphy attribute. + * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements + * that can be added to a scan request + * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information + * elements that can be added to a scheduled scan request + * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be + * used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute. + * + * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) + * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive + * scanning and include a zero-length SSID (wildcard) for wildcard scan + * @NL80211_ATTR_BSS: scan result BSS + * + * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain + * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_* + * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently + * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*) + * + * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies + * an array of command numbers (i.e. a mapping index to command number) + * that the driver for the given wiphy supports. + * + * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header + * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and + * NL80211_CMD_ASSOCIATE events + * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets) + * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type, + * represented as a u32 + * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and + * %NL80211_CMD_DISASSOCIATE, u16 + * + * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as + * a u32 + * + * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change + * due to considerations from a beacon hint. This attribute reflects + * the state of the channel _before_ the beacon hint processing. This + * attributes consists of a nested attribute containing + * NL80211_FREQUENCY_ATTR_* + * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change + * due to considerations from a beacon hint. This attribute reflects + * the state of the channel _after_ the beacon hint processing. This + * attributes consists of a nested attribute containing + * NL80211_FREQUENCY_ATTR_* + * + * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported + * cipher suites + * + * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look + * for other networks on different channels + * + * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this + * is used, e.g., with %NL80211_CMD_AUTHENTICATE event + * + * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is + * used for the association (&enum nl80211_mfp, represented as a u32); + * this attribute can be used + * with %NL80211_CMD_ASSOCIATE request + * + * @NL80211_ATTR_STA_FLAGS2: Attribute containing a + * &struct nl80211_sta_flag_update. + * + * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls + * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in + * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE + * request, the driver will assume that the port is unauthorized until + * authorized by user space. Otherwise, port is marked authorized by + * default in station mode. + * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the + * ethertype that will be used for key negotiation. It can be + * specified with the associate and connect commands. If it is not + * specified, the value defaults to 0x888E (PAE, 802.1X). This + * attribute is also used as a flag in the wiphy information to + * indicate that protocols other than PAE are supported. + * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with + * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom + * ethertype frames used for key negotiation must not be encrypted. + * + * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. + * We recommend using nested, driver-specific attributes within this. + * + * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT + * event was due to the AP disconnecting the station, and not due to + * a local disconnect request. + * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT + * event (u16) + * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating + * that protected APs should be used. This is also used with NEW_BEACON to + * indicate that the BSS is to use protection. + * + * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON + * to indicate which unicast key ciphers will be used with the connection + * (an array of u32). + * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which group key cipher will be used with the connection (a + * u32). + * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which WPA version(s) the AP we want to associate with is using + * (a u32 with flags from &enum nl80211_wpa_versions). + * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which key management algorithm(s) to use (an array of u32). + * + * @NL80211_ATTR_REQ_IE: (Re)association request information elements as + * sent out by the card, for ROAM and successful CONNECT events. + * @NL80211_ATTR_RESP_IE: (Re)association response information elements as + * sent by peer, for ROAM and successful CONNECT events. + * + * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE + * commands to specify using a reassociate frame + * + * @NL80211_ATTR_KEY: key information in a nested attribute with + * %NL80211_KEY_* sub-attributes + * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect() + * and join_ibss(), key information is in a nested attribute each + * with %NL80211_KEY_* sub-attributes + * + * @NL80211_ATTR_PID: Process ID of a network namespace. + * + * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for + * dumps. This number increases whenever the object list being + * dumped changes, and as such userspace can verify that it has + * obtained a complete and consistent snapshot by verifying that + * all dump messages contain the same generation number. If it + * changed then the list changed and the dump should be repeated + * completely from scratch. + * + * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface + * + * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of + * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute + * containing info as possible, see &enum survey_info. + * + * @NL80211_ATTR_PMKID: PMK material for PMKSA caching. + * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can + * cache, a wiphy attribute. + * + * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32. + * @NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION: Device attribute that + * specifies the maximum duration that can be requested with the + * remain-on-channel operation, in milliseconds, u32. + * + * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. + * + * @NL80211_ATTR_TX_RATES: Nested set of attributes + * (enum nl80211_tx_rate_attributes) describing TX rates per band. The + * enum nl80211_band value is used as the index (nla_type() of the nested + * data. If a band is not included, it will be configured to allow all + * rates based on negotiated supported rates information. This attribute + * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. + * + * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain + * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. + * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the + * @NL80211_CMD_REGISTER_FRAME command. + * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a + * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing + * information about which frame types can be transmitted with + * %NL80211_CMD_FRAME. + * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a + * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing + * information about which frame types can be registered for RX. + * + * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was + * acknowledged by the recipient. + * + * @NL80211_ATTR_PS_STATE: powersave state, using &enum nl80211_ps_state values. + * + * @NL80211_ATTR_CQM: connection quality monitor configuration in a + * nested attribute with %NL80211_ATTR_CQM_* sub-attributes. + * + * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command + * is requesting a local authentication/association state change without + * invoking actual management frame exchange. This can be used with + * NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE, + * NL80211_CMD_DISASSOCIATE. + * + * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations + * connected to this BSS. + * + * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See + * &enum nl80211_tx_power_setting for possible values. + * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units. + * This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING + * for non-automatic settings. + * + * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly + * means support for per-station GTKs. + * + * @NL80211_ATTR_WIPHY_ANTENNA_TX: Bitmap of allowed antennas for transmitting. + * This can be used to mask out antennas which are not attached or should + * not be used for transmitting. If an antenna is not selected in this + * bitmap the hardware is not allowed to transmit on this antenna. + * + * Each bit represents one antenna, starting with antenna 1 at the first + * bit. Depending on which antennas are selected in the bitmap, 802.11n + * drivers can derive which chainmasks to use (if all antennas belonging to + * a particular chain are disabled this chain should be disabled) and if + * a chain has diversity antennas wether diversity should be used or not. + * HT capabilities (STBC, TX Beamforming, Antenna selection) can be + * derived from the available chains after applying the antenna mask. + * Non-802.11n drivers can derive wether to use diversity or not. + * Drivers may reject configurations or RX/TX mask combinations they cannot + * support by returning -EINVAL. + * + * @NL80211_ATTR_WIPHY_ANTENNA_RX: Bitmap of allowed antennas for receiving. + * This can be used to mask out antennas which are not attached or should + * not be used for receiving. If an antenna is not selected in this bitmap + * the hardware should not be configured to receive on this antenna. + * For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX. + * + * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX: Bitmap of antennas which are available + * for configuration as TX antennas via the above parameters. + * + * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available + * for configuration as RX antennas via the above parameters. + * + * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS + * + * @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be + * transmitted on another channel when the channel given doesn't match + * the current channel. If the current channel doesn't match and this + * flag isn't set, the frame will be rejected. This is also used as an + * nl80211 capability flag. + * + * @NL80211_ATTR_BSS_HT_OPMODE: HT operation mode (u16) + * + * @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags + * attributes, specifying what a key should be set as default as. + * See &enum nl80211_key_default_types. + * + * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters. These cannot be + * changed once the mesh is active. + * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute + * containing attributes from &enum nl80211_meshconf_params. + * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver + * allows auth frames in a mesh to be passed to userspace for processing via + * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. + * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as + * defined in &enum nl80211_plink_state. Used when userspace is + * driving the peer link management state machine. + * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled. + * + * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy + * capabilities, the supported WoWLAN triggers + * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to + * indicate which WoW triggers should be enabled. This is also + * used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN + * triggers. + * + * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan + * cycles, in msecs. If short interval is supported by the driver + * and configured then this will be used only after the requested + * number of short intervals + * + * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more + * sets of attributes to match during scheduled scans. Only BSSs + * that match any of the sets will be reported. These are + * pass-thru filter rules. + * For a match to succeed, the BSS must match all attributes of a + * set. Since not every hardware supports matching all types of + * attributes, there is no guarantee that the reported BSSs are + * fully complying with the match sets and userspace needs to be + * able to ignore them by itself. + * Thus, the implementation is somewhat hardware-dependent, but + * this is only an optimization and the userspace application + * needs to handle all the non-filtered results anyway. + * If the match attributes don't make sense when combined with + * the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID + * is included in the probe request, but the match attributes + * will never let it go through), -EINVAL may be returned. + * If ommited, no filtering is done. + * + * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported + * interface combinations. In each nested item, it contains attributes + * defined in &enum nl80211_if_combination_attrs. + * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like + * %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that + * are managed in software: interfaces of these types aren't subject to + * any restrictions in their number or combinations. + * + * @NL80211_ATTR_REKEY_DATA: nested attribute containing the information + * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data. + * + * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan, + * nested array attribute containing an entry for each band, with the entry + * being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but + * without the length restriction (at most %NL80211_MAX_SUPP_RATES). + * + * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon + * and Probe Response (when response to wildcard Probe Request); see + * &enum nl80211_hidden_ssid, represented as a u32 + * + * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame. + * This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to + * provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the + * driver (or firmware) replies to Probe Request frames. + * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association + * Response frames. This is used with %NL80211_CMD_NEW_BEACON and + * %NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into + * (Re)Association Response frames when the driver (or firmware) replies to + * (Re)Association Request frames. + * + * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration + * of the station, see &enum nl80211_sta_wme_attr. + * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working + * as AP. + * + * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of + * roaming to another AP in the same ESS if the signal lever is low. + * + * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching + * candidate information, see &enum nl80211_pmksa_candidate_attr. + * + * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not + * for management frames transmission. In order to avoid p2p probe/action + * frames are being transmitted at CCK rate in 2GHz band, the user space + * applications use this attribute. + * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and + * %NL80211_CMD_FRAME commands. + * + * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup + * request, link setup confirm, link teardown, etc.). Values are + * described in the TDLS (802.11z) specification. + * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a + * TDLS conversation between two devices. + * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see + * &enum nl80211_tdls_operation, represented as a u8. + * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate + * as a TDLS peer sta. + * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown + * procedures should be performed by sending TDLS packets via + * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be + * used for asking the driver to perform a TDLS operation. + * + * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices + * that have AP support to indicate that they have the AP SME integrated + * with support for the features listed in this attribute, see + * &enum nl80211_ap_sme_features. + * + * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells + * the driver to not wait for an acknowledgement. Note that due to this, + * it will also not give a status callback nor return a cookie. This is + * mostly useful for probe responses to save airtime. + * + * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from + * &enum nl80211_feature_flags and is advertised in wiphy information. + * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe + * requests while operating in AP-mode. + * This attribute holds a bitmap of the supported protocols for + * offloading (see &enum nl80211_probe_resp_offload_support_attr). + * + * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire + * probe-response frame. The DA field in the 802.11 header is zero-ed out, + * to be filled by the FW. + * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable + * this feature. Currently, only supported in mac80211 drivers. + * @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the + * ATTR_HT_CAPABILITY to which attention should be paid. + * Currently, only mac80211 NICs support this feature. + * The values that may be configured are: + * MCS rates, MAX-AMSDU, HT-20-40 and HT_CAP_SGI_40 + * AMPDU density and AMPDU factor. + * All values are treated as suggestions and may be ignored + * by the driver as required. The actual values may be seen in + * the station debugfs ht_caps file. + * + * @NL80211_ATTR_DFS_REGION: region for regulatory rules which this country + * abides to when initiating radiation on DFS channels. A country maps + * to one DFS region. + * + * @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of + * up to 16 TIDs. + * + * @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be + * used by the drivers which has MLME in firmware and does not have support + * to report per station tx/rx activity to free up the staion entry from + * the list. This needs to be used when the driver advertises the + * capability to timeout the stations. + * + * @NL80211_ATTR_RX_SIGNAL_DBM: signal strength in dBm (as a 32-bit int); + * this attribute is (depending on the driver capabilities) added to + * received frames indicated with %NL80211_CMD_FRAME. + * + * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds + * or 0 to disable background scan. + * + * @NL80211_ATTR_USER_REG_HINT_TYPE: type of regulatory hint passed from + * userspace. If unset it is assumed the hint comes directly from + * a user. If set code could specify exactly what type of source + * was used to provide the hint. For the different types of + * allowed user regulatory hints see nl80211_user_reg_hint_type. + * + * @%NL80211_ATTR_IM_SCAN_RESULT: Flag attribute to enable intermediate + * scan result notification event (%NL80211_CMD_IM_SCAN_RESULT) + * for the %NL80211_CMD_TRIGGER_SCAN command. + * When set: will notify on each new scan result in the cache. + * + * @%NL80211_ATTR_IM_SCAN_RESULT_MIN_RSSI: Intermediate event filtering. + * When set: will notify only those new scan result whose signal + * strength of probe response/beacon (in dBm) is stronger than this + * negative value (usually: -20 dBm > X > -95 dBm). + * + * @%NL80211_ATTR_SCAN_MIN_DWELL: Minimum scan dwell time (in TUs), u32 + * attribute to setup minimum time to wait on each channel, if received + * at least one probe response during this period will continue waiting + * %NL80211_ATTR_SCAN_MAX_DWELL, otherwise will move to next channel. + * Relevant only for active scan, used with %NL80211_CMD_TRIGGER_SCAN + * command. This is optional attribute, so if it's not set driver should + * use hardware default values. + * @%NL80211_ATTR_SCAN_MAX_DWELL: Maximum scan dwell time (in TUs), u32 + * attribute to setup maximum time to wait on each channel. + * Relevant only for active scan, used with %NL80211_CMD_TRIGGER_SCAN + * command. This is optional attribute, so if it's not set driver should + * use hardware default values. + * @%NL80211_ATTR_SCAN_NUM_PROBE: Attribute (u8) to setup number of probe + * requests to transmit on each active scan channel, used with + * %NL80211_CMD_TRIGGER_SCAN command. + * + * @NL80211_ATTR_SCHED_SCAN_SHORT_INTERVAL: interval between + * each short interval scheduled scan cycle in msecs. + * @NL80211_ATTR_SCHED_SCAN_NUM_SHORT_INTERVALS: number of short + * sched scan intervals before switching to the long interval + * @NL80211_ATTR_ROAMING_DISABLED: indicates that the driver can't do roaming + * currently. + * + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use + */ +enum nl80211_attrs { +/* don't change the order or add anything between, this is ABI! */ + NL80211_ATTR_UNSPEC, + + NL80211_ATTR_WIPHY, + NL80211_ATTR_WIPHY_NAME, + + NL80211_ATTR_IFINDEX, + NL80211_ATTR_IFNAME, + NL80211_ATTR_IFTYPE, + + NL80211_ATTR_MAC, + + NL80211_ATTR_KEY_DATA, + NL80211_ATTR_KEY_IDX, + NL80211_ATTR_KEY_CIPHER, + NL80211_ATTR_KEY_SEQ, + NL80211_ATTR_KEY_DEFAULT, + + NL80211_ATTR_BEACON_INTERVAL, + NL80211_ATTR_DTIM_PERIOD, + NL80211_ATTR_BEACON_HEAD, + NL80211_ATTR_BEACON_TAIL, + + NL80211_ATTR_STA_AID, + NL80211_ATTR_STA_FLAGS, + NL80211_ATTR_STA_LISTEN_INTERVAL, + NL80211_ATTR_STA_SUPPORTED_RATES, + NL80211_ATTR_STA_VLAN, + NL80211_ATTR_STA_INFO, + + NL80211_ATTR_WIPHY_BANDS, + + NL80211_ATTR_MNTR_FLAGS, + + NL80211_ATTR_MESH_ID, + NL80211_ATTR_STA_PLINK_ACTION, + NL80211_ATTR_MPATH_NEXT_HOP, + NL80211_ATTR_MPATH_INFO, + + NL80211_ATTR_BSS_CTS_PROT, + NL80211_ATTR_BSS_SHORT_PREAMBLE, + NL80211_ATTR_BSS_SHORT_SLOT_TIME, + + NL80211_ATTR_HT_CAPABILITY, + + NL80211_ATTR_SUPPORTED_IFTYPES, + + NL80211_ATTR_REG_ALPHA2, + NL80211_ATTR_REG_RULES, + + NL80211_ATTR_MESH_CONFIG, + + NL80211_ATTR_BSS_BASIC_RATES, + + NL80211_ATTR_WIPHY_TXQ_PARAMS, + NL80211_ATTR_WIPHY_FREQ, + NL80211_ATTR_WIPHY_CHANNEL_TYPE, + + NL80211_ATTR_KEY_DEFAULT_MGMT, + + NL80211_ATTR_MGMT_SUBTYPE, + NL80211_ATTR_IE, + + NL80211_ATTR_MAX_NUM_SCAN_SSIDS, + + NL80211_ATTR_SCAN_FREQUENCIES, + NL80211_ATTR_SCAN_SSIDS, + NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */ + NL80211_ATTR_BSS, + + NL80211_ATTR_REG_INITIATOR, + NL80211_ATTR_REG_TYPE, + + NL80211_ATTR_SUPPORTED_COMMANDS, + + NL80211_ATTR_FRAME, + NL80211_ATTR_SSID, + NL80211_ATTR_AUTH_TYPE, + NL80211_ATTR_REASON_CODE, + + NL80211_ATTR_KEY_TYPE, + + NL80211_ATTR_MAX_SCAN_IE_LEN, + NL80211_ATTR_CIPHER_SUITES, + + NL80211_ATTR_FREQ_BEFORE, + NL80211_ATTR_FREQ_AFTER, + + NL80211_ATTR_FREQ_FIXED, + + + NL80211_ATTR_WIPHY_RETRY_SHORT, + NL80211_ATTR_WIPHY_RETRY_LONG, + NL80211_ATTR_WIPHY_FRAG_THRESHOLD, + NL80211_ATTR_WIPHY_RTS_THRESHOLD, + + NL80211_ATTR_TIMED_OUT, + + NL80211_ATTR_USE_MFP, + + NL80211_ATTR_STA_FLAGS2, + + NL80211_ATTR_CONTROL_PORT, + + NL80211_ATTR_TESTDATA, + + NL80211_ATTR_PRIVACY, + + NL80211_ATTR_DISCONNECTED_BY_AP, + NL80211_ATTR_STATUS_CODE, + + NL80211_ATTR_CIPHER_SUITES_PAIRWISE, + NL80211_ATTR_CIPHER_SUITE_GROUP, + NL80211_ATTR_WPA_VERSIONS, + NL80211_ATTR_AKM_SUITES, + + NL80211_ATTR_REQ_IE, + NL80211_ATTR_RESP_IE, + + NL80211_ATTR_PREV_BSSID, + + NL80211_ATTR_KEY, + NL80211_ATTR_KEYS, + + NL80211_ATTR_PID, + + NL80211_ATTR_4ADDR, + + NL80211_ATTR_SURVEY_INFO, + + NL80211_ATTR_PMKID, + NL80211_ATTR_MAX_NUM_PMKIDS, + + NL80211_ATTR_DURATION, + + NL80211_ATTR_COOKIE, + + NL80211_ATTR_WIPHY_COVERAGE_CLASS, + + NL80211_ATTR_TX_RATES, + + NL80211_ATTR_FRAME_MATCH, + + NL80211_ATTR_ACK, + + NL80211_ATTR_PS_STATE, + + NL80211_ATTR_CQM, + + NL80211_ATTR_LOCAL_STATE_CHANGE, + + NL80211_ATTR_AP_ISOLATE, + + NL80211_ATTR_WIPHY_TX_POWER_SETTING, + NL80211_ATTR_WIPHY_TX_POWER_LEVEL, + + NL80211_ATTR_TX_FRAME_TYPES, + NL80211_ATTR_RX_FRAME_TYPES, + NL80211_ATTR_FRAME_TYPE, + + NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + + NL80211_ATTR_SUPPORT_IBSS_RSN, + + NL80211_ATTR_WIPHY_ANTENNA_TX, + NL80211_ATTR_WIPHY_ANTENNA_RX, + + NL80211_ATTR_MCAST_RATE, + + NL80211_ATTR_OFFCHANNEL_TX_OK, + + NL80211_ATTR_BSS_HT_OPMODE, + + NL80211_ATTR_KEY_DEFAULT_TYPES, + + NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, + + NL80211_ATTR_MESH_SETUP, + + NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, + NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, + + NL80211_ATTR_SUPPORT_MESH_AUTH, + NL80211_ATTR_STA_PLINK_STATE, + + NL80211_ATTR_WOWLAN_TRIGGERS, + NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, + + NL80211_ATTR_SCHED_SCAN_INTERVAL, + + NL80211_ATTR_INTERFACE_COMBINATIONS, + NL80211_ATTR_SOFTWARE_IFTYPES, + + NL80211_ATTR_REKEY_DATA, + + NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, + NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, + + NL80211_ATTR_SCAN_SUPP_RATES, + + NL80211_ATTR_HIDDEN_SSID, + + NL80211_ATTR_IE_PROBE_RESP, + NL80211_ATTR_IE_ASSOC_RESP, + + NL80211_ATTR_STA_WME, + NL80211_ATTR_SUPPORT_AP_UAPSD, + + NL80211_ATTR_ROAM_SUPPORT, + + NL80211_ATTR_SCHED_SCAN_MATCH, + NL80211_ATTR_MAX_MATCH_SETS, + + NL80211_ATTR_PMKSA_CANDIDATE, + + NL80211_ATTR_TX_NO_CCK_RATE, + + NL80211_ATTR_TDLS_ACTION, + NL80211_ATTR_TDLS_DIALOG_TOKEN, + NL80211_ATTR_TDLS_OPERATION, + NL80211_ATTR_TDLS_SUPPORT, + NL80211_ATTR_TDLS_EXTERNAL_SETUP, + + NL80211_ATTR_DEVICE_AP_SME, + + NL80211_ATTR_DONT_WAIT_FOR_ACK, + + NL80211_ATTR_FEATURE_FLAGS, + + NL80211_ATTR_PROBE_RESP_OFFLOAD, + + NL80211_ATTR_PROBE_RESP, + + NL80211_ATTR_DFS_REGION, + + NL80211_ATTR_DISABLE_HT, + NL80211_ATTR_HT_CAPABILITY_MASK, + + NL80211_ATTR_NOACK_MAP, + + NL80211_ATTR_INACTIVITY_TIMEOUT, + + NL80211_ATTR_RX_SIGNAL_DBM, + + NL80211_ATTR_BG_SCAN_PERIOD, + + NL80211_ATTR_WDEV, + + NL80211_ATTR_USER_REG_HINT_TYPE, + + /* leave some room for new attributes in nl80211 updates */ + NL80211_ATTR_IM_SCAN_RESULT = NL80211_ATTR_BG_SCAN_PERIOD + 10, + NL80211_ATTR_IM_SCAN_RESULT_MIN_RSSI, + + NL80211_ATTR_SCAN_MIN_DWELL, + NL80211_ATTR_SCAN_MAX_DWELL, + NL80211_ATTR_SCAN_NUM_PROBE, + + NL80211_ATTR_SCHED_SCAN_SHORT_INTERVAL, + NL80211_ATTR_SCHED_SCAN_NUM_SHORT_INTERVALS, + + NL80211_ATTR_ROAMING_DISABLED, + + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, + NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 +}; + +/* source-level API compatibility */ +#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION +#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG + +/* + * Allow user space programs to use #ifdef on new attributes by defining them + * here + */ +#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT +#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY +#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES +#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS +#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ +#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE +#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE +#define NL80211_ATTR_IE NL80211_ATTR_IE +#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR +#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE +#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME +#define NL80211_ATTR_SSID NL80211_ATTR_SSID +#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE +#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE +#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE +#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP +#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS +#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES +#define NL80211_ATTR_KEY NL80211_ATTR_KEY +#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS +#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS + +#define NL80211_MAX_SUPP_RATES 32 +#define NL80211_MAX_SUPP_HT_RATES 77 +#define NL80211_MAX_SUPP_REG_RULES 32 +#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 +#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 +#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 +#define NL80211_HT_CAPABILITY_LEN 26 + +#define NL80211_MAX_NR_CIPHER_SUITES 5 +#define NL80211_MAX_NR_AKM_SUITES 2 + +#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10 + +/* default RSSI threshold for scan results if none specified. */ +#define NL80211_SCAN_RSSI_THOLD_OFF -300 + +#define NL80211_CQM_TXE_MAX_INTVL 1800 + +/** + * enum nl80211_iftype - (virtual) interface types + * + * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides + * @NL80211_IFTYPE_ADHOC: independent BSS member + * @NL80211_IFTYPE_STATION: managed BSS member + * @NL80211_IFTYPE_AP: access point + * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces + * are a bit special in that they must always be tied to a pre-existing + * AP type interface. + * @NL80211_IFTYPE_WDS: wireless distribution interface + * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames + * @NL80211_IFTYPE_MESH_POINT: mesh point + * @NL80211_IFTYPE_P2P_CLIENT: P2P client + * @NL80211_IFTYPE_P2P_GO: P2P group owner + * @NL80211_IFTYPE_MAX: highest interface type number currently defined + * @NUM_NL80211_IFTYPES: number of defined interface types + * + * These values are used with the %NL80211_ATTR_IFTYPE + * to set the type of an interface. + * + */ +enum nl80211_iftype { + NL80211_IFTYPE_UNSPECIFIED, + NL80211_IFTYPE_ADHOC, + NL80211_IFTYPE_STATION, + NL80211_IFTYPE_AP, + NL80211_IFTYPE_AP_VLAN, + NL80211_IFTYPE_WDS, + NL80211_IFTYPE_MONITOR, + NL80211_IFTYPE_MESH_POINT, + NL80211_IFTYPE_P2P_CLIENT, + NL80211_IFTYPE_P2P_GO, + + /* keep last */ + NUM_NL80211_IFTYPES, + NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1 +}; + +/** + * enum nl80211_sta_flags - station flags + * + * Station flags. When a station is added to an AP interface, it is + * assumed to be already associated (and hence authenticated.) + * + * @__NL80211_STA_FLAG_INVALID: attribute number 0 is reserved + * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) + * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames + * with short barker preamble + * @NL80211_STA_FLAG_WME: station is WME/QoS capable + * @NL80211_STA_FLAG_MFP: station uses management frame protection + * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated + * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer -- this flag should + * only be used in managed mode (even in the flags mask). Note that the + * flag can't be changed, it is only valid while adding a station, and + * attempts to change it will silently be ignored (rather than rejected + * as errors.) + * @NL80211_STA_FLAG_MAX: highest station flag number currently defined + * @__NL80211_STA_FLAG_AFTER_LAST: internal use + */ +enum nl80211_sta_flags { + __NL80211_STA_FLAG_INVALID, + NL80211_STA_FLAG_AUTHORIZED, + NL80211_STA_FLAG_SHORT_PREAMBLE, + NL80211_STA_FLAG_WME, + NL80211_STA_FLAG_MFP, + NL80211_STA_FLAG_AUTHENTICATED, + NL80211_STA_FLAG_TDLS_PEER, + + /* keep last */ + __NL80211_STA_FLAG_AFTER_LAST, + NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 +}; + +#define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER + +/** + * struct nl80211_sta_flag_update - station flags mask/set + * @mask: mask of station flags to set + * @set: which values to set them to + * + * Both mask and set contain bits as per &enum nl80211_sta_flags. + */ +struct nl80211_sta_flag_update { + __u32 mask; + __u32 set; +} __attribute__((packed)); + +/** + * enum nl80211_rate_info - bitrate information + * + * These attribute types are used with %NL80211_STA_INFO_TXRATE + * when getting information about the bitrate of a station. + * There are 2 attributes for bitrate, a legacy one that represents + * a 16-bit value, and new one that represents a 32-bit value. + * If the rate value fits into 16 bit, both attributes are reported + * with the same value. If the rate is too high to fit into 16 bits + * (>6.5535Gbps) only 32-bit attribute is included. + * User space tools encouraged to use the 32-bit attribute and fall + * back to the 16-bit one for compatibility with older kernels. + * + * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved + * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) + * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) + * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate + * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval + * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s) + * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined + * @__NL80211_RATE_INFO_AFTER_LAST: internal use + */ +enum nl80211_rate_info { + __NL80211_RATE_INFO_INVALID, + NL80211_RATE_INFO_BITRATE, + NL80211_RATE_INFO_MCS, + NL80211_RATE_INFO_40_MHZ_WIDTH, + NL80211_RATE_INFO_SHORT_GI, + NL80211_RATE_INFO_BITRATE32, + + /* keep last */ + __NL80211_RATE_INFO_AFTER_LAST, + NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1 +}; + +/** + * enum nl80211_sta_bss_param - BSS information collected by STA + * + * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM + * when getting information about the bitrate of a station. + * + * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved + * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag) + * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE: whether short preamble is enabled + * (flag) + * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME: whether short slot time is enabled + * (flag) + * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8) + * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16) + * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined + * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use + */ +enum nl80211_sta_bss_param { + __NL80211_STA_BSS_PARAM_INVALID, + NL80211_STA_BSS_PARAM_CTS_PROT, + NL80211_STA_BSS_PARAM_SHORT_PREAMBLE, + NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME, + NL80211_STA_BSS_PARAM_DTIM_PERIOD, + NL80211_STA_BSS_PARAM_BEACON_INTERVAL, + + /* keep last */ + __NL80211_STA_BSS_PARAM_AFTER_LAST, + NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1 +}; + +/** + * enum nl80211_sta_info - station information + * + * These attribute types are used with %NL80211_ATTR_STA_INFO + * when getting information about a station. + * + * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved + * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) + * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) + * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) + * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) + * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute + * containing info as possible, see &enum nl80211_rate_info + * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) + * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this + * station) + * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station) + * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station) + * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm) + * @NL80211_STA_INFO_LLID: the station's mesh LLID + * @NL80211_STA_INFO_PLID: the station's mesh PLID + * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station + * (see %enum nl80211_plink_state) + * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested + * attribute, like NL80211_STA_INFO_TX_BITRATE. + * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute + * containing info as possible, see &enum nl80211_sta_bss_param + * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected + * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update. + * @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32) + * @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64) + * @__NL80211_STA_INFO_AFTER_LAST: internal + * @NL80211_STA_INFO_MAX: highest possible station info attribute + */ +enum nl80211_sta_info { + __NL80211_STA_INFO_INVALID, + NL80211_STA_INFO_INACTIVE_TIME, + NL80211_STA_INFO_RX_BYTES, + NL80211_STA_INFO_TX_BYTES, + NL80211_STA_INFO_LLID, + NL80211_STA_INFO_PLID, + NL80211_STA_INFO_PLINK_STATE, + NL80211_STA_INFO_SIGNAL, + NL80211_STA_INFO_TX_BITRATE, + NL80211_STA_INFO_RX_PACKETS, + NL80211_STA_INFO_TX_PACKETS, + NL80211_STA_INFO_TX_RETRIES, + NL80211_STA_INFO_TX_FAILED, + NL80211_STA_INFO_SIGNAL_AVG, + NL80211_STA_INFO_RX_BITRATE, + NL80211_STA_INFO_BSS_PARAM, + NL80211_STA_INFO_CONNECTED_TIME, + NL80211_STA_INFO_STA_FLAGS, + NL80211_STA_INFO_BEACON_LOSS, + NL80211_STA_INFO_T_OFFSET, + + /* keep last */ + __NL80211_STA_INFO_AFTER_LAST, + NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 +}; + +/** + * enum nl80211_mpath_flags - nl80211 mesh path flags + * + * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active + * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running + * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN + * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set + * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded + */ +enum nl80211_mpath_flags { + NL80211_MPATH_FLAG_ACTIVE = 1<<0, + NL80211_MPATH_FLAG_RESOLVING = 1<<1, + NL80211_MPATH_FLAG_SN_VALID = 1<<2, + NL80211_MPATH_FLAG_FIXED = 1<<3, + NL80211_MPATH_FLAG_RESOLVED = 1<<4, +}; + +/** + * enum nl80211_mpath_info - mesh path information + * + * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting + * information about a mesh path. + * + * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved + * @NL80211_MPATH_INFO_FRAME_QLEN: number of queued frames for this destination + * @NL80211_MPATH_INFO_SN: destination sequence number + * @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path + * @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now + * @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in + * &enum nl80211_mpath_flags; + * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec + * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries + * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number + * currently defind + * @__NL80211_MPATH_INFO_AFTER_LAST: internal use + */ +enum nl80211_mpath_info { + __NL80211_MPATH_INFO_INVALID, + NL80211_MPATH_INFO_FRAME_QLEN, + NL80211_MPATH_INFO_SN, + NL80211_MPATH_INFO_METRIC, + NL80211_MPATH_INFO_EXPTIME, + NL80211_MPATH_INFO_FLAGS, + NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, + NL80211_MPATH_INFO_DISCOVERY_RETRIES, + + /* keep last */ + __NL80211_MPATH_INFO_AFTER_LAST, + NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 +}; + +/** + * enum nl80211_band_attr - band attributes + * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, + * an array of nested frequency attributes + * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, + * an array of nested bitrate attributes + * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as + * defined in 802.11n + * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE + * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n + * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n + * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as + * defined in 802.11ac + * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE + * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined + * @__NL80211_BAND_ATTR_AFTER_LAST: internal use + */ +enum nl80211_band_attr { + __NL80211_BAND_ATTR_INVALID, + NL80211_BAND_ATTR_FREQS, + NL80211_BAND_ATTR_RATES, + + NL80211_BAND_ATTR_HT_MCS_SET, + NL80211_BAND_ATTR_HT_CAPA, + NL80211_BAND_ATTR_HT_AMPDU_FACTOR, + NL80211_BAND_ATTR_HT_AMPDU_DENSITY, + + NL80211_BAND_ATTR_VHT_MCS_SET, + NL80211_BAND_ATTR_VHT_CAPA, + + /* keep last */ + __NL80211_BAND_ATTR_AFTER_LAST, + NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 +}; + +#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA + +/** + * enum nl80211_frequency_attr - frequency attributes + * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz + * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current + * regulatory domain. + * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is + * permitted on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm + * (100 * dBm). + * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number + * currently defined + * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use + */ +enum nl80211_frequency_attr { + __NL80211_FREQUENCY_ATTR_INVALID, + NL80211_FREQUENCY_ATTR_FREQ, + NL80211_FREQUENCY_ATTR_DISABLED, + NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, + NL80211_FREQUENCY_ATTR_NO_IBSS, + NL80211_FREQUENCY_ATTR_RADAR, + NL80211_FREQUENCY_ATTR_MAX_TX_POWER, + + /* keep last */ + __NL80211_FREQUENCY_ATTR_AFTER_LAST, + NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 +}; + +#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER + +/** + * enum nl80211_bitrate_attr - bitrate attributes + * @__NL80211_BITRATE_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps + * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported + * in 2.4 GHz band. + * @NL80211_BITRATE_ATTR_MAX: highest bitrate attribute number + * currently defined + * @__NL80211_BITRATE_ATTR_AFTER_LAST: internal use + */ +enum nl80211_bitrate_attr { + __NL80211_BITRATE_ATTR_INVALID, + NL80211_BITRATE_ATTR_RATE, + NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, + + /* keep last */ + __NL80211_BITRATE_ATTR_AFTER_LAST, + NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_initiator - Indicates the initiator of a reg domain request + * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world + * regulatory domain. + * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the + * regulatory domain. + * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the + * wireless core it thinks its knows the regulatory domain we should be in. + * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an + * 802.11 country information element with regulatory information it + * thinks we should consider. cfg80211 only processes the country + * code from the IE, and relies on the regulatory domain information + * structure passed by userspace (CRDA) from our wireless-regdb. + * If a channel is enabled but the country code indicates it should + * be disabled we disable the channel and re-enable it upon disassociation. + */ +enum nl80211_reg_initiator { + NL80211_REGDOM_SET_BY_CORE, + NL80211_REGDOM_SET_BY_USER, + NL80211_REGDOM_SET_BY_DRIVER, + NL80211_REGDOM_SET_BY_COUNTRY_IE, +}; + +/** + * enum nl80211_reg_type - specifies the type of regulatory domain + * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains + * to a specific country. When this is set you can count on the + * ISO / IEC 3166 alpha2 country code being valid. + * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory + * domain. + * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom + * driver specific world regulatory domain. These do not apply system-wide + * and are only applicable to the individual devices which have requested + * them to be applied. + * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product + * of an intersection between two regulatory domains -- the previously + * set regulatory domain on the system and the last accepted regulatory + * domain request to be processed. + */ +enum nl80211_reg_type { + NL80211_REGDOM_TYPE_COUNTRY, + NL80211_REGDOM_TYPE_WORLD, + NL80211_REGDOM_TYPE_CUSTOM_WORLD, + NL80211_REGDOM_TYPE_INTERSECTION, +}; + +/** + * enum nl80211_reg_rule_attr - regulatory rule attributes + * @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional + * considerations for a given frequency range. These are the + * &enum nl80211_reg_rule_flags. + * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory + * rule in KHz. This is not a center of frequency but an actual regulatory + * band edge. + * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule + * in KHz. This is not a center a frequency but an actual regulatory + * band edge. + * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this + * frequency range, in KHz. + * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain + * for a given frequency range. The value is in mBi (100 * dBi). + * If you don't have one then don't send this. + * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for + * a given frequency range. The value is in mBm (100 * dBm). + * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number + * currently defined + * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use + */ +enum nl80211_reg_rule_attr { + __NL80211_REG_RULE_ATTR_INVALID, + NL80211_ATTR_REG_RULE_FLAGS, + + NL80211_ATTR_FREQ_RANGE_START, + NL80211_ATTR_FREQ_RANGE_END, + NL80211_ATTR_FREQ_RANGE_MAX_BW, + + NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, + NL80211_ATTR_POWER_RULE_MAX_EIRP, + + /* keep last */ + __NL80211_REG_RULE_ATTR_AFTER_LAST, + NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_sched_scan_match_attr - scheduled scan match attributes + * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching, + * only report BSS with matching SSID. + * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a + * BSS in scan results. Filtering is turned off if not specified. + * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter + * attribute number currently defined + * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use + */ +enum nl80211_sched_scan_match_attr { + __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID, + + NL80211_SCHED_SCAN_MATCH_ATTR_SSID, + NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, + + /* keep last */ + __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, + NL80211_SCHED_SCAN_MATCH_ATTR_MAX = + __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1 +}; + +/* only for backward compatibility */ +#define NL80211_ATTR_SCHED_SCAN_MATCH_SSID NL80211_SCHED_SCAN_MATCH_ATTR_SSID + +/** + * enum nl80211_reg_rule_flags - regulatory rule flags + * + * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed + * @NL80211_RRF_NO_CCK: CCK modulation not allowed + * @NL80211_RRF_NO_INDOOR: indoor operation not allowed + * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed + * @NL80211_RRF_DFS: DFS support is required to be used + * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links + * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links + * @NL80211_RRF_PASSIVE_SCAN: passive scan is required + * @NL80211_RRF_NO_IBSS: no IBSS is allowed + */ +enum nl80211_reg_rule_flags { + NL80211_RRF_NO_OFDM = 1<<0, + NL80211_RRF_NO_CCK = 1<<1, + NL80211_RRF_NO_INDOOR = 1<<2, + NL80211_RRF_NO_OUTDOOR = 1<<3, + NL80211_RRF_DFS = 1<<4, + NL80211_RRF_PTP_ONLY = 1<<5, + NL80211_RRF_PTMP_ONLY = 1<<6, + NL80211_RRF_PASSIVE_SCAN = 1<<7, + NL80211_RRF_NO_IBSS = 1<<8, +}; + +/** + * enum nl80211_dfs_regions - regulatory DFS regions + * + * @NL80211_DFS_UNSET: Country has no DFS master region specified + * @NL80211_DFS_FCC: Country follows DFS master rules from FCC + * @NL80211_DFS_ETSI: Country follows DFS master rules from ETSI + * @NL80211_DFS_JP: Country follows DFS master rules from JP/MKK/Telec + */ +enum nl80211_dfs_regions { + NL80211_DFS_UNSET = 0, + NL80211_DFS_FCC = 1, + NL80211_DFS_ETSI = 2, + NL80211_DFS_JP = 3, +}; + +/** + * enum nl80211_user_reg_hint_type - type of user regulatory hint + * + * @NL80211_USER_REG_HINT_USER: a user sent the hint. This is always + * assumed if the attribute is not set. + * @NL80211_USER_REG_HINT_CELL_BASE: the hint comes from a cellular + * base station. Device drivers that have been tested to work + * properly to support this type of hint can enable these hints + * by setting the NL80211_FEATURE_CELL_BASE_REG_HINTS feature + * capability on the struct wiphy. The wireless core will + * ignore all cell base station hints until at least one device + * present has been registered with the wireless core that + * has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a + * supported feature. + */ +enum nl80211_user_reg_hint_type { + NL80211_USER_REG_HINT_USER = 0, + NL80211_USER_REG_HINT_CELL_BASE = 1, +}; + +/** + * enum nl80211_survey_info - survey information + * + * These attribute types are used with %NL80211_ATTR_SURVEY_INFO + * when getting information about a survey. + * + * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved + * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel + * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) + * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used + * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio + * spent on this channel + * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary + * channel was sensed busy (either due to activity or energy detect) + * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension + * channel was sensed busy + * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent + * receiving data + * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent + * transmitting data + * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number + * currently defined + * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use + */ +enum nl80211_survey_info { + __NL80211_SURVEY_INFO_INVALID, + NL80211_SURVEY_INFO_FREQUENCY, + NL80211_SURVEY_INFO_NOISE, + NL80211_SURVEY_INFO_IN_USE, + NL80211_SURVEY_INFO_CHANNEL_TIME, + NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, + NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, + NL80211_SURVEY_INFO_CHANNEL_TIME_RX, + NL80211_SURVEY_INFO_CHANNEL_TIME_TX, + + /* keep last */ + __NL80211_SURVEY_INFO_AFTER_LAST, + NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1 +}; + +/** + * enum nl80211_mntr_flags - monitor configuration flags + * + * Monitor configuration flags. + * + * @__NL80211_MNTR_FLAG_INVALID: reserved + * + * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS + * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP + * @NL80211_MNTR_FLAG_CONTROL: pass control frames + * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering + * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. + * overrides all other flags. + * + * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use + * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag + */ +enum nl80211_mntr_flags { + __NL80211_MNTR_FLAG_INVALID, + NL80211_MNTR_FLAG_FCSFAIL, + NL80211_MNTR_FLAG_PLCPFAIL, + NL80211_MNTR_FLAG_CONTROL, + NL80211_MNTR_FLAG_OTHER_BSS, + NL80211_MNTR_FLAG_COOK_FRAMES, + + /* keep last */ + __NL80211_MNTR_FLAG_AFTER_LAST, + NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 +}; + +/** + * enum nl80211_meshconf_params - mesh configuration parameters + * + * Mesh configuration parameters. These can be changed while the mesh is + * active. + * + * @__NL80211_MESHCONF_INVALID: internal use + * + * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in + * millisecond units, used by the Peer Link Open message + * + * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in + * millisecond units, used by the peer link management to close a peer link + * + * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in + * millisecond units + * + * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed + * on this mesh interface + * + * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link + * open retries that can be sent to establish a new peer link instance in a + * mesh + * + * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh + * point. + * + * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically + * open peer links when we detect compatible mesh peers. + * + * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames + * containing a PREQ that an MP can send to a particular destination (path + * target) + * + * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths + * (in milliseconds) + * + * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait + * until giving up on a path discovery (in milliseconds) + * + * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh + * points receiving a PREQ shall consider the forwarding information from + * the root to be valid. (TU = time unit) + * + * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in + * TUs) during which an MP can send only one action frame containing a PREQ + * reference element + * + * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) + * that it takes for an HWMP information element to propagate across the + * mesh + * + * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not + * + * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a + * source mesh point for path selection elements. + * + * @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between + * root announcements are transmitted. + * + * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has + * access to a broader network beyond the MBSS. This is done via Root + * Announcement frames. + * + * @NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL: The minimum interval of time (in + * TUs) during which a mesh STA can send only one Action frame containing a + * PERR element. + * + * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding + * or forwarding entity (default is TRUE - forwarding entity) + * + * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the + * threshold for average signal strength of candidate station to establish + * a peer link. + * + * @NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR: maximum number of neighbors + * to synchronize to for 11s default synchronization method + * (see 11C.12.2.2) + * + * @NL80211_MESHCONF_HT_OPMODE: set mesh HT protection mode. + * + * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute + * + * @NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT: The time (in TUs) for + * which mesh STAs receiving a proactive PREQ shall consider the forwarding + * information to the root mesh STA to be valid. + * + * @NL80211_MESHCONF_HWMP_ROOT_INTERVAL: The interval of time (in TUs) between + * proactive PREQs are transmitted. + * + * @NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL: The minimum interval of time + * (in TUs) during which a mesh STA can send only one Action frame + * containing a PREQ element for root path confirmation. + * + * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use + */ +enum nl80211_meshconf_params { + __NL80211_MESHCONF_INVALID, + NL80211_MESHCONF_RETRY_TIMEOUT, + NL80211_MESHCONF_CONFIRM_TIMEOUT, + NL80211_MESHCONF_HOLDING_TIMEOUT, + NL80211_MESHCONF_MAX_PEER_LINKS, + NL80211_MESHCONF_MAX_RETRIES, + NL80211_MESHCONF_TTL, + NL80211_MESHCONF_AUTO_OPEN_PLINKS, + NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, + NL80211_MESHCONF_PATH_REFRESH_TIME, + NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, + NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, + NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, + NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, + NL80211_MESHCONF_HWMP_ROOTMODE, + NL80211_MESHCONF_ELEMENT_TTL, + NL80211_MESHCONF_HWMP_RANN_INTERVAL, + NL80211_MESHCONF_GATE_ANNOUNCEMENTS, + NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, + NL80211_MESHCONF_FORWARDING, + NL80211_MESHCONF_RSSI_THRESHOLD, + NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, + NL80211_MESHCONF_HT_OPMODE, + NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, + NL80211_MESHCONF_HWMP_ROOT_INTERVAL, + NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, + + /* keep last */ + __NL80211_MESHCONF_ATTR_AFTER_LAST, + NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_mesh_setup_params - mesh setup parameters + * + * Mesh setup parameters. These are used to start/join a mesh and cannot be + * changed while the mesh is active. + * + * @__NL80211_MESH_SETUP_INVALID: Internal use + * + * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a + * vendor specific path selection algorithm or disable it to use the + * default HWMP. + * + * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a + * vendor specific path metric or disable it to use the default Airtime + * metric. + * + * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a + * robust security network ie, or a vendor specific information element + * that vendors will use to identify the path selection methods and + * metrics in use. + * + * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication + * daemon will be authenticating mesh candidates. + * + * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication + * daemon will be securing peer link frames. AMPE is a secured version of + * Mesh Peering Management (MPM) and is implemented with the assistance of + * a userspace daemon. When this flag is set, the kernel will send peer + * management frames to a userspace daemon that will implement AMPE + * functionality (security capabilities selection, key confirmation, and + * key management). When the flag is unset (default), the kernel can + * autonomously complete (unsecured) mesh peering without the need of a + * userspace daemon. + * + * @NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC: Enable this option to use a + * vendor specific synchronization method or disable it to use the default + * neighbor offset synchronization + * + * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number + * + * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use + */ +enum nl80211_mesh_setup_params { + __NL80211_MESH_SETUP_INVALID, + NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL, + NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC, + NL80211_MESH_SETUP_IE, + NL80211_MESH_SETUP_USERSPACE_AUTH, + NL80211_MESH_SETUP_USERSPACE_AMPE, + NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, + + /* keep last */ + __NL80211_MESH_SETUP_ATTR_AFTER_LAST, + NL80211_MESH_SETUP_ATTR_MAX = __NL80211_MESH_SETUP_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_txq_attr - TX queue parameter attributes + * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved + * @NL80211_TXQ_ATTR_AC: AC identifier (NL80211_AC_*) + * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning + * disabled + * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form + * 2^n-1 in the range 1..32767] + * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form + * 2^n-1 in the range 1..32767] + * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255] + * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal + * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number + */ +enum nl80211_txq_attr { + __NL80211_TXQ_ATTR_INVALID, + NL80211_TXQ_ATTR_AC, + NL80211_TXQ_ATTR_TXOP, + NL80211_TXQ_ATTR_CWMIN, + NL80211_TXQ_ATTR_CWMAX, + NL80211_TXQ_ATTR_AIFS, + + /* keep last */ + __NL80211_TXQ_ATTR_AFTER_LAST, + NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1 +}; + +enum nl80211_ac { + NL80211_AC_VO, + NL80211_AC_VI, + NL80211_AC_BE, + NL80211_AC_BK, + NL80211_NUM_ACS +}; + +/* backward compat */ +#define NL80211_TXQ_ATTR_QUEUE NL80211_TXQ_ATTR_AC +#define NL80211_TXQ_Q_VO NL80211_AC_VO +#define NL80211_TXQ_Q_VI NL80211_AC_VI +#define NL80211_TXQ_Q_BE NL80211_AC_BE +#define NL80211_TXQ_Q_BK NL80211_AC_BK + +enum nl80211_channel_type { + NL80211_CHAN_NO_HT, + NL80211_CHAN_HT20, + NL80211_CHAN_HT40MINUS, + NL80211_CHAN_HT40PLUS +}; + +/** + * enum nl80211_bss - netlink attributes for a BSS + * + * @__NL80211_BSS_INVALID: invalid + * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets) + * @NL80211_BSS_FREQUENCY: frequency in MHz (u32) + * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64) + * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) + * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) + * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the + * raw information elements from the probe response/beacon (bin); + * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are + * from a Probe Response frame; otherwise they are from a Beacon frame. + * However, if the driver does not indicate the source of the IEs, these + * IEs may be from either frame subtype. + * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon + * in mBm (100 * dBm) (s32) + * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon + * in unspecified units, scaled to 0..100 (u8) + * @NL80211_BSS_STATUS: status, if this BSS is "used" + * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms + * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information + * elements from a Beacon frame (bin); not present if no Beacon frame has + * yet been received + * @__NL80211_BSS_AFTER_LAST: internal + * @NL80211_BSS_MAX: highest BSS attribute + */ +enum nl80211_bss { + __NL80211_BSS_INVALID, + NL80211_BSS_BSSID, + NL80211_BSS_FREQUENCY, + NL80211_BSS_TSF, + NL80211_BSS_BEACON_INTERVAL, + NL80211_BSS_CAPABILITY, + NL80211_BSS_INFORMATION_ELEMENTS, + NL80211_BSS_SIGNAL_MBM, + NL80211_BSS_SIGNAL_UNSPEC, + NL80211_BSS_STATUS, + NL80211_BSS_SEEN_MS_AGO, + NL80211_BSS_BEACON_IES, + + /* keep last */ + __NL80211_BSS_AFTER_LAST, + NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1 +}; + +/** + * enum nl80211_bss_status - BSS "status" + * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS. + * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS. + * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS. + * + * The BSS status is a BSS attribute in scan dumps, which + * indicates the status the interface has wrt. this BSS. + */ +enum nl80211_bss_status { + NL80211_BSS_STATUS_AUTHENTICATED, + NL80211_BSS_STATUS_ASSOCIATED, + NL80211_BSS_STATUS_IBSS_JOINED, +}; + +/** + * enum nl80211_auth_type - AuthenticationType + * + * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication + * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only) + * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) + * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) + * @__NL80211_AUTHTYPE_NUM: internal + * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm + * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by + * trying multiple times); this is invalid in netlink -- leave out + * the attribute for this on CONNECT commands. + */ +enum nl80211_auth_type { + NL80211_AUTHTYPE_OPEN_SYSTEM, + NL80211_AUTHTYPE_SHARED_KEY, + NL80211_AUTHTYPE_FT, + NL80211_AUTHTYPE_NETWORK_EAP, + + /* keep last */ + __NL80211_AUTHTYPE_NUM, + NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1, + NL80211_AUTHTYPE_AUTOMATIC +}; + +/** + * enum nl80211_key_type - Key Type + * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key + * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key + * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS) + * @NUM_NL80211_KEYTYPES: number of defined key types + */ +enum nl80211_key_type { + NL80211_KEYTYPE_GROUP, + NL80211_KEYTYPE_PAIRWISE, + NL80211_KEYTYPE_PEERKEY, + + NUM_NL80211_KEYTYPES +}; + +/** + * enum nl80211_mfp - Management frame protection state + * @NL80211_MFP_NO: Management frame protection not used + * @NL80211_MFP_REQUIRED: Management frame protection required + */ +enum nl80211_mfp { + NL80211_MFP_NO, + NL80211_MFP_REQUIRED, +}; + +enum nl80211_wpa_versions { + NL80211_WPA_VERSION_1 = 1 << 0, + NL80211_WPA_VERSION_2 = 1 << 1, +}; + +/** + * enum nl80211_key_default_types - key default types + * @__NL80211_KEY_DEFAULT_TYPE_INVALID: invalid + * @NL80211_KEY_DEFAULT_TYPE_UNICAST: key should be used as default + * unicast key + * @NL80211_KEY_DEFAULT_TYPE_MULTICAST: key should be used as default + * multicast key + * @NUM_NL80211_KEY_DEFAULT_TYPES: number of default types + */ +enum nl80211_key_default_types { + __NL80211_KEY_DEFAULT_TYPE_INVALID, + NL80211_KEY_DEFAULT_TYPE_UNICAST, + NL80211_KEY_DEFAULT_TYPE_MULTICAST, + + NUM_NL80211_KEY_DEFAULT_TYPES +}; + +/** + * enum nl80211_key_attributes - key attributes + * @__NL80211_KEY_INVALID: invalid + * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of + * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC + * keys + * @NL80211_KEY_IDX: key ID (u8, 0-3) + * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 + * section 7.3.2.25.1, e.g. 0x000FAC04) + * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and + * CCMP keys, each six bytes in little endian + * @NL80211_KEY_DEFAULT: flag indicating default key + * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key + * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not + * specified the default depends on whether a MAC address was + * given with the command using the key or not (u32) + * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags + * attributes, specifying what a key should be set as default as. + * See &enum nl80211_key_default_types. + * @__NL80211_KEY_AFTER_LAST: internal + * @NL80211_KEY_MAX: highest key attribute + */ +enum nl80211_key_attributes { + __NL80211_KEY_INVALID, + NL80211_KEY_DATA, + NL80211_KEY_IDX, + NL80211_KEY_CIPHER, + NL80211_KEY_SEQ, + NL80211_KEY_DEFAULT, + NL80211_KEY_DEFAULT_MGMT, + NL80211_KEY_TYPE, + NL80211_KEY_DEFAULT_TYPES, + + /* keep last */ + __NL80211_KEY_AFTER_LAST, + NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 +}; + +/** + * enum nl80211_tx_rate_attributes - TX rate set attributes + * @__NL80211_TXRATE_INVALID: invalid + * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection + * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with + * 1 = 500 kbps) but without the IE length restriction (at most + * %NL80211_MAX_SUPP_RATES in a single array). + * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection + * in an array of MCS numbers. + * @__NL80211_TXRATE_AFTER_LAST: internal + * @NL80211_TXRATE_MAX: highest TX rate attribute + */ +enum nl80211_tx_rate_attributes { + __NL80211_TXRATE_INVALID, + NL80211_TXRATE_LEGACY, + NL80211_TXRATE_MCS, + + /* keep last */ + __NL80211_TXRATE_AFTER_LAST, + NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 +}; + +/** + * enum nl80211_band - Frequency band + * @NL80211_BAND_2GHZ: 2.4 GHz ISM band + * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz) + * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz) + */ +enum nl80211_band { + NL80211_BAND_2GHZ, + NL80211_BAND_5GHZ, + NL80211_BAND_60GHZ, +}; + +/** + * enum nl80211_ps_state - powersave state + * @NL80211_PS_DISABLED: powersave is disabled + * @NL80211_PS_ENABLED: powersave is enabled + */ +enum nl80211_ps_state { + NL80211_PS_DISABLED, + NL80211_PS_ENABLED, +}; + +/** + * enum nl80211_attr_cqm - connection quality monitor attributes + * @__NL80211_ATTR_CQM_INVALID: invalid + * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies + * the threshold for the RSSI level at which an event will be sent. Zero + * to disable. + * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies + * the minimum amount the RSSI level must change after an event before a + * new event may be issued (to reduce effects of RSSI oscillation). + * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event + * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many + * consecutive packets were not acknowledged by the peer + * @NL80211_ATTR_CQM_TXE_RATE: TX error rate in %. Minimum % of TX failures + * during the given %NL80211_ATTR_CQM_TXE_INTVL before an + * %NL80211_CMD_NOTIFY_CQM with reported %NL80211_ATTR_CQM_TXE_RATE and + * %NL80211_ATTR_CQM_TXE_PKTS is generated. + * @NL80211_ATTR_CQM_TXE_PKTS: number of attempted packets in a given + * %NL80211_ATTR_CQM_TXE_INTVL before %NL80211_ATTR_CQM_TXE_RATE is + * checked. + * @NL80211_ATTR_CQM_TXE_INTVL: interval in seconds. Specifies the periodic + * interval in which %NL80211_ATTR_CQM_TXE_PKTS and + * %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an + * %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting. + * @__NL80211_ATTR_CQM_AFTER_LAST: internal + * @NL80211_ATTR_CQM_MAX: highest key attribute + */ +enum nl80211_attr_cqm { + __NL80211_ATTR_CQM_INVALID, + NL80211_ATTR_CQM_RSSI_THOLD, + NL80211_ATTR_CQM_RSSI_HYST, + NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, + NL80211_ATTR_CQM_PKT_LOSS_EVENT, + NL80211_ATTR_CQM_TXE_RATE, + NL80211_ATTR_CQM_TXE_PKTS, + NL80211_ATTR_CQM_TXE_INTVL, + + /* keep last */ + __NL80211_ATTR_CQM_AFTER_LAST, + NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1 +}; + +/** + * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event + * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the + * configured threshold + * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the + * configured threshold + * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss. + * (Note that deauth/disassoc will still follow if the AP is not + * available. This event might get used as roaming event, etc.) + */ +enum nl80211_cqm_rssi_threshold_event { + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, + NL80211_CQM_RSSI_BEACON_LOSS_EVENT, +}; + + +/** + * enum nl80211_tx_power_setting - TX power adjustment + * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power + * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter + * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter + */ +enum nl80211_tx_power_setting { + NL80211_TX_POWER_AUTOMATIC, + NL80211_TX_POWER_LIMITED, + NL80211_TX_POWER_FIXED, +}; + +/** + * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute + * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute + * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has + * a zero bit are ignored + * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have + * a bit for each byte in the pattern. The lowest-order bit corresponds + * to the first byte of the pattern, but the bytes of the pattern are + * in a little-endian-like format, i.e. the 9th byte of the pattern + * corresponds to the lowest-order bit in the second byte of the mask. + * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where + * xx indicates "don't care") would be represented by a pattern of + * twelve zero bytes, and a mask of "0xed,0x07". + * Note that the pattern matching is done as though frames were not + * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked + * first (including SNAP header unpacking) and then matched. + * @NL80211_WOWLAN_ACTION: pattern action which can be either to wake up + * on this pattern or drop it and avoid wake up. This can be used to + * specify an excpetion/blacklist pattern that shouldn't cause wakeup + * despite the packet matching another wowlan pattern. For example: + * configure all IPv4 multicast to wake up except certain type of packets + * This can be either NL80211_WOWLAN_ACTION_ALLOW or DROP. + * If this attribute is missing the default would be ALLOW. + * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes + * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number + */ +enum nl80211_wowlan_packet_pattern_attr { + __NL80211_WOWLAN_PKTPAT_INVALID, + NL80211_WOWLAN_PKTPAT_MASK, + NL80211_WOWLAN_PKTPAT_PATTERN, + NL80211_WOWLAN_PKTPAT_ACTION = NL80211_WOWLAN_PKTPAT_PATTERN + 10, + + NUM_NL80211_WOWLAN_PKTPAT, + MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, +}; + + +/** + * enum nl80211_wowlan_action - WoWLAN packet pattern action + * @NL80211_WOWLAN_ACTION_ALLOW: this pattern should wake up the host + * and the packet should be forwarded to the host unless this packet + * matches a DROP rule. + * @NL80211_WOWLAN_ACTION_DROP: a packet containing this pattern shouldn't + * wake up the host. + */ +enum nl80211_wowlan_action { + NL80211_WOWLAN_ACTION_ALLOW, + NL80211_WOWLAN_ACTION_DROP, + + /* keep last */ + NUM_NL80211_WOWLAN_ACTION, + MAX_NL80211_WOWLAN_ACTION = NUM_NL80211_WOWLAN_ACTION - 1, +}; + +/** + * struct nl80211_wowlan_pattern_support - pattern support information + * @max_patterns: maximum number of patterns supported + * @min_pattern_len: minimum length of each pattern + * @max_pattern_len: maximum length of each pattern + * + * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when + * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the + * capability information given by the kernel to userspace. + */ +struct nl80211_wowlan_pattern_support { + __u32 max_patterns; + __u32 min_pattern_len; + __u32 max_pattern_len; +} __attribute__((packed)); + +/** + * enum nl80211_wowlan_triggers - WoWLAN trigger definitions + * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes + * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put + * the chip into a special state -- works best with chips that have + * support for low-power operation already (flag) + * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect + * is detected is implementation-specific (flag) + * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed + * by 16 repetitions of MAC addr, anywhere in payload) (flag) + * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns + * which are passed in an array of nested attributes, each nested attribute + * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern. + * Each pattern defines a wakeup packet. The matching is done on the MSDU, + * i.e. as though the packet was an 802.3 packet, so the pattern matching + * is done after the packet is converted to the MSDU. + * + * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute + * carrying a &struct nl80211_wowlan_pattern_support. + * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be + * used when setting, used only to indicate that GTK rekeying is supported + * by the device (flag) + * @NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE: wake up on GTK rekey failure (if + * done by the device) (flag) + * @NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST: wake up on EAP Identity Request + * packet (flag) + * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag) + * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released + * (on devices that have rfkill in the device) (flag) + * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers + * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number + */ +enum nl80211_wowlan_triggers { + __NL80211_WOWLAN_TRIG_INVALID, + NL80211_WOWLAN_TRIG_ANY, + NL80211_WOWLAN_TRIG_DISCONNECT, + NL80211_WOWLAN_TRIG_MAGIC_PKT, + NL80211_WOWLAN_TRIG_PKT_PATTERN, + NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED, + NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE, + NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, + NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, + NL80211_WOWLAN_TRIG_RFKILL_RELEASE, + + /* keep last */ + NUM_NL80211_WOWLAN_TRIG, + MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1 +}; + +/** + * enum nl80211_iface_limit_attrs - limit attributes + * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) + * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that + * can be chosen from this set of interface types (u32) + * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a + * flag attribute for each interface type in this set + * @NUM_NL80211_IFACE_LIMIT: number of attributes + * @MAX_NL80211_IFACE_LIMIT: highest attribute number + */ +enum nl80211_iface_limit_attrs { + NL80211_IFACE_LIMIT_UNSPEC, + NL80211_IFACE_LIMIT_MAX, + NL80211_IFACE_LIMIT_TYPES, + + /* keep last */ + NUM_NL80211_IFACE_LIMIT, + MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1 +}; + +/** + * enum nl80211_if_combination_attrs -- interface combination attributes + * + * @NL80211_IFACE_COMB_UNSPEC: (reserved) + * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits + * for given interface types, see &enum nl80211_iface_limit_attrs. + * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of + * interfaces that can be created in this group. This number doesn't + * apply to interfaces purely managed in software, which are listed + * in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE. + * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that + * beacon intervals within this group must be all the same even for + * infrastructure and AP/GO combinations, i.e. the GO(s) must adopt + * the infrastructure network's beacon interval. + * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many + * different channels may be used within this group. + * @NUM_NL80211_IFACE_COMB: number of attributes + * @MAX_NL80211_IFACE_COMB: highest attribute number + * + * Examples: + * limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2 + * => allows an AP and a STA that must match BIs + * + * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8 + * => allows 8 of AP/GO + * + * numbers = [ #{STA} <= 2 ], channels = 2, max = 2 + * => allows two STAs on different channels + * + * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4 + * => allows a STA plus three P2P interfaces + * + * The list of these four possiblities could completely be contained + * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate + * that any of these groups must match. + * + * "Combinations" of just a single interface will not be listed here, + * a single interface of any valid interface type is assumed to always + * be possible by itself. This means that implicitly, for each valid + * interface type, the following group always exists: + * numbers = [ #{} <= 1 ], channels = 1, max = 1 + */ +enum nl80211_if_combination_attrs { + NL80211_IFACE_COMB_UNSPEC, + NL80211_IFACE_COMB_LIMITS, + NL80211_IFACE_COMB_MAXNUM, + NL80211_IFACE_COMB_STA_AP_BI_MATCH, + NL80211_IFACE_COMB_NUM_CHANNELS, + + /* keep last */ + NUM_NL80211_IFACE_COMB, + MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1 +}; + + +/** + * enum nl80211_plink_state - state of a mesh peer link finite state machine + * + * @NL80211_PLINK_LISTEN: initial state, considered the implicit + * state of non existant mesh peer links + * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to + * this mesh peer + * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received + * from this mesh peer + * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been + * received from this mesh peer + * @NL80211_PLINK_ESTAB: mesh peer link is established + * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled + * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh + * plink are discarded + * @NUM_NL80211_PLINK_STATES: number of peer link states + * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states + */ +enum nl80211_plink_state { + NL80211_PLINK_LISTEN, + NL80211_PLINK_OPN_SNT, + NL80211_PLINK_OPN_RCVD, + NL80211_PLINK_CNF_RCVD, + NL80211_PLINK_ESTAB, + NL80211_PLINK_HOLDING, + NL80211_PLINK_BLOCKED, + + /* keep last */ + NUM_NL80211_PLINK_STATES, + MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1 +}; + +#define NL80211_KCK_LEN 16 +#define NL80211_KEK_LEN 16 +#define NL80211_REPLAY_CTR_LEN 8 + +/** + * enum nl80211_rekey_data - attributes for GTK rekey offload + * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes + * @NL80211_REKEY_DATA_KEK: key encryption key (binary) + * @NL80211_REKEY_DATA_KCK: key confirmation key (binary) + * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary) + * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal) + * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal) + */ +enum nl80211_rekey_data { + __NL80211_REKEY_DATA_INVALID, + NL80211_REKEY_DATA_KEK, + NL80211_REKEY_DATA_KCK, + NL80211_REKEY_DATA_REPLAY_CTR, + + /* keep last */ + NUM_NL80211_REKEY_DATA, + MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1 +}; + +/** + * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID + * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in + * Beacon frames) + * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element + * in Beacon frames + * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID + * element in Beacon frames but zero out each byte in the SSID + */ +enum nl80211_hidden_ssid { + NL80211_HIDDEN_SSID_NOT_IN_USE, + NL80211_HIDDEN_SSID_ZERO_LEN, + NL80211_HIDDEN_SSID_ZERO_CONTENTS +}; + +/** + * enum nl80211_sta_wme_attr - station WME attributes + * @__NL80211_STA_WME_INVALID: invalid number for nested attribute + * @NL80211_STA_WME_UAPSD_QUEUES: bitmap of uapsd queues. the format + * is the same as the AC bitmap in the QoS info field. + * @NL80211_STA_WME_MAX_SP: max service period. the format is the same + * as the MAX_SP field in the QoS info field (but already shifted down). + * @__NL80211_STA_WME_AFTER_LAST: internal + * @NL80211_STA_WME_MAX: highest station WME attribute + */ +enum nl80211_sta_wme_attr { + __NL80211_STA_WME_INVALID, + NL80211_STA_WME_UAPSD_QUEUES, + NL80211_STA_WME_MAX_SP, + + /* keep last */ + __NL80211_STA_WME_AFTER_LAST, + NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1 +}; + +/** + * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates + * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes + * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher + * priority) + * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets) + * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag) + * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes + * (internal) + * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute + * (internal) + */ +enum nl80211_pmksa_candidate_attr { + __NL80211_PMKSA_CANDIDATE_INVALID, + NL80211_PMKSA_CANDIDATE_INDEX, + NL80211_PMKSA_CANDIDATE_BSSID, + NL80211_PMKSA_CANDIDATE_PREAUTH, + + /* keep last */ + NUM_NL80211_PMKSA_CANDIDATE, + MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1 +}; + +/** + * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION + * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request + * @NL80211_TDLS_SETUP: Setup TDLS link + * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established + * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link + * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link + */ +enum nl80211_tdls_operation { + NL80211_TDLS_DISCOVERY_REQ, + NL80211_TDLS_SETUP, + NL80211_TDLS_TEARDOWN, + NL80211_TDLS_ENABLE_LINK, + NL80211_TDLS_DISABLE_LINK, +}; + +/* + * enum nl80211_ap_sme_features - device-integrated AP features + * Reserved for future use, no bits are defined in + * NL80211_ATTR_DEVICE_AP_SME yet. +enum nl80211_ap_sme_features { +}; + */ + +/** + * enum nl80211_feature_flags - device/driver features + * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back + * TX status to the socket error queue when requested with the + * socket option. + * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates. + * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up + * the connected inactive stations in AP mode. + * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested + * to work properly to suppport receiving regulatory hints from + * cellular base stations. + * @NL80211_FEATURE_SCHED_SCAN_INTERVALS: This driver supports using + * short interval for sched scan and then switching to a longer + * interval. + */ +enum nl80211_feature_flags { + NL80211_FEATURE_SK_TX_STATUS = 1 << 0, + NL80211_FEATURE_HT_IBSS = 1 << 1, + NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, + NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3, + + /* leave room for new feature flags */ + NL80211_FEATURE_SCHED_SCAN_INTERVALS = 1 << 20, +}; + +/** + * enum nl80211_probe_resp_offload_support_attr - optional supported + * protocols for probe-response offloading by the driver/FW. + * To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute. + * Each enum value represents a bit in the bitmap of supported + * protocols. Typically a subset of probe-requests belonging to a + * supported protocol will be excluded from offload and uploaded + * to the host. + * + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1 + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2 + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u + */ +enum nl80211_probe_resp_offload_support_attr { + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS = 1<<0, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 = 1<<1, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P = 1<<2, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3, +}; + +#endif /* __LINUX_NL80211_H */ diff --git a/hardware/libhardware_legacy/power/Android.mk b/hardware/libhardware_legacy/power/Android.mk new file mode 100644 index 00000000..3e3ff5d7 --- /dev/null +++ b/hardware/libhardware_legacy/power/Android.mk @@ -0,0 +1,3 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_SRC_FILES += power/power.c diff --git a/hardware/libhardware_legacy/power/power.c b/hardware/libhardware_legacy/power/power.c new file mode 100644 index 00000000..75b8e77c --- /dev/null +++ b/hardware/libhardware_legacy/power/power.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "power" +#include + +enum { + ACQUIRE_PARTIAL_WAKE_LOCK = 0, + RELEASE_WAKE_LOCK, + OUR_FD_COUNT +}; + +const char * const OLD_PATHS[] = { + "/sys/android_power/acquire_partial_wake_lock", + "/sys/android_power/release_wake_lock", +}; + +const char * const NEW_PATHS[] = { + "/sys/power/wake_lock", + "/sys/power/wake_unlock", +}; + +//XXX static pthread_once_t g_initialized = THREAD_ONCE_INIT; +static int g_initialized = 0; +static int g_fds[OUR_FD_COUNT]; +static int g_error = 1; + +static int64_t systemTime() +{ + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &t); + return t.tv_sec*1000000000LL + t.tv_nsec; +} + +static int +open_file_descriptors(const char * const paths[]) +{ + int i; + for (i=0; i= 0; +} + +#ifdef EXYNOS4X12_ENHANCEMENTS +void acquire_dvfs_lock() +{ +} + +void release_dvfs_lock() +{ +} +#endif diff --git a/hardware/libhardware_legacy/qemu.h b/hardware/libhardware_legacy/qemu.h new file mode 100644 index 00000000..f0bacbc0 --- /dev/null +++ b/hardware/libhardware_legacy/qemu.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _libs_hardware_qemu_h +#define _libs_hardware_qemu_h + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef QEMU_HARDWARE + +/* returns 1 iff we're running in the emulator */ +extern int qemu_check(void); + +/* a structure used to hold enough state to connect to a given + * QEMU communication channel, either through a qemud socket or + * a serial port. + * + * initialize the structure by zero-ing it out + */ +typedef struct { + char is_inited; + char is_available; + char is_qemud; + char is_qemud_old; + char is_tty; + int fd; + char device[32]; +} QemuChannel; + +/* try to open a qemu communication channel. + * returns a file descriptor on success, or -1 in case of + * error. + * + * 'channel' must be a QemuChannel structure that is empty + * on the first call. You can call this function several + * time to re-open the channel using the same 'channel' + * object to speed things a bit. + */ +extern int qemu_channel_open( QemuChannel* channel, + const char* name, + int mode ); + +/* create a command made of a 4-hexchar prefix followed + * by the content. the prefix contains the content's length + * in hexadecimal coding. + * + * 'buffer' must be at last 6 bytes + * returns -1 in case of overflow, or the command's total length + * otherwise (i.e. content length + 4) + */ +extern int qemu_command_format( char* buffer, + int buffer_size, + const char* format, + ... ); + +/* directly sends a command through the 'hw-control' channel. + * this will open the channel, send the formatted command, then + * close the channel automatically. + * returns 0 on success, or -1 on error. + */ +extern int qemu_control_command( const char* fmt, ... ); + +/* sends a question to the hw-control channel, then receive an answer in + * a user-allocated buffer. returns the length of the answer, or -1 + * in case of error. + * + * 'question' *must* have been formatted through qemu_command_format + */ +extern int qemu_control_query( const char* question, int questionlen, + char* answer, int answersize ); + +#endif /* QEMU_HARDWARE */ + +/* use QEMU_FALLBACK(call) to call a QEMU-specific callback */ +/* use QEMU_FALLBACK_VOID(call) if the function returns void */ +#ifdef QEMU_HARDWARE +# define QEMU_FALLBACK(x) \ + do { \ + if (qemu_check()) \ + return qemu_ ## x ; \ + } while (0) +# define QEMU_FALLBACK_VOID(x) \ + do { \ + if (qemu_check()) { \ + qemu_ ## x ; \ + return; \ + } \ + } while (0) +#else +# define QEMU_FALLBACK(x) ((void)0) +# define QEMU_FALLBACK_VOID(x) ((void)0) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _libs_hardware_qemu_h */ diff --git a/hardware/libhardware_legacy/qemu/Android.mk b/hardware/libhardware_legacy/qemu/Android.mk new file mode 100644 index 00000000..5171754e --- /dev/null +++ b/hardware/libhardware_legacy/qemu/Android.mk @@ -0,0 +1,3 @@ +ifeq ($(QEMU_HARDWARE),true) +LOCAL_SRC_FILES += qemu/qemu.c +endif diff --git a/hardware/libhardware_legacy/qemu/qemu.c b/hardware/libhardware_legacy/qemu/qemu.c new file mode 100644 index 00000000..739976f1 --- /dev/null +++ b/hardware/libhardware_legacy/qemu/qemu.c @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* this file contains various functions used by all libhardware modules + * that support QEMU emulation + */ +#include "qemu.h" +#define LOG_TAG "hardware-qemu" +#include +#include +#include +#include +#include +#include +#include +#include + +#define QEMU_DEBUG 0 + +#if QEMU_DEBUG +# define D(...) ALOGD(__VA_ARGS__) +#else +# define D(...) ((void)0) +#endif + +#include "hardware/qemu_pipe.h" + +int +qemu_check(void) +{ + static int in_qemu = -1; + + if (__builtin_expect(in_qemu < 0,0)) { + char propBuf[PROPERTY_VALUE_MAX]; + property_get("ro.kernel.qemu", propBuf, ""); + in_qemu = (propBuf[0] == '1'); + } + return in_qemu; +} + +static int +qemu_fd_write( int fd, const char* cmd, int len ) +{ + int len2; + do { + len2 = write(fd, cmd, len); + } while (len2 < 0 && errno == EINTR); + return len2; +} + +static int +qemu_fd_read( int fd, char* buff, int len ) +{ + int len2; + do { + len2 = read(fd, buff, len); + } while (len2 < 0 && errno == EINTR); + return len2; +} + +static int +qemu_channel_open_qemud_pipe( QemuChannel* channel, + const char* name ) +{ + int fd; + char pipe_name[512]; + + snprintf(pipe_name, sizeof(pipe_name), "qemud:%s", name); + fd = qemu_pipe_open(pipe_name); + if (fd < 0) { + D("no qemud pipe: %s", strerror(errno)); + return -1; + } + + channel->is_qemud = 1; + channel->fd = fd; + return 0; +} + +static int +qemu_channel_open_qemud( QemuChannel* channel, + const char* name ) +{ + int fd, ret, namelen = strlen(name); + char answer[2]; + + fd = socket_local_client( "qemud", + ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM ); + if (fd < 0) { + D("no qemud control socket: %s", strerror(errno)); + return -1; + } + + /* send service name to connect */ + if (qemu_fd_write(fd, name, namelen) != namelen) { + D("can't send service name to qemud: %s", + strerror(errno)); + close(fd); + return -1; + } + + /* read answer from daemon */ + if (qemu_fd_read(fd, answer, 2) != 2 || + answer[0] != 'O' || answer[1] != 'K') { + D("cant' connect to %s service through qemud", name); + close(fd); + return -1; + } + + channel->is_qemud = 1; + channel->fd = fd; + return 0; +} + + +static int +qemu_channel_open_qemud_old( QemuChannel* channel, + const char* name ) +{ + int fd; + + snprintf(channel->device, sizeof channel->device, + "qemud_%s", name); + + fd = socket_local_client( channel->device, + ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM ); + if (fd < 0) { + D("no '%s' control socket available: %s", + channel->device, strerror(errno)); + return -1; + } + + close(fd); + channel->is_qemud_old = 1; + return 0; +} + + +static int +qemu_channel_open_tty( QemuChannel* channel, + const char* name, + int mode ) +{ + char key[PROPERTY_KEY_MAX]; + char prop[PROPERTY_VALUE_MAX]; + int ret; + + ret = snprintf(key, sizeof key, "ro.kernel.android.%s", name); + if (ret >= (int)sizeof key) + return -1; + + if (property_get(key, prop, "") == 0) { + D("no kernel-provided %s device name", name); + return -1; + } + + ret = snprintf(channel->device, sizeof channel->device, + "/dev/%s", prop); + if (ret >= (int)sizeof channel->device) { + D("%s device name too long: '%s'", name, prop); + return -1; + } + + channel->is_tty = !memcmp("/dev/tty", channel->device, 8); + return 0; +} + +int +qemu_channel_open( QemuChannel* channel, + const char* name, + int mode ) +{ + int fd = -1; + + /* initialize the channel is needed */ + if (!channel->is_inited) + { + channel->is_inited = 1; + + do { + if (qemu_channel_open_qemud_pipe(channel, name) == 0) + break; + + if (qemu_channel_open_qemud(channel, name) == 0) + break; + + if (qemu_channel_open_qemud_old(channel, name) == 0) + break; + + if (qemu_channel_open_tty(channel, name, mode) == 0) + break; + + channel->is_available = 0; + return -1; + } while (0); + + channel->is_available = 1; + } + + /* try to open the file */ + if (!channel->is_available) { + errno = ENOENT; + return -1; + } + + if (channel->is_qemud) { + return dup(channel->fd); + } + + if (channel->is_qemud_old) { + do { + fd = socket_local_client( channel->device, + ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM ); + } while (fd < 0 && errno == EINTR); + } + else /* /dev/ttySn ? */ + { + do { + fd = open(channel->device, mode); + } while (fd < 0 && errno == EINTR); + + /* disable ECHO on serial lines */ + if (fd >= 0 && channel->is_tty) { + struct termios ios; + tcgetattr( fd, &ios ); + ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */ + tcsetattr( fd, TCSANOW, &ios ); + } + } + return fd; +} + + +static int +qemu_command_vformat( char* buffer, + int buffer_size, + const char* format, + va_list args ) +{ + char header[5]; + int len; + + if (buffer_size < 6) + return -1; + + len = vsnprintf(buffer+4, buffer_size-4, format, args); + if (len >= buffer_size-4) + return -1; + + snprintf(header, sizeof header, "%04x", len); + memcpy(buffer, header, 4); + return len + 4; +} + +extern int +qemu_command_format( char* buffer, + int buffer_size, + const char* format, + ... ) +{ + va_list args; + int ret; + + va_start(args, format); + ret = qemu_command_format(buffer, buffer_size, format, args); + va_end(args); + return ret; +} + + +static int +qemu_control_fd(void) +{ + static QemuChannel channel[1]; + int fd; + + fd = qemu_channel_open( channel, "hw-control", O_RDWR ); + if (fd < 0) { + D("%s: could not open control channel: %s", __FUNCTION__, + strerror(errno)); + } + return fd; +} + +static int +qemu_control_send(const char* cmd, int len) +{ + int fd, len2; + + if (len < 0) { + errno = EINVAL; + return -1; + } + + fd = qemu_control_fd(); + if (fd < 0) + return -1; + + len2 = qemu_fd_write(fd, cmd, len); + close(fd); + if (len2 != len) { + D("%s: could not send everything %d < %d", + __FUNCTION__, len2, len); + return -1; + } + return 0; +} + + +int +qemu_control_command( const char* fmt, ... ) +{ + va_list args; + char command[256]; + int len, fd; + + va_start(args, fmt); + len = qemu_command_vformat( command, sizeof command, fmt, args ); + va_end(args); + + if (len < 0 || len >= (int)sizeof command) { + if (len < 0) { + D("%s: could not send: %s", __FUNCTION__, strerror(errno)); + } else { + D("%s: too large %d > %d", __FUNCTION__, len, (int)(sizeof command)); + } + errno = EINVAL; + return -1; + } + + return qemu_control_send( command, len ); +} + +extern int qemu_control_query( const char* question, int questionlen, + char* answer, int answersize ) +{ + int ret, fd, len, result = -1; + char header[5], *end; + + if (questionlen <= 0) { + errno = EINVAL; + return -1; + } + + fd = qemu_control_fd(); + if (fd < 0) + return -1; + + ret = qemu_fd_write( fd, question, questionlen ); + if (ret != questionlen) { + D("%s: could not write all: %d < %d", __FUNCTION__, + ret, questionlen); + goto Exit; + } + + /* read a 4-byte header giving the length of the following content */ + ret = qemu_fd_read( fd, header, 4 ); + if (ret != 4) { + D("%s: could not read header (%d != 4)", + __FUNCTION__, ret); + goto Exit; + } + + header[4] = 0; + len = strtol( header, &end, 16 ); + if ( len < 0 || end == NULL || end != header+4 || len > answersize ) { + D("%s: could not parse header: '%s'", + __FUNCTION__, header); + goto Exit; + } + + /* read the answer */ + ret = qemu_fd_read( fd, answer, len ); + if (ret != len) { + D("%s: could not read all of answer %d < %d", + __FUNCTION__, ret, len); + goto Exit; + } + + result = len; + +Exit: + close(fd); + return result; +} diff --git a/hardware/libhardware_legacy/qemu_tracing/Android.mk b/hardware/libhardware_legacy/qemu_tracing/Android.mk new file mode 100644 index 00000000..8c5bab00 --- /dev/null +++ b/hardware/libhardware_legacy/qemu_tracing/Android.mk @@ -0,0 +1,4 @@ +# Copyright 2007 The Android Open Source Project + +LOCAL_SRC_FILES += qemu_tracing/qemu_tracing.c + diff --git a/hardware/libhardware_legacy/qemu_tracing/qemu_tracing.c b/hardware/libhardware_legacy/qemu_tracing/qemu_tracing.c new file mode 100644 index 00000000..847102c8 --- /dev/null +++ b/hardware/libhardware_legacy/qemu_tracing/qemu_tracing.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include + +// This is the pathname to the sysfs file that enables and disables +// tracing on the qemu emulator. +#define SYS_QEMU_TRACE_STATE "/sys/qemu_trace/state" + + +// This is the pathname to the sysfs file that adds new (address, symbol) +// pairs to the trace. +#define SYS_QEMU_TRACE_SYMBOL "/sys/qemu_trace/symbol" + +// The maximum length of a symbol name +#define MAX_SYMBOL_NAME_LENGTH (4 * 1024) + +// Allow space in the buffer for the address plus whitespace. +#define MAX_BUF_SIZE (MAX_SYMBOL_NAME_LENGTH + 20) + +// return 0 on success, or an error if the qemu driver cannot be opened +int qemu_start_tracing() +{ + int fd = open(SYS_QEMU_TRACE_STATE, O_WRONLY); + if (fd < 0) + return fd; + write(fd, "1\n", 2); + close(fd); + return 0; +} + +int qemu_stop_tracing() +{ + int fd = open(SYS_QEMU_TRACE_STATE, O_WRONLY); + if (fd < 0) + return fd; + write(fd, "0\n", 2); + close(fd); + return 0; +} + +int qemu_add_mapping(unsigned int addr, const char *name) +{ + char buf[MAX_BUF_SIZE]; + + if (strlen(name) > MAX_SYMBOL_NAME_LENGTH) + return EINVAL; + int fd = open(SYS_QEMU_TRACE_SYMBOL, O_WRONLY); + if (fd < 0) + return fd; + sprintf(buf, "%x %s\n", addr, name); + write(fd, buf, strlen(buf)); + close(fd); + return 0; +} + +int qemu_remove_mapping(unsigned int addr) +{ + char buf[MAX_BUF_SIZE]; + + int fd = open(SYS_QEMU_TRACE_SYMBOL, O_WRONLY); + if (fd < 0) + return fd; + sprintf(buf, "%x\n", addr); + write(fd, buf, strlen(buf)); + close(fd); + return 0; +} diff --git a/hardware/libhardware_legacy/uevent/Android.mk b/hardware/libhardware_legacy/uevent/Android.mk new file mode 100644 index 00000000..2d8b5247 --- /dev/null +++ b/hardware/libhardware_legacy/uevent/Android.mk @@ -0,0 +1,3 @@ +# Copyright 2008 The Android Open Source Project + +LOCAL_SRC_FILES += uevent/uevent.c diff --git a/hardware/libhardware_legacy/uevent/uevent.c b/hardware/libhardware_legacy/uevent/uevent.c new file mode 100644 index 00000000..b9e35571 --- /dev/null +++ b/hardware/libhardware_legacy/uevent/uevent.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + + +LIST_HEAD(uevent_handler_head, uevent_handler) uevent_handler_list; +pthread_mutex_t uevent_handler_list_lock = PTHREAD_MUTEX_INITIALIZER; + +struct uevent_handler { + void (*handler)(void *data, const char *msg, int msg_len); + void *handler_data; + LIST_ENTRY(uevent_handler) list; +}; + +static int fd = -1; + +/* Returns 0 on failure, 1 on success */ +int uevent_init() +{ + struct sockaddr_nl addr; + int sz = 64*1024; + int s; + + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_pid = getpid(); + addr.nl_groups = 0xffffffff; + + s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if(s < 0) + return 0; + + setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)); + + if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(s); + return 0; + } + + fd = s; + return (fd > 0); +} + +int uevent_get_fd() +{ + return fd; +} + +int uevent_next_event(char* buffer, int buffer_length) +{ + while (1) { + struct pollfd fds; + int nr; + + fds.fd = fd; + fds.events = POLLIN; + fds.revents = 0; + nr = poll(&fds, 1, -1); + + if(nr > 0 && (fds.revents & POLLIN)) { + int count = recv(fd, buffer, buffer_length, 0); + if (count > 0) { + struct uevent_handler *h; + pthread_mutex_lock(&uevent_handler_list_lock); + LIST_FOREACH(h, &uevent_handler_list, list) + h->handler(h->handler_data, buffer, buffer_length); + pthread_mutex_unlock(&uevent_handler_list_lock); + + return count; + } + } + } + + // won't get here + return 0; +} + +int uevent_add_native_handler(void (*handler)(void *data, const char *msg, int msg_len), + void *handler_data) +{ + struct uevent_handler *h; + + h = malloc(sizeof(struct uevent_handler)); + if (h == NULL) + return -1; + h->handler = handler; + h->handler_data = handler_data; + + pthread_mutex_lock(&uevent_handler_list_lock); + LIST_INSERT_HEAD(&uevent_handler_list, h, list); + pthread_mutex_unlock(&uevent_handler_list_lock); + + return 0; +} + +int uevent_remove_native_handler(void (*handler)(void *data, const char *msg, int msg_len)) +{ + struct uevent_handler *h; + int err = -1; + + pthread_mutex_lock(&uevent_handler_list_lock); + LIST_FOREACH(h, &uevent_handler_list, list) { + if (h->handler == handler) { + LIST_REMOVE(h, list); + err = 0; + break; + } + } + pthread_mutex_unlock(&uevent_handler_list_lock); + + return err; +} diff --git a/hardware/libhardware_legacy/vibrator/Android.mk b/hardware/libhardware_legacy/vibrator/Android.mk new file mode 100644 index 00000000..6f7e2623 --- /dev/null +++ b/hardware/libhardware_legacy/vibrator/Android.mk @@ -0,0 +1,9 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_SRC_FILES += vibrator/vibrator.c + +## Must point to a source file that implements the sendit() function +ifneq ($(BOARD_HAS_VIBRATOR_IMPLEMENTATION),) + LOCAL_SRC_FILES += $(BOARD_HAS_VIBRATOR_IMPLEMENTATION) + LOCAL_CFLAGS += -DUSE_ALTERNATIVE_VIBRATOR +endif diff --git a/hardware/libhardware_legacy/vibrator/vibrator.c b/hardware/libhardware_legacy/vibrator/vibrator.c new file mode 100644 index 00000000..b1c98eb4 --- /dev/null +++ b/hardware/libhardware_legacy/vibrator/vibrator.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "qemu.h" + +#include +#include +#include +#include + + +#ifdef USE_ALTERNATIVE_VIBRATOR +extern int sendit(int timeout_ms); +#else + +#define THE_DEVICE "/sys/class/timed_output/vibrator/enable" + +int vibrator_exists() +{ + int fd; + +#ifdef QEMU_HARDWARE + if (qemu_check()) { + return 1; + } +#endif + + fd = open(THE_DEVICE, O_RDWR); + if(fd < 0) + return 0; + close(fd); + return 1; +} + +static int sendit(int timeout_ms) +{ + int nwr, ret, fd; + char value[20]; + +#ifdef QEMU_HARDWARE + if (qemu_check()) { + return qemu_control_command( "vibrator:%d", timeout_ms ); + } +#endif + + fd = open(THE_DEVICE, O_RDWR); + if(fd < 0) + return errno; + + nwr = sprintf(value, "%d\n", timeout_ms); + ret = write(fd, value, nwr); + + close(fd); + + return (ret == nwr) ? 0 : -1; +} + +#endif + +int vibrator_on(int timeout_ms) +{ + /* constant on, up to maximum allowed time */ + return sendit(timeout_ms); +} + +int vibrator_off() +{ + return sendit(0); +} diff --git a/hardware/libhardware_legacy/wifi/Android.mk b/hardware/libhardware_legacy/wifi/Android.mk new file mode 100644 index 00000000..964b0db7 --- /dev/null +++ b/hardware/libhardware_legacy/wifi/Android.mk @@ -0,0 +1,75 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\" +LOCAL_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_PREFIX=\"wpa_ctrl_\" + +ifdef WIFI_DRIVER_MODULE_PATH_DHD +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_PATH_DHD=\"$(WIFI_DRIVER_MODULE_PATH_DHD)\" +endif +ifdef WIFI_DRIVER_MODULE_NAME_DHD +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_NAME_DHD=\"$(WIFI_DRIVER_MODULE_NAME_DHD)\" +endif +ifdef WIFI_DRIVER_MODULE_ARG_DHD +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_ARG_DHD=\"$(WIFI_DRIVER_MODULE_ARG_DHD)\" +endif +ifdef WIFI_DRIVER_FW_PATH_STA_DHD +LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_STA_DHD=\"$(WIFI_DRIVER_FW_PATH_STA_DHD)\" +endif +ifdef WIFI_DRIVER_FW_PATH_AP_DHD +LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_AP_DHD=\"$(WIFI_DRIVER_FW_PATH_AP_DHD)\" +endif +ifdef WIFI_DRIVER_FW_PATH_P2P_DHD +LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_P2P_DHD=\"$(WIFI_DRIVER_FW_PATH_P2P_DHD)\" +endif + +ifdef WIFI_DRIVER_MODULE_PATH +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_PATH=\"$(WIFI_DRIVER_MODULE_PATH)\" +endif +ifdef WIFI_DRIVER_MODULE_ARG +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_ARG=\"$(WIFI_DRIVER_MODULE_ARG)\" +endif +ifdef WIFI_DRIVER_MODULE_AP_ARG +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_AP_ARG=\"$(WIFI_DRIVER_MODULE_AP_ARG)\" +endif +ifdef WIFI_DRIVER_MODULE_NAME +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_NAME=\"$(WIFI_DRIVER_MODULE_NAME)\" +endif +ifdef WIFI_FIRMWARE_LOADER +LOCAL_CFLAGS += -DWIFI_FIRMWARE_LOADER=\"$(WIFI_FIRMWARE_LOADER)\" +endif +ifdef WIFI_DRIVER_LOADER_DELAY +LOCAL_CFLAGS += -DWIFI_DRIVER_LOADER_DELAY=$(WIFI_DRIVER_LOADER_DELAY) +endif +ifdef WIFI_DRIVER_FW_PATH_STA +LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_STA=\"$(WIFI_DRIVER_FW_PATH_STA)\" +endif +ifdef WIFI_DRIVER_FW_PATH_AP +LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_AP=\"$(WIFI_DRIVER_FW_PATH_AP)\" +endif +ifdef WIFI_DRIVER_FW_PATH_P2P +LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_P2P=\"$(WIFI_DRIVER_FW_PATH_P2P)\" +endif +ifdef WIFI_DRIVER_FW_PATH_PARAM +LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_PARAM=\"$(WIFI_DRIVER_FW_PATH_PARAM)\" +endif +ifdef WIFI_EXT_MODULE_PATH +LOCAL_CFLAGS += -DWIFI_EXT_MODULE_PATH=\"$(WIFI_EXT_MODULE_PATH)\" +endif +ifdef WIFI_EXT_MODULE_ARG +LOCAL_CFLAGS += -DWIFI_EXT_MODULE_ARG=\"$(WIFI_EXT_MODULE_ARG)\" +endif +ifdef WIFI_EXT_MODULE_NAME +LOCAL_CFLAGS += -DWIFI_EXT_MODULE_NAME=\"$(WIFI_EXT_MODULE_NAME)\" +endif + +LOCAL_SRC_FILES += wifi/wifi.c + +ifeq ($(BOARD_HAVE_SAMSUNG_WIFI),true) +LOCAL_CFLAGS += -DSAMSUNG_WIFI +endif + +ifeq ($(BOARD_USE_XIAOMI_MIONE_WIFI),true) + LOCAL_CFLAGS += -DXIAOMI_MIONE_WIFI +endif + +LOCAL_SHARED_LIBRARIES += libnetutils libreadmac diff --git a/hardware/libhardware_legacy/wifi/wifi.c b/hardware/libhardware_legacy/wifi/wifi.c new file mode 100644 index 00000000..36cf1cdf --- /dev/null +++ b/hardware/libhardware_legacy/wifi/wifi.c @@ -0,0 +1,1345 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USES_TI_MAC80211 +#include +#include +#include +#include +#include +#include +#include +#include "nl80211.h" +#endif + +#include "hardware_legacy/wifi.h" +#include "libwpa_client/wpa_ctrl.h" + +#define LOG_TAG "WifiHW" +#include "cutils/log.h" +#include "cutils/memory.h" +#include "cutils/misc.h" +#include "cutils/properties.h" +#include "private/android_filesystem_config.h" +#ifdef HAVE_LIBC_SYSTEM_PROPERTIES +#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ +#include +#endif + +/* PRIMARY refers to the connection on the primary interface + * SECONDARY refers to an optional connection on a p2p interface + * + * For concurrency, we only support one active p2p connection and + * one active STA connection at a time + */ +#define PRIMARY 0 +#define SECONDARY 1 +#define MAX_CONNS 2 + +static struct wpa_ctrl *ctrl_conn[MAX_CONNS]; +static struct wpa_ctrl *monitor_conn[MAX_CONNS]; + +/* socket pair used to exit from a blocking read */ +static int exit_sockets[MAX_CONNS][2]; + +extern int do_dhcp(); +extern int ifc_init(); +extern void ifc_close(); +extern char *dhcp_lasterror(); +extern void get_dhcp_info(); +extern int init_module(void *, unsigned long, const char *); +extern int delete_module(const char *, unsigned int); + +static int wifi_mode = 0; + +static char primary_iface[PROPERTY_VALUE_MAX]; +// TODO: use new ANDROID_SOCKET mechanism, once support for multiple +// sockets is in + +#ifdef USES_TI_MAC80211 +#define P2P_INTERFACE "p2p0" +struct nl_sock *nl_soc; +struct nl_cache *nl_cache; +struct genl_family *nl80211; +#endif + +#ifndef WIFI_DRIVER_MODULE_ARG +#define WIFI_DRIVER_MODULE_ARG "" +#endif +#ifndef WIFI_DRIVER_MODULE_AP_ARG +#define WIFI_DRIVER_MODULE_AP_ARG "" +#endif +#ifndef WIFI_FIRMWARE_LOADER +#define WIFI_FIRMWARE_LOADER "" +#endif +#define WIFI_TEST_INTERFACE "sta" + +#ifndef WIFI_DRIVER_FW_PATH_STA +#define WIFI_DRIVER_FW_PATH_STA NULL +#endif +#ifndef WIFI_DRIVER_FW_PATH_AP +#define WIFI_DRIVER_FW_PATH_AP NULL +#endif +#ifndef WIFI_DRIVER_FW_PATH_P2P +#define WIFI_DRIVER_FW_PATH_P2P NULL +#endif + +#ifndef WIFI_DRIVER_FW_PATH_STA_DHD +#define WIFI_DRIVER_FW_PATH_STA_DHD NULL +#endif +#ifndef WIFI_DRIVER_FW_PATH_AP_DHD +#define WIFI_DRIVER_FW_PATH_AP_DHD NULL +#endif +#ifndef WIFI_DRIVER_FW_PATH_P2P_DHD +#define WIFI_DRIVER_FW_PATH_P2P_DHD NULL +#endif + +#ifdef WIFI_EXT_MODULE_NAME +static const char EXT_MODULE_NAME[] = WIFI_EXT_MODULE_NAME; +#ifdef WIFI_EXT_MODULE_ARG +static const char EXT_MODULE_ARG[] = WIFI_EXT_MODULE_ARG; +#else +static const char EXT_MODULE_ARG[] = ""; +#endif +#endif +#ifdef WIFI_EXT_MODULE_PATH +static const char EXT_MODULE_PATH[] = WIFI_EXT_MODULE_PATH; +#endif + +#ifndef WIFI_DRIVER_FW_PATH_PARAM +#define WIFI_DRIVER_FW_PATH_PARAM "/sys/module/wlan/parameters/fwpath" +#endif + +static const char IFACE_DIR[] = "/data/system/wpa_supplicant"; +#ifdef WIFI_DRIVER_MODULE_PATH +#ifndef XIAOMI_MIONE_WIFI +static const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME; +static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " "; +static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH; +static const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG; +#else +/* WIFI_DRIVER_MODULE_ARG_DHD is longer than WIFI_DRIVER_MODULE_ARG */ +static char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME; +static char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " "; +static char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH; +static char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG_DHD; +static const char DRIVER_MODULE_NAME_DHD[] = WIFI_DRIVER_MODULE_NAME_DHD; +static const char DRIVER_MODULE_TAG_DHD[] = WIFI_DRIVER_MODULE_NAME_DHD " "; +static const char DRIVER_MODULE_PATH_DHD[] = WIFI_DRIVER_MODULE_PATH_DHD; +static const char DRIVER_MODULE_ARG_DHD[] = WIFI_DRIVER_MODULE_ARG; +#endif /* XIAOMI_MIONE_WIFI */ +#endif +static const char FIRMWARE_LOADER[] = WIFI_FIRMWARE_LOADER; +static const char DRIVER_PROP_NAME[] = "wlan.driver.status"; +static const char SUPPLICANT_NAME[] = "wpa_supplicant"; +static const char SUPP_PROP_NAME[] = "init.svc.wpa_supplicant"; +static const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant"; +static const char P2P_PROP_NAME[] = "init.svc.p2p_supplicant"; +static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf"; +static const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf"; +static const char P2P_CONFIG_FILE[] = "/data/misc/wifi/p2p_supplicant.conf"; +static const char CONTROL_IFACE_PATH[] = "/data/misc/wifi/sockets"; +static const char MODULE_FILE[] = "/proc/modules"; + +static const char SUPP_ENTROPY_FILE[] = WIFI_ENTROPY_FILE; +static unsigned char dummy_key[21] = { 0x02, 0x11, 0xbe, 0x33, 0x43, 0x35, + 0x68, 0x47, 0x84, 0x99, 0xa9, 0x2b, + 0x1c, 0xd3, 0xee, 0xff, 0xf1, 0xe2, + 0xf3, 0xf4, 0xf5 }; +extern char *read_mac(); +static char mac_buf[150]; +static int read_mac_ok; +/* Is either SUPPLICANT_NAME or P2P_SUPPLICANT_NAME */ +static char supplicant_name[PROPERTY_VALUE_MAX]; +/* Is either SUPP_PROP_NAME or P2P_PROP_NAME */ +static char supplicant_prop_name[PROPERTY_KEY_MAX]; + +#ifdef WIFI_DRIVER_MODULE_PATH +#ifdef XIAOMI_MIONE_WIFI +static int is_wifi_module_4330 = 0xff; + +static void check_wifi_module (void) +{ + const char path[] = "/sys/wifi_properties/wifi_module"; + char wifi_module[20]; + int fd; + + if (0xff == is_wifi_module_4330) { + fd = open(path, O_RDONLY); + if (fd < 0) { + ALOGE("unable to open %s: %s", path, strerror(errno)); + return ; + } + + if (read(fd, wifi_module, sizeof(wifi_module)) < 0) { + ALOGE("read %s failed: %s", path, strerror(errno)); + close(fd); + return ; + } + + if (0 == strncmp(wifi_module, "wifi_module=4330", 16)) { + is_wifi_module_4330 = 1; + strcpy(DRIVER_MODULE_NAME, DRIVER_MODULE_NAME_DHD); + strcpy(DRIVER_MODULE_TAG, DRIVER_MODULE_TAG_DHD); + strcpy(DRIVER_MODULE_PATH, DRIVER_MODULE_PATH_DHD); + } else { + is_wifi_module_4330 = 0; + strcpy(DRIVER_MODULE_ARG, DRIVER_MODULE_ARG_DHD); + } + + ALOGW("is_wifi_module_4330: %d", is_wifi_module_4330); + close(fd); + } +} +#endif +#endif + +static int is_primary_interface(const char *ifname) +{ + //Treat NULL as primary interface to allow control + //on STA without an interface + if (ifname == NULL || !strncmp(ifname, primary_iface, strlen(primary_iface))) { + return 1; + } + return 0; +} + +#ifdef SAMSUNG_WIFI +char* get_samsung_wifi_type() +{ + char buf[10]; + int fd = open("/data/.cid.info", O_RDONLY); + if (fd < 0) + return NULL; + + if (read(fd, buf, sizeof(buf)) < 0) { + close(fd); + return NULL; + } + + close(fd); + + if (strncmp(buf, "murata", 6) == 0) + return "_murata"; + + if (strncmp(buf, "semcove", 7) == 0) + return "_semcove"; + + return NULL; +} +#endif + +static int insmod(const char *filename, const char *args) +{ + void *module; + unsigned int size; + int ret; + + module = load_file(filename, &size); + if (!module) + return -1; + + ret = init_module(module, size, args); + + free(module); + + return ret; +} + +static int rmmod(const char *modname) +{ + int ret = -1; + int maxtry = 10; + + while (maxtry-- > 0) { + ret = delete_module(modname, O_NONBLOCK | O_EXCL); + if (ret < 0 && errno == EAGAIN) + usleep(500000); + else + break; + } + + if (ret != 0) + ALOGD("Unable to unload driver module \"%s\": %s\n", + modname, strerror(errno)); + return ret; +} + +int do_dhcp_request(int *ipaddr, int *gateway, int *mask, + int *dns1, int *dns2, int *server, int *lease) { + /* For test driver, always report success */ + if (strcmp(primary_iface, WIFI_TEST_INTERFACE) == 0) + return 0; + + if (ifc_init() < 0) + return -1; + + if (do_dhcp(primary_iface) < 0) { + ifc_close(); + return -1; + } + ifc_close(); + get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease); + return 0; +} + +const char *get_dhcp_error_string() { + return dhcp_lasterror(); +} + +int is_wifi_driver_loaded() { + char driver_status[PROPERTY_VALUE_MAX]; +#ifdef WIFI_DRIVER_MODULE_PATH + FILE *proc; + char line[sizeof(DRIVER_MODULE_TAG)+10]; + +#ifdef XIAOMI_MIONE_WIFI + check_wifi_module(); +#endif +#endif + + if (!property_get(DRIVER_PROP_NAME, driver_status, NULL) + || strcmp(driver_status, "ok") != 0) { + return 0; /* driver not loaded */ + } +#ifdef WIFI_DRIVER_MODULE_PATH + /* + * If the property says the driver is loaded, check to + * make sure that the property setting isn't just left + * over from a previous manual shutdown or a runtime + * crash. + */ + if ((proc = fopen(MODULE_FILE, "r")) == NULL) { + ALOGW("Could not open %s: %s", MODULE_FILE, strerror(errno)); + property_set(DRIVER_PROP_NAME, "unloaded"); + return 0; + } + while ((fgets(line, sizeof(line), proc)) != NULL) { + if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) { + fclose(proc); + return 1; + } + } + fclose(proc); + property_set(DRIVER_PROP_NAME, "unloaded"); + return 0; +#else + return 1; +#endif +} + +int wifi_load_driver() +{ +#ifdef WIFI_DRIVER_MODULE_PATH + char driver_status[PROPERTY_VALUE_MAX]; + int count = 100; /* wait at most 20 seconds for completion */ + char module_arg2[256]; +#ifdef SAMSUNG_WIFI + char* type = get_samsung_wifi_type(); + + if (wifi_mode == 1) { + snprintf(module_arg2, sizeof(module_arg2), "%s%s", DRIVER_MODULE_AP_ARG, type == NULL ? "" : type); + } else { + snprintf(module_arg2, sizeof(module_arg2), "%s%s", DRIVER_MODULE_ARG, type == NULL ? "" : type); + } + + if (insmod(DRIVER_MODULE_PATH, module_arg2) < 0) { +#else + + property_set(DRIVER_PROP_NAME, "loading"); + +#ifdef XIAOMI_MIONE_WIFI + check_wifi_module(); +#endif + +#ifdef WIFI_EXT_MODULE_PATH + if (insmod(EXT_MODULE_PATH, EXT_MODULE_ARG) < 0) + return -1; + usleep(200000); +#endif +#ifdef XIAOMI_MIONE_WIFI + if(is_wifi_module_4330 == 1) { + if (read_mac_ok == 0) { + read_wlan_mac(); + } + } + if (insmod(DRIVER_MODULE_PATH, is_wifi_module_4330 ? mac_buf : DRIVER_MODULE_ARG) < 0) { +#else + if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) { +#endif +#endif + +#ifdef WIFI_EXT_MODULE_NAME + rmmod(EXT_MODULE_NAME); +#endif + return -1; + } + + if (strcmp(FIRMWARE_LOADER,"") == 0) { +#ifdef WIFI_DRIVER_LOADER_DELAY + usleep(WIFI_DRIVER_LOADER_DELAY); +#endif + property_set(DRIVER_PROP_NAME, "ok"); + } + else { + property_set("ctl.start", FIRMWARE_LOADER); + } + sched_yield(); + while (count-- > 0) { + if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) { + if (strcmp(driver_status, "ok") == 0) + return 0; + else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) { + wifi_unload_driver(); + return -1; + } + } + usleep(200000); + } + property_set(DRIVER_PROP_NAME, "timeout"); + wifi_unload_driver(); + return -1; +#else + property_set(DRIVER_PROP_NAME, "ok"); + return 0; +#endif +} + +int wifi_unload_driver() +{ +#ifdef WIFI_DRIVER_MODULE_PATH +#ifdef XIAOMI_MIONE_WIFI + check_wifi_module(); +#endif +#endif + + usleep(200000); /* allow to finish interface down */ +#ifdef WIFI_DRIVER_MODULE_PATH + if (rmmod(DRIVER_MODULE_NAME) == 0) { + int count = 20; /* wait at most 10 seconds for completion */ + while (count-- > 0) { + if (!is_wifi_driver_loaded()) + break; + usleep(500000); + } + usleep(500000); /* allow card removal */ + if (count) { +#ifdef WIFI_EXT_MODULE_NAME + if (rmmod(EXT_MODULE_NAME) == 0) +#endif + return 0; + } + return -1; + } else + return -1; +#else + property_set(DRIVER_PROP_NAME, "unloaded"); + return 0; +#endif +} + +int ensure_entropy_file_exists() +{ + int ret; + int destfd; + + ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK); + if ((ret == 0) || (errno == EACCES)) { + if ((ret != 0) && + (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) { + ALOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); + return -1; + } + return 0; + } + destfd = TEMP_FAILURE_RETRY(open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660)); + if (destfd < 0) { + ALOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); + return -1; + } + + if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) { + ALOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); + close(destfd); + return -1; + } + close(destfd); + + /* chmod is needed because open() didn't set permisions properly */ + if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) { + ALOGE("Error changing permissions of %s to 0660: %s", + SUPP_ENTROPY_FILE, strerror(errno)); + unlink(SUPP_ENTROPY_FILE); + return -1; + } + + if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) { + ALOGE("Error changing group ownership of %s to %d: %s", + SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno)); + unlink(SUPP_ENTROPY_FILE); + return -1; + } + return 0; +} + +int update_ctrl_interface(const char *config_file) { + + int srcfd, destfd; + int nread; + char ifc[PROPERTY_VALUE_MAX]; + char *pbuf; + char *sptr; + struct stat sb; + + if (stat(config_file, &sb) != 0) + return -1; + + pbuf = malloc(sb.st_size + PROPERTY_VALUE_MAX); + if (!pbuf) + return 0; + srcfd = TEMP_FAILURE_RETRY(open(config_file, O_RDONLY)); + if (srcfd < 0) { + ALOGE("Cannot open \"%s\": %s", config_file, strerror(errno)); + free(pbuf); + return 0; + } + nread = TEMP_FAILURE_RETRY(read(srcfd, pbuf, sb.st_size)); + close(srcfd); + if (nread < 0) { + ALOGE("Cannot read \"%s\": %s", config_file, strerror(errno)); + free(pbuf); + return 0; + } + + if (!strcmp(config_file, SUPP_CONFIG_FILE)) { + property_get("wifi.interface", ifc, WIFI_TEST_INTERFACE); + } else { + strcpy(ifc, CONTROL_IFACE_PATH); + } + /* + * if there is a "ctrl_interface=" entry, re-write it ONLY if it is + * NOT a directory. The non-directory value option is an Android add-on + * that allows the control interface to be exchanged through an environment + * variable (initialized by the "init" program when it starts a service + * with a "socket" option). + * + * The is deemed to be a directory if the "DIR=" form is used or + * the value begins with "/". + */ + if ((sptr = strstr(pbuf, "ctrl_interface=")) && + (!strstr(pbuf, "ctrl_interface=DIR=")) && + (!strstr(pbuf, "ctrl_interface=/"))) { + char *iptr = sptr + strlen("ctrl_interface="); + int ilen = 0; + int mlen = strlen(ifc); + int nwrite; + if (strncmp(ifc, iptr, mlen) != 0) { + ALOGE("ctrl_interface != %s", ifc); + while (((ilen + (iptr - pbuf)) < nread) && (iptr[ilen] != '\n')) + ilen++; + mlen = ((ilen >= mlen) ? ilen : mlen) + 1; + memmove(iptr + mlen, iptr + ilen + 1, nread - (iptr + ilen + 1 - pbuf)); + memset(iptr, '\n', mlen); + memcpy(iptr, ifc, strlen(ifc)); + destfd = TEMP_FAILURE_RETRY(open(config_file, O_RDWR, 0660)); + if (destfd < 0) { + ALOGE("Cannot update \"%s\": %s", config_file, strerror(errno)); + free(pbuf); + return -1; + } + TEMP_FAILURE_RETRY(write(destfd, pbuf, nread + mlen - ilen -1)); + close(destfd); + } + } + free(pbuf); + return 0; +} + +int ensure_config_file_exists(const char *config_file) +{ + char buf[2048]; + int srcfd, destfd; + struct stat sb; + int nread; + int ret; + + ret = access(config_file, R_OK|W_OK); + if ((ret == 0) || (errno == EACCES)) { + if ((ret != 0) && + (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) { + ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno)); + return -1; + } + /* return if filesize is at least 10 bytes */ + if (stat(config_file, &sb) == 0 && sb.st_size > 10) { + return update_ctrl_interface(config_file); + } + } else if (errno != ENOENT) { + ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno)); + return -1; + } + + srcfd = TEMP_FAILURE_RETRY(open(SUPP_CONFIG_TEMPLATE, O_RDONLY)); + if (srcfd < 0) { + ALOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); + return -1; + } + + destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT|O_RDWR, 0660)); + if (destfd < 0) { + close(srcfd); + ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno)); + return -1; + } + + while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) { + if (nread < 0) { + ALOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); + close(srcfd); + close(destfd); + unlink(config_file); + return -1; + } + TEMP_FAILURE_RETRY(write(destfd, buf, nread)); + } + + close(destfd); + close(srcfd); + + /* chmod is needed because open() didn't set permisions properly */ + if (chmod(config_file, 0660) < 0) { + ALOGE("Error changing permissions of %s to 0660: %s", + config_file, strerror(errno)); + unlink(config_file); + return -1; + } + + if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) { + ALOGE("Error changing group ownership of %s to %d: %s", + config_file, AID_WIFI, strerror(errno)); + unlink(config_file); + return -1; + } + return update_ctrl_interface(config_file); +} + +/** + * wifi_wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that + * may be left over from clients that were previously connected to + * wpa_supplicant. This keeps these files from being orphaned in the + * event of crashes that prevented them from being removed as part + * of the normal orderly shutdown. + */ +void wifi_wpa_ctrl_cleanup(void) +{ + DIR *dir; + struct dirent entry; + struct dirent *result; + size_t dirnamelen; + size_t maxcopy; + char pathname[PATH_MAX]; + char *namep; + char *local_socket_dir = CONFIG_CTRL_IFACE_CLIENT_DIR; + char *local_socket_prefix = CONFIG_CTRL_IFACE_CLIENT_PREFIX; + + if ((dir = opendir(local_socket_dir)) == NULL) + return; + + dirnamelen = (size_t)snprintf(pathname, sizeof(pathname), "%s/", local_socket_dir); + if (dirnamelen >= sizeof(pathname)) { + closedir(dir); + return; + } + namep = pathname + dirnamelen; + maxcopy = PATH_MAX - dirnamelen; + while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { + if (strncmp(entry.d_name, local_socket_prefix, strlen(local_socket_prefix)) == 0) { + if (strlcpy(namep, entry.d_name, maxcopy) < maxcopy) { + unlink(pathname); + } + } + } + closedir(dir); +} + +#ifdef USES_TI_MAC80211 +static int init_nl() +{ + int err; + + nl_soc = nl_socket_alloc(); + if (!nl_soc) { + ALOGE("Failed to allocate netlink socket."); + return -ENOMEM; + } + + if (genl_connect(nl_soc)) { + ALOGE("Failed to connect to generic netlink."); + err = -ENOLINK; + goto out_handle_destroy; + } + + genl_ctrl_alloc_cache(nl_soc, &nl_cache); + if (!nl_cache) { + ALOGE("Failed to allocate generic netlink cache."); + err = -ENOMEM; + goto out_handle_destroy; + } + + nl80211 = genl_ctrl_search_by_name(nl_cache, "nl80211"); + if (!nl80211) { + ALOGE("nl80211 not found."); + err = -ENOENT; + goto out_cache_free; + } + + return 0; + +out_cache_free: + nl_cache_free(nl_cache); +out_handle_destroy: + nl_socket_free(nl_soc); + return err; +} + +static void deinit_nl() +{ + genl_family_put(nl80211); + nl_cache_free(nl_cache); + nl_socket_free(nl_soc); +} + +// ignore the "." and ".." entries +static int dir_filter(const struct dirent *name) +{ + if (0 == strcmp("..", name->d_name) || + 0 == strcmp(".", name->d_name)) + return 0; + + return 1; +} + +// lookup the only active phy +int phy_lookup() +{ + char buf[200]; + int fd, pos; + struct dirent **namelist; + int n, i; + + n = scandir("/sys/class/ieee80211", &namelist, dir_filter, + (int (*)(const struct dirent**, const struct dirent**))alphasort); + if (n != 1) { + ALOGE("unexpected - found %d phys in /sys/class/ieee80211", n); + for (i = 0; i < n; i++) + free(namelist[i]); + free(namelist); + return -1; + } + + snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", + namelist[0]->d_name); + free(namelist[0]); + free(namelist); + + fd = open(buf, O_RDONLY); + if (fd < 0) + return -1; + pos = read(fd, buf, sizeof(buf) - 1); + if (pos < 0) { + close(fd); + return -1; + } + buf[pos] = '\0'; + close(fd); + return atoi(buf); +} + +int nl_error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) +{ + int *ret = (int *)arg; + *ret = err->error; + return NL_STOP; +} + +int nl_finish_handler(struct nl_msg *msg, void *arg) +{ + int *ret = (int *)arg; + *ret = 0; + return NL_SKIP; +} + +int nl_ack_handler(struct nl_msg *msg, void *arg) +{ + int *ret = (int *)arg; + *ret = 0; + return NL_STOP; +} + +static int execute_nl_interface_cmd(const char *iface, + enum nl80211_iftype type, + uint8_t cmd) +{ + struct nl_cb *cb; + struct nl_msg *msg; + int devidx = 0; + int err; + int add_interface = (cmd == NL80211_CMD_NEW_INTERFACE); + + if (add_interface) { + devidx = phy_lookup(); + } else { + devidx = if_nametoindex(iface); + if (devidx == 0) { + ALOGE("failed to translate ifname to idx"); + return -errno; + } + } + + msg = nlmsg_alloc(); + if (!msg) { + ALOGE("failed to allocate netlink message"); + return 2; + } + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) { + ALOGE("failed to allocate netlink callbacks"); + err = 2; + goto out_free_msg; + } + + genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0, 0, cmd, 0); + + if (add_interface) { + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); + } else { + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); + } + + if (add_interface) { + NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, iface); + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type); + } + + err = nl_send_auto_complete(nl_soc, msg); + if (err < 0) + goto out; + + err = 1; + + nl_cb_err(cb, NL_CB_CUSTOM, nl_error_handler, &err); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl_finish_handler, &err); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl_ack_handler, &err); + + while (err > 0) + nl_recvmsgs(nl_soc, cb); +out: + nl_cb_put(cb); +out_free_msg: + nlmsg_free(msg); + return err; +nla_put_failure: + ALOGW("building message failed"); + return 2; +} + +int add_remove_p2p_interface(int add) +{ + int ret; + + ret = init_nl(); + if (ret != 0) + return ret; + + if (add) { + ret = execute_nl_interface_cmd(P2P_INTERFACE, NL80211_IFTYPE_STATION, + NL80211_CMD_NEW_INTERFACE); + if (ret != 0) { + ALOGE("could not add P2P interface: %d", ret); + goto cleanup; + } + } else { + ret = execute_nl_interface_cmd(P2P_INTERFACE, NL80211_IFTYPE_STATION, + NL80211_CMD_DEL_INTERFACE); + if (ret != 0) { + ALOGE("could not remove P2P interface: %d", ret); + goto cleanup; + } + } + + ALOGD("added/removed p2p interface. add: %d", add); + +cleanup: + deinit_nl(); + return ret; +} +#endif /* USES_TI_MAC80211 */ + +int wifi_start_supplicant(int p2p_supported) +{ + char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; + int count = 200; /* wait at most 20 seconds for completion */ +#ifdef HAVE_LIBC_SYSTEM_PROPERTIES + const prop_info *pi; + unsigned serial = 0, i; +#endif + +#ifdef WIFI_DRIVER_MODULE_PATH +#ifdef XIAOMI_MIONE_WIFI + check_wifi_module(); +#endif +#endif + + if (p2p_supported) { + strcpy(supplicant_name, P2P_SUPPLICANT_NAME); + strcpy(supplicant_prop_name, P2P_PROP_NAME); + + /* Ensure p2p config file is created */ + if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) { + ALOGE("Failed to create a p2p config file"); + return -1; + } + + } else { + strcpy(supplicant_name, SUPPLICANT_NAME); + strcpy(supplicant_prop_name, SUPP_PROP_NAME); + } + + /* Check whether already running */ + if (property_get(supplicant_name, supp_status, NULL) + && strcmp(supp_status, "running") == 0) { + return 0; + } + + /* Before starting the daemon, make sure its config file exists */ + if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) { + ALOGE("Wi-Fi will not be enabled"); + return -1; + } + + if (ensure_entropy_file_exists() < 0) { + ALOGE("Wi-Fi entropy file was not created"); + } + +#ifdef USES_TI_MAC80211 + if (p2p_supported && add_remove_p2p_interface(1) < 0) { + ALOGE("Wi-Fi - could not create p2p interface"); + return -1; + } +#endif + + /* Clear out any stale socket files that might be left over. */ + wifi_wpa_ctrl_cleanup(); + + /* Reset sockets used for exiting from hung state */ + for (i=0; i running => stopped (i.e., + * it start up, but fails right away) from the case in which + * it starts in the stopped state and never manages to start + * running at all. + */ + pi = __system_property_find(supplicant_prop_name); + if (pi != NULL) { + serial = pi->serial; + } +#endif + property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE); + + property_set("ctl.start", supplicant_name); + sched_yield(); + + while (count-- > 0) { +#ifdef HAVE_LIBC_SYSTEM_PROPERTIES + if (pi == NULL) { + pi = __system_property_find(supplicant_prop_name); + } + if (pi != NULL) { + __system_property_read(pi, NULL, supp_status); + if (strcmp(supp_status, "running") == 0) { + return 0; + } else if (pi->serial != serial && + strcmp(supp_status, "stopped") == 0) { + return -1; + } + } +#else + if (property_get(supplicant_prop_name, supp_status, NULL)) { + if (strcmp(supp_status, "running") == 0) + return 0; + } +#endif + usleep(100000); + } + return -1; +} + +int wifi_stop_supplicant(int p2p_supported) +{ + char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; + int count = 50; /* wait at most 5 seconds for completion */ + + if (p2p_supported) { + strcpy(supplicant_name, P2P_SUPPLICANT_NAME); + strcpy(supplicant_prop_name, P2P_PROP_NAME); + } else { + strcpy(supplicant_name, SUPPLICANT_NAME); + strcpy(supplicant_prop_name, SUPP_PROP_NAME); + } + + /* Check whether supplicant already stopped */ + if (property_get(supplicant_prop_name, supp_status, NULL) + && strcmp(supp_status, "stopped") == 0) { + return 0; + } + + property_set("ctl.stop", supplicant_name); + sched_yield(); + + while (count-- > 0) { + if (property_get(supplicant_prop_name, supp_status, NULL)) { + if (strcmp(supp_status, "stopped") == 0) + return 0; + } + usleep(100000); + } + ALOGE("Failed to stop supplicant"); + return -1; +} + +int wifi_connect_on_socket_path(int index, const char *path) +{ + char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; + + /* Make sure supplicant is running */ + if (!property_get(supplicant_prop_name, supp_status, NULL) + || strcmp(supp_status, "running") != 0) { + ALOGE("Supplicant not running, cannot connect"); + return -1; + } + + ctrl_conn[index] = wpa_ctrl_open(path); + if (ctrl_conn[index] == NULL) { + ALOGE("Unable to open connection to supplicant on \"%s\": %s", + path, strerror(errno)); + return -1; + } + monitor_conn[index] = wpa_ctrl_open(path); + if (monitor_conn[index] == NULL) { + wpa_ctrl_close(ctrl_conn[index]); + ctrl_conn[index] = NULL; + return -1; + } + if (wpa_ctrl_attach(monitor_conn[index]) != 0) { + wpa_ctrl_close(monitor_conn[index]); + wpa_ctrl_close(ctrl_conn[index]); + ctrl_conn[index] = monitor_conn[index] = NULL; + return -1; + } + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets[index]) == -1) { + wpa_ctrl_close(monitor_conn[index]); + wpa_ctrl_close(ctrl_conn[index]); + ctrl_conn[index] = monitor_conn[index] = NULL; + return -1; + } + + return 0; +} + +/* Establishes the control and monitor socket connections on the interface */ +int wifi_connect_to_supplicant(const char *ifname) +{ + char path[256]; + + if (is_primary_interface(ifname)) { + if (access(IFACE_DIR, F_OK) == 0) { + snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface); + } else { + strlcpy(path, primary_iface, sizeof(path)); + } + return wifi_connect_on_socket_path(PRIMARY, path); + } else { + sprintf(path, "%s/%s", CONTROL_IFACE_PATH, ifname); + return wifi_connect_on_socket_path(SECONDARY, path); + } +} + +int wifi_send_command(int index, const char *cmd, char *reply, size_t *reply_len) +{ + int ret; + + if (ctrl_conn[index] == NULL) { + ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd); + return -1; + } + ret = wpa_ctrl_request(ctrl_conn[index], cmd, strlen(cmd), reply, reply_len, NULL); + if (ret == -2) { + ALOGD("'%s' command timed out.\n", cmd); + /* unblocks the monitor receive socket for termination */ + TEMP_FAILURE_RETRY(write(exit_sockets[index][0], "T", 1)); + return -2; + } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) { + return -1; + } + if (strncmp(cmd, "PING", 4) == 0) { + reply[*reply_len] = '\0'; + } + return 0; +} + +int wifi_ctrl_recv(int index, char *reply, size_t *reply_len) +{ + int res; + int ctrlfd = wpa_ctrl_get_fd(monitor_conn[index]); + struct pollfd rfds[2]; + + memset(rfds, 0, 2 * sizeof(struct pollfd)); + rfds[0].fd = ctrlfd; + rfds[0].events |= POLLIN; + rfds[1].fd = exit_sockets[index][1]; + rfds[1].events |= POLLIN; + res = TEMP_FAILURE_RETRY(poll(rfds, 2, -1)); + if (res < 0) { + ALOGE("Error poll = %d", res); + return res; + } + if (rfds[0].revents & POLLIN) { + return wpa_ctrl_recv(monitor_conn[index], reply, reply_len); + } else if (rfds[1].revents & POLLIN) { + /* Close only the p2p sockets on receive side + * see wifi_close_supplicant_connection() + */ + if (index == SECONDARY) { + ALOGD("close sockets %d", index); + wifi_close_sockets(index); + } + } + return -2; +} + +int wifi_wait_on_socket(int index, char *buf, size_t buflen) +{ + size_t nread = buflen - 1; + int fd; + fd_set rfds; + int result; + struct timeval tval; + struct timeval *tptr; + + if (monitor_conn[index] == NULL) { + ALOGD("Connection closed\n"); + strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1); + buf[buflen-1] = '\0'; + return strlen(buf); + } + + result = wifi_ctrl_recv(index, buf, &nread); + + /* Terminate reception on exit socket */ + if (result == -2) { + strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1); + buf[buflen-1] = '\0'; + return strlen(buf); + } + + if (result < 0) { + ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno)); + strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1); + buf[buflen-1] = '\0'; + return strlen(buf); + } + buf[nread] = '\0'; + /* Check for EOF on the socket */ + if (result == 0 && nread == 0) { + /* Fabricate an event to pass up */ + ALOGD("Received EOF on supplicant socket\n"); + strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1); + buf[buflen-1] = '\0'; + return strlen(buf); + } + /* + * Events strings are in the format + * + * CTRL-EVENT-XXX + * + * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG, + * etc.) and XXX is the event name. The level information is not useful + * to us, so strip it off. + */ + if (buf[0] == '<') { + char *match = strchr(buf, '>'); + if (match != NULL) { + nread -= (match+1-buf); + memmove(buf, match+1, nread+1); + } + } + + return nread; +} + +int wifi_wait_for_event(const char *ifname, char *buf, size_t buflen) +{ + if (is_primary_interface(ifname)) { + return wifi_wait_on_socket(PRIMARY, buf, buflen); + } else { + return wifi_wait_on_socket(SECONDARY, buf, buflen); + } +} + +void wifi_close_sockets(int index) +{ + if (ctrl_conn[index] != NULL) { + wpa_ctrl_close(ctrl_conn[index]); + ctrl_conn[index] = NULL; + } + + if (monitor_conn[index] != NULL) { + wpa_ctrl_close(monitor_conn[index]); + monitor_conn[index] = NULL; + } + + if (exit_sockets[index][0] >= 0) { + close(exit_sockets[index][0]); + exit_sockets[index][0] = -1; + } + + if (exit_sockets[index][1] >= 0) { + close(exit_sockets[index][1]); + exit_sockets[index][1] = -1; + } +} + +void wifi_close_supplicant_connection(const char *ifname) +{ + char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; + int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */ + + if (is_primary_interface(ifname)) { + wifi_close_sockets(PRIMARY); + } else { + /* p2p socket termination needs unblocking the monitor socket + * STA connection does not need it since supplicant gets shutdown + */ + TEMP_FAILURE_RETRY(write(exit_sockets[SECONDARY][0], "T", 1)); + /* p2p sockets are closed after the monitor thread + * receives the terminate on the exit socket + */ + return; + } + + while (count-- > 0) { + if (property_get(supplicant_prop_name, supp_status, NULL)) { + if (strcmp(supp_status, "stopped") == 0) + return; + } + usleep(100000); + } +} + +int wifi_command(const char *ifname, const char *command, char *reply, size_t *reply_len) +{ + if (is_primary_interface(ifname)) { + return wifi_send_command(PRIMARY, command, reply, reply_len); + } else { + return wifi_send_command(SECONDARY, command, reply, reply_len); + } +} + +const char *wifi_get_fw_path(int fw_type) +{ +#ifdef XIAOMI_MIONE_WIFI + check_wifi_module(); + ALOGD("Wifi Module checked"); +#endif + switch (fw_type) { + case WIFI_GET_FW_PATH_STA: +#ifndef XIAOMI_MIONE_WIFI + return WIFI_DRIVER_FW_PATH_STA; +#else + return is_wifi_module_4330 ? WIFI_DRIVER_FW_PATH_STA_DHD : WIFI_DRIVER_FW_PATH_STA; +#endif + case WIFI_GET_FW_PATH_AP: +#ifndef XIAOMI_MIONE_WIFI + return WIFI_DRIVER_FW_PATH_AP; +#else + ALOGD("ApFirmware=%s", is_wifi_module_4330 ? WIFI_DRIVER_FW_PATH_AP_DHD : WIFI_DRIVER_FW_PATH_AP); + return is_wifi_module_4330 ? WIFI_DRIVER_FW_PATH_AP_DHD : WIFI_DRIVER_FW_PATH_AP; +#endif + case WIFI_GET_FW_PATH_P2P: +#ifndef XIAOMI_MIONE_WIFI + return WIFI_DRIVER_FW_PATH_P2P; +#else + return is_wifi_module_4330 ? WIFI_DRIVER_FW_PATH_P2P_DHD : WIFI_DRIVER_FW_PATH_P2P; +#endif + } + return NULL; +} + +int wifi_change_fw_path(const char *fwpath) +{ + int len; + int fd; + int ret = 0; + + if (!fwpath) + return ret; + fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY)); + if (fd < 0) { + ALOGE("Failed to open wlan fw path param (%s)", strerror(errno)); + return -1; + } + len = strlen(fwpath) + 1; + if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) { + ALOGE("Failed to write wlan fw path param (%s)", strerror(errno)); + ret = -1; + } + close(fd); + return ret; +} + +int wifi_set_mode(int mode) { + wifi_mode = mode; + return 0; +} +#ifdef XIAOMI_MIONE_WIFI +/* The Xiaomi MI-One Plus read mac function */ +int read_wlan_mac() { + char *x; + if(!strcmp(mac_buf,"")) { + x=read_mac(); + sprintf(mac_buf,"%s mac=0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x", DRIVER_MODULE_ARG, x[20], x[16], x[12], x[8], x[4], x[0]); + } + ALOGI("Got WLAN MAC Address: %s \ ",mac_buf); + read_mac_ok = 1; + return 0; +} +#endif diff --git a/hardware/msm7k b/hardware/msm7k new file mode 160000 index 00000000..e2d92ef1 --- /dev/null +++ b/hardware/msm7k @@ -0,0 +1 @@ +Subproject commit e2d92ef15492cdecc2c495e962a39e3669d945a7 diff --git a/hardware/qcom/audio b/hardware/qcom/audio new file mode 160000 index 00000000..12de8f95 --- /dev/null +++ b/hardware/qcom/audio @@ -0,0 +1 @@ +Subproject commit 12de8f9578890e2fe7ad9f1a4b4ee5fa228f598a diff --git a/hardware/qcom/audio-caf b/hardware/qcom/audio-caf new file mode 160000 index 00000000..8995c4ac --- /dev/null +++ b/hardware/qcom/audio-caf @@ -0,0 +1 @@ +Subproject commit 8995c4ac812b640de04813d2592be350700e05f7 diff --git a/hardware/qcom/bt b/hardware/qcom/bt new file mode 160000 index 00000000..ad7eab09 --- /dev/null +++ b/hardware/qcom/bt @@ -0,0 +1 @@ +Subproject commit ad7eab092dae95101a71f1dd758086ad042dcf1d diff --git a/hardware/qcom/camera b/hardware/qcom/camera new file mode 160000 index 00000000..bc283bd0 --- /dev/null +++ b/hardware/qcom/camera @@ -0,0 +1 @@ +Subproject commit bc283bd0139f959581a18f56ad63452ff54bbcc5 diff --git a/hardware/qcom/display b/hardware/qcom/display new file mode 160000 index 00000000..c962bf8b --- /dev/null +++ b/hardware/qcom/display @@ -0,0 +1 @@ +Subproject commit c962bf8b8fa4d9a6400811296fb270f47db68cf4 diff --git a/hardware/qcom/display-caf b/hardware/qcom/display-caf new file mode 160000 index 00000000..a4efddea --- /dev/null +++ b/hardware/qcom/display-caf @@ -0,0 +1 @@ +Subproject commit a4efddea5f685b160caebaa8d03b6ff126777fd2 diff --git a/hardware/qcom/display-legacy b/hardware/qcom/display-legacy new file mode 160000 index 00000000..aa9e7f22 --- /dev/null +++ b/hardware/qcom/display-legacy @@ -0,0 +1 @@ +Subproject commit aa9e7f22a3da094ec5ef4c9c1407bf59f4994a7f diff --git a/hardware/qcom/gps b/hardware/qcom/gps new file mode 160000 index 00000000..ca269d72 --- /dev/null +++ b/hardware/qcom/gps @@ -0,0 +1 @@ +Subproject commit ca269d72a988b1b564d5d90ef714e6aefb1c3d47 diff --git a/hardware/qcom/keymaster b/hardware/qcom/keymaster new file mode 160000 index 00000000..46bf12b5 --- /dev/null +++ b/hardware/qcom/keymaster @@ -0,0 +1 @@ +Subproject commit 46bf12b55801218a984e9549b98185bc46763f90 diff --git a/hardware/qcom/media b/hardware/qcom/media new file mode 160000 index 00000000..aaad4616 --- /dev/null +++ b/hardware/qcom/media @@ -0,0 +1 @@ +Subproject commit aaad4616a3cecd4f631d1d167fc97b3cb65f66d8 diff --git a/hardware/qcom/media-caf b/hardware/qcom/media-caf new file mode 160000 index 00000000..5234181e --- /dev/null +++ b/hardware/qcom/media-caf @@ -0,0 +1 @@ +Subproject commit 5234181ec526471bdacadd876cc202b65c53035b diff --git a/hardware/qcom/media-legacy b/hardware/qcom/media-legacy new file mode 160000 index 00000000..79d649f1 --- /dev/null +++ b/hardware/qcom/media-legacy @@ -0,0 +1 @@ +Subproject commit 79d649f13cb444527fc2978f141d09ede9073707 diff --git a/hardware/qcom/power b/hardware/qcom/power new file mode 160000 index 00000000..53cc747d --- /dev/null +++ b/hardware/qcom/power @@ -0,0 +1 @@ +Subproject commit 53cc747d50331ae982dd52e22a60c80048bcb4d9 diff --git a/hardware/qcom/wlan b/hardware/qcom/wlan new file mode 160000 index 00000000..59d7a95b --- /dev/null +++ b/hardware/qcom/wlan @@ -0,0 +1 @@ +Subproject commit 59d7a95be90328306ac2dfef31a5663f1f2d76fc diff --git a/hardware/ril b/hardware/ril new file mode 160000 index 00000000..73aea090 --- /dev/null +++ b/hardware/ril @@ -0,0 +1 @@ +Subproject commit 73aea09045fa9bdaa09cab9111486c726f506adb diff --git a/hardware/samsung_slsi/exynos5 b/hardware/samsung_slsi/exynos5 new file mode 160000 index 00000000..320c939e --- /dev/null +++ b/hardware/samsung_slsi/exynos5 @@ -0,0 +1 @@ +Subproject commit 320c939ef471644fcb618cd3b5688e68694170a9 diff --git a/hardware/ti/omap3 b/hardware/ti/omap3 new file mode 160000 index 00000000..f3af1146 --- /dev/null +++ b/hardware/ti/omap3 @@ -0,0 +1 @@ +Subproject commit f3af1146a6329b84f316cf1bf98bcd574d17b7b3 diff --git a/hardware/ti/omap4xxx b/hardware/ti/omap4xxx new file mode 160000 index 00000000..de825f2f --- /dev/null +++ b/hardware/ti/omap4xxx @@ -0,0 +1 @@ +Subproject commit de825f2f08fad153116807ea18002e4590bd71bb diff --git a/hardware/ti/wlan b/hardware/ti/wlan new file mode 160000 index 00000000..da8f6d2c --- /dev/null +++ b/hardware/ti/wlan @@ -0,0 +1 @@ +Subproject commit da8f6d2c2a7c413eba12c5adcbd65c3316943d1e diff --git a/hardware/ti/wpan b/hardware/ti/wpan new file mode 160000 index 00000000..dbcd8668 --- /dev/null +++ b/hardware/ti/wpan @@ -0,0 +1 @@ +Subproject commit dbcd8668ad59d5c59a21c6835926b471ea133255 diff --git a/patch_device/aries/Android.mk b/patch_device/aries/Android.mk new file mode 100644 index 00000000..896b0431 --- /dev/null +++ b/patch_device/aries/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH := $(call my-dir) +include $(MIUI_CLEAR) +MIUI_PRODUCT := aries +MIUI_KERNEL := $(LOCAL_PATH)/kernel + +MIUI_KERNEL_BASE := 0x80200000 --ramdiskaddr 0x82200000 +MIUI_KERNEL_CMDLINE := console=null androidboot.hardware=qcom ehci-hcd.park=3 maxcpus=2 +MIUI_KERNEL_PAGESIZE := 2048 + +MIUI_PRODUCT_ROOT := $(LOCAL_PATH)/root +MIUI_DEVICE_CONFIG := $(LOCAL_PATH)/device.conf + +BOARD_HAS_DUALSYSTEM_PARTITIONS := true +TARGET_NEEDS_VSYNC := true +include $(MIUI_RECOVERY) diff --git a/patch_device/aries/device.conf b/patch_device/aries/device.conf new file mode 100644 index 00000000..08f010ca --- /dev/null +++ b/patch_device/aries/device.conf @@ -0,0 +1,14 @@ +ini_set("customkeycode_up", "115"); +ini_set("customkeycode_down", "114"); +ini_set("customkeycode_select", "116"); +ini_set("customkeycode_menu", "229"); +ini_set("customkeycode_back", "158"); + +#ini_set("force_colorspace", "gbra"); //bule +ini_set("force_colorspace", "grba"); +#ini_set("force_colorspace", "grba"); //yellow select +#ini_set("force_colorspace", "argb");//yellow background +#ini_set("force_colorspace", "brga"); //blue select +ini_set("rom_device", "Xiaomi MI2"); +ini_set("rom_date", "2013-07"); +ini_set("lun_file", "/sys/devices/virtual/android_usb/android0/f_mass_storage/lun/file"); diff --git a/patch_device/aries/kernel b/patch_device/aries/kernel new file mode 100644 index 00000000..bc18cdf0 Binary files /dev/null and b/patch_device/aries/kernel differ diff --git a/patch_device/aries/root/default.prop b/patch_device/aries/root/default.prop new file mode 100644 index 00000000..521a39ea --- /dev/null +++ b/patch_device/aries/root/default.prop @@ -0,0 +1,89 @@ +# +# ADDITIONAL_DEFAULT_PROPERTIES +# +ro.adb.secure=0 +ro.secure=0 +ro.allow.mock.location=1 +ro.debuggable=1 +rild.libpath=/system/lib/libril-qc-qmi-1.so +persist.sys.usb.config=mtp,adb +# begin build properties +# autogenerated by buildinfo.sh +ro.build.id=JDQ39E +ro.build.display.id=cm_aries-userdebug 4.2.2 JDQ39E eng.huangqiwu.20130718.145016 test-keys +ro.build.version.incremental=eng.huangqiwu.20130718.145016 +ro.build.version.sdk=17 +ro.build.version.codename=REL +ro.build.version.release=4.2.2 +ro.build.date=Thu Jul 18 14:51:03 CST 2013 +ro.build.date.utc=0 +ro.build.type=userdebug +ro.build.user=huangqiwu +ro.build.host=xiaomi +ro.build.tags=test-keys +ro.product.model=MI 2 +ro.product.brand=Xiaomi +ro.product.name=aries +ro.product.device=aries +ro.product.board=MSM8960 +ro.product.cpu.abi=armeabi-v7a +ro.product.cpu.abi2=armeabi +ro.product.manufacturer=Xiaomi +ro.product.locale.language=en +ro.product.locale.region=US +ro.wifi.channels= +ro.board.platform=msm8960 +# ro.build.product is obsolete; use ro.product.device +ro.build.product=aries +# Do not try to parse ro.build.description or .fingerprint +ro.build.description=aries-user 4.2.2 JDQ39 573038 release-keys +ro.build.fingerprint=Xiaomi/aries/aries:4.2.2/JDQ39/573038:user/release-keys +ro.build.characteristics=nosdcard +ro.cm.device=aries +# end build properties + +# +# ADDITIONAL_BUILD_PROPERTIES +# +ro.rommanager.developerid=cyanogenmod +keyguard.no_require_sim=true +ro.url.legal=http://www.google.com/intl/%s/mobile/android/basic/phone-legal.html +ro.url.legal.android_privacy=http://www.google.com/intl/%s/mobile/android/basic/privacy.html +ro.com.google.clientidbase=android-google +ro.com.android.wifi-watchlist=GoogleGuest +ro.setupwizard.enterprise_mode=1 +ro.com.android.dateformat=MM-dd-yyyy +ro.com.android.dataroaming=false +ro.cm.version=10.1-20130718-UNOFFICIAL-aries +ro.modversion=10.1-20130718-UNOFFICIAL-aries +ro.config.ringtone=Orion.ogg +ro.config.notification_sound=Argon.ogg +ro.config.alarm_alert=Hassium.ogg +ro.carrier=unknown +ro.opengles.version=131072 +ro.sf.lcd_density=320 +persist.audio.handset.mic=dmic +persist.audio.fluence.mode=endfire +persist.audio.lowlatency.rec=false +af.resampler.quality=4 +persist.radio.apm_sim_not_pwdn=1 +ro.telephony.call_ring.multiple=0 +debug.mdpcomp.maxlayer=3 +ro.qualcomm.bt.hci_transport=smd +telephony.lteOnCdmaDevice=0 +drm.service.enabled=true +wifi.interface=wlan0 +wifi.supplicant_scan_interval=15 +media.aac_51_output_enabled=true +debug.prerotation.disable=1 +debug.egl.recordable.rgba8888=1 +dalvik.vm.heapstartsize=8m +dalvik.vm.heapgrowthlimit=192m +dalvik.vm.heapsize=512m +dalvik.vm.heaptargetutilization=0.75 +dalvik.vm.heapminfree=2m +dalvik.vm.heapmaxfree=8m +dalvik.vm.lockprof.threshold=500 +dalvik.vm.dexopt-flags=m=y +net.bt.name=Android +dalvik.vm.stack-trace-file=/data/anr/traces.txt diff --git a/patch_device/aries/root/etc/recovery.fstab b/patch_device/aries/root/etc/recovery.fstab new file mode 100644 index 00000000..703d8394 --- /dev/null +++ b/patch_device/aries/root/etc/recovery.fstab @@ -0,0 +1,17 @@ +/boot emmc /dev/block/platform/msm_sdcc.1/by-name/boot +/boot1 emmc /dev/block/platform/msm_sdcc.1/by-name/boot1 +/recovery emmc /dev/block/platform/msm_sdcc.1/by-name/recovery +/misc emmc /dev/block/platform/msm_sdcc.1/by-name/misc +/system ext4 /dev/block/platform/msm_sdcc.1/by-name/system +/system1 ext4 /dev/block/platform/msm_sdcc.1/by-name/system1 +/data ext4 /dev/block/platform/msm_sdcc.1/by-name/userdata length=-16384 +/cache ext4 /dev/block/platform/msm_sdcc.1/by-name/cache +/radio emmc /dev/block/platform/msm_sdcc.1/by-name/modem +/radio1 emmc /dev/block/platform/msm_sdcc.1/by-name/modem1 +/sbl1 emmc /dev/block/platform/msm_sdcc.1/by-name/sbl1 +/sbl2 emmc /dev/block/platform/msm_sdcc.1/by-name/sbl2 +/sbl3 emmc /dev/block/platform/msm_sdcc.1/by-name/sbl3 +/tz emmc /dev/block/platform/msm_sdcc.1/by-name/tz +/rpm emmc /dev/block/platform/msm_sdcc.1/by-name/rpm +/aboot emmc /dev/block/platform/msm_sdcc.1/by-name/aboot +/sdcard ext4 /dev/block/platform/msm_sdcc.1/by-name/storage diff --git a/patch_device/aries/root/init b/patch_device/aries/root/init new file mode 100755 index 00000000..61bc4c1f Binary files /dev/null and b/patch_device/aries/root/init differ diff --git a/patch_device/aries/root/init.qcom.class_core.sh b/patch_device/aries/root/init.qcom.class_core.sh new file mode 100755 index 00000000..eaed5c87 --- /dev/null +++ b/patch_device/aries/root/init.qcom.class_core.sh @@ -0,0 +1,259 @@ +#!/system/bin/sh +# Copyright (c) 2012, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Code Aurora nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# Set platform variables +target=`getprop ro.board.platform` +soc_hwplatform=`cat /sys/devices/system/soc/soc0/hw_platform` 2> /dev/null +soc_hwid=`cat /sys/devices/system/soc/soc0/id` 2> /dev/null +soc_hwver=`cat /sys/devices/system/soc/soc0/platform_version` 2> /dev/null + + +# Dynamic Memory Managment (DMM) provides a sys file system to the userspace +# that can be used to plug in/out memory that has been configured as unstable. +# This unstable memory can be in Active or In-Active State. +# Each of which the userspace can request by writing to a sys file. +# +# ro.dev.dmm = 1; Indicates that DMM is enabled in the Android User Space. This +# property is set in the Android system properties file. +# +# If ro.dev.dmm.dpd.start_address is set here then the target has a memory +# configuration that supports DynamicMemoryManagement. +init_DMM() +{ + block=-1 + + case "$target" in + "msm7630_surf" | "msm7630_1x" | "msm7630_fusion" | "msm8960") + ;; + *) + return + ;; + esac + + mem="/sys/devices/system/memory" + op=`cat $mem/movable_start_bytes` + case "$op" in + "0") + log -p i -t DMM DMM Disabled. movable_start_bytes not set: $op + ;; + + "$mem/movable_start_bytes: No such file or directory ") + log -p i -t DMM DMM Disabled. movable_start_bytes does not exist: $op + ;; + + *) + log -p i -t DMM DMM available. movable_start_bytes at $op + movable_start_bytes=0x`cat $mem/movable_start_bytes` + block_size_bytes=0x`cat $mem/block_size_bytes` + block=$((#${movable_start_bytes}/${block_size_bytes})) + + chown system.system $mem/memory$block/state + chown system.system $mem/probe + chown system.system $mem/active + chown system.system $mem/remove + + case "$target" in + "msm7630_surf" | "msm7630_1x" | "msm7630_fusion") + echo $movable_start_bytes > $mem/probe + case "$?" in + "0") + log -p i -t DMM $movable_start_bytes to physical hotplug succeeded. + ;; + *) + log -p e -t DMM $movable_start_bytes to physical hotplug failed. + return + ;; + esac + + echo online > $mem/memory$block/state + case "$?" in + "0") + log -p i -t DMM \'echo online\' to logical hotplug succeeded. + ;; + *) + log -p e -t DMM \'echo online\' to logical hotplug failed. + return + ;; + esac + ;; + esac + + setprop ro.dev.dmm.dpd.start_address $movable_start_bytes + setprop ro.dev.dmm.dpd.block $block + ;; + esac + + case "$target" in + "msm8960") + return + ;; + esac + + # For 7X30 targets: + # ro.dev.dmm.dpd.start_address is set when the target has a 2x256Mb memory + # configuration. This is also used to indicate that the target is capable of + # setting EBI-1 to Deep Power Down or Self Refresh. + op=`cat $mem/low_power_memory_start_bytes` + case "$op" in + "0") + log -p i -t DMM Self-Refresh-Only Disabled. low_power_memory_start_bytes not set:$op + ;; + "$mem/low_power_memory_start_bytes No such file or directory ") + log -p i -t DMM Self-Refresh-Only Disabled. low_power_memory_start_bytes does not exist:$op + ;; + *) + log -p i -t DMM Self-Refresh-Only available. low_power_memory_start_bytes at $op + ;; + esac +} + +# +# For controlling console and shell on console on 8960 - perist.serial.enable 8960 +# On other target use default ro.debuggable property. +# +serial=`getprop persist.serial.enable` +dserial=`getprop ro.debuggable` +case "$target" in + "msm8960") + case "$serial" in + "0") + echo 0 > /sys/devices/platform/msm_serial_hsl.0/console + ;; + "1") + echo 1 > /sys/devices/platform/msm_serial_hsl.0/console + start console + ;; + *) + case "$dserial" in + "1") + start console + ;; + esac + ;; + esac + ;; + *) + case "$dserial" in + "1") + start console + ;; + esac + ;; +esac + +# +# Allow persistent faking of bms +# User needs to set fake bms charge in persist.bms.fake_batt_capacity +# +fake_batt_capacity=`getprop persist.bms.fake_batt_capacity` +case "$fake_batt_capacity" in + "") ;; #Do nothing here + * ) + case $target in + "msm8960") + echo "$fake_batt_capacity" > /sys/module/pm8921_bms/parameters/bms_fake_battery + ;; + esac +esac + +case "$target" in + "msm7630_surf" | "msm7630_1x" | "msm7630_fusion") + case "$soc_hwplatform" in + "FFA" | "SVLTE_FFA") + # linking to surf_keypad_qwerty.kcm.bin instead of surf_keypad_numeric.kcm.bin so that + # the UI keyboard works fine. + ln -s /system/usr/keychars/surf_keypad_qwerty.kcm.bin /system/usr/keychars/surf_keypad.kcm.bin + ;; + "Fluid") + setprop ro.sf.lcd_density 240 + setprop qcom.bt.dev_power_class 2 + ;; + *) + ln -s /system/usr/keychars/surf_keypad_qwerty.kcm.bin /system/usr/keychars/surf_keypad.kcm.bin + ;; + esac + + insmod /system/lib/modules/ss_mfcinit.ko + insmod /system/lib/modules/ss_vencoder.ko + insmod /system/lib/modules/ss_vdecoder.ko + chmod 0666 /dev/ss_mfc_reg + chmod 0666 /dev/ss_vdec + chmod 0666 /dev/ss_venc + + init_DMM + ;; + + "msm8660") + case "$soc_hwplatform" in + "Fluid") + setprop ro.sf.lcd_density 240 + ;; + "Dragon") + setprop ro.sound.alsa "WM8903" + ;; + esac + ;; + + "msm8960") + # lcd density is write-once. Hence the separate switch case + case "$soc_hwplatform" in + "Liquid") + if [ "$soc_hwver" == "196608" ]; then # version 0x30000 is 3D sku + setprop ro.sf.hwrotation 90 + fi + + setprop ro.sf.lcd_density 160 + ;; + "MTP") + setprop ro.sf.lcd_density 240 + ;; + *) + case "$soc_hwid" in + "109") + setprop ro.sf.lcd_density 160 + ;; + *) + setprop ro.sf.lcd_density 240 + ;; + esac + ;; + esac + + #Set up composition type based on the target + case "$soc_hwid" in + 109| 116 | 117 | 118 | 120 | 121| 130) + #APQ8064, MSM8930, MSM8630, MSM8230, + # MSM8627, MSM8227, MPQ8064 + setprop debug.composition.type gpu + ;; + *) + esac + + init_DMM + ;; +esac diff --git a/patch_device/aries/root/init.qcom.class_main.sh b/patch_device/aries/root/init.qcom.class_main.sh new file mode 100755 index 00000000..df7735d5 --- /dev/null +++ b/patch_device/aries/root/init.qcom.class_main.sh @@ -0,0 +1,122 @@ +#!/system/bin/sh +# Copyright (c) 2012, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Code Aurora nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# +# start ril-daemon only for targets on which radio is present +# +baseband=`getprop ro.baseband` +multirild=`getprop ro.multi.rild` +dsds=`getprop persist.dsds.enabled` +netmgr=`getprop ro.use_data_netmgrd` + +case "$baseband" in + "apq") + setprop ro.radio.noril yes + stop ril-daemon +esac + +case "$baseband" in + "msm" | "csfb" | "svlte2a" | "mdm" | "sglte" | "unknown") + start qmuxd + case "$baseband" in + "svlte2a" | "csfb" | "sglte") + start qmiproxy + esac + case "$multirild" in + "true") + case "$dsds" in + "true") + start ril-daemon1 + esac + esac + case "$netmgr" in + "true") + start netmgrd + esac +esac + +# +# enable bluetooth profiles dynamically +# +case $baseband in + "apq") + setprop ro.qualcomm.bluetooth.opp true + setprop ro.qualcomm.bluetooth.hfp false + setprop ro.qualcomm.bluetooth.hsp false + setprop ro.qualcomm.bluetooth.pbap true + setprop ro.qualcomm.bluetooth.ftp true + setprop ro.qualcomm.bluetooth.map true + setprop ro.qualcomm.bluetooth.nap false + setprop ro.qualcomm.bluetooth.sap false + setprop ro.qualcomm.bluetooth.dun false + ;; + "mdm" | "svlte2a" | "svlte1" | "csfb") + setprop ro.qualcomm.bluetooth.opp true + setprop ro.qualcomm.bluetooth.hfp true + setprop ro.qualcomm.bluetooth.hsp true + setprop ro.qualcomm.bluetooth.pbap true + setprop ro.qualcomm.bluetooth.ftp true + setprop ro.qualcomm.bluetooth.map true + setprop ro.qualcomm.bluetooth.nap true + setprop ro.qualcomm.bluetooth.sap true + setprop ro.qualcomm.bluetooth.dun false + ;; + "msm") + setprop ro.qualcomm.bluetooth.opp true + setprop ro.qualcomm.bluetooth.hfp true + setprop ro.qualcomm.bluetooth.hsp true + setprop ro.qualcomm.bluetooth.pbap true + setprop ro.qualcomm.bluetooth.ftp true + setprop ro.qualcomm.bluetooth.map true + setprop ro.qualcomm.bluetooth.nap true + setprop ro.qualcomm.bluetooth.sap true + setprop ro.qualcomm.bluetooth.dun true + ;; + "mpq") + setprop ro.qualcomm.bluetooth.opp false + setprop ro.qualcomm.bluetooth.hfp false + setprop ro.qualcomm.bluetooth.hsp false + setprop ro.qualcomm.bluetooth.pbap false + setprop ro.qualcomm.bluetooth.ftp false + setprop ro.qualcomm.bluetooth.map false + setprop ro.qualcomm.bluetooth.nap false + setprop ro.qualcomm.bluetooth.sap false + setprop ro.qualcomm.bluetooth.dun false + ;; + *) + setprop ro.qualcomm.bluetooth.opp true + setprop ro.qualcomm.bluetooth.hfp true + setprop ro.qualcomm.bluetooth.hsp true + setprop ro.qualcomm.bluetooth.pbap true + setprop ro.qualcomm.bluetooth.ftp true + setprop ro.qualcomm.bluetooth.map true + setprop ro.qualcomm.bluetooth.nap true + setprop ro.qualcomm.bluetooth.sap true + setprop ro.qualcomm.bluetooth.dun true + ;; +esac diff --git a/patch_device/aries/root/init.qcom.sh b/patch_device/aries/root/init.qcom.sh new file mode 100755 index 00000000..b2e456fd --- /dev/null +++ b/patch_device/aries/root/init.qcom.sh @@ -0,0 +1,135 @@ +#!/system/bin/sh +# Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Code Aurora nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +target=`getprop ro.board.platform` + +# +# Function to start sensors for DSPS enabled platforms +# +start_sensors() +{ + mkdir -p /data/system/sensors + touch /data/system/sensors/settings + chmod 775 /data/system/sensors + chmod 664 /data/system/sensors/settings + + mkdir -p /data/misc/sensors + chmod 775 /data/misc/sensors + mkdir -p /persist/misc/sensors + chmod 775 /persist/misc/sensors + + if [ ! -s /data/system/sensors/settings ]; then + # If the settings file is empty, enable sensors HAL + # Otherwise leave the file with it's current contents + echo 1 > /data/system/sensors/settings + fi + start sensors +} + +start_battery_monitor() +{ + chown root.system /sys/module/pm8921_bms/parameters/* + chmod 0660 /sys/module/pm8921_bms/parameters/* + mkdir -p /data/bms + chown root.system /data/bms + chmod 0770 /data/bms + start battery_monitor +} + +baseband=`getprop ro.baseband` + +# +# Suppress default route installation during RA for IPV6; user space will take +# care of this +# +for file in /proc/sys/net/ipv6/conf/* +do + echo 0 > $file/accept_ra_defrtr +done + +# +# Start gpsone_daemon for SVLTE Type I & II devices +# +case "$target" in + "msm7630_fusion") + start gpsone_daemon +esac +case "$baseband" in + "svlte2a") + start gpsone_daemon + start bridgemgrd +esac +case "$target" in + "msm7630_surf" | "msm8660" | "msm8960") + start quipc_igsn +esac +case "$target" in + "msm7630_surf" | "msm8660" | "msm8960") + start quipc_main +esac + +#case "$target" in +# "msm8960") +# start location_mq +# start xtwifi_inet +# start xtwifi_client +#esac + +case "$target" in + "msm7630_surf" | "msm7630_1x" | "msm7630_fusion") + value=`cat /sys/devices/system/soc/soc0/hw_platform` + case "$value" in + "Fluid") + start profiler_daemon;; + esac + ;; + "msm8660" ) + platformvalue=`cat /sys/devices/system/soc/soc0/hw_platform` + case "$platformvalue" in + "Fluid") + start_sensors + start profiler_daemon;; + esac + ;; + "msm8960") + start_sensors + case "$baseband" in + "msm") + start_battery_monitor;; + esac + + platformvalue=`cat /sys/devices/system/soc/soc0/hw_platform` + case "$platformvalue" in + "Fluid") + start profiler_daemon;; + "Liquid") + start profiler_daemon;; + esac + ;; + +esac diff --git a/patch_device/aries/root/init.qcom.usb.sh b/patch_device/aries/root/init.qcom.usb.sh new file mode 100755 index 00000000..d3da35c2 --- /dev/null +++ b/patch_device/aries/root/init.qcom.usb.sh @@ -0,0 +1,156 @@ +#!/system/bin/sh +# Copyright (c) 2012, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Code Aurora Forum, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# Update USB serial number from persist storage if present, if not update +# with value passed from kernel command line, if none of these values are +# set then use the default value. This order is needed as for devices which +# do not have unique serial number. +# User needs to set unique usb serial number to persist.usb.serialno +# +serialno=`getprop persist.usb.serialno` +case "$serialno" in + "") + serialnum=`getprop ro.serialno` + case "$serialnum" in + "");; #Do nothing, use default serial number + *) + echo "$serialnum" > /sys/class/android_usb/android0/iSerial + esac + ;; + *) + echo "$serialno" > /sys/class/android_usb/android0/iSerial +esac + +chown root.system /sys/devices/platform/msm_hsusb/gadget/wakeup +chmod 220 /sys/devices/platform/msm_hsusb/gadget/wakeup + +# +# Allow persistent usb charging disabling +# User needs to set usb charging disabled in persist.usb.chgdisabled +# +target=`getprop ro.board.platform` +usbchgdisabled=`getprop persist.usb.chgdisabled` +case "$usbchgdisabled" in + "") ;; #Do nothing here + * ) + case $target in + "msm8660") + echo "$usbchgdisabled" > /sys/module/pmic8058_charger/parameters/disabled + echo "$usbchgdisabled" > /sys/module/smb137b/parameters/disabled + ;; + "msm8960") + echo "$usbchgdisabled" > /sys/module/pm8921_charger/parameters/disabled + ;; + esac +esac + +usbcurrentlimit=`getprop persist.usb.currentlimit` +case "$usbcurrentlimit" in + "") ;; #Do nothing here + * ) + case $target in + "msm8960") + echo "$usbcurrentlimit" > /sys/module/pm8921_charger/parameters/usb_max_current + ;; + esac +esac +# +# Allow USB enumeration with default PID/VID +# +baseband=`getprop ro.baseband` +echo 1 > /sys/class/android_usb/f_mass_storage/lun/nofua +usb_config=`getprop persist.sys.usb.config` +debug_config=`getprop ro.debuggable` +case "$usb_config" in + "" | "adb") #USB persist config not set, select default configuration + case $target in + "msm8974") + setprop persist.sys.usb.config diag,adb + ;; + "msm8960") + case "$baseband" in + "mdm") + if [ "$debug_config" = "0" ]; then + setprop persist.sys.usb.config mtp + else + setprop persist.sys.usb.config mtp,adb + fi + ;; + "sglte") + setprop persist.sys.usb.config diag,diag_mdm,serial_smd,serial_tty,serial_hsuart,rmnet_hsuart,mass_storage,adb + ;; + *) + if [ "$debug_config" = "0" ]; then + setprop persist.sys.usb.config mtp + else + setprop persist.sys.usb.config mtp,adb + fi + ;; + esac + ;; + "msm7627a") + setprop persist.sys.usb.config diag,serial_smd,serial_tty,rmnet_smd,mass_storage,adb + ;; + * ) + case "$baseband" in + "svlte2a") + setprop persist.sys.usb.config diag,diag_mdm,serial_sdio,serial_smd,rmnet_smd_sdio,mass_storage,adb + ;; + "csfb") + setprop persist.sys.usb.config diag,diag_mdm,serial_sdio,serial_tty,rmnet_sdio,mass_storage,adb + ;; + *) + setprop persist.sys.usb.config mass_storage,adb + ;; + esac + ;; + esac + ;; + * ) ;; #USB persist config exists, do nothing +esac + +# +# Add support for exposing lun0 as cdrom in mass-storage +# +target=`getprop ro.product.device` +cdromname="/system/etc/cdrom_install.iso" +cdromenable=`getprop persist.service.cdrom.enable` +case "$target" in + "msm7627a" | "msm8625") + case "$cdromenable" in + 0) + echo "" > /sys/class/android_usb/android0/f_mass_storage/lun0/file + ;; + 1) + echo "mounting usbcdrom lun" + echo $cdromname > /sys/class/android_usb/android0/f_mass_storage/lun0/file + ;; + esac + ;; +esac diff --git a/patch_device/aries/root/init.rc b/patch_device/aries/root/init.rc new file mode 100755 index 00000000..4d48d575 --- /dev/null +++ b/patch_device/aries/root/init.rc @@ -0,0 +1,76 @@ +on early-init + start ueventd + +on init + export PATH /sbin + export ANDROID_ROOT /system + export ANDROID_DATA /data + export EXTERNAL_STORAGE /sdcard + + symlink /system/etc /etc + symlink /etc/recovery.fstab /etc/fstab + + mkdir /storage_int + mkdir /sdcard + mkdir /system + mkdir /data + mkdir /cache + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp + + write /sys/class/android_usb/android0/enable 0 + write /sys/class/android_usb/android0/idVendor 18D1 + write /sys/class/android_usb/android0/idProduct 9025 + write /sys/class/android_usb/android0/functions mass_storage,adb + write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer} + write /sys/class/android_usb/android0/iProduct ${ro.product.model} + write /sys/class/android_usb/android0/iSerial ${ro.serialno} + write /sys/module/rpm_resources/enable_low_power/L2_cache 1 + write /sys/module/rpm_resources/enable_low_power/pxo 1 + write /sys/module/rpm_resources/enable_low_power/vdd_dig 2 + write /sys/module/rpm_resources/enable_low_power/vdd_mem 2 + write /sys/module/pm_8x60/modes/cpu0/power_collapse/suspend_enabled 1 + write /sys/module/pm_8x60/modes/cpu0/standalone_power_collapse/suspend_enabled 1 + write /sys/module/pm_8x60/modes/cpu0/power_collapse/idle_enabled 1 + write /sys/module/pm_8x60/modes/cpu0/standalone_power_collapse/idle_enabled 1 + write /sys/module/pm_8x60/modes/cpu1/power_collapse/suspend_enabled 1 + write /sys/module/pm_8x60/modes/cpu2/power_collapse/suspend_enabled 1 + write /sys/module/pm_8x60/modes/cpu3/power_collapse/suspend_enabled 1 + write /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor "userspace" + write /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 1026000 + write /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor "userspace" + write /sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq 1026000 + write /sys/devices/system/cpu/cpu1/online 1 + write /sys/devices/system/cpu/cpu2/online 0 + write /sys/devices/system/cpu/cpu3/online 0 + # Always start adbd on userdebug and eng builds + write /sys/class/android_usb/android0/enable 1 + start adbd + +on boot + + ifup lo + hostname localhost + domainname localdomain + + class_start default + class_start late_start + +service ueventd /sbin/ueventd + critical + +service recovery /sbin/recovery.sh + +service adbd /sbin/adbd recovery + disabled + +service sdcard /sbin/mount_sdcard.sh + class late_start + +# Restart adbd so it can run as root +on property:service.adb.root=1 + write /sys/class/android_usb/android0/enable 0 + restart adbd + write /sys/class/android_usb/android0/enable 1 diff --git a/patch_device/aries/root/res/images/background.png b/patch_device/aries/root/res/images/background.png new file mode 100644 index 00000000..bec01733 Binary files /dev/null and b/patch_device/aries/root/res/images/background.png differ diff --git a/patch_device/aries/root/res/images/battery_charging.png b/patch_device/aries/root/res/images/battery_charging.png new file mode 100644 index 00000000..c7082baf Binary files /dev/null and b/patch_device/aries/root/res/images/battery_charging.png differ diff --git a/patch_device/aries/root/res/images/battery_drained.png b/patch_device/aries/root/res/images/battery_drained.png new file mode 100644 index 00000000..2da999b2 Binary files /dev/null and b/patch_device/aries/root/res/images/battery_drained.png differ diff --git a/patch_device/aries/root/res/images/battery_full.png b/patch_device/aries/root/res/images/battery_full.png new file mode 100644 index 00000000..3c6b81b9 Binary files /dev/null and b/patch_device/aries/root/res/images/battery_full.png differ diff --git a/patch_device/aries/root/res/images/battery_low.png b/patch_device/aries/root/res/images/battery_low.png new file mode 100644 index 00000000..ada62021 Binary files /dev/null and b/patch_device/aries/root/res/images/battery_low.png differ diff --git a/patch_device/aries/root/res/images/battery_normal.png b/patch_device/aries/root/res/images/battery_normal.png new file mode 100644 index 00000000..bf1c4263 Binary files /dev/null and b/patch_device/aries/root/res/images/battery_normal.png differ diff --git a/patch_device/aries/root/res/images/choose_language.png b/patch_device/aries/root/res/images/choose_language.png new file mode 100644 index 00000000..a813e0a1 Binary files /dev/null and b/patch_device/aries/root/res/images/choose_language.png differ diff --git a/patch_device/aries/root/res/images/digit_0.png b/patch_device/aries/root/res/images/digit_0.png new file mode 100644 index 00000000..543b988e Binary files /dev/null and b/patch_device/aries/root/res/images/digit_0.png differ diff --git a/patch_device/aries/root/res/images/digit_1.png b/patch_device/aries/root/res/images/digit_1.png new file mode 100644 index 00000000..0586930a Binary files /dev/null and b/patch_device/aries/root/res/images/digit_1.png differ diff --git a/patch_device/aries/root/res/images/digit_2.png b/patch_device/aries/root/res/images/digit_2.png new file mode 100644 index 00000000..65dcb0e9 Binary files /dev/null and b/patch_device/aries/root/res/images/digit_2.png differ diff --git a/patch_device/aries/root/res/images/digit_3.png b/patch_device/aries/root/res/images/digit_3.png new file mode 100644 index 00000000..3bf91d92 Binary files /dev/null and b/patch_device/aries/root/res/images/digit_3.png differ diff --git a/patch_device/aries/root/res/images/digit_4.png b/patch_device/aries/root/res/images/digit_4.png new file mode 100644 index 00000000..65c586a5 Binary files /dev/null and b/patch_device/aries/root/res/images/digit_4.png differ diff --git a/patch_device/aries/root/res/images/digit_5.png b/patch_device/aries/root/res/images/digit_5.png new file mode 100644 index 00000000..65e3d431 Binary files /dev/null and b/patch_device/aries/root/res/images/digit_5.png differ diff --git a/patch_device/aries/root/res/images/digit_6.png b/patch_device/aries/root/res/images/digit_6.png new file mode 100644 index 00000000..fac104eb Binary files /dev/null and b/patch_device/aries/root/res/images/digit_6.png differ diff --git a/patch_device/aries/root/res/images/digit_7.png b/patch_device/aries/root/res/images/digit_7.png new file mode 100644 index 00000000..ab737094 Binary files /dev/null and b/patch_device/aries/root/res/images/digit_7.png differ diff --git a/patch_device/aries/root/res/images/digit_8.png b/patch_device/aries/root/res/images/digit_8.png new file mode 100644 index 00000000..71573fea Binary files /dev/null and b/patch_device/aries/root/res/images/digit_8.png differ diff --git a/patch_device/aries/root/res/images/digit_9.png b/patch_device/aries/root/res/images/digit_9.png new file mode 100644 index 00000000..644bcefa Binary files /dev/null and b/patch_device/aries/root/res/images/digit_9.png differ diff --git a/patch_device/aries/root/res/images/icon_ok.png b/patch_device/aries/root/res/images/icon_ok.png new file mode 100644 index 00000000..cf9e9f1c Binary files /dev/null and b/patch_device/aries/root/res/images/icon_ok.png differ diff --git a/patch_device/aries/root/res/images/icon_smile.png b/patch_device/aries/root/res/images/icon_smile.png new file mode 100644 index 00000000..1acd568e Binary files /dev/null and b/patch_device/aries/root/res/images/icon_smile.png differ diff --git a/patch_device/aries/root/res/images/icon_usb_connected.png b/patch_device/aries/root/res/images/icon_usb_connected.png new file mode 100644 index 00000000..2de06fb0 Binary files /dev/null and b/patch_device/aries/root/res/images/icon_usb_connected.png differ diff --git a/patch_device/aries/root/res/images/icon_usb_no_connection.png b/patch_device/aries/root/res/images/icon_usb_no_connection.png new file mode 100644 index 00000000..b1d8d329 Binary files /dev/null and b/patch_device/aries/root/res/images/icon_usb_no_connection.png differ diff --git a/patch_device/aries/root/res/images/indeterminate01.png b/patch_device/aries/root/res/images/indeterminate01.png new file mode 100644 index 00000000..5fabc7d0 Binary files /dev/null and b/patch_device/aries/root/res/images/indeterminate01.png differ diff --git a/patch_device/aries/root/res/images/indeterminate02.png b/patch_device/aries/root/res/images/indeterminate02.png new file mode 100644 index 00000000..eb157fc4 Binary files /dev/null and b/patch_device/aries/root/res/images/indeterminate02.png differ diff --git a/patch_device/aries/root/res/images/indeterminate03.png b/patch_device/aries/root/res/images/indeterminate03.png new file mode 100644 index 00000000..77991237 Binary files /dev/null and b/patch_device/aries/root/res/images/indeterminate03.png differ diff --git a/patch_device/aries/root/res/images/indeterminate04.png b/patch_device/aries/root/res/images/indeterminate04.png new file mode 100644 index 00000000..6950f56a Binary files /dev/null and b/patch_device/aries/root/res/images/indeterminate04.png differ diff --git a/patch_device/aries/root/res/images/indeterminate05.png b/patch_device/aries/root/res/images/indeterminate05.png new file mode 100644 index 00000000..37ab7316 Binary files /dev/null and b/patch_device/aries/root/res/images/indeterminate05.png differ diff --git a/patch_device/aries/root/res/images/indeterminate06.png b/patch_device/aries/root/res/images/indeterminate06.png new file mode 100644 index 00000000..84e9a99d Binary files /dev/null and b/patch_device/aries/root/res/images/indeterminate06.png differ diff --git a/patch_device/aries/root/res/images/key_usage_all.png b/patch_device/aries/root/res/images/key_usage_all.png new file mode 100644 index 00000000..f78c9d59 Binary files /dev/null and b/patch_device/aries/root/res/images/key_usage_all.png differ diff --git a/patch_device/aries/root/res/images/lang_ch_normal.png b/patch_device/aries/root/res/images/lang_ch_normal.png new file mode 100644 index 00000000..e0bea7db Binary files /dev/null and b/patch_device/aries/root/res/images/lang_ch_normal.png differ diff --git a/patch_device/aries/root/res/images/lang_ch_selected.png b/patch_device/aries/root/res/images/lang_ch_selected.png new file mode 100644 index 00000000..c9fa4719 Binary files /dev/null and b/patch_device/aries/root/res/images/lang_ch_selected.png differ diff --git a/patch_device/aries/root/res/images/lang_en_normal.png b/patch_device/aries/root/res/images/lang_en_normal.png new file mode 100644 index 00000000..601463bc Binary files /dev/null and b/patch_device/aries/root/res/images/lang_en_normal.png differ diff --git a/patch_device/aries/root/res/images/lang_en_selected.png b/patch_device/aries/root/res/images/lang_en_selected.png new file mode 100644 index 00000000..59b5fd5c Binary files /dev/null and b/patch_device/aries/root/res/images/lang_en_selected.png differ diff --git a/patch_device/aries/root/res/images/logo.png b/patch_device/aries/root/res/images/logo.png new file mode 100644 index 00000000..8d81f548 Binary files /dev/null and b/patch_device/aries/root/res/images/logo.png differ diff --git a/patch_device/aries/root/res/images/percent_symbol.png b/patch_device/aries/root/res/images/percent_symbol.png new file mode 100644 index 00000000..8054927b Binary files /dev/null and b/patch_device/aries/root/res/images/percent_symbol.png differ diff --git a/patch_device/aries/root/res/images/progress_empty.png b/patch_device/aries/root/res/images/progress_empty.png new file mode 100644 index 00000000..a6b6ae21 Binary files /dev/null and b/patch_device/aries/root/res/images/progress_empty.png differ diff --git a/patch_device/aries/root/res/images/progress_fill.png b/patch_device/aries/root/res/images/progress_fill.png new file mode 100644 index 00000000..4d12f508 Binary files /dev/null and b/patch_device/aries/root/res/images/progress_fill.png differ diff --git a/patch_device/aries/root/sbin/adbd b/patch_device/aries/root/sbin/adbd new file mode 100755 index 00000000..dd9f9352 Binary files /dev/null and b/patch_device/aries/root/sbin/adbd differ diff --git a/patch_device/aries/root/sbin/nandroid-md5.sh b/patch_device/aries/root/sbin/nandroid-md5.sh new file mode 100755 index 00000000..03d4a462 --- /dev/null +++ b/patch_device/aries/root/sbin/nandroid-md5.sh @@ -0,0 +1,12 @@ +#!/sbin/sh +cd $1 +rm -f /tmp/nandroid.md5 +md5sum * .* > /tmp/nandroid.md5 +cp /tmp/nandroid.md5 . +# need this because wildcard seems to cause md5sum to return 1 +if [ -f nandroid.md5 ] +then + return 0 +else + return 1 +fi \ No newline at end of file diff --git a/patch_device/aries/root/sbin/offmode_charging b/patch_device/aries/root/sbin/offmode_charging new file mode 100644 index 00000000..59376125 Binary files /dev/null and b/patch_device/aries/root/sbin/offmode_charging differ diff --git a/patch_device/aries/root/sbin/recovery.sh b/patch_device/aries/root/sbin/recovery.sh new file mode 100755 index 00000000..cc45bbc6 --- /dev/null +++ b/patch_device/aries/root/sbin/recovery.sh @@ -0,0 +1,9 @@ +#!/sbin/sh +export PATH=/sbin + +nohup /sbin/stock > /dev/null & +recovery_pid="$!" +sleep 2 +kill -STOP "$recovery_pid" +/sbin/recovery + diff --git a/patch_device/aries/root/sbin/sdparted b/patch_device/aries/root/sbin/sdparted new file mode 100755 index 00000000..74e24a64 --- /dev/null +++ b/patch_device/aries/root/sbin/sdparted @@ -0,0 +1,655 @@ +#!/sbin/sh + +# do logging, if not excluded with -x +LOGFILE="/data/sdparted.log" +[ "$1" != "-x" ] && echo "$0" "$@" >> "$LOGFILE" && "$0" -x "$@" 2>&1 | tee -a "$LOGFILE" && exit +shift + +ShowError() { echo ; echo " err: $1" ; echo ; exit 1 ; } + +ShowMessage() { echo ; echo " msg: $1" ; } + +ShowHelp() { + +cat <. + default=total sdcard size - (ext + swap) + + --extsize|-es SIZE[MG] set the size of the ext partition to . + default=$EXTSIZE + + --swapsize|-ss SIZE[MG] set the size of the swap partition to . + if set to 0, no swap partition will be created. + default=$SWAPSIZE + + --extfs|-efs TYPE set the filesystem of ext partition to . + valid types=ext2, ext3, ext4 + default=$EXTFS + + + --upgradefs|-ufs TYPE upgrades existing ext partition to . + this operation will NOT wipe your sdcard and + cannot be used with any partition creation options. + valid types=ext3, ext4 + + --downgradefs|-dfs TYPE downgrades existing ext partition to . + this operation will NOT wipe your sdcard and + cannot be used with any partition creation options. + valid types=ext2 + + + --interactive|-i interactive mode + + --help|-h display this help + + --printonly|-po display sdcard information + + --silent|-s do not prompt user, not even initial warning. + + +examples: + $SCRIPTNAME creates swap=$SWAPSIZE ext2=$EXTSIZE fat32=remaining free space + $SCRIPTNAME -efs ext4 creates swap=$SWAPSIZE ext4=$EXTSIZE fat32=remaining free space + $SCRIPTNAME -fs 1.5G -efs ext3 creates swap=$SWAPSIZE ext3=$EXTSIZE fat32=1536 + $SCRIPTNAME -es 256M -ss 0 creates no swap ext2=256 fat32=remaining free space + $SCRIPTNAME -ufs ext4 upgrades ext partition to ext4 + +DONEHELP + +} + +UserAbort() { + + WHILEEXIT= + + while [ -z "$WHILEEXIT" ] + do + echo -n "do you want to continue? (Y/n) " + read response + echo + [ "$response" = "Y" ] || [ "$response" = "n" ] || [ "$response" = "N" ] && WHILEEXIT="$response" + done + + echo "$response" > /dev/null 2>&1 >>"$LOGFILE" + + [ "$response" != "Y" ] + +} + +UnmountAll () { + + # unmount all partitions so we can work with $SDPATH + # i'm assuming no more than 3 partitions + # maybe make a little more elegant later + echo -n "unmounting all partitions..." + umount "$FATPATH" > /dev/null 2>&1 >>"$LOGFILE" + umount "$EXTPATH" > /dev/null 2>&1 >>"$LOGFILE" + umount "$SWAPPATH" > /dev/null 2>&1 >>"$LOGFILE" + echo "done" + echo + +} + + +CheckReqs() { + + echo -n "checking script requirements..." + # check for valid sdcard + [ -e $SDPATH ] || ShowError "$SDPATH does not exist!" + + # look for necessary programs + [ -e $CMPARTED ] || ShowError "$CMPARTED does not exist!" + [ -e $CMTUNE2FS ] || ShowError "$CMTUNE2FS does not exist!" + [ -e $CME2FSCK ] || ShowError "$CME2FSCK does not exist!" + + # verify cm-v1.4 + PARTEDREV=`"$CMPARTED" "$SDPATH" version | grep Parted | cut -d" " -f3` + [ "$PARTEDREV" == "1.8.8.1.179-aef3" ] || ShowError "you are not using parted v1.8.8.1.179-aef3!" + echo "done" + echo + +} + +CheckTableType() { + + TABLETYPE=`"$CMPARTED" "$SDPATH" print | grep Table: | cut -d" " -f3` + + [ "$TABLETYPE" == "loop" -o "$TABLETYPE" == "msdos" ] && TTISOK=1 || TTISOK=0 + [ "$TABLETYPE" == "loop" ] && TTISLOOP=1 || TTISLOOP=0 + [ "$TABLETYPE" == "msdos" ] && TTISMSDOS=1 || TTISMOSDOS=0 + +} + +ValidateExtArg() { + + FUNC_RET="nonzero" + + # validating argument + [ "$1" != "ext2" ] && [ "$1" != "ext3" ] && [ "$1" != "ext4" ] && FUNC_RET= + + [ -z "$FUNC_RET" ] && [ -z "$IMODE" ] && ShowError "$1 is not a valid filesystem." + [ -z "$FUNC_RET" ] && [ -n "$IMODE" ] && ShowMessage "$1 is not a valid filesystem." + + # return valid argument + [ -n "$FUNC_RET" ] && FUNC_RET="$1" + +} + +ValidateSizeArg() { + + # check for zero-length arg to protect expr length + [ -z "$1" ] && ShowError "zero-length argument passed to size-validator" + + SIZEMB= + ARGLEN=`expr length $1` + SIZELEN=$(($ARGLEN-1)) + SIZEARG=`expr substr $1 1 $SIZELEN` + SIZEUNIT=`expr substr $1 $ARGLEN 1` + + # check if SIZEARG is an integer + if [ $SIZEARG -eq $SIZEARG 2> /dev/null ] ; then + # look for G + [ "$SIZEUNIT" == "G" ] && SIZEMB=$(($SIZEARG * 1024)) + # look for M + [ "$SIZEUNIT" == "M" ] && SIZEMB=$SIZEARG + # no units on arg AND prevents using bogus size units + [ -z "$SIZEMB" ] && [ $SIZEUNIT -eq $SIZEUNIT 2> /dev/null ] && SIZEMB=$1 + # check if SIZEARG is a floating point number, GB only + elif [ `expr index "$SIZEARG" .` != 0 ] && [ "$SIZEUNIT" == "G" ] ; then + INT=`echo "$SIZEARG" | cut -d"." -f1` + FRAC=`echo "$SIZEARG" | cut -d"." -f2` + SIGDIGITS=`expr length $FRAC` + + [ -z "$INT" ] && INT=0 + INTMB=$(($INT * 1024)) + FRACMB=$((($FRAC * 1024) / (10**$SIGDIGITS))) + SIZEMB=$(($INTMB + $FRACMB)) + # it's not a valid size + else + [ -z "$IMODE" ] && ShowError "$1 is not a valid size" + fi + + [ -z "$SIZEMB" ] && [ -n "$IMODE" ] && ShowMessage "$1 is not a valid size" + + # return valid argument in MB + FUNC_RET=$SIZEMB + +} + +CalculatePartitions() { + + # get size of sdcard in MB & do some math + SDSIZEMB=`"$CMPARTED" "$SDPATH" unit MB print | grep $SDPATH | cut -d" " -f3` + SDSIZE=${SDSIZEMB%MB} + [ -n "$FATSIZE" ] || FATSIZE=$(($SDSIZE - $EXTSIZE - $SWAPSIZE)) + EXTEND=$(($FATSIZE + $EXTSIZE)) + SWAPEND=$(($EXTEND + $SWAPSIZE)) + + # check for fatsize of 0 + [ $FATSIZE -le 0 ] && ShowError "must have a fat32 partition greater than 0MB" + + # check for zero-length sdsize... + # indicative of parted not reporting length + # correctly b/c of error on sdcard + [ -z "$SDSIZE" ] && ShowError "zero-length argument passed to partition-calculator" + + # make sure we're not being asked to do the impossible + [ $(($FATSIZE + $EXTSIZE + $SWAPSIZE)) -gt $SDSIZE ] && [ -z "$IMODE" ] && ShowError "sum of requested partitions is greater than sdcard size" + +} + + +UpgradeDowngradeOnly() { + + if [ -n "$UEXTFSONLY" ] ; then + echo + [ -n "$CREATEPART" ] && ShowError "cannot use upgrade option when creating partitions, use -efs instead" + [ -n "$DEXTFSONLY" ] && ShowError "cannot upgrade AND downgrade, it just doesn't make sense" + echo "you have chosen to upgrade $EXTPATH to $UEXTFSONLY." + echo "this action will NOT delete any data from sdcard." + echo + [ -z "$SILENTRUN" ] && UserAbort && ShowError "script canceled by user" + echo + UpgradeExt "$UEXTFSONLY" + ShowCardInfo + elif [ -n "$DEXTFSONLY" ] ; then + echo + [ -n "$CREATEPART" ] && ShowError "cannot use downgrade option when creating partitions." + [ -n "$UEXTFSONLY" ] && ShowError "cannot downgrade AND upgrade, it just doesn't make sense." + echo "you have chosen to downgrade $EXTPATH to $DEXTFSONLY." + echo "this action will NOT delete any data from sdcard." + echo + [ -z "$SILENTRUN" ] && UserAbort && ShowError "script canceled by user" + echo + DowngradeExt "$DEXTFSONLY" + ShowCardInfo + fi + +} + +PrepareSdCard() { + + echo + if [ $TTISOK -eq 0 ] ; then + echo "partition 1 may not be aligned to cylinder boundaries." + echo "to continue, this must be corrected." + elif [ $TTISLOOP -gt 0 ] ; then + echo "your sdcard's partition table type is $TABLETYPE." + echo "to continue, partition table must be set to 'msdos'." + elif [ $TTISMSDOS -gt 0 ] ; then + # just a reminder..in a later version, + # i may implement resizing of partitions, + # so this will be unnecessary. but until then... + echo "to continue, all existing partitions must be removed." + else + # this is not good, and should never happen + # if it does, there is a serious problem + ShowError "sdcard failed table type check." + fi + + echo + echo "this action will remove all data from your sdcard." + echo + [ -z "$SILENTRUN" ] && UserAbort && ShowError "script canceled by user" + + [ $TTISOK -eq 0 ] && echo -n "correcting cylinder boundaries..." + [ $TTISLOOP -gt 0 ] && echo -n "setting partition table to msdos..." + [ $TTISMSDOS -gt 0 ] && echo -n "removing all partitions..." + + "$CMPARTED" -s "$SDPATH" mklabel msdos 2>&1 >>"$LOGFILE" + echo "done" + echo + +} + +ShowActions() { + + echo + echo "total size of sdcard=$SDSIZEMB" + echo + echo "the following actions will be performed:" + echo " -create $FATSIZE""MB fat32 partition" + [ $EXTSIZE -gt 0 ] && echo " -create $EXTSIZE""MB ext2 partition" + [ $SWAPSIZE -gt 0 ] && echo " -create $SWAPSIZE""MB swap partition" + [ "$EXTFS" != "ext2" ] && echo " -ext2 partition will be upgraded to $EXTFS" + echo + [ -z "$SILENTRUN" ] && UserAbort && ShowError "script canceled by user" + echo + +} + +ShowCardInfo() { + + CheckTableType + + echo + echo "retrieving current sdcard information..." + + if [ $TTISOK -gt 0 ] ; then + echo + parted "$SDPATH" print + echo + echo "script log is located @ /data/sdparted.log" + exit 0 + else + echo + echo "partition 1 may not be aligned to cylinder boundaries." + ShowError "cannot complete print operation." + fi + echo + +} + + +PartitionSdCard() { + + echo "performing selected actions..." + echo + + if [ $FATSIZE -gt 0 ] ; then + echo -n "creating fat32 partition..." + "$CMPARTED" -s "$SDPATH" mkpartfs primary fat32 0 "$FATSIZE"MB 2>&1 >>"$LOGFILE" + echo "done" + fi + + if [ $EXTSIZE -gt 0 ] ; then + echo -n "creating ext2 partition..." + "$CMPARTED" -s "$SDPATH" mkpartfs primary ext2 "$FATSIZE"MB "$EXTEND"MB 2>&1 >>"$LOGFILE" + "$CMTUNE2FS" -L sd-ext "$EXTPATH" 2>&1 >>"$LOGFILE" + echo "done" + fi + + if [ $SWAPSIZE -gt 0 ] ; then + echo -n "creating swap partition..." + "$CMPARTED" -s "$SDPATH" mkpartfs primary linux-swap "$EXTEND"MB "$SWAPEND"MB 2>&1 >>"$LOGFILE" + echo "done" + fi + echo + +} + +UpgradeExt() { + + # check for no upgrade + [ "$1" == "ext2" ] && return + # check for ext partition + [ ! -e "$EXTPATH" ] && ShowError "$EXTPATH does not exist" + + # have to use -m switch for this check b/c parted incorrectly + # reports all ext partitions as ext2 when running print + CHECKEXTFS=`"$CMPARTED" -m "$SDPATH" print | grep ext | cut -d":" -f5` + [ "$CHECKEXTFS" == "$1" ] && ShowError "$EXTPATH is already $1" + + # grabbed the code bits for ext3 from upgrade_fs(credit:cyanogen) + # check for ext2...must upgrade to ext3 first b4 ext4 + if [ "$1" == "ext3" -o "$1" == "ext4" ] ; then + echo -n "adding journaling to $EXTPATH..." + umount /system/sd > /dev/null 2>&1 >>"$LOGFILE" + "$CME2FSCK" -p "$EXTPATH" 2>&1 >>"$LOGFILE" + "$CMTUNE2FS" -c0 -i0 -j "$EXTPATH" 2>&1 >>"$LOGFILE" + echo "done" + fi + + # and got convert to ext4 from xda-forum(credit:Denkai) + if [ "$1" == "ext4" ] ; then + echo -n "converting $EXTPATH to ext4 filesystem..." + umount /system/sd > /dev/null 2>&1 >>"$LOGFILE" + "$CMTUNE2FS" -O extents,uninit_bg,dir_index "$EXTPATH" 2>&1 >>"$LOGFILE" + "$CME2FSCK" -fpDC0 "$EXTPATH" 2>&1 >>"$LOGFILE" + echo "done" + fi + echo + +} + +DowngradeExt() { + + # check for ext partition + [ ! -e "$EXTPATH" ] && ShowError "$EXTPATH does not exist" + + # have to use print for this check b/c parted incorrectly + # reports all ext partitions as ext2 when running print + CHECKEXTFS=`"$CMPARTED" -m "$SDPATH" print | grep ext | cut -d":" -f5` + [ "$CHECKEXTFS" == "$1" ] && ShowError "$EXTPATH is already $1" + + if [ "$CHECKEXTFS" == "ext4" -o "$1" == "ext3" ] ; then + # interweb says downgrading from ext4 is not possible + # without a backup/restore procedure. + # if i figure it out, i'll implement it. + ShowError "downgrading from ext4 is not currently supported" + fi + + if [ "$1" == "ext2" ] ; then + echo -n "removing journaling from $EXTPATH..." + umount /system/sd > /dev/null 2>&1 >>"$LOGFILE" + "$CMTUNE2FS" -O ^has_journal "$EXTPATH" 2>&1 >>"$LOGFILE" + "$CME2FSCK" -fp "$EXTPATH" 2>&1 >>"$LOGFILE" + echo "done" + fi + echo + +} + + +Interactive() { + +cat < /dev/null 2>&1 >>"$LOGFILE" + + ValidateSizeArg "$SWAPRESP" + SWAPTEST="$FUNC_RET" + [ -n "$SWAPTEST" ] && [ $SWAPTEST -gt $SDSIZE ] && ShowMessage "$SWAPRESP > available space($(($SDSIZE))M)." && SWAPTEST= + done + + SWAPSIZE=$SWAPTEST + +} + +GetExtSize() { + + EXTTEST= + + while [ -z "$EXTTEST" ] + do + echo + echo -n "ext partition size [default=$EXTSIZE]: " + read EXTRESP + + [ -z "$EXTRESP" ] && EXTRESP="$EXTSIZE" + echo "$EXTRESP" > /dev/null 2>&1 >>"$LOGFILE" + + ValidateSizeArg "$EXTRESP" + EXTTEST="$FUNC_RET" + + [ -n "$EXTTEST" ] && [ $EXTTEST -gt $(($SDSIZE - $SWAPSIZE)) ] && ShowMessage "$EXTRESP > available space($(($SDSIZE - $SWAPSIZE))M)." && EXTTEST= + done + + EXTSIZE=$EXTTEST + +} + +GetExtType() { + + FSTEST= + + while [ -z "$FSTEST" ] + do + echo + echo -n "ext partition type [default=$EXTFS]: " + read FSRESP + + [ -z "$FSRESP" ] && FSRESP="$EXTFS" + echo "$FSRESP" > /dev/null 2>&1 >>"$LOGFILE" + + ValidateExtArg "$FSRESP" + FSTEST="$FUNC_RET" + done + + EXTFS="$FSTEST" + +} + +GetFatSize() { + + FATTEST= + + while [ -z "$FATTEST" ] + do + echo + echo -n "fat partition size [default=$FATSIZE]: " + read FATRESP + + [ -z "$FATRESP" ] && FATRESP="$FATSIZE" + echo "$FATRESP" > /dev/null 2>&1 >>"$LOGFILE" + + ValidateSizeArg "$FATRESP" + FATTEST="$FUNC_RET" + + [ -n "$FATTEST" ] && [ $FATTEST -gt $FATSIZE ] && ShowMessage "$FATRESP > available space($(($SDSIZE - $SWAPSIZE - $EXTSIZE))M)." && FATTEST= + [ -n "$FATTEST" ] && [ $FATTEST -le 0 ] && ShowMessage "must have a fat32 partition greater than 0MB" && FATTEST= + done + + FATSIZE=$FATTEST + +} + + +SCRIPTNAME="sdparted" +SCRIPTREV="0.6" +MYNAME="51dusty" + +IMODE= +SILENTRUN= +CREATEPART= +FUNC_RET= + +UEXTFSONLY= +DEXTFSONLY= + +TTISOK= +TTISLOOP= +TTISMSDOS= + +SDSIZE= +SDSIZEMB= +SDINFO=$(cat /etc/fstab | grep /sdcard | awk '{print $1}') +if [ -L "$SDINFO" ] +then + SDPATH=$(ls -l $SDINFO | awk '{print $11}') +else + SDPATH=$SDINFO +fi +# we may now have an SDPATH, let's make sure its on mmcblkX or mmcblkXp1 +CHECK_SDPATH1=$(echo $SDPATH | grep mmcblk.$) +CHECK_SDPATH2=$(echo $SDPATH | grep mmcblk.p1$) +if [ -z "$CHECK_SDPATH1" ] +then + if [ -z "$CHECK_SDPATH2" ] + then + echo fail1 + unset SDPATH + else + LEN=${#SDPATH} + BLKLEN=$(expr $LEN - 2) + SDPATH=${SDPATH:0:$BLKLEN} + fi +fi + + +FATSIZE= +FATTYPE="fat32" +FATPATH=$SDPATH"p1" + +EXTSIZE=512 +EXTFS="ext2" +EXTPATH=$SDPATH"p2" +EXTEND= + +SWAPSIZE=32 +SWAPTYPE="linux-swap" +SWAPPATH=$SDPATH"p3" +SWAPEND= + +CMPARTED="/sbin/parted" +CMTUNE2FS="/sbin/tune2fs" +CME2FSCK="/sbin/e2fsck" + +# give the output some breathing room +echo "$SCRIPTREV" >> "$LOGFILE" +echo + +# check for arguments +while [ $# -gt 0 ] ; do + case "$1" in + + -h|--help) ShowHelp ; exit 0 ;; + + -fs|--fatsize) shift ; ValidateSizeArg "$1" ; FATSIZE="$FUNC_RET" ; CREATEPART="$1" ;; + -es|--extsize) shift ; ValidateSizeArg "$1" ; EXTSIZE="$FUNC_RET" ; CREATEPART="$1" ;; + -ss|--swapsize) shift ; ValidateSizeArg "$1" ; SWAPSIZE="$FUNC_RET" ; CREATEPART="$1" ;; + -efs|--extfs) shift ; ValidateExtArg "$1" ; EXTFS="$FUNC_RET" ; CREATEPART="$1" ;; + + -ufs|--upgradefs) shift ; ValidateExtArg "$1" ; UEXTFSONLY="$FUNC_RET" ;; + -dfs|--downgradefs) shift ; ValidateExtArg "$1" ; DEXTFSONLY="$FUNC_RET" ;; + + -i|--interactive) IMODE="$1" ;; + + -s|--silent) SILENTRUN="$1" ;; + + -po|--printonly) ShowCardInfo ;; + + *) ShowHelp ; ShowError "unknown argument '$1'" ;; + + esac + shift +done + +# can't do silent when in interactive mode +[ -n "$IMODE" ] && SILENTRUN= + +# make sure sdcard exists and all needed files are here +CheckReqs + +# unmount all +UnmountAll + +# upgrade only? downgrade only? +UpgradeDowngradeOnly + +# check table +CheckTableType + +# prep card +PrepareSdCard + +# check for interactive mode +[ -n "$IMODE" ] && Interactive + +# do some math +CalculatePartitions + +# last chance to cancel +ShowActions + +# partition card +PartitionSdCard + +# upgrade fs if necessary +UpgradeExt "$EXTFS" + +# say goodbye and show print output +ShowCardInfo diff --git a/patch_device/aries/root/sbin/stock b/patch_device/aries/root/sbin/stock new file mode 100755 index 00000000..dd64a7bc Binary files /dev/null and b/patch_device/aries/root/sbin/stock differ diff --git a/patch_device/aries/root/sbin/tune2fs b/patch_device/aries/root/sbin/tune2fs new file mode 100755 index 00000000..279f460f Binary files /dev/null and b/patch_device/aries/root/sbin/tune2fs differ diff --git a/patch_device/aries/root/ueventd.goldfish.rc b/patch_device/aries/root/ueventd.goldfish.rc new file mode 100644 index 00000000..8de70496 --- /dev/null +++ b/patch_device/aries/root/ueventd.goldfish.rc @@ -0,0 +1,5 @@ +# These settings are specific to running under the Android emulator +/dev/qemu_trace 0666 system system +/dev/qemu_pipe 0666 system system +/dev/ttyS* 0666 system system +/proc 0666 system system diff --git a/patch_device/aries/root/ueventd.qcom.rc b/patch_device/aries/root/ueventd.qcom.rc new file mode 100644 index 00000000..88eb27e5 --- /dev/null +++ b/patch_device/aries/root/ueventd.qcom.rc @@ -0,0 +1,100 @@ +# Copyright (c) 2012, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Code Aurora nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# the DIAG device node is not world writable/readable. +/dev/diag 0660 system qcom_diag + +/dev/genlock 0666 system system +/dev/kgsl 0666 system system +/dev/kgsl-3d0 0666 system system +/dev/kgsl-2d0 0666 root root +/dev/kgsl-2d1 0666 root root +/dev/ion 0664 system system +/dev/rtc0 0600 system system +/dev/smd0 0660 system system +/dev/smd4 0660 system system +/dev/smd7 0660 bluetooth bluetooth +/dev/rfcomm0 0660 bluetooth bluetooth +/dev/smdcntl0 0640 radio radio +/dev/smdcntl1 0640 radio radio +/dev/smdcntl2 0640 radio radio +/dev/smdcntl3 0640 radio radio +/dev/smdcntl4 0640 radio radio +/dev/smdcntl5 0640 radio radio +/dev/smdcntl6 0640 radio radio +/dev/smdcntl7 0640 radio radio +/dev/smuxctl32 0640 radio radio +/dev/sdioctl0 0640 radio radio +/dev/sdioctl1 0640 radio radio +/dev/sdioctl2 0640 radio radio +/dev/sdioctl3 0640 radio radio +/dev/sdioctl4 0640 radio radio +/dev/sdioctl5 0640 radio radio +/dev/sdioctl6 0640 radio radio +/dev/sdioctl7 0640 radio radio +/dev/sdioctl8 0640 radio radio +/dev/rmnet_mux_ctrl 0640 radio radio +/dev/hsicctl0 0640 radio radio +/dev/hsicctl1 0640 radio radio +/dev/hsicctl2 0640 radio radio +/dev/hsicctl3 0640 radio radio +/dev/video* 0660 system camera +/dev/media* 0660 system camera +/dev/v4l-subdev* 0660 system camera +/dev/gemini0 0660 system camera +/dev/msm_camera/* 0660 system camera +/dev/gemini/ 0660 system camera +/dev/msm_vidc_reg 0660 system audio +/dev/msm_vidc_dec 0660 system audio +/dev/msm_vidc_dec_sec 0660 system audio +/dev/msm_vidc_enc 0660 system audio +/dev/msm_rotator 0664 system system +/dev/hw_random 0660 system system + +#permissions for audio +/dev/msm_qcelp 0660 system audio +/dev/msm_evrc 0660 system audio +/dev/msm_wma 0660 system audio +/dev/msm_wmapro 0660 system audio +/dev/msm_amrnb 0660 system audio +/dev/msm_amrwb 0660 system audio +/dev/msm_aac 0660 system audio +/dev/msm_multi_aac 0660 system audio +/dev/msm_aac_in 0660 system audio +/dev/msm_qcelp_in 0660 system audio +/dev/msm_evrc_in 0660 system audio +/dev/msm_amrnb_in 0640 system audio +/dev/smd3 0660 bluetooth bluetooth +/dev/smd2 0660 bluetooth bluetooth +/dev/ttyHSL1 0660 system system +/dev/mdm 0660 system system +/sys/devices/virtual/smdpkt/smdcntl* open_timeout 0664 radio radio +/dev/sdio_tty_ciq_00 0660 system system +/dev/tty_sdio_00 0660 system system +/dev/ttyGS0 0660 system system +/dev/i2c-5 0660 media media +/dev/hw_random 0640 root system diff --git a/patch_device/aries/root/ueventd.rc b/patch_device/aries/root/ueventd.rc new file mode 100644 index 00000000..cee3e73e --- /dev/null +++ b/patch_device/aries/root/ueventd.rc @@ -0,0 +1,113 @@ +/dev/null 0666 root root +/dev/zero 0666 root root +/dev/full 0666 root root +/dev/ptmx 0666 root root +/dev/tty 0666 root root +/dev/random 0666 root root +/dev/urandom 0666 root root +/dev/ashmem 0666 root root +/dev/binder 0666 root root + +# Anyone can read the logs, but if they're not in the "logs" +# group, then they'll only see log entries for their UID. +/dev/log/* 0666 root log + +# the msm hw3d client device node is world writable/readable. +/dev/msm_hw3dc 0666 root root + +# the DIAG device node is not world writable/readable. +/dev/diag 0660 system qcom_diag + +# gpu driver for adreno200 is globally accessible +/dev/kgsl 0666 root root + +# kms driver for drm based gpu +/dev/dri/* 0666 root graphics + +# these should not be world writable +/dev/diag_arm9 0660 radio radio +/dev/android_adb 0660 adb adb +/dev/android_adb_enable 0660 adb adb +/dev/ttyMSM0 0600 bluetooth bluetooth +/dev/uhid 0660 system net_bt_stack +/dev/uinput 0660 system net_bt_stack +/dev/alarm 0664 system radio +/dev/tty0 0660 root system +/dev/graphics/* 0660 root graphics +/dev/msm_hw3dm 0660 system graphics +/dev/input/* 0660 root input +/dev/eac 0660 root audio +/dev/cam 0660 root camera +/dev/pmem 0660 system graphics +/dev/pmem_adsp* 0660 system audio +/dev/pmem_camera* 0660 system camera +/dev/oncrpc/* 0660 root system +/dev/adsp/* 0660 system audio +/dev/snd/* 0660 system audio +/dev/mt9t013 0660 system system +/dev/msm_camera/* 0660 system camera +/dev/akm8976_daemon 0640 compass system +/dev/akm8976_aot 0640 compass system +/dev/akm8973_daemon 0640 compass system +/dev/akm8973_aot 0640 compass system +/dev/bma150 0640 compass system +/dev/cm3602 0640 compass system +/dev/akm8976_pffd 0640 compass system +/dev/lightsensor 0640 system system +/dev/msm_pcm_out* 0660 system audio +/dev/msm_pcm_in* 0660 system audio +/dev/msm_pcm_ctl* 0660 system audio +/dev/msm_snd* 0660 system audio +/dev/msm_mp3* 0660 system audio +/dev/audience_a1026* 0660 system audio +/dev/tpa2018d1* 0660 system audio +/dev/msm_audpre 0660 system audio +/dev/msm_audio_ctl 0660 system audio +/dev/htc-acoustic 0660 system audio +/dev/vdec 0660 system audio +/dev/q6venc 0660 system audio +/dev/snd/dsp 0660 system audio +/dev/snd/dsp1 0660 system audio +/dev/snd/mixer 0660 system audio +/dev/smd0 0640 radio radio +/dev/qmi 0640 radio radio +/dev/qmi0 0640 radio radio +/dev/qmi1 0640 radio radio +/dev/qmi2 0640 radio radio +/dev/bus/usb/* 0660 root usb +/dev/mtp_usb 0660 root mtp +/dev/usb_accessory 0660 root usb +/dev/tun 0660 system vpn + +# CDMA radio interface MUX +/dev/ts0710mux* 0640 radio radio +/dev/ppp 0660 radio vpn + +# sysfs properties +/sys/devices/virtual/input/input* enable 0660 root input +/sys/devices/virtual/input/input* poll_delay 0660 root input +/sys/devices/virtual/usb_composite/* enable 0664 root system + +/sys/devices/system/cpu/cpufreq ondemand/boostfreq 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/boostpulse 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/boosttime 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/sampling_rate 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/io_is_busy 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/down_differential 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/powersave_bias 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/sampling_down_factor 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/up_threshold 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/up_threshold_multi_core 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/down_differential_multi_core 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/optimal_freq 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/sync_freq 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/up_threshold_any_cpu_load 0664 system system + +/sys/devices/system/cpu/cpufreq interactive/boostpulse 0664 system system +/sys/devices/system/cpu/cpufreq interactive/timer_rate 0664 system system +/sys/devices/system/cpu/cpufreq interactive/min_sample_rate 0664 system system +/sys/devices/system/cpu/cpufreq interactive/min_sample_time 0664 system system +/sys/devices/system/cpu/cpufreq interactive/hispeed_freq 0664 system system +/sys/devices/system/cpu/cpufreq interactive/go_hispeed_load 0664 system system +/sys/devices/system/cpu/cpufreq interactive/above_hispeed_delay 0664 system system +/sys/devices/system/cpu/cpufreq interactive/io_is_busy 0664 system system diff --git a/patch_device/crespo/root/init.rc b/patch_device/crespo/root/init.rc index 554d4e63..d93fbc83 100644 --- a/patch_device/crespo/root/init.rc +++ b/patch_device/crespo/root/init.rc @@ -13,7 +13,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/ef39s/device.conf b/patch_device/ef39s/device.conf index 9c5d6c62..5186f65b 100755 --- a/patch_device/ef39s/device.conf +++ b/patch_device/ef39s/device.conf @@ -1,6 +1,5 @@ ini_set("rom_device", "A800S"); ini_set("rom_name", "MIUI Recovery for A800S"); -ini_set("rom_version", "2.04"); ini_set("rom_author", "syhost"); ini_set("rom_date", "2012-12-02"); diff --git a/patch_device/ef39s/root/init.rc b/patch_device/ef39s/root/init.rc index 554d4e63..d93fbc83 100755 --- a/patch_device/ef39s/root/init.rc +++ b/patch_device/ef39s/root/init.rc @@ -13,7 +13,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/ef40s/device.conf b/patch_device/ef40s/device.conf index 64f3ab7b..e4667682 100755 --- a/patch_device/ef40s/device.conf +++ b/patch_device/ef40s/device.conf @@ -1,6 +1,5 @@ ini_set("rom_device", "A810S"); ini_set("rom_name", "MIUI Recovery for A810S"); -ini_set("rom_version", "2.04"); ini_set("rom_author", "syhost"); ini_set("rom_date", "2012-12-02"); diff --git a/patch_device/ef40s/root/init.rc b/patch_device/ef40s/root/init.rc index 554d4e63..d93fbc83 100755 --- a/patch_device/ef40s/root/init.rc +++ b/patch_device/ef40s/root/init.rc @@ -13,7 +13,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/ef65l/device.conf b/patch_device/ef65l/device.conf index 77d883b9..e26f17a6 100755 --- a/patch_device/ef65l/device.conf +++ b/patch_device/ef65l/device.conf @@ -1,6 +1,5 @@ ini_set("rom_device", "A820L"); ini_set("rom_name", "MIUI Recovery for A820L"); -ini_set("rom_version", "2.04"); ini_set("rom_author", "syhost"); ini_set("rom_date", "2012-12-02"); diff --git a/patch_device/ef65l/root/init.rc b/patch_device/ef65l/root/init.rc index 554d4e63..d93fbc83 100755 --- a/patch_device/ef65l/root/init.rc +++ b/patch_device/ef65l/root/init.rc @@ -13,7 +13,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/finder/root/init.rc b/patch_device/finder/root/init.rc index 074f6f51..95b1f6b5 100755 --- a/patch_device/finder/root/init.rc +++ b/patch_device/finder/root/init.rc @@ -14,7 +14,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/honor/root/init.rc b/patch_device/honor/root/init.rc index 3da57fd0..b3352afb 100755 --- a/patch_device/honor/root/init.rc +++ b/patch_device/honor/root/init.rc @@ -18,7 +18,10 @@ on init mkdir /system mkdir /sdcard - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/hwU9200/root/init.rc b/patch_device/hwU9200/root/init.rc index a88cdec4..6a095439 100755 --- a/patch_device/hwU9200/root/init.rc +++ b/patch_device/hwU9200/root/init.rc @@ -12,7 +12,10 @@ on init mkdir /data mkdir /cache mkdir /cust - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp setprop ro.hwboottype boot_recovery diff --git a/patch_device/hwU9500/root/init.rc b/patch_device/hwU9500/root/init.rc index ce0aba70..6764d1b8 100755 --- a/patch_device/hwU9500/root/init.rc +++ b/patch_device/hwU9500/root/init.rc @@ -18,7 +18,10 @@ on init mkdir /data mkdir /cache mkdir /cust - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp setprop ro.hwboottype boot_recovery diff --git a/patch_device/lu6200/root/init.rc b/patch_device/lu6200/root/init.rc index 832b8640..f02efefc 100755 --- a/patch_device/lu6200/root/init.rc +++ b/patch_device/lu6200/root/init.rc @@ -17,7 +17,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/maguro/root/init.rc b/patch_device/maguro/root/init.rc index 554d4e63..d93fbc83 100644 --- a/patch_device/maguro/root/init.rc +++ b/patch_device/maguro/root/init.rc @@ -13,7 +13,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/mione_plus/Android.mk b/patch_device/mione_plus/Android.mk new file mode 100644 index 00000000..4f18bb7a --- /dev/null +++ b/patch_device/mione_plus/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH := $(call my-dir) +include $(MIUI_CLEAR) +MIUI_PRODUCT := mione_plus +MIUI_KERNEL := $(LOCAL_PATH)/kernel + +MIUI_KERNEL_BASE := 0x40200000 --ramdiskaddr 0x41400000 +MIUI_KERNEL_CMDLINE := console=ttyHSL0,115200,n8 androidboot.hardware=qcom kgsl.mmutype=gpummu vmalloc=400M +MIUI_KERNEL_PAGESIZE := 2048 + +MIUI_PRODUCT_ROOT := $(LOCAL_PATH)/root +MIUI_DEVICE_CONFIG := $(LOCAL_PATH)/device.conf + +#TARGET_USE_PIXEL_FORMAT_BGR565 := true +BOARD_HAS_DUALSYSTEM_PARTITIONS := true +TARGET_NEEDS_VSYNC := true +include $(MIUI_RECOVERY) diff --git a/patch_device/mione_plus/device.conf b/patch_device/mione_plus/device.conf new file mode 100644 index 00000000..20b3fb40 --- /dev/null +++ b/patch_device/mione_plus/device.conf @@ -0,0 +1,3 @@ +ini_set("rom_device", "MI-ONE Plus"); +ini_set("rom_date", "2013-07"); +ini_set("lun_file", "/sys/devices/virtual/android_usb/android0/f_mass_storage/lun/file"); diff --git a/patch_device/mione_plus/kernel b/patch_device/mione_plus/kernel new file mode 100644 index 00000000..08ef11e7 Binary files /dev/null and b/patch_device/mione_plus/kernel differ diff --git a/patch_device/mione_plus/root/default.prop b/patch_device/mione_plus/root/default.prop new file mode 100644 index 00000000..c24bb865 --- /dev/null +++ b/patch_device/mione_plus/root/default.prop @@ -0,0 +1,155 @@ +# +# ADDITIONAL_DEFAULT_PROPERTIES +# + +ro.secure=0 +ro.allow.mock.location=0 +ro.debuggable=1 +persist.sys.usb.config=adb +# begin build properties +# autogenerated by buildinfo.sh +ro.build.id=JDQ39E +ro.build.display.id=JDQ39E +ro.build.version.incremental=JDQ39E +ro.build.version.sdk=17 +ro.build.version.codename=REL +ro.build.version.release=4.2.2 +ro.build.date=2013年 07月 26日 星期五 12:13:55 CST +ro.build.date.utc=0 +ro.build.type=userdebug +ro.build.user=peter +ro.build.host=petercxy +ro.build.tags=test-keys +ro.product.model=MI-ONE Plus +ro.product.brand=Xiaomi +ro.product.name=mione_plus +ro.product.device=mione_plus +ro.product.board=mione +ro.product.cpu.abi=armeabi-v7a +ro.product.cpu.abi2=armeabi +ro.product.manufacturer=Xiaomi +ro.product.locale.language=zh +ro.product.locale.region=CN +ro.wifi.channels= +ro.board.platform=msm8660 +# ro.build.product is obsolete; use ro.product.device +ro.build.product=mione_plus +# Do not try to parse ro.build.description or .fingerprint +ro.build.description=mione_plus-userdebug 4.1.2 JZO54K QDS84 test-keys +ro.build.fingerprint=Xiaomi/mione_plus/mione_plus:4.1.2/JZO54K/QDS84:userdebug/test-keys +ro.build.characteristics=phone +ro.mk.device=mione_plus +# end build properties +# +# system.prop for mione +# + +# Default network type +# 7 => Global +ro.telephony.default_network=7 +ro.cdma.home.operator.numeric=46003 +ro.cdma.factory=china + +# Ril +ro.ril.oem.nosim.ecclist=911,112,120,122,110,119 +persist.radio.apm_sim_not_pwdn=1 +rild.libpath=/system/lib/libril-qc-qmi-1.so +rild.libargs=-d /dev/smd0 +persist.rild.nitz_plmn= +persist.rild.nitz_long_ons_0= +persist.rild.nitz_long_ons_1= +persist.rild.nitz_long_ons_2= +persist.rild.nitz_long_ons_3= +persist.rild.nitz_short_ons_0= +persist.rild.nitz_short_ons_1= +persist.rild.nitz_short_ons_2= +persist.rild.nitz_short_ons_3= +ril.subscription.types=NV,RUIM +telephony.lteOnCdmaDevice=0 +DEVICE_PROVISIONED=1 +ro.vendor.extension_library=/system/lib/libqc-opt.so + +# Graphics +debug.sf.hw=1 +debug.composition.type=dyn +debug.enabletr=true +ro.sf.compbypass.enable=1 +ro.sf.lcd_density=240 +dev.pm.dyn_samplingrate=1 +ro.hdmi.enable=false + +# +# system props for the data modules +# +ro.use_data_netmgrd=true + +# +# system prop for opengles version +# +# 131072 is decimal for 0x20000 to report version 2 +ro.opengles.version=131072 + +# +# system prop for multi ring +# +ro.telephony.call_ring.multiple=false + +# +# system prop for requesting Master role in incoming Bluetooth connection. +# +ro.bluetooth.request.master=true + +# System property for cabl +ro.qualcomm.cabl=0 + +# +# System prop for sending transmit power request to RIL during WiFi hotspot on/off +# +#ro.ril.transmitpower=true + +# system property for thermald +persist.thermal.monitor=true + +# Misc. +persist.timed.enable=true + +# start adb as root on boot +service.adb.root=1 + +#mass_storage +ro.vold.umsdirtyratio=50 + +# +# ADDITIONAL_BUILD_PROPERTIES +# +keyguard.no_require_sim=true +ro.url.legal=http://www.google.com/intl/%s/mobile/android/basic/phone-legal.html +ro.url.legal.android_privacy=http://www.google.com/intl/%s/mobile/android/basic/privacy.html +ro.com.google.clientidbase=android-google +ro.com.android.wifi-watchlist=GoogleGuest +ro.setupwizard.enterprise_mode=1 +ro.com.android.dateformat=MM-dd-yyyy +ro.com.android.dataroaming=false +ro.mk.support=bbs.mfunz.com +ro.mk.version=MK42.2.RC4-mione_plus-201307261213-UNOFFICIAL +ro.modversion=MK42.2.RC4-mione_plus-201307261213-UNOFFICIAL +ro.config.ringtone=Ring_Digital_02.ogg +ro.config.notification_sound=F1_New_SMS.ogg +ro.config.alarm_alert=Alarm_Beep_03.ogg +ro.carrier=unknown +com.qc.hardware=true +debug.egl.hw=1 +debug.mdpcomp.logs=0 +debug.sf.hw=1 +dev.pm.dyn_samplingrate=1 +ro.opengles.version=131072 +dalvik.vm.dexopt-flags=m=y +dalvik.vm.heapstartsize=8m +dalvik.vm.heapgrowthlimit=64m +dalvik.vm.heapsize=256m +dalvik.vm.heaptargetutilization=0.75 +dalvik.vm.heapminfree=2m +dalvik.vm.heapmaxfree=8m +dalvik.vm.lockprof.threshold=500 +net.bt.name=Android +dalvik.vm.stack-trace-file=/data/anr/traces.txt diff --git a/patch_device/mione_plus/root/etc/recovery.fstab b/patch_device/mione_plus/root/etc/recovery.fstab new file mode 100644 index 00000000..bd3ff05a --- /dev/null +++ b/patch_device/mione_plus/root/etc/recovery.fstab @@ -0,0 +1,47 @@ +# Copyright (c) 2011, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Code Aurora Forum, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# mount point fstype device [device2] + +/boot emmc /dev/block/platform/msm_sdcc.1/by-name/boot +/boot1 emmc /dev/block/platform/msm_sdcc.1/by-name/boot1 +/cache ext4 /dev/block/platform/msm_sdcc.1/by-name/cache +/data ext4 /dev/block/platform/msm_sdcc.1/by-name/userdata +/misc emmc /dev/block/platform/msm_sdcc.1/by-name/misc +/recovery emmc /dev/block/platform/msm_sdcc.1/by-name/recovery +/sdcard vfat /dev/block/mmcblk1p1 /dev/block/mmcblk1 +/system ext4 /dev/block/platform/msm_sdcc.1/by-name/system +/system1 ext4 /dev/block/platform/msm_sdcc.1/by-name/system1 +/radio emmc /dev/block/platform/msm_sdcc.1/by-name/modem +/radio1 emmc /dev/block/platform/msm_sdcc.1/by-name/modem +/sbl1 emmc /dev/block/platform/msm_sdcc.1/by-name/sbl1 +/sbl2 emmc /dev/block/platform/msm_sdcc.1/by-name/sbl2 +/sbl3 emmc /dev/block/platform/msm_sdcc.1/by-name/sbl3 +/tz emmc /dev/block/platform/msm_sdcc.1/by-name/tz +/rpm emmc /dev/block/platform/msm_sdcc.1/by-name/rpm +/aboot emmc /dev/block/platform/msm_sdcc.1/by-name/aboot + diff --git a/patch_device/mione_plus/root/init b/patch_device/mione_plus/root/init new file mode 100755 index 00000000..9f8bece4 Binary files /dev/null and b/patch_device/mione_plus/root/init differ diff --git a/patch_device/mione_plus/root/init.qcom.class_core.sh b/patch_device/mione_plus/root/init.qcom.class_core.sh new file mode 100755 index 00000000..eaed5c87 --- /dev/null +++ b/patch_device/mione_plus/root/init.qcom.class_core.sh @@ -0,0 +1,259 @@ +#!/system/bin/sh +# Copyright (c) 2012, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Code Aurora nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# Set platform variables +target=`getprop ro.board.platform` +soc_hwplatform=`cat /sys/devices/system/soc/soc0/hw_platform` 2> /dev/null +soc_hwid=`cat /sys/devices/system/soc/soc0/id` 2> /dev/null +soc_hwver=`cat /sys/devices/system/soc/soc0/platform_version` 2> /dev/null + + +# Dynamic Memory Managment (DMM) provides a sys file system to the userspace +# that can be used to plug in/out memory that has been configured as unstable. +# This unstable memory can be in Active or In-Active State. +# Each of which the userspace can request by writing to a sys file. +# +# ro.dev.dmm = 1; Indicates that DMM is enabled in the Android User Space. This +# property is set in the Android system properties file. +# +# If ro.dev.dmm.dpd.start_address is set here then the target has a memory +# configuration that supports DynamicMemoryManagement. +init_DMM() +{ + block=-1 + + case "$target" in + "msm7630_surf" | "msm7630_1x" | "msm7630_fusion" | "msm8960") + ;; + *) + return + ;; + esac + + mem="/sys/devices/system/memory" + op=`cat $mem/movable_start_bytes` + case "$op" in + "0") + log -p i -t DMM DMM Disabled. movable_start_bytes not set: $op + ;; + + "$mem/movable_start_bytes: No such file or directory ") + log -p i -t DMM DMM Disabled. movable_start_bytes does not exist: $op + ;; + + *) + log -p i -t DMM DMM available. movable_start_bytes at $op + movable_start_bytes=0x`cat $mem/movable_start_bytes` + block_size_bytes=0x`cat $mem/block_size_bytes` + block=$((#${movable_start_bytes}/${block_size_bytes})) + + chown system.system $mem/memory$block/state + chown system.system $mem/probe + chown system.system $mem/active + chown system.system $mem/remove + + case "$target" in + "msm7630_surf" | "msm7630_1x" | "msm7630_fusion") + echo $movable_start_bytes > $mem/probe + case "$?" in + "0") + log -p i -t DMM $movable_start_bytes to physical hotplug succeeded. + ;; + *) + log -p e -t DMM $movable_start_bytes to physical hotplug failed. + return + ;; + esac + + echo online > $mem/memory$block/state + case "$?" in + "0") + log -p i -t DMM \'echo online\' to logical hotplug succeeded. + ;; + *) + log -p e -t DMM \'echo online\' to logical hotplug failed. + return + ;; + esac + ;; + esac + + setprop ro.dev.dmm.dpd.start_address $movable_start_bytes + setprop ro.dev.dmm.dpd.block $block + ;; + esac + + case "$target" in + "msm8960") + return + ;; + esac + + # For 7X30 targets: + # ro.dev.dmm.dpd.start_address is set when the target has a 2x256Mb memory + # configuration. This is also used to indicate that the target is capable of + # setting EBI-1 to Deep Power Down or Self Refresh. + op=`cat $mem/low_power_memory_start_bytes` + case "$op" in + "0") + log -p i -t DMM Self-Refresh-Only Disabled. low_power_memory_start_bytes not set:$op + ;; + "$mem/low_power_memory_start_bytes No such file or directory ") + log -p i -t DMM Self-Refresh-Only Disabled. low_power_memory_start_bytes does not exist:$op + ;; + *) + log -p i -t DMM Self-Refresh-Only available. low_power_memory_start_bytes at $op + ;; + esac +} + +# +# For controlling console and shell on console on 8960 - perist.serial.enable 8960 +# On other target use default ro.debuggable property. +# +serial=`getprop persist.serial.enable` +dserial=`getprop ro.debuggable` +case "$target" in + "msm8960") + case "$serial" in + "0") + echo 0 > /sys/devices/platform/msm_serial_hsl.0/console + ;; + "1") + echo 1 > /sys/devices/platform/msm_serial_hsl.0/console + start console + ;; + *) + case "$dserial" in + "1") + start console + ;; + esac + ;; + esac + ;; + *) + case "$dserial" in + "1") + start console + ;; + esac + ;; +esac + +# +# Allow persistent faking of bms +# User needs to set fake bms charge in persist.bms.fake_batt_capacity +# +fake_batt_capacity=`getprop persist.bms.fake_batt_capacity` +case "$fake_batt_capacity" in + "") ;; #Do nothing here + * ) + case $target in + "msm8960") + echo "$fake_batt_capacity" > /sys/module/pm8921_bms/parameters/bms_fake_battery + ;; + esac +esac + +case "$target" in + "msm7630_surf" | "msm7630_1x" | "msm7630_fusion") + case "$soc_hwplatform" in + "FFA" | "SVLTE_FFA") + # linking to surf_keypad_qwerty.kcm.bin instead of surf_keypad_numeric.kcm.bin so that + # the UI keyboard works fine. + ln -s /system/usr/keychars/surf_keypad_qwerty.kcm.bin /system/usr/keychars/surf_keypad.kcm.bin + ;; + "Fluid") + setprop ro.sf.lcd_density 240 + setprop qcom.bt.dev_power_class 2 + ;; + *) + ln -s /system/usr/keychars/surf_keypad_qwerty.kcm.bin /system/usr/keychars/surf_keypad.kcm.bin + ;; + esac + + insmod /system/lib/modules/ss_mfcinit.ko + insmod /system/lib/modules/ss_vencoder.ko + insmod /system/lib/modules/ss_vdecoder.ko + chmod 0666 /dev/ss_mfc_reg + chmod 0666 /dev/ss_vdec + chmod 0666 /dev/ss_venc + + init_DMM + ;; + + "msm8660") + case "$soc_hwplatform" in + "Fluid") + setprop ro.sf.lcd_density 240 + ;; + "Dragon") + setprop ro.sound.alsa "WM8903" + ;; + esac + ;; + + "msm8960") + # lcd density is write-once. Hence the separate switch case + case "$soc_hwplatform" in + "Liquid") + if [ "$soc_hwver" == "196608" ]; then # version 0x30000 is 3D sku + setprop ro.sf.hwrotation 90 + fi + + setprop ro.sf.lcd_density 160 + ;; + "MTP") + setprop ro.sf.lcd_density 240 + ;; + *) + case "$soc_hwid" in + "109") + setprop ro.sf.lcd_density 160 + ;; + *) + setprop ro.sf.lcd_density 240 + ;; + esac + ;; + esac + + #Set up composition type based on the target + case "$soc_hwid" in + 109| 116 | 117 | 118 | 120 | 121| 130) + #APQ8064, MSM8930, MSM8630, MSM8230, + # MSM8627, MSM8227, MPQ8064 + setprop debug.composition.type gpu + ;; + *) + esac + + init_DMM + ;; +esac diff --git a/patch_device/mione_plus/root/init.qcom.class_main.sh b/patch_device/mione_plus/root/init.qcom.class_main.sh new file mode 100755 index 00000000..df7735d5 --- /dev/null +++ b/patch_device/mione_plus/root/init.qcom.class_main.sh @@ -0,0 +1,122 @@ +#!/system/bin/sh +# Copyright (c) 2012, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Code Aurora nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# +# start ril-daemon only for targets on which radio is present +# +baseband=`getprop ro.baseband` +multirild=`getprop ro.multi.rild` +dsds=`getprop persist.dsds.enabled` +netmgr=`getprop ro.use_data_netmgrd` + +case "$baseband" in + "apq") + setprop ro.radio.noril yes + stop ril-daemon +esac + +case "$baseband" in + "msm" | "csfb" | "svlte2a" | "mdm" | "sglte" | "unknown") + start qmuxd + case "$baseband" in + "svlte2a" | "csfb" | "sglte") + start qmiproxy + esac + case "$multirild" in + "true") + case "$dsds" in + "true") + start ril-daemon1 + esac + esac + case "$netmgr" in + "true") + start netmgrd + esac +esac + +# +# enable bluetooth profiles dynamically +# +case $baseband in + "apq") + setprop ro.qualcomm.bluetooth.opp true + setprop ro.qualcomm.bluetooth.hfp false + setprop ro.qualcomm.bluetooth.hsp false + setprop ro.qualcomm.bluetooth.pbap true + setprop ro.qualcomm.bluetooth.ftp true + setprop ro.qualcomm.bluetooth.map true + setprop ro.qualcomm.bluetooth.nap false + setprop ro.qualcomm.bluetooth.sap false + setprop ro.qualcomm.bluetooth.dun false + ;; + "mdm" | "svlte2a" | "svlte1" | "csfb") + setprop ro.qualcomm.bluetooth.opp true + setprop ro.qualcomm.bluetooth.hfp true + setprop ro.qualcomm.bluetooth.hsp true + setprop ro.qualcomm.bluetooth.pbap true + setprop ro.qualcomm.bluetooth.ftp true + setprop ro.qualcomm.bluetooth.map true + setprop ro.qualcomm.bluetooth.nap true + setprop ro.qualcomm.bluetooth.sap true + setprop ro.qualcomm.bluetooth.dun false + ;; + "msm") + setprop ro.qualcomm.bluetooth.opp true + setprop ro.qualcomm.bluetooth.hfp true + setprop ro.qualcomm.bluetooth.hsp true + setprop ro.qualcomm.bluetooth.pbap true + setprop ro.qualcomm.bluetooth.ftp true + setprop ro.qualcomm.bluetooth.map true + setprop ro.qualcomm.bluetooth.nap true + setprop ro.qualcomm.bluetooth.sap true + setprop ro.qualcomm.bluetooth.dun true + ;; + "mpq") + setprop ro.qualcomm.bluetooth.opp false + setprop ro.qualcomm.bluetooth.hfp false + setprop ro.qualcomm.bluetooth.hsp false + setprop ro.qualcomm.bluetooth.pbap false + setprop ro.qualcomm.bluetooth.ftp false + setprop ro.qualcomm.bluetooth.map false + setprop ro.qualcomm.bluetooth.nap false + setprop ro.qualcomm.bluetooth.sap false + setprop ro.qualcomm.bluetooth.dun false + ;; + *) + setprop ro.qualcomm.bluetooth.opp true + setprop ro.qualcomm.bluetooth.hfp true + setprop ro.qualcomm.bluetooth.hsp true + setprop ro.qualcomm.bluetooth.pbap true + setprop ro.qualcomm.bluetooth.ftp true + setprop ro.qualcomm.bluetooth.map true + setprop ro.qualcomm.bluetooth.nap true + setprop ro.qualcomm.bluetooth.sap true + setprop ro.qualcomm.bluetooth.dun true + ;; +esac diff --git a/patch_device/mione_plus/root/init.qcom.sh b/patch_device/mione_plus/root/init.qcom.sh new file mode 100755 index 00000000..03dab73d --- /dev/null +++ b/patch_device/mione_plus/root/init.qcom.sh @@ -0,0 +1,133 @@ +#!/system/bin/sh +# Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Code Aurora nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +target=`getprop ro.board.platform` + +# +# Function to start sensors for DSPS enabled platforms +# +start_sensors() +{ + mkdir -p /data/system/sensors + touch /data/system/sensors/settings + chmod 775 /data/system/sensors + chmod 664 /data/system/sensors/settings + + mkdir -p /data/misc/sensors + chmod 775 /data/misc/sensors + + if [ ! -s /data/system/sensors/settings ]; then + # If the settings file is empty, enable sensors HAL + # Otherwise leave the file with it's current contents + echo 1 > /data/system/sensors/settings + fi + start sensors +} + +start_battery_monitor() +{ + chown root.system /sys/module/pm8921_bms/parameters/* + chmod 0660 /sys/module/pm8921_bms/parameters/* + mkdir -p /data/bms + chown root.system /data/bms + chmod 0770 /data/bms + start battery_monitor +} + +baseband=`getprop ro.baseband` + +# +# Suppress default route installation during RA for IPV6; user space will take +# care of this +# +for file in /proc/sys/net/ipv6/conf/* +do + echo 0 > $file/accept_ra_defrtr +done + +# +# Start gpsone_daemon for SVLTE Type I & II devices +# +case "$target" in + "msm7630_fusion") + start gpsone_daemon +esac +case "$baseband" in + "svlte2a") + start gpsone_daemon + start bridgemgrd +esac +case "$target" in + "msm7630_surf" | "msm8660" | "msm8960" | "mione") + start quipc_igsn +esac +case "$target" in + "msm7630_surf" | "msm8660" | "msm8960" | "mione") + start quipc_main +esac + +case "$target" in + "msm8960") + start location_mq + start xtwifi_inet + start xtwifi_client +esac + +case "$target" in + "msm7630_surf" | "msm7630_1x" | "msm7630_fusion") + value=`cat /sys/devices/system/soc/soc0/hw_platform` + case "$value" in + "Fluid") + start profiler_daemon;; + esac + ;; + "msm8660" ) + platformvalue=`cat /sys/devices/system/soc/soc0/hw_platform` + case "$platformvalue" in + "Fluid") + start_sensors + start profiler_daemon;; + esac + ;; + "msm8960") + start_sensors + case "$baseband" in + "msm") + start_battery_monitor;; + esac + + platformvalue=`cat /sys/devices/system/soc/soc0/hw_platform` + case "$platformvalue" in + "Fluid") + start profiler_daemon;; + "Liquid") + start profiler_daemon;; + esac + ;; + +esac diff --git a/patch_device/mione_plus/root/init.qcom.usb.sh b/patch_device/mione_plus/root/init.qcom.usb.sh new file mode 100755 index 00000000..dd3832e9 --- /dev/null +++ b/patch_device/mione_plus/root/init.qcom.usb.sh @@ -0,0 +1,151 @@ +#!/system/bin/sh +# Copyright (c) 2012, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Code Aurora Forum, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# Update USB serial number from persist storage if present, if not update +# with value passed from kernel command line, if none of these values are +# set then use the default value. This order is needed as for devices which +# do not have unique serial number. +# User needs to set unique usb serial number to persist.usb.serialno +# +serialno=`getprop persist.usb.serialno` +case "$serialno" in + "") + serialnum=`getprop ro.serialno` + case "$serialnum" in + "");; #Do nothing, use default serial number + *) + echo "$serialnum" > /sys/class/android_usb/android0/iSerial + esac + ;; + *) + echo "$serialno" > /sys/class/android_usb/android0/iSerial +esac + +# We won't do the following actions if in charge-only mode, so exit +if [ "$1" == "chargemode" ]; then + exit 0 +fi +chown root.system /sys/devices/platform/msm_hsusb/gadget/wakeup +chmod 220 /sys/devices/platform/msm_hsusb/gadget/wakeup + +# +# Allow persistent usb charging disabling +# User needs to set usb charging disabled in persist.usb.chgdisabled +# +target=`getprop ro.board.platform` +usbchgdisabled=`getprop persist.usb.chgdisabled` +case "$usbchgdisabled" in + "") ;; #Do nothing here + * ) + case $target in + "msm8660" | "mione") + echo "$usbchgdisabled" > /sys/module/pmic8058_charger/parameters/disabled + echo "$usbchgdisabled" > /sys/module/smb137b/parameters/disabled + ;; + "msm8960") + echo "$usbchgdisabled" > /sys/module/pm8921_charger/parameters/disabled + ;; + esac +esac + +usbcurrentlimit=`getprop persist.usb.currentlimit` +case "$usbcurrentlimit" in + "") ;; #Do nothing here + * ) + case $target in + "msm8960") + echo "$usbcurrentlimit" > /sys/module/pm8921_charger/parameters/usb_max_current + ;; + esac +esac +# +# Allow USB enumeration with default PID/VID +# +baseband=`getprop ro.baseband` +echo 1 > /sys/class/android_usb/f_mass_storage/lun/nofua +usb_config=`getprop persist.sys.usb.config` +case "$usb_config" in + "" | "adb") #USB persist config not set, select default configuration + case $target in + "msm8974") + setprop persist.sys.usb.config diag,adb + ;; + "msm8960") + case "$baseband" in + "mdm") + setprop persist.sys.usb.config diag,diag_mdm,serial_hsic,serial_tty,rmnet_hsic,mass_storage,adb + ;; + "sglte") + setprop persist.sys.usb.config diag,diag_mdm,serial_smd,serial_tty,serial_hsuart,rmnet_hsuart,mass_storage,adb + ;; + *) + setprop persist.sys.usb.config diag,serial_smd,serial_tty,rmnet_bam,mass_storage,adb + ;; + esac + ;; + "msm7627a") + setprop persist.sys.usb.config diag,serial_smd,serial_tty,rmnet_smd,mass_storage,adb + ;; + * ) + case "$baseband" in + "svlte2a") + setprop persist.sys.usb.config diag,diag_mdm,serial_sdio,serial_smd,rmnet_smd_sdio,mass_storage,adb + ;; + "csfb") + setprop persist.sys.usb.config diag,diag_mdm,serial_sdio,serial_tty,rmnet_sdio,mass_storage,adb + ;; + *) + setprop persist.sys.usb.config mass_storage,adb + ;; + esac + ;; + esac + ;; + * ) ;; #USB persist config exists, do nothing +esac + +# +# Add support for exposing lun0 as cdrom in mass-storage +# +target=`getprop ro.product.device` +cdromname="/system/etc/cdrom_install.iso" +cdromenable=`getprop persist.service.cdrom.enable` +case "$target" in + "msm7627a" | "msm8625") + case "$cdromenable" in + 0) + echo "" > /sys/class/android_usb/android0/f_mass_storage/lun0/file + ;; + 1) + echo "mounting usbcdrom lun" + echo $cdromname > /sys/class/android_usb/android0/f_mass_storage/lun0/file + ;; + esac + ;; +esac diff --git a/patch_device/mione_plus/root/init.rc b/patch_device/mione_plus/root/init.rc new file mode 100644 index 00000000..70dce870 --- /dev/null +++ b/patch_device/mione_plus/root/init.rc @@ -0,0 +1,62 @@ +#import /init.recovery.${ro.hardware}.rc + +on early-init + start ueventd + +on init + export PATH /sbin + export ANDROID_ROOT /system + export ANDROID_DATA /data + export EXTERNAL_STORAGE /sdcard + + symlink /system/etc /etc + symlink /etc/recovery.fstab /etc/fstab + + mkdir /boot + mkdir /recovery + mkdir /sdcard + mkdir /internal_sd + mkdir /external_sd + mkdir /sd-ext + mkdir /datadata + mkdir /emmc + mkdir /system + mkdir /data + mkdir /cache + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp + + write /sys/class/android_usb/android0/enable 0 + write /sys/class/android_usb/android0/idVendor 18D1 + write /sys/class/android_usb/android0/idProduct 9025 + write /sys/class/android_usb/android0/functions mass_storage,adb + write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer} + write /sys/class/android_usb/android0/iProduct ${ro.product.model} + write /sys/class/android_usb/android0/iSerial ${ro.serialno} + + +on boot + + ifup lo + hostname localhost + domainname localdomain + + class_start default + +service ueventd /sbin/ueventd + critical + +service recovery /sbin/recovery.sh + +service adbd /sbin/adbd recovery + disabled + +# Recovery will start adb once it has checked the keys + +# Restart adbd so it can run as root +on property:service.adb.root=1 + write /sys/class/android_usb/android0/enable 0 + restart adbd + write /sys/class/android_usb/android0/enable 1 diff --git a/patch_device/mione_plus/root/res/images/background.png b/patch_device/mione_plus/root/res/images/background.png new file mode 100644 index 00000000..8d93f953 Binary files /dev/null and b/patch_device/mione_plus/root/res/images/background.png differ diff --git a/patch_device/mione_plus/root/res/images/battery_charging.png b/patch_device/mione_plus/root/res/images/battery_charging.png new file mode 100644 index 00000000..adf4fb2b Binary files /dev/null and b/patch_device/mione_plus/root/res/images/battery_charging.png differ diff --git a/patch_device/mione_plus/root/res/images/battery_drained.png b/patch_device/mione_plus/root/res/images/battery_drained.png new file mode 100644 index 00000000..180d735e Binary files /dev/null and b/patch_device/mione_plus/root/res/images/battery_drained.png differ diff --git a/patch_device/mione_plus/root/res/images/battery_full.png b/patch_device/mione_plus/root/res/images/battery_full.png new file mode 100644 index 00000000..4f9224ec Binary files /dev/null and b/patch_device/mione_plus/root/res/images/battery_full.png differ diff --git a/patch_device/mione_plus/root/res/images/battery_low.png b/patch_device/mione_plus/root/res/images/battery_low.png new file mode 100644 index 00000000..e255802c Binary files /dev/null and b/patch_device/mione_plus/root/res/images/battery_low.png differ diff --git a/patch_device/mione_plus/root/res/images/battery_normal.png b/patch_device/mione_plus/root/res/images/battery_normal.png new file mode 100644 index 00000000..3d54e233 Binary files /dev/null and b/patch_device/mione_plus/root/res/images/battery_normal.png differ diff --git a/patch_device/mione_plus/root/res/images/logo.png b/patch_device/mione_plus/root/res/images/logo.png new file mode 100644 index 00000000..833d79c2 Binary files /dev/null and b/patch_device/mione_plus/root/res/images/logo.png differ diff --git a/patch_device/mione_plus/root/res/keys b/patch_device/mione_plus/root/res/keys new file mode 100644 index 00000000..85d50b36 --- /dev/null +++ b/patch_device/mione_plus/root/res/keys @@ -0,0 +1,2 @@ +{64,0xc926ad21,{1795090719,2141396315,950055447,2581568430,4268923165,1920809988,546586521,3498997798,1776797858,3740060814,1805317999,1429410244,129622599,1422441418,1783893377,1222374759,2563319927,323993566,28517732,609753416,1826472888,215237850,4261642700,4049082591,3228462402,774857746,154822455,2497198897,2758199418,3019015328,2794777644,87251430,2534927978,120774784,571297800,3695899472,2479925187,3811625450,3401832990,2394869647,3267246207,950095497,555058928,414729973,1136544882,3044590084,465547824,4058146728,2731796054,1689838846,3890756939,1048029507,895090649,247140249,178744550,3547885223,3165179243,109881576,3944604415,1044303212,3772373029,2985150306,3737520932,3599964420},{3437017481,3784475129,2800224972,3086222688,251333580,2131931323,512774938,325948880,2657486437,2102694287,3820568226,792812816,1026422502,2053275343,2800889200,3113586810,165549746,4273519969,4065247892,1902789247,772932719,3941848426,3652744109,216871947,3164400649,1942378755,3996765851,1055777370,964047799,629391717,2232744317,3910558992,191868569,2758883837,3682816752,2997714732,2702529250,3570700455,3776873832,3924067546,3555689545,2758825434,1323144535,61311905,1997411085,376844204,213777604,4077323584,9135381,1625809335,2804742137,2952293945,1117190829,4237312782,1825108855,3013147971,1111251351,2568837572,1684324211,2520978805,367251975,810756730,2353784344,1175080310}}, +v2 {64,0x8c19515,{2267803075,2155202542,3428666249,2289357871,3101875489,3421893626,375102440,367268888,3240637216,147228331,3986846572,2155847077,1033156464,212596747,3504857095,1961598871,2155566915,2938703649,1069109363,812181285,3063599466,4046293299,616324805,3804756385,1738423279,2798945001,3928301422,709944353,61392525,1538166200,1970895265,2947571600,3647527553,1928263263,1177870517,3579217768,2070168947,2864945296,3102241092,4289878917,268595374,534917530,1009836769,457775207,2884369862,2123245531,2539340656,1294987434,3658455428,2201452824,3683629849,4011252493,3721247845,132081929,2067100356,2293243411,2053362104,350635388,4087336621,984377757,2067387843,901413160,1764862602,2960537190},{3256021046,1169831571,130373652,209995355,1527507907,367569927,4158614985,780827169,731420093,1683288541,12415362,2189810087,1274538966,3338376350,2458760902,2282385876,3820364140,780554982,3437673519,41436205,3036288792,2188727898,3970099681,885896369,3537303713,1702282559,1922740860,2951591174,826479288,1389094710,1369188371,2412673655,818759962,846411775,248558683,3001437562,2935143977,946162587,3017089654,2007163057,3766984402,50238908,368326016,3893099881,1110019910,3604466346,3535668102,2811094810,4081318274,2275422629,3797751960,3794817139,722046889,1504267713,1448327384,3100672401,945344459,1478781545,3910687360,3494757401,956371323,2555226286,2970595229,645359558}} diff --git a/patch_device/mione_plus/root/sbin/recovery.sh b/patch_device/mione_plus/root/sbin/recovery.sh new file mode 100755 index 00000000..cc45bbc6 --- /dev/null +++ b/patch_device/mione_plus/root/sbin/recovery.sh @@ -0,0 +1,9 @@ +#!/sbin/sh +export PATH=/sbin + +nohup /sbin/stock > /dev/null & +recovery_pid="$!" +sleep 2 +kill -STOP "$recovery_pid" +/sbin/recovery + diff --git a/patch_device/mione_plus/root/sbin/stock b/patch_device/mione_plus/root/sbin/stock new file mode 100755 index 00000000..034f9086 Binary files /dev/null and b/patch_device/mione_plus/root/sbin/stock differ diff --git a/patch_device/mione_plus/root/ueventd.goldfish.rc b/patch_device/mione_plus/root/ueventd.goldfish.rc new file mode 100644 index 00000000..8de70496 --- /dev/null +++ b/patch_device/mione_plus/root/ueventd.goldfish.rc @@ -0,0 +1,5 @@ +# These settings are specific to running under the Android emulator +/dev/qemu_trace 0666 system system +/dev/qemu_pipe 0666 system system +/dev/ttyS* 0666 system system +/proc 0666 system system diff --git a/patch_device/mione_plus/root/ueventd.mione.rc b/patch_device/mione_plus/root/ueventd.mione.rc new file mode 100644 index 00000000..e4af4079 --- /dev/null +++ b/patch_device/mione_plus/root/ueventd.mione.rc @@ -0,0 +1,120 @@ +# Author: Alex.wang (iptux7#gmail.com) +# Create: 2012-12-06 22:49 +# +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/dev/rtc0 0600 system system + +# the DIAG device node is world writable/readable. +/dev/diag 0666 root root + +# the genlock client device node is world writable/readable. +/dev/genlock 0666 root root + +# gpu driver for adreno200 is globally accessible +/dev/kgsl-3d0 0666 root root +/dev/kgsl-2d0 0666 root root +/dev/kgsl-2d1 0666 root root + + +/dev/ttyHS0 0600 bluetooth bluetooth +/dev/ttyGS0 0660 system system +/dev/sdio_tty_ciq_00 0660 system system + +/dev/msm_rotator 0660 system graphics +/dev/pmem_audio 0660 system audio +/dev/pmem_smipool* 0660 system camera +/dev/oncrpc/* 0660 root qcom_oncrpc +/dev/radio0 0644 fm_radio fm_radio +/dev/i2c-0 0664 root system +/dev/i2c-1 0664 root system +/dev/i2c-2 0664 root system +/dev/i2c-4 0664 root system +/dev/msm_mvs 0660 system audio +/dev/msm_voicememo 0660 system audio +/dev/tzcom 0660 system drmrpc +/dev/qseecom 0660 system drmrpc +/dev/qce 0660 system drmrpc +/dev/msm_pcm_lp_dec 0660 system audio +/dev/smd4 0660 system system +/dev/smd3 0660 bluetooth bluetooth +/dev/smd2 0660 bluetooth bluetooth +/dev/smd7 0640 radio radio +/dev/smdcntl0 0640 radio radio +/dev/smdcntl1 0640 radio radio +/dev/smdcntl2 0640 radio radio +/dev/smdcntl3 0640 radio radio +/dev/smdcntl4 0640 radio radio +/dev/smdcntl5 0640 radio radio +/dev/smdcntl6 0640 radio radio +/dev/smdcntl7 0640 radio radio +/dev/sdioctl0 0640 radio radio +/dev/sdioctl1 0640 radio radio +/dev/sdioctl2 0640 radio radio +/dev/sdioctl3 0640 radio radio +/dev/sdioctl4 0640 radio radio +/dev/sdioctl4 0640 radio radio +/dev/sdioctl5 0640 radio radio +/dev/sdioctl6 0640 radio radio +/dev/sdioctl7 0640 radio radio +/dev/sdioctl8 0640 radio radio +/dev/rmnet_mux_ctrl 0640 radio radio +/dev/hsicctl0 0640 radio radio +/dev/hsicctl1 0640 radio radio +/dev/hsicctl2 0640 radio radio +/dev/hsicctl3 0640 radio radio +/dev/qemu_trace 0666 system system +/dev/gemini0 0660 system camera +/dev/mdm 0660 system system +/dev/ttyHSL1 0660 system system +/dev/tty_sdio_00 0660 system system +/dev/block/mmcblk0p17 0660 system system +/dev/block/mmcblk0p18 0660 system system +/dev/video* 0660 system camera +/dev/oncrpc/300000ba:00010000 0660 system drmrpc +#regular apps need to be able to open ion +/dev/ion 0664 system system +#rfcomm device for Bluetooth DUN +/dev/rfcomm0 0660 bluetooth bluetooth + +/sys/devices/virtual/input/input* mode_6d 0660 root input +/sys/devices/virtual/input/input* dump_period 0660 root input +/sys/devices/virtual/input/input* null_value 0660 root input + +#permissions for video +/dev/msm_vidc_reg 0660 system audio +/dev/msm_vidc_dec 0660 system audio +/dev/msm_vidc_dec_sec 0660 system audio +/dev/msm_vidc_enc 0660 system audio +#permissions for audio +/dev/msm_amrnb 0660 system audio +/dev/msm_amrwb 0660 system audio +/dev/msm_aac 0660 system audio +/dev/msm_multi_aac 0660 system audio +/dev/msm_aac_in 0660 system audio +/dev/msm_qcelp 0660 system audio +/dev/msm_evrc 0660 system audio +/dev/msm_fm 0660 system audio +/dev/msm_acdb 0660 system audio +/dev/msm_rtac 0660 system audio +/dev/msm_wma 0660 system audio +/dev/msm_wmapro 0660 system audio +/dev/msm_qcelp_in 0660 system audio +/dev/msm_evrc_in 0660 system audio +/dev/msm_preproc_ctl 0660 system audio +/dev/msm_a2dp_in 0640 system audio +/dev/msm_amrnb_in 0640 system audio +/sys/devices/virtual/smdpkt/smdcntl* open_timeout 0664 radio radio +#permissions for sensors +/dev/msm_dsps 0660 system system + diff --git a/patch_device/mione_plus/root/ueventd.qcom.rc b/patch_device/mione_plus/root/ueventd.qcom.rc new file mode 100644 index 00000000..03faf286 --- /dev/null +++ b/patch_device/mione_plus/root/ueventd.qcom.rc @@ -0,0 +1,99 @@ +# Copyright (c) 2012, Code Aurora Forum. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Code Aurora nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# the DIAG device node is not world writable/readable. +/dev/diag 0660 system qcom_diag + +/dev/genlock 0666 system system +/dev/kgsl 0666 system system +/dev/kgsl-3d0 0666 system system +/dev/kgsl-2d0 0666 root root +/dev/kgsl-2d1 0666 root root +/dev/ion 0664 system system +/dev/rtc0 0600 system system +/dev/smd0 0660 system system +/dev/smd4 0660 system system +/dev/smd7 0660 bluetooth bluetooth +/dev/rfcomm0 0660 bluetooth bluetooth +/dev/smdcntl0 0640 radio radio +/dev/smdcntl1 0640 radio radio +/dev/smdcntl2 0640 radio radio +/dev/smdcntl3 0640 radio radio +/dev/smdcntl4 0640 radio radio +/dev/smdcntl5 0640 radio radio +/dev/smdcntl6 0640 radio radio +/dev/smdcntl7 0640 radio radio +/dev/smuxctl32 0640 radio radio +/dev/sdioctl0 0640 radio radio +/dev/sdioctl1 0640 radio radio +/dev/sdioctl2 0640 radio radio +/dev/sdioctl3 0640 radio radio +/dev/sdioctl4 0640 radio radio +/dev/sdioctl5 0640 radio radio +/dev/sdioctl6 0640 radio radio +/dev/sdioctl7 0640 radio radio +/dev/sdioctl8 0640 radio radio +/dev/rmnet_mux_ctrl 0640 radio radio +/dev/hsicctl0 0640 radio radio +/dev/hsicctl1 0640 radio radio +/dev/hsicctl2 0640 radio radio +/dev/hsicctl3 0640 radio radio +/dev/video* 0660 system camera +/dev/media* 0660 system camera +/dev/v4l-subdev* 0660 system camera +/dev/gemini0 0660 system camera +/dev/msm_camera/* 0660 system camera +/dev/gemini/ 0660 system camera +/dev/msm_vidc_reg 0660 system audio +/dev/msm_vidc_dec 0660 system audio +/dev/msm_vidc_dec_sec 0660 system audio +/dev/msm_vidc_enc 0660 system audio +/dev/msm_rotator 0664 system system +/dev/hw_random 0660 system system + +#permissions for audio +/dev/msm_qcelp 0660 system audio +/dev/msm_evrc 0660 system audio +/dev/msm_wma 0660 system audio +/dev/msm_wmapro 0660 system audio +/dev/msm_amrnb 0660 system audio +/dev/msm_amrwb 0660 system audio +/dev/msm_aac 0660 system audio +/dev/msm_multi_aac 0660 system audio +/dev/msm_aac_in 0660 system audio +/dev/msm_qcelp_in 0660 system audio +/dev/msm_evrc_in 0660 system audio +/dev/msm_amrnb_in 0640 system audio +/dev/smd3 0660 bluetooth bluetooth +/dev/smd2 0660 bluetooth bluetooth +/dev/ttyHSL1 0660 system system +/dev/mdm 0660 system system +/sys/devices/virtual/smdpkt/smdcntl* open_timeout 0664 radio radio +/dev/sdio_tty_ciq_00 0660 system system +/dev/tty_sdio_00 0660 system system +/dev/ttyGS0 0660 system system +/dev/i2c-5 0660 media media diff --git a/patch_device/mione_plus/root/ueventd.rc b/patch_device/mione_plus/root/ueventd.rc new file mode 100644 index 00000000..6b7213c5 --- /dev/null +++ b/patch_device/mione_plus/root/ueventd.rc @@ -0,0 +1,106 @@ +/dev/null 0666 root root +/dev/zero 0666 root root +/dev/full 0666 root root +/dev/ptmx 0666 root root +/dev/tty 0666 root root +/dev/random 0666 root root +/dev/urandom 0666 root root +/dev/ashmem 0666 root root +/dev/binder 0666 root root + +# Anyone can read the logs, but if they're not in the "logs" +# group, then they'll only see log entries for their UID. +/dev/log/* 0666 root log + +# the msm hw3d client device node is world writable/readable. +/dev/msm_hw3dc 0666 root root + +# the DIAG device node is not world writable/readable. +/dev/diag 0660 system qcom_diag + +# gpu driver for adreno200 is globally accessible +/dev/kgsl 0666 root root + +# these should not be world writable +/dev/diag_arm9 0660 radio radio +/dev/android_adb 0660 adb adb +/dev/android_adb_enable 0660 adb adb +/dev/ttyMSM0 0600 bluetooth bluetooth +/dev/uinput 0660 system bluetooth +/dev/alarm 0664 system radio +/dev/tty0 0660 root system +/dev/graphics/* 0660 system graphics +/dev/msm_hw3dm 0660 system graphics +/dev/input/* 0660 root input +/dev/eac 0660 root audio +/dev/cam 0660 root camera +/dev/pmem 0660 system graphics +/dev/pmem_audio 0660 system audio +/dev/pmem_adsp* 0660 system audio +/dev/pmem_camera* 0660 system camera +/dev/oncrpc/* 0660 root qcom_oncrpc +/dev/gss 0660 gps gps +/dev/adsp/* 0660 system audio +/dev/snd/* 0660 system audio +/dev/mt9t013 0660 system system +/dev/msm_camera/* 0660 system system +/dev/akm8976_daemon 0640 compass system +/dev/akm8976_aot 0640 compass system +/dev/akm8973_daemon 0640 compass system +/dev/akm8973_aot 0640 compass system +/dev/bma150 0640 compass system +/dev/cm3602 0640 compass system +/dev/akm8976_pffd 0640 compass system +/dev/lightsensor 0640 system system +/dev/radio0 0644 fm_radio fm_radio +/dev/msm_pcm_out* 0660 system audio +/dev/msm_pcm_in* 0660 system audio +/dev/msm_voicememo 0660 system audio +/dev/msm_pcm_ctl* 0660 system audio +/dev/msm_snd* 0660 system audio +/dev/msm_mp3* 0660 system audio +/dev/audience_a1026* 0660 system audio +/dev/tpa2018d1* 0660 system audio +/dev/msm_audpre 0660 system audio +/dev/msm_audio_ctl 0660 system audio +/dev/htc-acoustic 0660 system audio +/dev/vdec 0660 system audio +/dev/qseecom 0660 system drmrpc +/dev/q6venc 0660 system audio +/dev/snd/dsp 0660 system audio +/dev/snd/dsp1 0660 system audio +/dev/snd/mixer 0660 system audio +/dev/msm_pcm_lp_dec 0660 system audio +/dev/msm_mvs 0660 system audio +/dev/smd0 0640 radio radio +/dev/qmi 0640 radio radio +/dev/qmi0 0640 radio radio +/dev/qmi1 0640 radio radio +/dev/qmi2 0640 radio radio +/dev/bus/usb/* 0660 root usb +/dev/mtp_usb 0660 root mtp +/dev/usb_accessory 0660 root usb +/dev/tun 0660 system vpn +/dev/msm_qcelp_in 0660 system audio +/dev/msm_evrc_in 0660 system audio +/dev/msm_preproc_ctl 0660 system audio +/dev/msm_qcelp 0660 system audio +/dev/msm_evrc 0660 system audio +/dev/msm_acdb 0660 system audio +/dev/msm_fm 0660 system audio +/dev/msm_ac3 0660 system audio +/dev/msm_cad 0660 system audio +/dev/msm_rtac 0660 system audio +/dev/oncrpc/300000ba:00010000 0660 system drmrpc + +# CDMA radio interface MUX +/dev/ts0710mux* 0640 radio radio +/dev/ppp 0660 radio vpn + +# sysfs properties +/sys/devices/virtual/input/input* enable 0660 root input +/sys/devices/virtual/input/input* poll_delay 0660 root input +/sys/devices/virtual/input/input* mode_6d 0660 root input +/sys/devices/virtual/input/input* dump_period 0660 root input +/sys/devices/virtual/input/input* null_value 0660 root input +/sys/devices/virtual/usb_composite/* enable 0664 root system diff --git a/patch_device/note2/root/init.rc b/patch_device/note2/root/init.rc index 4f3cbb30..c6d6ea9a 100755 --- a/patch_device/note2/root/init.rc +++ b/patch_device/note2/root/init.rc @@ -14,7 +14,7 @@ on init mkdir /cache mkdir /preload mkdir /efs - mount /tmp /tmp tmpfs + mkdir /tmp chown root shell /tmp chmod 0775 /tmp diff --git a/patch_device/saga/root/init.rc b/patch_device/saga/root/init.rc index 43d31d61..eeabe18a 100755 --- a/patch_device/saga/root/init.rc +++ b/patch_device/saga/root/init.rc @@ -17,7 +17,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/sentsation/root/init.rc b/patch_device/sentsation/root/init.rc index 832b8640..f02efefc 100644 --- a/patch_device/sentsation/root/init.rc +++ b/patch_device/sentsation/root/init.rc @@ -17,7 +17,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/shooteru/root/init.rc b/patch_device/shooteru/root/init.rc index c2586577..f0c0ab1e 100755 --- a/patch_device/shooteru/root/init.rc +++ b/patch_device/shooteru/root/init.rc @@ -17,7 +17,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/ville/root/init.rc b/patch_device/ville/root/init.rc index 832b8640..f02efefc 100644 --- a/patch_device/ville/root/init.rc +++ b/patch_device/ville/root/init.rc @@ -17,7 +17,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/patch_device/vivo/root/init.rc b/patch_device/vivo/root/init.rc index 43d31d61..eeabe18a 100755 --- a/patch_device/vivo/root/init.rc +++ b/patch_device/vivo/root/init.rc @@ -17,7 +17,10 @@ on init mkdir /system mkdir /data mkdir /cache - mount /tmp /tmp tmpfs + mkdir /tmp + + chown root shell /tmp + chmod 0777 /tmp on boot diff --git a/prebuilt b/prebuilt new file mode 160000 index 00000000..7accce96 --- /dev/null +++ b/prebuilt @@ -0,0 +1 @@ +Subproject commit 7accce9650a2aa5526bc853617d36fc41dfceb58 diff --git a/readme b/readme index 12b20ad2..9552bb58 100644 --- a/readme +++ b/readme @@ -1,10 +1,31 @@ +About +------------ +MIUI Recovery is a powerful Touch Recovery based on AROMA Installer's code. + +How to build +--------------- 1 the project is build android recovery only; -2 before building, make sure copy project android_prebuilt, android_bionic and anroid_hardware to the directory ,which from ICS. +2 before building, make sure copy project android_prebuilt, android_bionic and android_hardware to the directory ,which from ICS.(If you don't have these projects,see https://github.com/PeterCxy) 3 Steps as following: $. build/envsetup.sh - $make crespo - please see the out/patch_device/crespo/ , find recovery.img + $make + please see the out/patch_device// , find recovery.img 4 please check Makefile to obtain the supported devices; +5 If hasn't been supported,you can port by yourself. + +关于 +--------------- +MIUI Recovery是一个基于AROMA Installler代码制作的强大的触摸版Recovery。 +如何编译 +--------------- +1 这个项目仅用于编译Recovery +2 编译之前,请把ICS源码中的prebuilt bionic hardware复制到本Recovery目录下(没有的话,在 https://github.com/PeterCxy 可以找到) +3 编译步骤: + $. build/envsetup.sh + $make <你的设备> + 请前往 out/patch_device/<你的设备>/ ,找到 recovery.img +4 请确保Makefile中有您的设备支持 +5 如果您的设备未被支持,请自行适配 diff --git a/src/Android.mk b/src/Android.mk index 557239ae..b581cde2 100755 --- a/src/Android.mk +++ b/src/Android.mk @@ -13,7 +13,8 @@ LOCAL_SRC_FILES := \ firmware.c \ nandroid.c \ verifier.c \ - recovery.c + recovery.c \ + sideload.c LOCAL_MODULE := recovery @@ -35,7 +36,6 @@ LOCAL_CFLAGS += -DUSE_EXT4 LOCAL_C_INCLUDES += system/extras/ext4_utils LOCAL_STATIC_LIBRARIES += libext4_utils libz endif - # This binary is in the recovery ramdisk, which is otherwise a copy of root. # It gets copied there in config/Makefile. LOCAL_MODULE_TAGS suppresses # a (redundant) copy of the binary in /system/bin for user builds. @@ -52,7 +52,7 @@ LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt LOCAL_STATIC_LIBRARIES += libedify libcrecovery libflashutils libmmcutils libbmlutils LOCAL_STATIC_LIBRARIES += libmkyaffs2image libunyaffs liberase_image libdump_image libflash_image LOCAL_STATIC_LIBRARIES += libmiui libcutils -LOCAL_STATIC_LIBRARIES += libstdc++ libc libm +LOCAL_STATIC_LIBRARIES += libstdc++ libc libm libminadbd LOCAL_C_INCLUDES += system/extras/ext4_utils @@ -104,6 +104,7 @@ include $(commands_recovery_local_path)/bmlutils/Android.mk include $(commands_recovery_local_path)/flashutils/Android.mk include $(commands_recovery_local_path)/libcrecovery/Android.mk #end +include $(commands_recovery_local_path)/minadbd/Android.mk include $(commands_recovery_local_path)/miui/Android.mk include $(commands_recovery_local_path)/minelf/Android.mk include $(commands_recovery_local_path)/minzip/Android.mk diff --git a/src/common.h b/src/common.h index e6352a55..0e52366b 100755 --- a/src/common.h +++ b/src/common.h @@ -17,7 +17,7 @@ #define RECOVERY_COMMON_H #include - +#include // Initialize the graphics system. @@ -96,6 +96,8 @@ typedef struct { const char* fs_options; const char* fs_options2; + + struct stat stat; } Volume; typedef struct { @@ -119,5 +121,9 @@ typedef struct { // fopen a file, mounting volumes and making parent dirs as necessary. FILE* fopen_path(const char *path, const char *mode); - +#define DUALBOOT_ITEM_INTERCHANGED -2 +#define DUALBOOT_ITEM_ABORT -1 +#define DUALBOOT_ITEM_BOTH 0 +#define DUALBOOT_ITEM_SYSTEM0 1 +#define DUALBOOT_ITEM_SYSTEM1 2 #endif // RECOVERY_COMMON_H diff --git a/src/crash.patch b/src/crash.patch new file mode 100644 index 00000000..d91a5c68 --- /dev/null +++ b/src/crash.patch @@ -0,0 +1,83 @@ +From 0c27228cdd07d6d9eb942c35dc28adef3aa38319 Mon Sep 17 00:00:00 2001 +From: Koushik Dutta +Date: Wed, 12 Dec 2012 17:15:18 -0800 +Subject: [PATCH] Fix crash in recovery that occurs during backup. + +Change-Id: I8d13646eede75c64878b50a8b6f4617a48e10b32 +--- + libcrecovery/popen.c | 25 +++++++++++-------------- + 1 file changed, 11 insertions(+), 14 deletions(-) + +diff --git a/libcrecovery/popen.c b/libcrecovery/popen.c +index 73d3c74..59a7bd4 100644 +--- a/libcrecovery/popen.c ++++ b/libcrecovery/popen.c +@@ -50,6 +50,8 @@ static struct pid { + pid_t pid; + } *pidlist; + ++extern char **environ; ++ + FILE * + __popen(const char *program, const char *type) + { +@@ -57,6 +59,7 @@ __popen(const char *program, const char *type) + FILE *iop; + int pdes[2]; + pid_t pid; ++ char *argp[] = {"sh", "-c", NULL, NULL}; + + if ((*type != 'r' && *type != 'w') || type[1] != '\0') { + errno = EINVAL; +@@ -71,7 +74,7 @@ __popen(const char *program, const char *type) + return (NULL); + } + +- switch (pid = vfork()) { ++ switch (pid = fork()) { + case -1: /* Error. */ + (void)close(pdes[0]); + (void)close(pdes[1]); +@@ -82,24 +85,17 @@ __popen(const char *program, const char *type) + { + struct pid *pcur; + /* +- * because vfork() instead of fork(), must leak FILE *, +- * but luckily we are terminally headed for an execl() ++ * We fork()'d, we got our own copy of the list, no ++ * contention. + */ + for (pcur = pidlist; pcur; pcur = pcur->next) + close(fileno(pcur->fp)); + + if (*type == 'r') { +- int tpdes1 = pdes[1]; +- + (void) close(pdes[0]); +- /* +- * We must NOT modify pdes, due to the +- * semantics of vfork. +- */ +- if (tpdes1 != STDOUT_FILENO) { +- (void)dup2(tpdes1, STDOUT_FILENO); +- (void)close(tpdes1); +- tpdes1 = STDOUT_FILENO; ++ if (pdes[1] != STDOUT_FILENO) { ++ (void)dup2(pdes[1], STDOUT_FILENO); ++ (void)close(pdes[1]); + } + } else { + (void)close(pdes[1]); +@@ -108,7 +104,8 @@ __popen(const char *program, const char *type) + (void)close(pdes[0]); + } + } +- execl(_PATH_BSHELL, "sh", "-c", program, (char *)NULL); ++ argp[2] = (char *)program; ++ execve(_PATH_BSHELL, argp, environ); + _exit(127); + /* NOTREACHED */ + } +-- +1.8.1.2 + diff --git a/src/libcrecovery/popen.c b/src/libcrecovery/popen.c index 73d3c743..59a7bd47 100755 --- a/src/libcrecovery/popen.c +++ b/src/libcrecovery/popen.c @@ -50,6 +50,8 @@ static struct pid { pid_t pid; } *pidlist; +extern char **environ; + FILE * __popen(const char *program, const char *type) { @@ -57,6 +59,7 @@ __popen(const char *program, const char *type) FILE *iop; int pdes[2]; pid_t pid; + char *argp[] = {"sh", "-c", NULL, NULL}; if ((*type != 'r' && *type != 'w') || type[1] != '\0') { errno = EINVAL; @@ -71,7 +74,7 @@ __popen(const char *program, const char *type) return (NULL); } - switch (pid = vfork()) { + switch (pid = fork()) { case -1: /* Error. */ (void)close(pdes[0]); (void)close(pdes[1]); @@ -82,24 +85,17 @@ __popen(const char *program, const char *type) { struct pid *pcur; /* - * because vfork() instead of fork(), must leak FILE *, - * but luckily we are terminally headed for an execl() + * We fork()'d, we got our own copy of the list, no + * contention. */ for (pcur = pidlist; pcur; pcur = pcur->next) close(fileno(pcur->fp)); if (*type == 'r') { - int tpdes1 = pdes[1]; - (void) close(pdes[0]); - /* - * We must NOT modify pdes, due to the - * semantics of vfork. - */ - if (tpdes1 != STDOUT_FILENO) { - (void)dup2(tpdes1, STDOUT_FILENO); - (void)close(tpdes1); - tpdes1 = STDOUT_FILENO; + if (pdes[1] != STDOUT_FILENO) { + (void)dup2(pdes[1], STDOUT_FILENO); + (void)close(pdes[1]); } } else { (void)close(pdes[1]); @@ -108,7 +104,8 @@ __popen(const char *program, const char *type) (void)close(pdes[0]); } } - execl(_PATH_BSHELL, "sh", "-c", program, (char *)NULL); + argp[2] = (char *)program; + execve(_PATH_BSHELL, argp, environ); _exit(127); /* NOTREACHED */ } diff --git a/src/minadbd/Android.mk b/src/minadbd/Android.mk new file mode 100644 index 00000000..5a4de682 --- /dev/null +++ b/src/minadbd/Android.mk @@ -0,0 +1,32 @@ +# Copyright 2005 The Android Open Source Project +# +# Android.mk for adb +# + +LOCAL_PATH:= $(call my-dir) + +# minadbd library +# ========================================================= + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + adb.c \ + fdevent.c \ + transport.c \ + transport_usb.c \ + sockets.c \ + services.c \ + usb_linux_client.c \ + utils.c + +LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter +LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE + +LOCAL_MODULE := libminadbd + +LOCAL_STATIC_LIBRARIES := libcutils libc +include $(BUILD_STATIC_LIBRARY) + + + diff --git a/src/minadbd/README.txt b/src/minadbd/README.txt new file mode 100644 index 00000000..c9df484c --- /dev/null +++ b/src/minadbd/README.txt @@ -0,0 +1,39 @@ +The contents of this directory are copied from system/core/adb, with +the following changes: + +adb.c + - much support for host mode and non-linux OS's stripped out; this + version only runs as adbd on the device. + - always setuid/setgid's itself to the shell user + - only uses USB transport + - references to JDWP removed + - main() removed + - all ADB_HOST and win32 code removed + - removed listeners, logging code, background server (for host) + +adb.h + - minor changes to match adb.c changes + +sockets.c + - references to JDWP removed + - ADB_HOST code removed + +services.c + - all services except echo_service (which is commented out) removed + - all host mode support removed + - sideload_service() added; this is the only service supported. It + receives a single blob of data, writes it to a fixed filename, and + makes the process exit. + +Android.mk + - only builds in adbd mode; builds as static library instead of a + standalone executable. + +sysdeps.h + - changes adb_creat() to use O_NOFOLLOW + +transport.c + - removed ADB_HOST code + +transport_usb.c + - removed ADB_HOST code diff --git a/src/minadbd/adb.c b/src/minadbd/adb.c new file mode 100644 index 00000000..659fda79 --- /dev/null +++ b/src/minadbd/adb.c @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define TRACE_TAG TRACE_ADB + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "adb.h" +#include "../common.h" + +#include +#include +#include + +#if ADB_TRACE +ADB_MUTEX_DEFINE( D_lock ); +#endif + +int HOST = 0; + +static const char *adb_device_banner = "sideload"; + +void fatal(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(-1); +} + +void fatal_errno(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "error: %s: ", strerror(errno)); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(-1); +} + +int adb_trace_mask; + +/* read a comma/space/colum/semi-column separated list of tags + * from the ADB_TRACE environment variable and build the trace + * mask from it. note that '1' and 'all' are special cases to + * enable all tracing + */ +void adb_trace_init(void) +{ + const char* p = getenv("ADB_TRACE"); + const char* q; + + static const struct { + const char* tag; + int flag; + } tags[] = { + { "1", 0 }, + { "all", 0 }, + { "adb", TRACE_ADB }, + { "sockets", TRACE_SOCKETS }, + { "packets", TRACE_PACKETS }, + { "rwx", TRACE_RWX }, + { "usb", TRACE_USB }, + { "sync", TRACE_SYNC }, + { "sysdeps", TRACE_SYSDEPS }, + { "transport", TRACE_TRANSPORT }, + { "jdwp", TRACE_JDWP }, + { "services", TRACE_SERVICES }, + { NULL, 0 } + }; + + if (p == NULL) + return; + + /* use a comma/column/semi-colum/space separated list */ + while (*p) { + int len, tagn; + + q = strpbrk(p, " ,:;"); + if (q == NULL) { + q = p + strlen(p); + } + len = q - p; + + for (tagn = 0; tags[tagn].tag != NULL; tagn++) + { + int taglen = strlen(tags[tagn].tag); + + if (len == taglen && !memcmp(tags[tagn].tag, p, len) ) + { + int flag = tags[tagn].flag; + if (flag == 0) { + adb_trace_mask = ~0; + return; + } + adb_trace_mask |= (1 << flag); + break; + } + } + p = q; + if (*p) + p++; + } +} + + +apacket *get_apacket(void) +{ + apacket *p = malloc(sizeof(apacket)); + if(p == 0) fatal("failed to allocate an apacket"); + memset(p, 0, sizeof(apacket) - MAX_PAYLOAD); + return p; +} + +void put_apacket(apacket *p) +{ + free(p); +} + +void handle_online(void) +{ + D("adb: online\n"); +} + +void handle_offline(atransport *t) +{ + D("adb: offline\n"); + //Close the associated usb + run_transport_disconnects(t); +} + +#if TRACE_PACKETS +#define DUMPMAX 32 +void print_packet(const char *label, apacket *p) +{ + char *tag; + char *x; + unsigned count; + + switch(p->msg.command){ + case A_SYNC: tag = "SYNC"; break; + case A_CNXN: tag = "CNXN" ; break; + case A_OPEN: tag = "OPEN"; break; + case A_OKAY: tag = "OKAY"; break; + case A_CLSE: tag = "CLSE"; break; + case A_WRTE: tag = "WRTE"; break; + default: tag = "????"; break; + } + + fprintf(stderr, "%s: %s %08x %08x %04x \"", + label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length); + count = p->msg.data_length; + x = (char*) p->data; + if(count > DUMPMAX) { + count = DUMPMAX; + tag = "\n"; + } else { + tag = "\"\n"; + } + while(count-- > 0){ + if((*x >= ' ') && (*x < 127)) { + fputc(*x, stderr); + } else { + fputc('.', stderr); + } + x++; + } + fprintf(stderr, tag); +} +#endif + +static void send_ready(unsigned local, unsigned remote, atransport *t) +{ + D("Calling send_ready \n"); + apacket *p = get_apacket(); + p->msg.command = A_OKAY; + p->msg.arg0 = local; + p->msg.arg1 = remote; + send_packet(p, t); +} + +static void send_close(unsigned local, unsigned remote, atransport *t) +{ + D("Calling send_close \n"); + apacket *p = get_apacket(); + p->msg.command = A_CLSE; + p->msg.arg0 = local; + p->msg.arg1 = remote; + send_packet(p, t); +} + +static void send_connect(atransport *t) +{ + D("Calling send_connect \n"); + apacket *cp = get_apacket(); + cp->msg.command = A_CNXN; + cp->msg.arg0 = A_VERSION; + cp->msg.arg1 = MAX_PAYLOAD; + snprintf((char*) cp->data, sizeof cp->data, "%s::", + HOST ? "host" : adb_device_banner); + cp->msg.data_length = strlen((char*) cp->data) + 1; + send_packet(cp, t); +} + +void parse_banner(char *banner, atransport *t) +{ + char *type, *product, *end; + + D("parse_banner: %s\n", banner); + type = banner; + product = strchr(type, ':'); + if(product) { + *product++ = 0; + } else { + product = ""; + } + + /* remove trailing ':' */ + end = strchr(product, ':'); + if(end) *end = 0; + + /* save product name in device structure */ + if (t->product == NULL) { + t->product = strdup(product); + } else if (strcmp(product, t->product) != 0) { + free(t->product); + t->product = strdup(product); + } + + if(!strcmp(type, "bootloader")){ + D("setting connection_state to CS_BOOTLOADER\n"); + t->connection_state = CS_BOOTLOADER; + update_transports(); + return; + } + + if(!strcmp(type, "device")) { + D("setting connection_state to CS_DEVICE\n"); + t->connection_state = CS_DEVICE; + update_transports(); + return; + } + + if(!strcmp(type, "recovery")) { + D("setting connection_state to CS_RECOVERY\n"); + t->connection_state = CS_RECOVERY; + update_transports(); + return; + } + + if(!strcmp(type, "sideload")) { + D("setting connection_state to CS_SIDELOAD\n"); + t->connection_state = CS_SIDELOAD; + update_transports(); + return; + } + + t->connection_state = CS_HOST; +} + +void handle_packet(apacket *p, atransport *t) +{ + asocket *s; + + D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0], + ((char*) (&(p->msg.command)))[1], + ((char*) (&(p->msg.command)))[2], + ((char*) (&(p->msg.command)))[3]); + print_packet("recv", p); + + switch(p->msg.command){ + case A_SYNC: + if(p->msg.arg0){ + send_packet(p, t); + if(HOST) send_connect(t); + } else { + t->connection_state = CS_OFFLINE; + handle_offline(t); + send_packet(p, t); + } + return; + + case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */ + /* XXX verify version, etc */ + if(t->connection_state != CS_OFFLINE) { + t->connection_state = CS_OFFLINE; + handle_offline(t); + } + parse_banner((char*) p->data, t); + handle_online(); + if(!HOST) send_connect(t); + break; + + case A_OPEN: /* OPEN(local-id, 0, "destination") */ + if(t->connection_state != CS_OFFLINE) { + char *name = (char*) p->data; + name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0; + s = create_local_service_socket(name); + if(s == 0) { + send_close(0, p->msg.arg0, t); + } else { + s->peer = create_remote_socket(p->msg.arg0, t); + s->peer->peer = s; + send_ready(s->id, s->peer->id, t); + s->ready(s); + } + } + break; + + case A_OKAY: /* READY(local-id, remote-id, "") */ + if(t->connection_state != CS_OFFLINE) { + if((s = find_local_socket(p->msg.arg1))) { + if(s->peer == 0) { + s->peer = create_remote_socket(p->msg.arg0, t); + s->peer->peer = s; + } + s->ready(s); + } + } + break; + + case A_CLSE: /* CLOSE(local-id, remote-id, "") */ + if(t->connection_state != CS_OFFLINE) { + if((s = find_local_socket(p->msg.arg1))) { + s->close(s); + } + } + break; + + case A_WRTE: + if(t->connection_state != CS_OFFLINE) { + if((s = find_local_socket(p->msg.arg1))) { + unsigned rid = p->msg.arg0; + p->len = p->msg.data_length; + + if(s->enqueue(s, p) == 0) { + D("Enqueue the socket\n"); + send_ready(s->id, rid, t); + } + return; + } + } + break; + + default: + printf("handle_packet: what is %08x?!\n", p->msg.command); + } + + put_apacket(p); +} + +static void adb_cleanup(void) +{ + usb_cleanup(); +} + +int adb_main() +{ + atexit(adb_cleanup); +#if defined(HAVE_FORKEXEC) + // No SIGCHLD. Let the service subproc handle its children. + signal(SIGPIPE, SIG_IGN); +#endif + + init_transport_registration(); + + // The minimal version of adbd only uses USB. + if (access("/dev/android_adb", F_OK) == 0) { + // listen on USB + LOGE("listen on USB\n"); + usb_init(); + } + + if (setgid(AID_SHELL) != 0) { + LOGE("failed to setgid to shell\n"); + exit(1); + } + if (setuid(AID_SHELL) != 0) { + LOGE("failed to setuid to shell\n"); + exit(1); + } + LOGE("userid is %d\n", getuid()); + + LOGE("Event loop starting\n"); + + fdevent_loop(); + + usb_cleanup(); + + return 0; +} diff --git a/src/minadbd/adb.h b/src/minadbd/adb.h new file mode 100644 index 00000000..98fa5972 --- /dev/null +++ b/src/minadbd/adb.h @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ADB_H +#define __ADB_H + +#include + +#include "transport.h" /* readx(), writex() */ +#include "fdevent.h" + +#define MAX_PAYLOAD 4096 + +#define A_SYNC 0x434e5953 +#define A_CNXN 0x4e584e43 +#define A_OPEN 0x4e45504f +#define A_OKAY 0x59414b4f +#define A_CLSE 0x45534c43 +#define A_WRTE 0x45545257 + +#define A_VERSION 0x01000000 // ADB protocol version + +#define ADB_VERSION_MAJOR 1 // Used for help/version information +#define ADB_VERSION_MINOR 0 // Used for help/version information + +#define ADB_SERVER_VERSION 29 // Increment this when we want to force users to start a new adb server + +typedef struct amessage amessage; +typedef struct apacket apacket; +typedef struct asocket asocket; +typedef struct aservice aservice; +typedef struct atransport atransport; +typedef struct adisconnect adisconnect; +typedef struct usb_handle usb_handle; + +struct amessage { + unsigned command; /* command identifier constant */ + unsigned arg0; /* first argument */ + unsigned arg1; /* second argument */ + unsigned data_length; /* length of payload (0 is allowed) */ + unsigned data_check; /* checksum of data payload */ + unsigned magic; /* command ^ 0xffffffff */ +}; + +struct apacket +{ + apacket *next; + + unsigned len; + unsigned char *ptr; + + amessage msg; + unsigned char data[MAX_PAYLOAD]; +}; + +/* An asocket represents one half of a connection between a local and +** remote entity. A local asocket is bound to a file descriptor. A +** remote asocket is bound to the protocol engine. +*/ +struct asocket { + /* chain pointers for the local/remote list of + ** asockets that this asocket lives in + */ + asocket *next; + asocket *prev; + + /* the unique identifier for this asocket + */ + unsigned id; + + /* flag: set when the socket's peer has closed + ** but packets are still queued for delivery + */ + int closing; + + /* the asocket we are connected to + */ + + asocket *peer; + + /* For local asockets, the fde is used to bind + ** us to our fd event system. For remote asockets + ** these fields are not used. + */ + fdevent fde; + int fd; + + /* queue of apackets waiting to be written + */ + apacket *pkt_first; + apacket *pkt_last; + + /* enqueue is called by our peer when it has data + ** for us. It should return 0 if we can accept more + ** data or 1 if not. If we return 1, we must call + ** peer->ready() when we once again are ready to + ** receive data. + */ + int (*enqueue)(asocket *s, apacket *pkt); + + /* ready is called by the peer when it is ready for + ** us to send data via enqueue again + */ + void (*ready)(asocket *s); + + /* close is called by the peer when it has gone away. + ** we are not allowed to make any further calls on the + ** peer once our close method is called. + */ + void (*close)(asocket *s); + + /* socket-type-specific extradata */ + void *extra; + + /* A socket is bound to atransport */ + atransport *transport; +}; + + +/* the adisconnect structure is used to record a callback that +** will be called whenever a transport is disconnected (e.g. by the user) +** this should be used to cleanup objects that depend on the +** transport (e.g. remote sockets, etc...) +*/ +struct adisconnect +{ + void (*func)(void* opaque, atransport* t); + void* opaque; + adisconnect* next; + adisconnect* prev; +}; + + +/* a transport object models the connection to a remote device or emulator +** there is one transport per connected device/emulator. a "local transport" +** connects through TCP (for the emulator), while a "usb transport" through +** USB (for real devices) +** +** note that kTransportHost doesn't really correspond to a real transport +** object, it's a special value used to indicate that a client wants to +** connect to a service implemented within the ADB server itself. +*/ +typedef enum transport_type { + kTransportUsb, + kTransportLocal, + kTransportAny, + kTransportHost, +} transport_type; + +struct atransport +{ + atransport *next; + atransport *prev; + + int (*read_from_remote)(apacket *p, atransport *t); + int (*write_to_remote)(apacket *p, atransport *t); + void (*close)(atransport *t); + void (*kick)(atransport *t); + + int fd; + int transport_socket; + fdevent transport_fde; + int ref_count; + unsigned sync_token; + int connection_state; + transport_type type; + + /* usb handle or socket fd as needed */ + usb_handle *usb; + int sfd; + + /* used to identify transports for clients */ + char *serial; + char *product; + int adb_port; // Use for emulators (local transport) + + /* a list of adisconnect callbacks called when the transport is kicked */ + int kicked; + adisconnect disconnects; +}; + + +void print_packet(const char *label, apacket *p); + +asocket *find_local_socket(unsigned id); +void install_local_socket(asocket *s); +void remove_socket(asocket *s); +void close_all_sockets(atransport *t); + +#define LOCAL_CLIENT_PREFIX "emulator-" + +asocket *create_local_socket(int fd); +asocket *create_local_service_socket(const char *destination); + +asocket *create_remote_socket(unsigned id, atransport *t); +void connect_to_remote(asocket *s, const char *destination); +void connect_to_smartsocket(asocket *s); + +void fatal(const char *fmt, ...); +void fatal_errno(const char *fmt, ...); + +void handle_packet(apacket *p, atransport *t); +void send_packet(apacket *p, atransport *t); + +void get_my_path(char *s, size_t maxLen); +int launch_server(int server_port); +int adb_main(); + + +/* transports are ref-counted +** get_device_transport does an acquire on your behalf before returning +*/ +void init_transport_registration(void); +int list_transports(char *buf, size_t bufsize); +void update_transports(void); + +asocket* create_device_tracker(void); + +/* Obtain a transport from the available transports. +** If state is != CS_ANY, only transports in that state are considered. +** If serial is non-NULL then only the device with that serial will be chosen. +** If no suitable transport is found, error is set. +*/ +atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out); +void add_transport_disconnect( atransport* t, adisconnect* dis ); +void remove_transport_disconnect( atransport* t, adisconnect* dis ); +void run_transport_disconnects( atransport* t ); +void kick_transport( atransport* t ); + +/* initialize a transport object's func pointers and state */ +#if ADB_HOST +int get_available_local_transport_index(); +#endif +int init_socket_transport(atransport *t, int s, int port, int local); +void init_usb_transport(atransport *t, usb_handle *usb, int state); + +/* for MacOS X cleanup */ +void close_usb_devices(); + +/* cause new transports to be init'd and added to the list */ +void register_socket_transport(int s, const char *serial, int port, int local); + +/* these should only be used for the "adb disconnect" command */ +void unregister_transport(atransport *t); +void unregister_all_tcp_transports(); + +void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable); + +/* this should only be used for transports with connection_state == CS_NOPERM */ +void unregister_usb_transport(usb_handle *usb); + +atransport *find_transport(const char *serial); +#if ADB_HOST +atransport* find_emulator_transport_by_adb_port(int adb_port); +#endif + +int service_to_fd(const char *name); +#if ADB_HOST +asocket *host_service_to_socket(const char* name, const char *serial); +#endif + +#if !ADB_HOST +typedef enum { + BACKUP, + RESTORE +} BackupOperation; +int backup_service(BackupOperation operation, char* args); +void framebuffer_service(int fd, void *cookie); +void log_service(int fd, void *cookie); +void remount_service(int fd, void *cookie); +char * get_log_file_path(const char * log_name); +#endif + +/* packet allocator */ +apacket *get_apacket(void); +void put_apacket(apacket *p); + +int check_header(apacket *p); +int check_data(apacket *p); + +/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */ + +#define ADB_TRACE 1 + +/* IMPORTANT: if you change the following list, don't + * forget to update the corresponding 'tags' table in + * the adb_trace_init() function implemented in adb.c + */ +typedef enum { + TRACE_ADB = 0, /* 0x001 */ + TRACE_SOCKETS, + TRACE_PACKETS, + TRACE_TRANSPORT, + TRACE_RWX, /* 0x010 */ + TRACE_USB, + TRACE_SYNC, + TRACE_SYSDEPS, + TRACE_JDWP, /* 0x100 */ + TRACE_SERVICES, +} AdbTrace; + +#if ADB_TRACE + + extern int adb_trace_mask; + extern unsigned char adb_trace_output_count; + void adb_trace_init(void); + +# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0) + + /* you must define TRACE_TAG before using this macro */ +# define D(...) \ + do { \ + if (ADB_TRACING) { \ + int save_errno = errno; \ + adb_mutex_lock(&D_lock); \ + fprintf(stderr, "%s::%s():", \ + __FILE__, __FUNCTION__); \ + errno = save_errno; \ + fprintf(stderr, __VA_ARGS__ ); \ + fflush(stderr); \ + adb_mutex_unlock(&D_lock); \ + errno = save_errno; \ + } \ + } while (0) +# define DR(...) \ + do { \ + if (ADB_TRACING) { \ + int save_errno = errno; \ + adb_mutex_lock(&D_lock); \ + errno = save_errno; \ + fprintf(stderr, __VA_ARGS__ ); \ + fflush(stderr); \ + adb_mutex_unlock(&D_lock); \ + errno = save_errno; \ + } \ + } while (0) +#else +# define D(...) ((void)0) +# define DR(...) ((void)0) +# define ADB_TRACING 0 +#endif + + +#if !TRACE_PACKETS +#define print_packet(tag,p) do {} while (0) +#endif + +#if ADB_HOST_ON_TARGET +/* adb and adbd are coexisting on the target, so use 5038 for adb + * to avoid conflicting with adbd's usage of 5037 + */ +# define DEFAULT_ADB_PORT 5038 +#else +# define DEFAULT_ADB_PORT 5037 +#endif + +#define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555 + +#define ADB_CLASS 0xff +#define ADB_SUBCLASS 0x42 +#define ADB_PROTOCOL 0x1 + + +void local_init(int port); +int local_connect(int port); +int local_connect_arbitrary_ports(int console_port, int adb_port); + +/* usb host/client interface */ +void usb_init(); +void usb_cleanup(); +int usb_write(usb_handle *h, const void *data, int len); +int usb_read(usb_handle *h, void *data, int len); +int usb_close(usb_handle *h); +void usb_kick(usb_handle *h); + +/* used for USB device detection */ +#if ADB_HOST +int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol); +#endif + +unsigned host_to_le32(unsigned n); +int adb_commandline(int argc, char **argv); + +int connection_state(atransport *t); + +#define CS_ANY -1 +#define CS_OFFLINE 0 +#define CS_BOOTLOADER 1 +#define CS_DEVICE 2 +#define CS_HOST 3 +#define CS_RECOVERY 4 +#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */ +#define CS_SIDELOAD 6 + +extern int HOST; +extern int SHELL_EXIT_NOTIFY_FD; + +#define CHUNK_SIZE (64*1024) + +int sendfailmsg(int fd, const char *reason); +int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s); + +#define ADB_SIDELOAD_FILENAME "/tmp/update.zip" + +#endif diff --git a/src/minadbd/fdevent.c b/src/minadbd/fdevent.c new file mode 100644 index 00000000..5c374a71 --- /dev/null +++ b/src/minadbd/fdevent.c @@ -0,0 +1,695 @@ +/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c +** +** Copyright 2006, Brian Swetland +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "fdevent.h" +#include "transport.h" +#include "sysdeps.h" + + +/* !!! Do not enable DEBUG for the adb that will run as the server: +** both stdout and stderr are used to communicate between the client +** and server. Any extra output will cause failures. +*/ +#define DEBUG 0 /* non-0 will break adb server */ + +// This socket is used when a subproc shell service exists. +// It wakes up the fdevent_loop() and cause the correct handling +// of the shell's pseudo-tty master. I.e. force close it. +int SHELL_EXIT_NOTIFY_FD = -1; + +static void fatal(const char *fn, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:", fn); + vfprintf(stderr, fmt, ap); + va_end(ap); + abort(); +} + +#define FATAL(x...) fatal(__FUNCTION__, x) + +#if DEBUG +#define D(...) \ + do { \ + adb_mutex_lock(&D_lock); \ + int save_errno = errno; \ + fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__); \ + errno = save_errno; \ + fprintf(stderr, __VA_ARGS__); \ + adb_mutex_unlock(&D_lock); \ + errno = save_errno; \ + } while(0) +static void dump_fde(fdevent *fde, const char *info) +{ + adb_mutex_lock(&D_lock); + fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd, + fde->state & FDE_READ ? 'R' : ' ', + fde->state & FDE_WRITE ? 'W' : ' ', + fde->state & FDE_ERROR ? 'E' : ' ', + info); + adb_mutex_unlock(&D_lock); +} +#else +#define D(...) ((void)0) +#define dump_fde(fde, info) do { } while(0) +#endif + +#define FDE_EVENTMASK 0x00ff +#define FDE_STATEMASK 0xff00 + +#define FDE_ACTIVE 0x0100 +#define FDE_PENDING 0x0200 +#define FDE_CREATED 0x0400 + +static void fdevent_plist_enqueue(fdevent *node); +static void fdevent_plist_remove(fdevent *node); +static fdevent *fdevent_plist_dequeue(void); +static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata); + +static fdevent list_pending = { + .next = &list_pending, + .prev = &list_pending, +}; + +static fdevent **fd_table = 0; +static int fd_table_max = 0; + +#ifdef CRAPTASTIC +//HAVE_EPOLL + +#include + +static int epoll_fd = -1; + +static void fdevent_init() +{ + /* XXX: what's a good size for the passed in hint? */ + epoll_fd = epoll_create(256); + + if(epoll_fd < 0) { + perror("epoll_create() failed"); + exit(1); + } + + /* mark for close-on-exec */ + fcntl(epoll_fd, F_SETFD, FD_CLOEXEC); +} + +static void fdevent_connect(fdevent *fde) +{ + struct epoll_event ev; + + memset(&ev, 0, sizeof(ev)); + ev.events = 0; + ev.data.ptr = fde; + +#if 0 + if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) { + perror("epoll_ctl() failed\n"); + exit(1); + } +#endif +} + +static void fdevent_disconnect(fdevent *fde) +{ + struct epoll_event ev; + + memset(&ev, 0, sizeof(ev)); + ev.events = 0; + ev.data.ptr = fde; + + /* technically we only need to delete if we + ** were actively monitoring events, but let's + ** be aggressive and do it anyway, just in case + ** something's out of sync + */ + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev); +} + +static void fdevent_update(fdevent *fde, unsigned events) +{ + struct epoll_event ev; + int active; + + active = (fde->state & FDE_EVENTMASK) != 0; + + memset(&ev, 0, sizeof(ev)); + ev.events = 0; + ev.data.ptr = fde; + + if(events & FDE_READ) ev.events |= EPOLLIN; + if(events & FDE_WRITE) ev.events |= EPOLLOUT; + if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP); + + fde->state = (fde->state & FDE_STATEMASK) | events; + + if(active) { + /* we're already active. if we're changing to *no* + ** events being monitored, we need to delete, otherwise + ** we need to just modify + */ + if(ev.events) { + if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) { + perror("epoll_ctl() failed\n"); + exit(1); + } + } else { + if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) { + perror("epoll_ctl() failed\n"); + exit(1); + } + } + } else { + /* we're not active. if we're watching events, we need + ** to add, otherwise we can just do nothing + */ + if(ev.events) { + if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) { + perror("epoll_ctl() failed\n"); + exit(1); + } + } + } +} + +static void fdevent_process() +{ + struct epoll_event events[256]; + fdevent *fde; + int i, n; + + n = epoll_wait(epoll_fd, events, 256, -1); + + if(n < 0) { + if(errno == EINTR) return; + perror("epoll_wait"); + exit(1); + } + + for(i = 0; i < n; i++) { + struct epoll_event *ev = events + i; + fde = ev->data.ptr; + + if(ev->events & EPOLLIN) { + fde->events |= FDE_READ; + } + if(ev->events & EPOLLOUT) { + fde->events |= FDE_WRITE; + } + if(ev->events & (EPOLLERR | EPOLLHUP)) { + fde->events |= FDE_ERROR; + } + if(fde->events) { + if(fde->state & FDE_PENDING) continue; + fde->state |= FDE_PENDING; + fdevent_plist_enqueue(fde); + } + } +} + +#else /* USE_SELECT */ + +#ifdef HAVE_WINSOCK +#include +#else +#include +#endif + +static fd_set read_fds; +static fd_set write_fds; +static fd_set error_fds; + +static int select_n = 0; + +static void fdevent_init(void) +{ + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + FD_ZERO(&error_fds); +} + +static void fdevent_connect(fdevent *fde) +{ + if(fde->fd >= select_n) { + select_n = fde->fd + 1; + } +} + +static void fdevent_disconnect(fdevent *fde) +{ + int i, n; + + FD_CLR(fde->fd, &read_fds); + FD_CLR(fde->fd, &write_fds); + FD_CLR(fde->fd, &error_fds); + + for(n = 0, i = 0; i < select_n; i++) { + if(fd_table[i] != 0) n = i; + } + select_n = n + 1; +} + +static void fdevent_update(fdevent *fde, unsigned events) +{ + if(events & FDE_READ) { + FD_SET(fde->fd, &read_fds); + } else { + FD_CLR(fde->fd, &read_fds); + } + if(events & FDE_WRITE) { + FD_SET(fde->fd, &write_fds); + } else { + FD_CLR(fde->fd, &write_fds); + } + if(events & FDE_ERROR) { + FD_SET(fde->fd, &error_fds); + } else { + FD_CLR(fde->fd, &error_fds); + } + + fde->state = (fde->state & FDE_STATEMASK) | events; +} + +/* Looks at fd_table[] for bad FDs and sets bit in fds. +** Returns the number of bad FDs. +*/ +static int fdevent_fd_check(fd_set *fds) +{ + int i, n = 0; + fdevent *fde; + + for(i = 0; i < select_n; i++) { + fde = fd_table[i]; + if(fde == 0) continue; + if(fcntl(i, F_GETFL, NULL) < 0) { + FD_SET(i, fds); + n++; + // fde->state |= FDE_DONT_CLOSE; + + } + } + return n; +} + +#if !DEBUG +static inline void dump_all_fds(const char *extra_msg) {} +#else +static void dump_all_fds(const char *extra_msg) +{ +int i; + fdevent *fde; + // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank + char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff; + size_t max_chars = FD_SETSIZE * 6 + 1; + int printed_out; +#define SAFE_SPRINTF(...) \ + do { \ + printed_out = snprintf(pb, max_chars, __VA_ARGS__); \ + if (printed_out <= 0) { \ + D("... snprintf failed.\n"); \ + return; \ + } \ + if (max_chars < (unsigned int)printed_out) { \ + D("... snprintf out of space.\n"); \ + return; \ + } \ + pb += printed_out; \ + max_chars -= printed_out; \ + } while(0) + + for(i = 0; i < select_n; i++) { + fde = fd_table[i]; + SAFE_SPRINTF("%d", i); + if(fde == 0) { + SAFE_SPRINTF("? "); + continue; + } + if(fcntl(i, F_GETFL, NULL) < 0) { + SAFE_SPRINTF("b"); + } + SAFE_SPRINTF(" "); + } + D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff); +} +#endif + +static void fdevent_process() +{ + int i, n; + fdevent *fde; + unsigned events; + fd_set rfd, wfd, efd; + + memcpy(&rfd, &read_fds, sizeof(fd_set)); + memcpy(&wfd, &write_fds, sizeof(fd_set)); + memcpy(&efd, &error_fds, sizeof(fd_set)); + + dump_all_fds("pre select()"); + + n = select(select_n, &rfd, &wfd, &efd, NULL); + int saved_errno = errno; + D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0); + + dump_all_fds("post select()"); + + if(n < 0) { + switch(saved_errno) { + case EINTR: return; + case EBADF: + // Can't trust the FD sets after an error. + FD_ZERO(&wfd); + FD_ZERO(&efd); + FD_ZERO(&rfd); + break; + default: + D("Unexpected select() error=%d\n", saved_errno); + return; + } + } + if(n <= 0) { + // We fake a read, as the rest of the code assumes + // that errors will be detected at that point. + n = fdevent_fd_check(&rfd); + } + + for(i = 0; (i < select_n) && (n > 0); i++) { + events = 0; + if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; } + if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; } + if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; } + + if(events) { + fde = fd_table[i]; + if(fde == 0) + FATAL("missing fde for fd %d\n", i); + + fde->events |= events; + + D("got events fde->fd=%d events=%04x, state=%04x\n", + fde->fd, fde->events, fde->state); + if(fde->state & FDE_PENDING) continue; + fde->state |= FDE_PENDING; + fdevent_plist_enqueue(fde); + } + } +} + +#endif + +static void fdevent_register(fdevent *fde) +{ + if(fde->fd < 0) { + FATAL("bogus negative fd (%d)\n", fde->fd); + } + + if(fde->fd >= fd_table_max) { + int oldmax = fd_table_max; + if(fde->fd > 32000) { + FATAL("bogus huuuuge fd (%d)\n", fde->fd); + } + if(fd_table_max == 0) { + fdevent_init(); + fd_table_max = 256; + } + while(fd_table_max <= fde->fd) { + fd_table_max *= 2; + } + fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max); + if(fd_table == 0) { + FATAL("could not expand fd_table to %d entries\n", fd_table_max); + } + memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax)); + } + + fd_table[fde->fd] = fde; +} + +static void fdevent_unregister(fdevent *fde) +{ + if((fde->fd < 0) || (fde->fd >= fd_table_max)) { + FATAL("fd out of range (%d)\n", fde->fd); + } + + if(fd_table[fde->fd] != fde) { + FATAL("fd_table out of sync [%d]\n", fde->fd); + } + + fd_table[fde->fd] = 0; + + if(!(fde->state & FDE_DONT_CLOSE)) { + dump_fde(fde, "close"); + adb_close(fde->fd); + } +} + +static void fdevent_plist_enqueue(fdevent *node) +{ + fdevent *list = &list_pending; + + node->next = list; + node->prev = list->prev; + node->prev->next = node; + list->prev = node; +} + +static void fdevent_plist_remove(fdevent *node) +{ + node->prev->next = node->next; + node->next->prev = node->prev; + node->next = 0; + node->prev = 0; +} + +static fdevent *fdevent_plist_dequeue(void) +{ + fdevent *list = &list_pending; + fdevent *node = list->next; + + if(node == list) return 0; + + list->next = node->next; + list->next->prev = list; + node->next = 0; + node->prev = 0; + + return node; +} + +static void fdevent_call_fdfunc(fdevent* fde) +{ + unsigned events = fde->events; + fde->events = 0; + if(!(fde->state & FDE_PENDING)) return; + fde->state &= (~FDE_PENDING); + dump_fde(fde, "callback"); + fde->func(fde->fd, events, fde->arg); +} + +static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata) +{ + + D("subproc handling on fd=%d ev=%04x\n", fd, ev); + + // Hook oneself back into the fde's suitable for select() on read. + if((fd < 0) || (fd >= fd_table_max)) { + FATAL("fd %d out of range for fd_table \n", fd); + } + fdevent *fde = fd_table[fd]; + fdevent_add(fde, FDE_READ); + + if(ev & FDE_READ){ + int subproc_fd; + + if(readx(fd, &subproc_fd, sizeof(subproc_fd))) { + FATAL("Failed to read the subproc's fd from fd=%d\n", fd); + } + if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) { + D("subproc_fd %d out of range 0, fd_table_max=%d\n", + subproc_fd, fd_table_max); + return; + } + fdevent *subproc_fde = fd_table[subproc_fd]; + if(!subproc_fde) { + D("subproc_fd %d cleared from fd_table\n", subproc_fd); + return; + } + if(subproc_fde->fd != subproc_fd) { + // Already reallocated? + D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd); + return; + } + + subproc_fde->force_eof = 1; + + int rcount = 0; + ioctl(subproc_fd, FIONREAD, &rcount); + D("subproc with fd=%d has rcount=%d err=%d\n", + subproc_fd, rcount, errno); + + if(rcount) { + // If there is data left, it will show up in the select(). + // This works because there is no other thread reading that + // data when in this fd_func(). + return; + } + + D("subproc_fde.state=%04x\n", subproc_fde->state); + subproc_fde->events |= FDE_READ; + if(subproc_fde->state & FDE_PENDING) { + return; + } + subproc_fde->state |= FDE_PENDING; + fdevent_call_fdfunc(subproc_fde); + } +} + +fdevent *fdevent_create(int fd, fd_func func, void *arg) +{ + fdevent *fde = (fdevent*) malloc(sizeof(fdevent)); + if(fde == 0) return 0; + fdevent_install(fde, fd, func, arg); + fde->state |= FDE_CREATED; + return fde; +} + +void fdevent_destroy(fdevent *fde) +{ + if(fde == 0) return; + if(!(fde->state & FDE_CREATED)) { + FATAL("fde %p not created by fdevent_create()\n", fde); + } + fdevent_remove(fde); +} + +void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) +{ + memset(fde, 0, sizeof(fdevent)); + fde->state = FDE_ACTIVE; + fde->fd = fd; + fde->force_eof = 0; + fde->func = func; + fde->arg = arg; + +#ifndef HAVE_WINSOCK + fcntl(fd, F_SETFL, O_NONBLOCK); +#endif + fdevent_register(fde); + dump_fde(fde, "connect"); + fdevent_connect(fde); + fde->state |= FDE_ACTIVE; +} + +void fdevent_remove(fdevent *fde) +{ + if(fde->state & FDE_PENDING) { + fdevent_plist_remove(fde); + } + + if(fde->state & FDE_ACTIVE) { + fdevent_disconnect(fde); + dump_fde(fde, "disconnect"); + fdevent_unregister(fde); + } + + fde->state = 0; + fde->events = 0; +} + + +void fdevent_set(fdevent *fde, unsigned events) +{ + events &= FDE_EVENTMASK; + + if((fde->state & FDE_EVENTMASK) == events) return; + + if(fde->state & FDE_ACTIVE) { + fdevent_update(fde, events); + dump_fde(fde, "update"); + } + + fde->state = (fde->state & FDE_STATEMASK) | events; + + if(fde->state & FDE_PENDING) { + /* if we're pending, make sure + ** we don't signal an event that + ** is no longer wanted. + */ + fde->events &= (~events); + if(fde->events == 0) { + fdevent_plist_remove(fde); + fde->state &= (~FDE_PENDING); + } + } +} + +void fdevent_add(fdevent *fde, unsigned events) +{ + fdevent_set( + fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK)); +} + +void fdevent_del(fdevent *fde, unsigned events) +{ + fdevent_set( + fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK))); +} + +void fdevent_subproc_setup() +{ + int s[2]; + + if(adb_socketpair(s)) { + FATAL("cannot create shell-exit socket-pair\n"); + } + SHELL_EXIT_NOTIFY_FD = s[0]; + fdevent *fde; + fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL); + if(!fde) + FATAL("cannot create fdevent for shell-exit handler\n"); + fdevent_add(fde, FDE_READ); +} + +void fdevent_loop() +{ + fdevent *fde; + fdevent_subproc_setup(); + + for(;;) { + D("--- ---- waiting for events\n"); + + fdevent_process(); + + while((fde = fdevent_plist_dequeue())) { + fdevent_call_fdfunc(fde); + } + } +} diff --git a/src/minadbd/fdevent.h b/src/minadbd/fdevent.h new file mode 100644 index 00000000..a0ebe2a7 --- /dev/null +++ b/src/minadbd/fdevent.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __FDEVENT_H +#define __FDEVENT_H + +#include /* for int64_t */ + +/* events that may be observed */ +#define FDE_READ 0x0001 +#define FDE_WRITE 0x0002 +#define FDE_ERROR 0x0004 +#define FDE_TIMEOUT 0x0008 + +/* features that may be set (via the events set/add/del interface) */ +#define FDE_DONT_CLOSE 0x0080 + +typedef struct fdevent fdevent; + +typedef void (*fd_func)(int fd, unsigned events, void *userdata); + +/* Allocate and initialize a new fdevent object + * Note: use FD_TIMER as 'fd' to create a fd-less object + * (used to implement timers). +*/ +fdevent *fdevent_create(int fd, fd_func func, void *arg); + +/* Uninitialize and deallocate an fdevent object that was +** created by fdevent_create() +*/ +void fdevent_destroy(fdevent *fde); + +/* Initialize an fdevent object that was externally allocated +*/ +void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg); + +/* Uninitialize an fdevent object that was initialized by +** fdevent_install() +*/ +void fdevent_remove(fdevent *item); + +/* Change which events should cause notifications +*/ +void fdevent_set(fdevent *fde, unsigned events); +void fdevent_add(fdevent *fde, unsigned events); +void fdevent_del(fdevent *fde, unsigned events); + +void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms); + +/* loop forever, handling events. +*/ +void fdevent_loop(); + +struct fdevent +{ + fdevent *next; + fdevent *prev; + + int fd; + int force_eof; + + unsigned short state; + unsigned short events; + + fd_func func; + void *arg; +}; + + +#endif diff --git a/src/minadbd/mutex_list.h b/src/minadbd/mutex_list.h new file mode 100644 index 00000000..652dd734 --- /dev/null +++ b/src/minadbd/mutex_list.h @@ -0,0 +1,26 @@ +/* the list of mutexes used by adb */ +/* #ifndef __MUTEX_LIST_H + * Do not use an include-guard. This file is included once to declare the locks + * and once in win32 to actually do the runtime initialization. + */ +#ifndef ADB_MUTEX +#error ADB_MUTEX not defined when including this file +#endif +ADB_MUTEX(dns_lock) +ADB_MUTEX(socket_list_lock) +ADB_MUTEX(transport_lock) +#if ADB_HOST +ADB_MUTEX(local_transports_lock) +#endif +ADB_MUTEX(usb_lock) + +// Sadly logging to /data/adb/adb-... is not thread safe. +// After modifying adb.h::D() to count invocations: +// DEBUG(jpa):0:Handling main() +// DEBUG(jpa):1:[ usb_init - starting thread ] +// (Oopsies, no :2:, and matching message is also gone.) +// DEBUG(jpa):3:[ usb_thread - opening device ] +// DEBUG(jpa):4:jdwp control socket started (10) +ADB_MUTEX(D_lock) + +#undef ADB_MUTEX diff --git a/src/minadbd/services.c b/src/minadbd/services.c new file mode 100644 index 00000000..aef37f7e --- /dev/null +++ b/src/minadbd/services.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "fdevent.h" + +#define TRACE_TAG TRACE_SERVICES +#include "adb.h" + +typedef struct stinfo stinfo; + +struct stinfo { + void (*func)(int fd, void *cookie); + int fd; + void *cookie; +}; + + +void *service_bootstrap_func(void *x) +{ + stinfo *sti = x; + sti->func(sti->fd, sti->cookie); + free(sti); + return 0; +} + +static void sideload_service(int s, void *cookie) +{ + unsigned char buf[4096]; + unsigned count = (unsigned) cookie; + int fd; + + fprintf(stderr, "sideload_service invoked\n"); + + fd = adb_creat(ADB_SIDELOAD_FILENAME, 0644); + if(fd < 0) { + fprintf(stderr, "failed to create %s\n", ADB_SIDELOAD_FILENAME); + adb_close(s); + return; + } + + while(count > 0) { + unsigned xfer = (count > 4096) ? 4096 : count; + if(readx(s, buf, xfer)) break; + if(writex(fd, buf, xfer)) break; + count -= xfer; + } + + if(count == 0) { + writex(s, "OKAY", 4); + } else { + writex(s, "FAIL", 4); + } + adb_close(fd); + adb_close(s); + + if (count == 0) { + fprintf(stderr, "adbd exiting after successful sideload\n"); + sleep(1); + exit(0); + } +} + + +#if 0 +static void echo_service(int fd, void *cookie) +{ + char buf[4096]; + int r; + char *p; + int c; + + for(;;) { + r = read(fd, buf, 4096); + if(r == 0) goto done; + if(r < 0) { + if(errno == EINTR) continue; + else goto done; + } + + c = r; + p = buf; + while(c > 0) { + r = write(fd, p, c); + if(r > 0) { + c -= r; + p += r; + continue; + } + if((r < 0) && (errno == EINTR)) continue; + goto done; + } + } +done: + close(fd); +} +#endif + +static int create_service_thread(void (*func)(int, void *), void *cookie) +{ + stinfo *sti; + adb_thread_t t; + int s[2]; + + if(adb_socketpair(s)) { + printf("cannot create service socket pair\n"); + return -1; + } + + sti = malloc(sizeof(stinfo)); + if(sti == 0) fatal("cannot allocate stinfo"); + sti->func = func; + sti->cookie = cookie; + sti->fd = s[1]; + + if(adb_thread_create( &t, service_bootstrap_func, sti)){ + free(sti); + adb_close(s[0]); + adb_close(s[1]); + printf("cannot create service thread\n"); + return -1; + } + + D("service thread started, %d:%d\n",s[0], s[1]); + return s[0]; +} + +int service_to_fd(const char *name) +{ + int ret = -1; + + if (!strncmp(name, "sideload:", 9)) { + ret = create_service_thread(sideload_service, (void*) atoi(name + 9)); +#if 0 + } else if(!strncmp(name, "echo:", 5)){ + ret = create_service_thread(echo_service, 0); +#endif + } + if (ret >= 0) { + close_on_exec(ret); + } + return ret; +} diff --git a/src/minadbd/sockets.c b/src/minadbd/sockets.c new file mode 100644 index 00000000..2dd64615 --- /dev/null +++ b/src/minadbd/sockets.c @@ -0,0 +1,730 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "sysdeps.h" + +#define TRACE_TAG TRACE_SOCKETS +#include "adb.h" + +ADB_MUTEX_DEFINE( socket_list_lock ); + +static void local_socket_close_locked(asocket *s); + +int sendfailmsg(int fd, const char *reason) +{ + char buf[9]; + int len; + len = strlen(reason); + if(len > 0xffff) len = 0xffff; + snprintf(buf, sizeof buf, "FAIL%04x", len); + if(writex(fd, buf, 8)) return -1; + return writex(fd, reason, len); +} + +//extern int online; + +static unsigned local_socket_next_id = 1; + +static asocket local_socket_list = { + .next = &local_socket_list, + .prev = &local_socket_list, +}; + +/* the the list of currently closing local sockets. +** these have no peer anymore, but still packets to +** write to their fd. +*/ +static asocket local_socket_closing_list = { + .next = &local_socket_closing_list, + .prev = &local_socket_closing_list, +}; + +asocket *find_local_socket(unsigned id) +{ + asocket *s; + asocket *result = NULL; + + adb_mutex_lock(&socket_list_lock); + for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { + if (s->id == id) { + result = s; + break; + } + } + adb_mutex_unlock(&socket_list_lock); + + return result; +} + +static void +insert_local_socket(asocket* s, asocket* list) +{ + s->next = list; + s->prev = s->next->prev; + s->prev->next = s; + s->next->prev = s; +} + + +void install_local_socket(asocket *s) +{ + adb_mutex_lock(&socket_list_lock); + + s->id = local_socket_next_id++; + insert_local_socket(s, &local_socket_list); + + adb_mutex_unlock(&socket_list_lock); +} + +void remove_socket(asocket *s) +{ + // socket_list_lock should already be held + if (s->prev && s->next) + { + s->prev->next = s->next; + s->next->prev = s->prev; + s->next = 0; + s->prev = 0; + s->id = 0; + } +} + +void close_all_sockets(atransport *t) +{ + asocket *s; + + /* this is a little gross, but since s->close() *will* modify + ** the list out from under you, your options are limited. + */ + adb_mutex_lock(&socket_list_lock); +restart: + for(s = local_socket_list.next; s != &local_socket_list; s = s->next){ + if(s->transport == t || (s->peer && s->peer->transport == t)) { + local_socket_close_locked(s); + goto restart; + } + } + adb_mutex_unlock(&socket_list_lock); +} + +static int local_socket_enqueue(asocket *s, apacket *p) +{ + D("LS(%d): enqueue %d\n", s->id, p->len); + + p->ptr = p->data; + + /* if there is already data queue'd, we will receive + ** events when it's time to write. just add this to + ** the tail + */ + if(s->pkt_first) { + goto enqueue; + } + + /* write as much as we can, until we + ** would block or there is an error/eof + */ + while(p->len > 0) { + int r = adb_write(s->fd, p->ptr, p->len); + if(r > 0) { + p->len -= r; + p->ptr += r; + continue; + } + if((r == 0) || (errno != EAGAIN)) { + D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) ); + s->close(s); + return 1; /* not ready (error) */ + } else { + break; + } + } + + if(p->len == 0) { + put_apacket(p); + return 0; /* ready for more data */ + } + +enqueue: + p->next = 0; + if(s->pkt_first) { + s->pkt_last->next = p; + } else { + s->pkt_first = p; + } + s->pkt_last = p; + + /* make sure we are notified when we can drain the queue */ + fdevent_add(&s->fde, FDE_WRITE); + + return 1; /* not ready (backlog) */ +} + +static void local_socket_ready(asocket *s) +{ + /* far side is ready for data, pay attention to + readable events */ + fdevent_add(&s->fde, FDE_READ); +// D("LS(%d): ready()\n", s->id); +} + +static void local_socket_close(asocket *s) +{ + adb_mutex_lock(&socket_list_lock); + local_socket_close_locked(s); + adb_mutex_unlock(&socket_list_lock); +} + +// be sure to hold the socket list lock when calling this +static void local_socket_destroy(asocket *s) +{ + apacket *p, *n; + D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd); + + /* IMPORTANT: the remove closes the fd + ** that belongs to this socket + */ + fdevent_remove(&s->fde); + + /* dispose of any unwritten data */ + for(p = s->pkt_first; p; p = n) { + D("LS(%d): discarding %d bytes\n", s->id, p->len); + n = p->next; + put_apacket(p); + } + remove_socket(s); + free(s); +} + + +static void local_socket_close_locked(asocket *s) +{ + D("entered. LS(%d) fd=%d\n", s->id, s->fd); + if(s->peer) { + D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n", + s->id, s->peer->id, s->peer->fd); + s->peer->peer = 0; + // tweak to avoid deadlock + if (s->peer->close == local_socket_close) { + local_socket_close_locked(s->peer); + } else { + s->peer->close(s->peer); + } + s->peer = 0; + } + + /* If we are already closing, or if there are no + ** pending packets, destroy immediately + */ + if (s->closing || s->pkt_first == NULL) { + int id = s->id; + local_socket_destroy(s); + D("LS(%d): closed\n", id); + return; + } + + /* otherwise, put on the closing list + */ + D("LS(%d): closing\n", s->id); + s->closing = 1; + fdevent_del(&s->fde, FDE_READ); + remove_socket(s); + D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd); + insert_local_socket(s, &local_socket_closing_list); +} + +static void local_socket_event_func(int fd, unsigned ev, void *_s) +{ + asocket *s = _s; + + D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev); + + /* put the FDE_WRITE processing before the FDE_READ + ** in order to simplify the code. + */ + if(ev & FDE_WRITE){ + apacket *p; + + while((p = s->pkt_first) != 0) { + while(p->len > 0) { + int r = adb_write(fd, p->ptr, p->len); + if(r > 0) { + p->ptr += r; + p->len -= r; + continue; + } + if(r < 0) { + /* returning here is ok because FDE_READ will + ** be processed in the next iteration loop + */ + if(errno == EAGAIN) return; + if(errno == EINTR) continue; + } + D(" closing after write because r=%d and errno is %d\n", r, errno); + s->close(s); + return; + } + + if(p->len == 0) { + s->pkt_first = p->next; + if(s->pkt_first == 0) s->pkt_last = 0; + put_apacket(p); + } + } + + /* if we sent the last packet of a closing socket, + ** we can now destroy it. + */ + if (s->closing) { + D(" closing because 'closing' is set after write\n"); + s->close(s); + return; + } + + /* no more packets queued, so we can ignore + ** writable events again and tell our peer + ** to resume writing + */ + fdevent_del(&s->fde, FDE_WRITE); + s->peer->ready(s->peer); + } + + + if(ev & FDE_READ){ + apacket *p = get_apacket(); + unsigned char *x = p->data; + size_t avail = MAX_PAYLOAD; + int r; + int is_eof = 0; + + while(avail > 0) { + r = adb_read(fd, x, avail); + D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail); + if(r > 0) { + avail -= r; + x += r; + continue; + } + if(r < 0) { + if(errno == EAGAIN) break; + if(errno == EINTR) continue; + } + + /* r = 0 or unhandled error */ + is_eof = 1; + break; + } + D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n", + s->id, s->fd, r, is_eof, s->fde.force_eof); + if((avail == MAX_PAYLOAD) || (s->peer == 0)) { + put_apacket(p); + } else { + p->len = MAX_PAYLOAD - avail; + + r = s->peer->enqueue(s->peer, p); + D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r); + + if(r < 0) { + /* error return means they closed us as a side-effect + ** and we must return immediately. + ** + ** note that if we still have buffered packets, the + ** socket will be placed on the closing socket list. + ** this handler function will be called again + ** to process FDE_WRITE events. + */ + return; + } + + if(r > 0) { + /* if the remote cannot accept further events, + ** we disable notification of READs. They'll + ** be enabled again when we get a call to ready() + */ + fdevent_del(&s->fde, FDE_READ); + } + } + /* Don't allow a forced eof if data is still there */ + if((s->fde.force_eof && !r) || is_eof) { + D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof); + s->close(s); + } + } + + if(ev & FDE_ERROR){ + /* this should be caught be the next read or write + ** catching it here means we may skip the last few + ** bytes of readable data. + */ +// s->close(s); + D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd); + + return; + } +} + +asocket *create_local_socket(int fd) +{ + asocket *s = calloc(1, sizeof(asocket)); + if (s == NULL) fatal("cannot allocate socket"); + s->fd = fd; + s->enqueue = local_socket_enqueue; + s->ready = local_socket_ready; + s->close = local_socket_close; + install_local_socket(s); + + fdevent_install(&s->fde, fd, local_socket_event_func, s); +/* fdevent_add(&s->fde, FDE_ERROR); */ + //fprintf(stderr, "Created local socket in create_local_socket \n"); + D("LS(%d): created (fd=%d)\n", s->id, s->fd); + return s; +} + +asocket *create_local_service_socket(const char *name) +{ + asocket *s; + int fd; + + fd = service_to_fd(name); + if(fd < 0) return 0; + + s = create_local_socket(fd); + D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); + return s; +} + +/* a Remote socket is used to send/receive data to/from a given transport object +** it needs to be closed when the transport is forcibly destroyed by the user +*/ +typedef struct aremotesocket { + asocket socket; + adisconnect disconnect; +} aremotesocket; + +static int remote_socket_enqueue(asocket *s, apacket *p) +{ + D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n", + s->id, s->fd, s->peer->fd); + p->msg.command = A_WRTE; + p->msg.arg0 = s->peer->id; + p->msg.arg1 = s->id; + p->msg.data_length = p->len; + send_packet(p, s->transport); + return 1; +} + +static void remote_socket_ready(asocket *s) +{ + D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n", + s->id, s->fd, s->peer->fd); + apacket *p = get_apacket(); + p->msg.command = A_OKAY; + p->msg.arg0 = s->peer->id; + p->msg.arg1 = s->id; + send_packet(p, s->transport); +} + +static void remote_socket_close(asocket *s) +{ + D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n", + s->id, s->fd, s->peer?s->peer->fd:-1); + apacket *p = get_apacket(); + p->msg.command = A_CLSE; + if(s->peer) { + p->msg.arg0 = s->peer->id; + s->peer->peer = 0; + D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n", + s->id, s->peer->id, s->peer->fd); + s->peer->close(s->peer); + } + p->msg.arg1 = s->id; + send_packet(p, s->transport); + D("RS(%d): closed\n", s->id); + remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); + free(s); +} + +static void remote_socket_disconnect(void* _s, atransport* t) +{ + asocket* s = _s; + asocket* peer = s->peer; + + D("remote_socket_disconnect RS(%d)\n", s->id); + if (peer) { + peer->peer = NULL; + peer->close(peer); + } + remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); + free(s); +} + +asocket *create_remote_socket(unsigned id, atransport *t) +{ + asocket *s = calloc(1, sizeof(aremotesocket)); + adisconnect* dis = &((aremotesocket*)s)->disconnect; + + if (s == NULL) fatal("cannot allocate socket"); + s->id = id; + s->enqueue = remote_socket_enqueue; + s->ready = remote_socket_ready; + s->close = remote_socket_close; + s->transport = t; + + dis->func = remote_socket_disconnect; + dis->opaque = s; + add_transport_disconnect( t, dis ); + D("RS(%d): created\n", s->id); + return s; +} + +void connect_to_remote(asocket *s, const char *destination) +{ + D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd); + apacket *p = get_apacket(); + int len = strlen(destination) + 1; + + if(len > (MAX_PAYLOAD-1)) { + fatal("destination oversized"); + } + + D("LS(%d): connect('%s')\n", s->id, destination); + p->msg.command = A_OPEN; + p->msg.arg0 = s->id; + p->msg.data_length = len; + strcpy((char*) p->data, destination); + send_packet(p, s->transport); +} + + +/* this is used by magic sockets to rig local sockets to + send the go-ahead message when they connect */ +static void local_socket_ready_notify(asocket *s) +{ + s->ready = local_socket_ready; + s->close = local_socket_close; + adb_write(s->fd, "OKAY", 4); + s->ready(s); +} + +/* this is used by magic sockets to rig local sockets to + send the failure message if they are closed before + connected (to avoid closing them without a status message) */ +static void local_socket_close_notify(asocket *s) +{ + s->ready = local_socket_ready; + s->close = local_socket_close; + sendfailmsg(s->fd, "closed"); + s->close(s); +} + +unsigned unhex(unsigned char *s, int len) +{ + unsigned n = 0, c; + + while(len-- > 0) { + switch((c = *s++)) { + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': case '8': + case '9': + c -= '0'; + break; + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + c = c - 'a' + 10; + break; + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': + c = c - 'A' + 10; + break; + default: + return 0xffffffff; + } + + n = (n << 4) | c; + } + + return n; +} + +/* skip_host_serial return the position in a string + skipping over the 'serial' parameter in the ADB protocol, + where parameter string may be a host:port string containing + the protocol delimiter (colon). */ +char *skip_host_serial(char *service) { + char *first_colon, *serial_end; + + first_colon = strchr(service, ':'); + if (!first_colon) { + /* No colon in service string. */ + return NULL; + } + serial_end = first_colon; + if (isdigit(serial_end[1])) { + serial_end++; + while ((*serial_end) && isdigit(*serial_end)) { + serial_end++; + } + if ((*serial_end) != ':') { + // Something other than numbers was found, reset the end. + serial_end = first_colon; + } + } + return serial_end; +} + +static int smart_socket_enqueue(asocket *s, apacket *p) +{ + unsigned len; + + D("SS(%d): enqueue %d\n", s->id, p->len); + + if(s->pkt_first == 0) { + s->pkt_first = p; + s->pkt_last = p; + } else { + if((s->pkt_first->len + p->len) > MAX_PAYLOAD) { + D("SS(%d): overflow\n", s->id); + put_apacket(p); + goto fail; + } + + memcpy(s->pkt_first->data + s->pkt_first->len, + p->data, p->len); + s->pkt_first->len += p->len; + put_apacket(p); + + p = s->pkt_first; + } + + /* don't bother if we can't decode the length */ + if(p->len < 4) return 0; + + len = unhex(p->data, 4); + if((len < 1) || (len > 1024)) { + D("SS(%d): bad size (%d)\n", s->id, len); + goto fail; + } + + D("SS(%d): len is %d\n", s->id, len ); + /* can't do anything until we have the full header */ + if((len + 4) > p->len) { + D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len); + return 0; + } + + p->data[len + 4] = 0; + + D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4)); + + if (s->transport == NULL) { + char* error_string = "unknown failure"; + s->transport = acquire_one_transport (CS_ANY, + kTransportAny, NULL, &error_string); + + if (s->transport == NULL) { + sendfailmsg(s->peer->fd, error_string); + goto fail; + } + } + + if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) { + /* if there's no remote we fail the connection + ** right here and terminate it + */ + sendfailmsg(s->peer->fd, "device offline (x)"); + goto fail; + } + + + /* instrument our peer to pass the success or fail + ** message back once it connects or closes, then + ** detach from it, request the connection, and + ** tear down + */ + s->peer->ready = local_socket_ready_notify; + s->peer->close = local_socket_close_notify; + s->peer->peer = 0; + /* give him our transport and upref it */ + s->peer->transport = s->transport; + + connect_to_remote(s->peer, (char*) (p->data + 4)); + s->peer = 0; + s->close(s); + return 1; + +fail: + /* we're going to close our peer as a side-effect, so + ** return -1 to signal that state to the local socket + ** who is enqueueing against us + */ + s->close(s); + return -1; +} + +static void smart_socket_ready(asocket *s) +{ + D("SS(%d): ready\n", s->id); +} + +static void smart_socket_close(asocket *s) +{ + D("SS(%d): closed\n", s->id); + if(s->pkt_first){ + put_apacket(s->pkt_first); + } + if(s->peer) { + s->peer->peer = 0; + s->peer->close(s->peer); + s->peer = 0; + } + free(s); +} + +asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act)) +{ + D("Creating smart socket \n"); + asocket *s = calloc(1, sizeof(asocket)); + if (s == NULL) fatal("cannot allocate socket"); + s->enqueue = smart_socket_enqueue; + s->ready = smart_socket_ready; + s->close = smart_socket_close; + s->extra = action_cb; + + D("SS(%d): created %p\n", s->id, action_cb); + return s; +} + +void smart_socket_action(asocket *s, const char *act) +{ + +} + +void connect_to_smartsocket(asocket *s) +{ + D("Connecting to smart socket \n"); + asocket *ss = create_smart_socket(smart_socket_action); + s->peer = ss; + ss->peer = s; + s->ready(s); +} diff --git a/src/minadbd/sysdeps.h b/src/minadbd/sysdeps.h new file mode 100644 index 00000000..800ddb75 --- /dev/null +++ b/src/minadbd/sysdeps.h @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* this file contains system-dependent definitions used by ADB + * they're related to threads, sockets and file descriptors + */ +#ifndef _ADB_SYSDEPS_H +#define _ADB_SYSDEPS_H + +#ifdef __CYGWIN__ +# undef _WIN32 +#endif + +#ifdef _WIN32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OS_PATH_SEPARATOR '\\' +#define OS_PATH_SEPARATOR_STR "\\" + +typedef CRITICAL_SECTION adb_mutex_t; + +#define ADB_MUTEX_DEFINE(x) adb_mutex_t x + +/* declare all mutexes */ +/* For win32, adb_sysdeps_init() will do the mutex runtime initialization. */ +#define ADB_MUTEX(x) extern adb_mutex_t x; +#include "mutex_list.h" + +extern void adb_sysdeps_init(void); + +static __inline__ void adb_mutex_lock( adb_mutex_t* lock ) +{ + EnterCriticalSection( lock ); +} + +static __inline__ void adb_mutex_unlock( adb_mutex_t* lock ) +{ + LeaveCriticalSection( lock ); +} + +typedef struct { unsigned tid; } adb_thread_t; + +typedef void* (*adb_thread_func_t)(void* arg); + +typedef void (*win_thread_func_t)(void* arg); + +static __inline__ int adb_thread_create( adb_thread_t *thread, adb_thread_func_t func, void* arg) +{ + thread->tid = _beginthread( (win_thread_func_t)func, 0, arg ); + if (thread->tid == (unsigned)-1L) { + return -1; + } + return 0; +} + +static __inline__ void close_on_exec(int fd) +{ + /* nothing really */ +} + +extern void disable_tcp_nagle(int fd); + +#define lstat stat /* no symlinks on Win32 */ + +#define S_ISLNK(m) 0 /* no symlinks on Win32 */ + +static __inline__ int adb_unlink(const char* path) +{ + int rc = unlink(path); + + if (rc == -1 && errno == EACCES) { + /* unlink returns EACCES when the file is read-only, so we first */ + /* try to make it writable, then unlink again... */ + rc = chmod(path, _S_IREAD|_S_IWRITE ); + if (rc == 0) + rc = unlink(path); + } + return rc; +} +#undef unlink +#define unlink ___xxx_unlink + +static __inline__ int adb_mkdir(const char* path, int mode) +{ + return _mkdir(path); +} +#undef mkdir +#define mkdir ___xxx_mkdir + +extern int adb_open(const char* path, int options); +extern int adb_creat(const char* path, int mode); +extern int adb_read(int fd, void* buf, int len); +extern int adb_write(int fd, const void* buf, int len); +extern int adb_lseek(int fd, int pos, int where); +extern int adb_shutdown(int fd); +extern int adb_close(int fd); + +static __inline__ int unix_close(int fd) +{ + return close(fd); +} +#undef close +#define close ____xxx_close + +static __inline__ int unix_read(int fd, void* buf, size_t len) +{ + return read(fd, buf, len); +} +#undef read +#define read ___xxx_read + +static __inline__ int unix_write(int fd, const void* buf, size_t len) +{ + return write(fd, buf, len); +} +#undef write +#define write ___xxx_write + +static __inline__ int adb_open_mode(const char* path, int options, int mode) +{ + return adb_open(path, options); +} + +static __inline__ int unix_open(const char* path, int options,...) +{ + if ((options & O_CREAT) == 0) + { + return open(path, options); + } + else + { + int mode; + va_list args; + va_start( args, options ); + mode = va_arg( args, int ); + va_end( args ); + return open(path, options, mode); + } +} +#define open ___xxx_unix_open + + +/* normally provided by */ +extern void* load_file(const char* pathname, unsigned* psize); + +/* normally provided by */ +extern int socket_loopback_client(int port, int type); +extern int socket_network_client(const char *host, int port, int type); +extern int socket_loopback_server(int port, int type); +extern int socket_inaddr_any_server(int port, int type); + +/* normally provided by "fdevent.h" */ + +#define FDE_READ 0x0001 +#define FDE_WRITE 0x0002 +#define FDE_ERROR 0x0004 +#define FDE_DONT_CLOSE 0x0080 + +typedef struct fdevent fdevent; + +typedef void (*fd_func)(int fd, unsigned events, void *userdata); + +fdevent *fdevent_create(int fd, fd_func func, void *arg); +void fdevent_destroy(fdevent *fde); +void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg); +void fdevent_remove(fdevent *item); +void fdevent_set(fdevent *fde, unsigned events); +void fdevent_add(fdevent *fde, unsigned events); +void fdevent_del(fdevent *fde, unsigned events); +void fdevent_loop(); + +struct fdevent { + fdevent *next; + fdevent *prev; + + int fd; + int force_eof; + + unsigned short state; + unsigned short events; + + fd_func func; + void *arg; +}; + +static __inline__ void adb_sleep_ms( int mseconds ) +{ + Sleep( mseconds ); +} + +extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen); + +#undef accept +#define accept ___xxx_accept + +static __inline__ int adb_socket_setbufsize( int fd, int bufsize ) +{ + int opt = bufsize; + return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)); +} + +extern int adb_socketpair( int sv[2] ); + +static __inline__ char* adb_dirstart( const char* path ) +{ + char* p = strchr(path, '/'); + char* p2 = strchr(path, '\\'); + + if ( !p ) + p = p2; + else if ( p2 && p2 > p ) + p = p2; + + return p; +} + +static __inline__ char* adb_dirstop( const char* path ) +{ + char* p = strrchr(path, '/'); + char* p2 = strrchr(path, '\\'); + + if ( !p ) + p = p2; + else if ( p2 && p2 > p ) + p = p2; + + return p; +} + +static __inline__ int adb_is_absolute_host_path( const char* path ) +{ + return isalpha(path[0]) && path[1] == ':' && path[2] == '\\'; +} + +#else /* !_WIN32 a.k.a. Unix */ + +#include "fdevent.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define OS_PATH_SEPARATOR '/' +#define OS_PATH_SEPARATOR_STR "/" + +typedef pthread_mutex_t adb_mutex_t; + +#define ADB_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define adb_mutex_init pthread_mutex_init +#define adb_mutex_lock pthread_mutex_lock +#define adb_mutex_unlock pthread_mutex_unlock +#define adb_mutex_destroy pthread_mutex_destroy + +#define ADB_MUTEX_DEFINE(m) adb_mutex_t m = PTHREAD_MUTEX_INITIALIZER + +#define adb_cond_t pthread_cond_t +#define adb_cond_init pthread_cond_init +#define adb_cond_wait pthread_cond_wait +#define adb_cond_broadcast pthread_cond_broadcast +#define adb_cond_signal pthread_cond_signal +#define adb_cond_destroy pthread_cond_destroy + +/* declare all mutexes */ +#define ADB_MUTEX(x) extern adb_mutex_t x; +#include "mutex_list.h" + +static __inline__ void close_on_exec(int fd) +{ + fcntl( fd, F_SETFD, FD_CLOEXEC ); +} + +static __inline__ int unix_open(const char* path, int options,...) +{ + if ((options & O_CREAT) == 0) + { + return open(path, options); + } + else + { + int mode; + va_list args; + va_start( args, options ); + mode = va_arg( args, int ); + va_end( args ); + return open(path, options, mode); + } +} + +static __inline__ int adb_open_mode( const char* pathname, int options, int mode ) +{ + return open( pathname, options, mode ); +} + +static __inline__ int adb_creat(const char* path, int mode) +{ + int fd = open(path, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, mode); + + if ( fd < 0 ) + return -1; + + close_on_exec(fd); + return fd; +} +#undef creat +#define creat ___xxx_creat + +static __inline__ int adb_open( const char* pathname, int options ) +{ + int fd = open( pathname, options ); + if (fd < 0) + return -1; + close_on_exec( fd ); + return fd; +} +#undef open +#define open ___xxx_open + +static __inline__ int adb_shutdown(int fd) +{ + return shutdown(fd, SHUT_RDWR); +} +#undef shutdown +#define shutdown ____xxx_shutdown + +static __inline__ int adb_close(int fd) +{ + return close(fd); +} +#undef close +#define close ____xxx_close + + +static __inline__ int adb_read(int fd, void* buf, size_t len) +{ + return read(fd, buf, len); +} + +#undef read +#define read ___xxx_read + +static __inline__ int adb_write(int fd, const void* buf, size_t len) +{ + return write(fd, buf, len); +} +#undef write +#define write ___xxx_write + +static __inline__ int adb_lseek(int fd, int pos, int where) +{ + return lseek(fd, pos, where); +} +#undef lseek +#define lseek ___xxx_lseek + +static __inline__ int adb_unlink(const char* path) +{ + return unlink(path); +} +#undef unlink +#define unlink ___xxx_unlink + +static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) +{ + int fd; + + fd = accept(serverfd, addr, addrlen); + if (fd >= 0) + close_on_exec(fd); + + return fd; +} + +#undef accept +#define accept ___xxx_accept + +#define unix_read adb_read +#define unix_write adb_write +#define unix_close adb_close + +typedef pthread_t adb_thread_t; + +typedef void* (*adb_thread_func_t)( void* arg ); + +static __inline__ int adb_thread_create( adb_thread_t *pthread, adb_thread_func_t start, void* arg ) +{ + pthread_attr_t attr; + + pthread_attr_init (&attr); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + return pthread_create( pthread, &attr, start, arg ); +} + +static __inline__ int adb_socket_setbufsize( int fd, int bufsize ) +{ + int opt = bufsize; + return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); +} + +static __inline__ void disable_tcp_nagle(int fd) +{ + int on = 1; + setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) ); +} + + +static __inline__ int unix_socketpair( int d, int type, int protocol, int sv[2] ) +{ + return socketpair( d, type, protocol, sv ); +} + +static __inline__ int adb_socketpair( int sv[2] ) +{ + int rc; + + rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv ); + if (rc < 0) + return -1; + + close_on_exec( sv[0] ); + close_on_exec( sv[1] ); + return 0; +} + +#undef socketpair +#define socketpair ___xxx_socketpair + +static __inline__ void adb_sleep_ms( int mseconds ) +{ + usleep( mseconds*1000 ); +} + +static __inline__ int adb_mkdir(const char* path, int mode) +{ + return mkdir(path, mode); +} +#undef mkdir +#define mkdir ___xxx_mkdir + +static __inline__ void adb_sysdeps_init(void) +{ +} + +static __inline__ char* adb_dirstart(const char* path) +{ + return strchr(path, '/'); +} + +static __inline__ char* adb_dirstop(const char* path) +{ + return strrchr(path, '/'); +} + +static __inline__ int adb_is_absolute_host_path( const char* path ) +{ + return path[0] == '/'; +} + +#endif /* !_WIN32 */ + +#endif /* _ADB_SYSDEPS_H */ diff --git a/src/minadbd/transport.c b/src/minadbd/transport.c new file mode 100644 index 00000000..ff200493 --- /dev/null +++ b/src/minadbd/transport.c @@ -0,0 +1,824 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "sysdeps.h" + +#define TRACE_TAG TRACE_TRANSPORT +#include "adb.h" + +static void transport_unref(atransport *t); + +static atransport transport_list = { + .next = &transport_list, + .prev = &transport_list, +}; + +ADB_MUTEX_DEFINE( transport_lock ); + +#if ADB_TRACE +#define MAX_DUMP_HEX_LEN 16 +static void dump_hex( const unsigned char* ptr, size_t len ) +{ + int nn, len2 = len; + // Build a string instead of logging each character. + // MAX chars in 2 digit hex, one space, MAX chars, one '\0'. + char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer; + + if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN; + + for (nn = 0; nn < len2; nn++) { + sprintf(pb, "%02x", ptr[nn]); + pb += 2; + } + sprintf(pb++, " "); + + for (nn = 0; nn < len2; nn++) { + int c = ptr[nn]; + if (c < 32 || c > 127) + c = '.'; + *pb++ = c; + } + *pb++ = '\0'; + DR("%s\n", buffer); +} +#endif + +void +kick_transport(atransport* t) +{ + if (t && !t->kicked) + { + int kicked; + + adb_mutex_lock(&transport_lock); + kicked = t->kicked; + if (!kicked) + t->kicked = 1; + adb_mutex_unlock(&transport_lock); + + if (!kicked) + t->kick(t); + } +} + +void +run_transport_disconnects(atransport* t) +{ + adisconnect* dis = t->disconnects.next; + + D("%s: run_transport_disconnects\n", t->serial); + while (dis != &t->disconnects) { + adisconnect* next = dis->next; + dis->func( dis->opaque, t ); + dis = next; + } +} + +#if ADB_TRACE +static void +dump_packet(const char* name, const char* func, apacket* p) +{ + unsigned command = p->msg.command; + int len = p->msg.data_length; + char cmd[9]; + char arg0[12], arg1[12]; + int n; + + for (n = 0; n < 4; n++) { + int b = (command >> (n*8)) & 255; + if (b < 32 || b >= 127) + break; + cmd[n] = (char)b; + } + if (n == 4) { + cmd[4] = 0; + } else { + /* There is some non-ASCII name in the command, so dump + * the hexadecimal value instead */ + snprintf(cmd, sizeof cmd, "%08x", command); + } + + if (p->msg.arg0 < 256U) + snprintf(arg0, sizeof arg0, "%d", p->msg.arg0); + else + snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0); + + if (p->msg.arg1 < 256U) + snprintf(arg1, sizeof arg1, "%d", p->msg.arg1); + else + snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1); + + D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", + name, func, cmd, arg0, arg1, len); + dump_hex(p->data, len); +} +#endif /* ADB_TRACE */ + +static int +read_packet(int fd, const char* name, apacket** ppacket) +{ + char *p = (char*)ppacket; /* really read a packet address */ + int r; + int len = sizeof(*ppacket); + char buff[8]; + if (!name) { + snprintf(buff, sizeof buff, "fd=%d", fd); + name = buff; + } + while(len > 0) { + r = adb_read(fd, p, len); + if(r > 0) { + len -= r; + p += r; + } else { + D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); + if((r < 0) && (errno == EINTR)) continue; + return -1; + } + } + +#if ADB_TRACE + if (ADB_TRACING) { + dump_packet(name, "from remote", *ppacket); + } +#endif + return 0; +} + +static int +write_packet(int fd, const char* name, apacket** ppacket) +{ + char *p = (char*) ppacket; /* we really write the packet address */ + int r, len = sizeof(ppacket); + char buff[8]; + if (!name) { + snprintf(buff, sizeof buff, "fd=%d", fd); + name = buff; + } + +#if ADB_TRACE + if (ADB_TRACING) { + dump_packet(name, "to remote", *ppacket); + } +#endif + len = sizeof(ppacket); + while(len > 0) { + r = adb_write(fd, p, len); + if(r > 0) { + len -= r; + p += r; + } else { + D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); + if((r < 0) && (errno == EINTR)) continue; + return -1; + } + } + return 0; +} + +static void transport_socket_events(int fd, unsigned events, void *_t) +{ + atransport *t = _t; + D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events); + if(events & FDE_READ){ + apacket *p = 0; + if(read_packet(fd, t->serial, &p)){ + D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd); + } else { + handle_packet(p, (atransport *) _t); + } + } +} + +void send_packet(apacket *p, atransport *t) +{ + unsigned char *x; + unsigned sum; + unsigned count; + + p->msg.magic = p->msg.command ^ 0xffffffff; + + count = p->msg.data_length; + x = (unsigned char *) p->data; + sum = 0; + while(count-- > 0){ + sum += *x++; + } + p->msg.data_check = sum; + + print_packet("send", p); + + if (t == NULL) { + D("Transport is null \n"); + // Zap errno because print_packet() and other stuff have errno effect. + errno = 0; + fatal_errno("Transport is null"); + } + + if(write_packet(t->transport_socket, t->serial, &p)){ + fatal_errno("cannot enqueue packet on transport socket"); + } +} + +/* The transport is opened by transport_register_func before +** the input and output threads are started. +** +** The output thread issues a SYNC(1, token) message to let +** the input thread know to start things up. In the event +** of transport IO failure, the output thread will post a +** SYNC(0,0) message to ensure shutdown. +** +** The transport will not actually be closed until both +** threads exit, but the input thread will kick the transport +** on its way out to disconnect the underlying device. +*/ + +static void *output_thread(void *_t) +{ + atransport *t = _t; + apacket *p; + + D("%s: starting transport output thread on fd %d, SYNC online (%d)\n", + t->serial, t->fd, t->sync_token + 1); + p = get_apacket(); + p->msg.command = A_SYNC; + p->msg.arg0 = 1; + p->msg.arg1 = ++(t->sync_token); + p->msg.magic = A_SYNC ^ 0xffffffff; + if(write_packet(t->fd, t->serial, &p)) { + put_apacket(p); + D("%s: failed to write SYNC packet\n", t->serial); + goto oops; + } + + D("%s: data pump started\n", t->serial); + for(;;) { + p = get_apacket(); + + if(t->read_from_remote(p, t) == 0){ + D("%s: received remote packet, sending to transport\n", + t->serial); + if(write_packet(t->fd, t->serial, &p)){ + put_apacket(p); + D("%s: failed to write apacket to transport\n", t->serial); + goto oops; + } + } else { + D("%s: remote read failed for transport\n", t->serial); + put_apacket(p); + break; + } + } + + D("%s: SYNC offline for transport\n", t->serial); + p = get_apacket(); + p->msg.command = A_SYNC; + p->msg.arg0 = 0; + p->msg.arg1 = 0; + p->msg.magic = A_SYNC ^ 0xffffffff; + if(write_packet(t->fd, t->serial, &p)) { + put_apacket(p); + D("%s: failed to write SYNC apacket to transport", t->serial); + } + +oops: + D("%s: transport output thread is exiting\n", t->serial); + kick_transport(t); + transport_unref(t); + return 0; +} + +static void *input_thread(void *_t) +{ + atransport *t = _t; + apacket *p; + int active = 0; + + D("%s: starting transport input thread, reading from fd %d\n", + t->serial, t->fd); + + for(;;){ + if(read_packet(t->fd, t->serial, &p)) { + D("%s: failed to read apacket from transport on fd %d\n", + t->serial, t->fd ); + break; + } + if(p->msg.command == A_SYNC){ + if(p->msg.arg0 == 0) { + D("%s: transport SYNC offline\n", t->serial); + put_apacket(p); + break; + } else { + if(p->msg.arg1 == t->sync_token) { + D("%s: transport SYNC online\n", t->serial); + active = 1; + } else { + D("%s: transport ignoring SYNC %d != %d\n", + t->serial, p->msg.arg1, t->sync_token); + } + } + } else { + if(active) { + D("%s: transport got packet, sending to remote\n", t->serial); + t->write_to_remote(p, t); + } else { + D("%s: transport ignoring packet while offline\n", t->serial); + } + } + + put_apacket(p); + } + + // this is necessary to avoid a race condition that occured when a transport closes + // while a client socket is still active. + close_all_sockets(t); + + D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd); + kick_transport(t); + transport_unref(t); + return 0; +} + + +static int transport_registration_send = -1; +static int transport_registration_recv = -1; +static fdevent transport_registration_fde; + +void update_transports(void) +{ + // nothing to do on the device side +} + +typedef struct tmsg tmsg; +struct tmsg +{ + atransport *transport; + int action; +}; + +static int +transport_read_action(int fd, struct tmsg* m) +{ + char *p = (char*)m; + int len = sizeof(*m); + int r; + + while(len > 0) { + r = adb_read(fd, p, len); + if(r > 0) { + len -= r; + p += r; + } else { + if((r < 0) && (errno == EINTR)) continue; + D("transport_read_action: on fd %d, error %d: %s\n", + fd, errno, strerror(errno)); + return -1; + } + } + return 0; +} + +static int +transport_write_action(int fd, struct tmsg* m) +{ + char *p = (char*)m; + int len = sizeof(*m); + int r; + + while(len > 0) { + r = adb_write(fd, p, len); + if(r > 0) { + len -= r; + p += r; + } else { + if((r < 0) && (errno == EINTR)) continue; + D("transport_write_action: on fd %d, error %d: %s\n", + fd, errno, strerror(errno)); + return -1; + } + } + return 0; +} + +static void transport_registration_func(int _fd, unsigned ev, void *data) +{ + tmsg m; + adb_thread_t output_thread_ptr; + adb_thread_t input_thread_ptr; + int s[2]; + atransport *t; + + if(!(ev & FDE_READ)) { + return; + } + + if(transport_read_action(_fd, &m)) { + fatal_errno("cannot read transport registration socket"); + } + + t = m.transport; + + if(m.action == 0){ + D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket); + + /* IMPORTANT: the remove closes one half of the + ** socket pair. The close closes the other half. + */ + fdevent_remove(&(t->transport_fde)); + adb_close(t->fd); + + adb_mutex_lock(&transport_lock); + t->next->prev = t->prev; + t->prev->next = t->next; + adb_mutex_unlock(&transport_lock); + + run_transport_disconnects(t); + + if (t->product) + free(t->product); + if (t->serial) + free(t->serial); + + memset(t,0xee,sizeof(atransport)); + free(t); + + update_transports(); + return; + } + + /* don't create transport threads for inaccessible devices */ + if (t->connection_state != CS_NOPERM) { + /* initial references are the two threads */ + t->ref_count = 2; + + if(adb_socketpair(s)) { + fatal_errno("cannot open transport socketpair"); + } + + D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]); + + t->transport_socket = s[0]; + t->fd = s[1]; + + fdevent_install(&(t->transport_fde), + t->transport_socket, + transport_socket_events, + t); + + fdevent_set(&(t->transport_fde), FDE_READ); + + if(adb_thread_create(&input_thread_ptr, input_thread, t)){ + fatal_errno("cannot create input thread"); + } + + if(adb_thread_create(&output_thread_ptr, output_thread, t)){ + fatal_errno("cannot create output thread"); + } + } + + /* put us on the master device list */ + adb_mutex_lock(&transport_lock); + t->next = &transport_list; + t->prev = transport_list.prev; + t->next->prev = t; + t->prev->next = t; + adb_mutex_unlock(&transport_lock); + + t->disconnects.next = t->disconnects.prev = &t->disconnects; + + update_transports(); +} + +void init_transport_registration(void) +{ + int s[2]; + + if(adb_socketpair(s)){ + fatal_errno("cannot open transport registration socketpair"); + } + + transport_registration_send = s[0]; + transport_registration_recv = s[1]; + + fdevent_install(&transport_registration_fde, + transport_registration_recv, + transport_registration_func, + 0); + + fdevent_set(&transport_registration_fde, FDE_READ); +} + +/* the fdevent select pump is single threaded */ +static void register_transport(atransport *transport) +{ + tmsg m; + m.transport = transport; + m.action = 1; + D("transport: %s registered\n", transport->serial); + if(transport_write_action(transport_registration_send, &m)) { + fatal_errno("cannot write transport registration socket\n"); + } +} + +static void remove_transport(atransport *transport) +{ + tmsg m; + m.transport = transport; + m.action = 0; + D("transport: %s removed\n", transport->serial); + if(transport_write_action(transport_registration_send, &m)) { + fatal_errno("cannot write transport registration socket\n"); + } +} + + +static void transport_unref_locked(atransport *t) +{ + t->ref_count--; + if (t->ref_count == 0) { + D("transport: %s unref (kicking and closing)\n", t->serial); + if (!t->kicked) { + t->kicked = 1; + t->kick(t); + } + t->close(t); + remove_transport(t); + } else { + D("transport: %s unref (count=%d)\n", t->serial, t->ref_count); + } +} + +static void transport_unref(atransport *t) +{ + if (t) { + adb_mutex_lock(&transport_lock); + transport_unref_locked(t); + adb_mutex_unlock(&transport_lock); + } +} + +void add_transport_disconnect(atransport* t, adisconnect* dis) +{ + adb_mutex_lock(&transport_lock); + dis->next = &t->disconnects; + dis->prev = dis->next->prev; + dis->prev->next = dis; + dis->next->prev = dis; + adb_mutex_unlock(&transport_lock); +} + +void remove_transport_disconnect(atransport* t, adisconnect* dis) +{ + dis->prev->next = dis->next; + dis->next->prev = dis->prev; + dis->next = dis->prev = dis; +} + + +atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out) +{ + atransport *t; + atransport *result = NULL; + int ambiguous = 0; + +retry: + if (error_out) + *error_out = "device not found"; + + adb_mutex_lock(&transport_lock); + for (t = transport_list.next; t != &transport_list; t = t->next) { + if (t->connection_state == CS_NOPERM) { + if (error_out) + *error_out = "insufficient permissions for device"; + continue; + } + + /* check for matching serial number */ + if (serial) { + if (t->serial && !strcmp(serial, t->serial)) { + result = t; + break; + } + } else { + if (ttype == kTransportUsb && t->type == kTransportUsb) { + if (result) { + if (error_out) + *error_out = "more than one device"; + ambiguous = 1; + result = NULL; + break; + } + result = t; + } else if (ttype == kTransportLocal && t->type == kTransportLocal) { + if (result) { + if (error_out) + *error_out = "more than one emulator"; + ambiguous = 1; + result = NULL; + break; + } + result = t; + } else if (ttype == kTransportAny) { + if (result) { + if (error_out) + *error_out = "more than one device and emulator"; + ambiguous = 1; + result = NULL; + break; + } + result = t; + } + } + } + adb_mutex_unlock(&transport_lock); + + if (result) { + /* offline devices are ignored -- they are either being born or dying */ + if (result && result->connection_state == CS_OFFLINE) { + if (error_out) + *error_out = "device offline"; + result = NULL; + } + /* check for required connection state */ + if (result && state != CS_ANY && result->connection_state != state) { + if (error_out) + *error_out = "invalid device state"; + result = NULL; + } + } + + if (result) { + /* found one that we can take */ + if (error_out) + *error_out = NULL; + } else if (state != CS_ANY && (serial || !ambiguous)) { + adb_sleep_ms(1000); + goto retry; + } + + return result; +} + +void register_socket_transport(int s, const char *serial, int port, int local) +{ + atransport *t = calloc(1, sizeof(atransport)); + char buff[32]; + + if (!serial) { + snprintf(buff, sizeof buff, "T-%p", t); + serial = buff; + } + D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port); + if ( init_socket_transport(t, s, port, local) < 0 ) { + adb_close(s); + free(t); + return; + } + if(serial) { + t->serial = strdup(serial); + } + register_transport(t); +} + +void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable) +{ + atransport *t = calloc(1, sizeof(atransport)); + D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, + serial ? serial : ""); + init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM)); + if(serial) { + t->serial = strdup(serial); + } + register_transport(t); +} + +/* this should only be used for transports with connection_state == CS_NOPERM */ +void unregister_usb_transport(usb_handle *usb) +{ + atransport *t; + adb_mutex_lock(&transport_lock); + for(t = transport_list.next; t != &transport_list; t = t->next) { + if (t->usb == usb && t->connection_state == CS_NOPERM) { + t->next->prev = t->prev; + t->prev->next = t->next; + break; + } + } + adb_mutex_unlock(&transport_lock); +} + +#undef TRACE_TAG +#define TRACE_TAG TRACE_RWX + +int readx(int fd, void *ptr, size_t len) +{ + char *p = ptr; + int r; +#if ADB_TRACE + int len0 = len; +#endif + D("readx: fd=%d wanted=%d\n", fd, (int)len); + while(len > 0) { + r = adb_read(fd, p, len); + if(r > 0) { + len -= r; + p += r; + } else { + if (r < 0) { + D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); + if (errno == EINTR) + continue; + } else { + D("readx: fd=%d disconnected\n", fd); + } + return -1; + } + } + +#if ADB_TRACE + D("readx: fd=%d wanted=%d got=%d\n", fd, len0, len0 - len); + dump_hex( ptr, len0 ); +#endif + return 0; +} + +int writex(int fd, const void *ptr, size_t len) +{ + char *p = (char*) ptr; + int r; + +#if ADB_TRACE + D("writex: fd=%d len=%d: ", fd, (int)len); + dump_hex( ptr, len ); +#endif + while(len > 0) { + r = adb_write(fd, p, len); + if(r > 0) { + len -= r; + p += r; + } else { + if (r < 0) { + D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); + if (errno == EINTR) + continue; + } else { + D("writex: fd=%d disconnected\n", fd); + } + return -1; + } + } + return 0; +} + +int check_header(apacket *p) +{ + if(p->msg.magic != (p->msg.command ^ 0xffffffff)) { + D("check_header(): invalid magic\n"); + return -1; + } + + if(p->msg.data_length > MAX_PAYLOAD) { + D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length); + return -1; + } + + return 0; +} + +int check_data(apacket *p) +{ + unsigned count, sum; + unsigned char *x; + + count = p->msg.data_length; + x = p->data; + sum = 0; + while(count-- > 0) { + sum += *x++; + } + + if(sum != p->msg.data_check) { + return -1; + } else { + return 0; + } +} diff --git a/src/minadbd/transport.h b/src/minadbd/transport.h new file mode 100644 index 00000000..992e0528 --- /dev/null +++ b/src/minadbd/transport.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TRANSPORT_H +#define __TRANSPORT_H + +/* convenience wrappers around read/write that will retry on +** EINTR and/or short read/write. Returns 0 on success, -1 +** on error or EOF. +*/ +int readx(int fd, void *ptr, size_t len); +int writex(int fd, const void *ptr, size_t len); +#endif /* __TRANSPORT_H */ diff --git a/src/minadbd/transport_usb.c b/src/minadbd/transport_usb.c new file mode 100644 index 00000000..91cbf615 --- /dev/null +++ b/src/minadbd/transport_usb.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#define TRACE_TAG TRACE_TRANSPORT +#include "adb.h" + +#ifdef HAVE_BIG_ENDIAN +#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) +static inline void fix_endians(apacket *p) +{ + p->msg.command = H4(p->msg.command); + p->msg.arg0 = H4(p->msg.arg0); + p->msg.arg1 = H4(p->msg.arg1); + p->msg.data_length = H4(p->msg.data_length); + p->msg.data_check = H4(p->msg.data_check); + p->msg.magic = H4(p->msg.magic); +} +unsigned host_to_le32(unsigned n) +{ + return H4(n); +} +#else +#define fix_endians(p) do {} while (0) +unsigned host_to_le32(unsigned n) +{ + return n; +} +#endif + +static int remote_read(apacket *p, atransport *t) +{ + if(usb_read(t->usb, &p->msg, sizeof(amessage))){ + D("remote usb: read terminated (message)\n"); + return -1; + } + + fix_endians(p); + + if(check_header(p)) { + D("remote usb: check_header failed\n"); + return -1; + } + + if(p->msg.data_length) { + if(usb_read(t->usb, p->data, p->msg.data_length)){ + D("remote usb: terminated (data)\n"); + return -1; + } + } + + if(check_data(p)) { + D("remote usb: check_data failed\n"); + return -1; + } + + return 0; +} + +static int remote_write(apacket *p, atransport *t) +{ + unsigned size = p->msg.data_length; + + fix_endians(p); + + if(usb_write(t->usb, &p->msg, sizeof(amessage))) { + D("remote usb: 1 - write terminated\n"); + return -1; + } + if(p->msg.data_length == 0) return 0; + if(usb_write(t->usb, &p->data, size)) { + D("remote usb: 2 - write terminated\n"); + return -1; + } + + return 0; +} + +static void remote_close(atransport *t) +{ + usb_close(t->usb); + t->usb = 0; +} + +static void remote_kick(atransport *t) +{ + usb_kick(t->usb); +} + +void init_usb_transport(atransport *t, usb_handle *h, int state) +{ + D("transport: usb\n"); + t->close = remote_close; + t->kick = remote_kick; + t->read_from_remote = remote_read; + t->write_to_remote = remote_write; + t->sync_token = 1; + t->connection_state = state; + t->type = kTransportUsb; + t->usb = h; + + HOST = 0; +} diff --git a/src/minadbd/usb_linux_client.c b/src/minadbd/usb_linux_client.c new file mode 100644 index 00000000..635fa4bb --- /dev/null +++ b/src/minadbd/usb_linux_client.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "sysdeps.h" + +#define TRACE_TAG TRACE_USB +#include "adb.h" + + +struct usb_handle +{ + int fd; + adb_cond_t notify; + adb_mutex_t lock; +}; + +void usb_cleanup() +{ + // nothing to do here +} + +static void *usb_open_thread(void *x) +{ + struct usb_handle *usb = (struct usb_handle *)x; + int fd; + + while (1) { + // wait until the USB device needs opening + adb_mutex_lock(&usb->lock); + while (usb->fd != -1) + adb_cond_wait(&usb->notify, &usb->lock); + adb_mutex_unlock(&usb->lock); + + D("[ usb_thread - opening device ]\n"); + do { + /* XXX use inotify? */ + fd = unix_open("/dev/android_adb", O_RDWR); + if (fd < 0) { + // to support older kernels + fd = unix_open("/dev/android", O_RDWR); + } + if (fd < 0) { + adb_sleep_ms(1000); + } + } while (fd < 0); + D("[ opening device succeeded ]\n"); + + close_on_exec(fd); + usb->fd = fd; + + D("[ usb_thread - registering device ]\n"); + register_usb_transport(usb, 0, 1); + } + + // never gets here + return 0; +} + +int usb_write(usb_handle *h, const void *data, int len) +{ + int n; + + D("about to write (fd=%d, len=%d)\n", h->fd, len); + n = adb_write(h->fd, data, len); + if(n != len) { + D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", + h->fd, n, errno, strerror(errno)); + return -1; + } + D("[ done fd=%d ]\n", h->fd); + return 0; +} + +int usb_read(usb_handle *h, void *data, int len) +{ + int n; + + D("about to read (fd=%d, len=%d)\n", h->fd, len); + n = adb_read(h->fd, data, len); + if(n != len) { + D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", + h->fd, n, errno, strerror(errno)); + return -1; + } + D("[ done fd=%d ]\n", h->fd); + return 0; +} + +void usb_init() +{ + usb_handle *h; + adb_thread_t tid; + int fd; + + h = calloc(1, sizeof(usb_handle)); + h->fd = -1; + adb_cond_init(&h->notify, 0); + adb_mutex_init(&h->lock, 0); + + // Open the file /dev/android_adb_enable to trigger + // the enabling of the adb USB function in the kernel. + // We never touch this file again - just leave it open + // indefinitely so the kernel will know when we are running + // and when we are not. + fd = unix_open("/dev/android_adb_enable", O_RDWR); + if (fd < 0) { + D("failed to open /dev/android_adb_enable\n"); + } else { + close_on_exec(fd); + } + + D("[ usb_init - starting thread ]\n"); + if(adb_thread_create(&tid, usb_open_thread, h)){ + fatal_errno("cannot create usb thread"); + } +} + +void usb_kick(usb_handle *h) +{ + D("usb_kick\n"); + adb_mutex_lock(&h->lock); + adb_close(h->fd); + h->fd = -1; + + // notify usb_open_thread that we are disconnected + adb_cond_signal(&h->notify); + adb_mutex_unlock(&h->lock); +} + +int usb_close(usb_handle *h) +{ + // nothing to do here + return 0; +} diff --git a/src/minadbd/utils.c b/src/minadbd/utils.c new file mode 100644 index 00000000..91518bab --- /dev/null +++ b/src/minadbd/utils.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "utils.h" +#include +#include +#include + +char* +buff_addc (char* buff, char* buffEnd, int c) +{ + int avail = buffEnd - buff; + + if (avail <= 0) /* already in overflow mode */ + return buff; + + if (avail == 1) { /* overflowing, the last byte is reserved for zero */ + buff[0] = 0; + return buff + 1; + } + + buff[0] = (char) c; /* add char and terminating zero */ + buff[1] = 0; + return buff + 1; +} + +char* +buff_adds (char* buff, char* buffEnd, const char* s) +{ + int slen = strlen(s); + + return buff_addb(buff, buffEnd, s, slen); +} + +char* +buff_addb (char* buff, char* buffEnd, const void* data, int len) +{ + int avail = (buffEnd - buff); + + if (avail <= 0 || len <= 0) /* already overflowing */ + return buff; + + if (len > avail) + len = avail; + + memcpy(buff, data, len); + + buff += len; + + /* ensure there is a terminating zero */ + if (buff >= buffEnd) { /* overflow */ + buff[-1] = 0; + } else + buff[0] = 0; + + return buff; +} + +char* +buff_add (char* buff, char* buffEnd, const char* format, ... ) +{ + int avail; + + avail = (buffEnd - buff); + + if (avail > 0) { + va_list args; + int nn; + + va_start(args, format); + nn = vsnprintf( buff, avail, format, args); + va_end(args); + + if (nn < 0) { + /* some C libraries return -1 in case of overflow, + * but they will also do that if the format spec is + * invalid. We assume ADB is not buggy enough to + * trigger that last case. */ + nn = avail; + } + else if (nn > avail) { + nn = avail; + } + + buff += nn; + + /* ensure that there is a terminating zero */ + if (buff >= buffEnd) + buff[-1] = 0; + else + buff[0] = 0; + } + return buff; +} diff --git a/src/minadbd/utils.h b/src/minadbd/utils.h new file mode 100644 index 00000000..f70ecd24 --- /dev/null +++ b/src/minadbd/utils.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _ADB_UTILS_H +#define _ADB_UTILS_H + +/* bounded buffer functions */ + +/* all these functions are used to append data to a bounded buffer. + * + * after each operation, the buffer is guaranteed to be zero-terminated, + * even in the case of an overflow. they all return the new buffer position + * which allows one to use them in succession, only checking for overflows + * at the end. For example: + * + * BUFF_DECL(temp,p,end,1024); + * char* p; + * + * p = buff_addc(temp, end, '"'); + * p = buff_adds(temp, end, string); + * p = buff_addc(temp, end, '"'); + * + * if (p >= end) { + * overflow detected. note that 'temp' is + * zero-terminated for safety. + * } + * return strdup(temp); + */ + +/* tries to add a character to the buffer, in case of overflow + * this will only write a terminating zero and return buffEnd. + */ +char* buff_addc (char* buff, char* buffEnd, int c); + +/* tries to add a string to the buffer */ +char* buff_adds (char* buff, char* buffEnd, const char* s); + +/* tries to add a bytes to the buffer. the input can contain zero bytes, + * but a terminating zero will always be appended at the end anyway + */ +char* buff_addb (char* buff, char* buffEnd, const void* data, int len); + +/* tries to add a formatted string to a bounded buffer */ +char* buff_add (char* buff, char* buffEnd, const char* format, ... ); + +/* convenience macro used to define a bounded buffer, as well as + * a 'cursor' and 'end' variables all in one go. + * + * note: this doesn't place an initial terminating zero in the buffer, + * you need to use one of the buff_ functions for this. or simply + * do _cursor[0] = 0 manually. + */ +#define BUFF_DECL(_buff,_cursor,_end,_size) \ + char _buff[_size], *_cursor=_buff, *_end = _cursor + (_size) + +#endif /* _ADB_UTILS_H */ diff --git a/src/miui/Android.mk b/src/miui/Android.mk index a03a1eea..827f51fb 100755 --- a/src/miui/Android.mk +++ b/src/miui/Android.mk @@ -77,7 +77,15 @@ LOCAL_SRC_FILES := \ $(libmiui_common_src_files) LOCAL_C_INCLUDES += $(libmiui_common_includes) LOCAL_CFLAGS := $(MYDEFINE_CFLAGS) - +ifeq ($(TARGET_USE_PIXEL_FORMAT_BGR565), true) +LOCAL_CFLAGS += -DPIXEL_FORMAT_BGR565 +endif +ifeq ($(BOARD_HAS_DUALSYSTEM_PARTITIONS), true) +LOCAL_CFLAGS += -DDUALSYSTEM_PARTITIONS +endif +ifeq ($(TARGET_NEEDS_VSYNC), true) +LOCAL_CFLAGS += -DNEEDS_VSYNC +endif LOCAL_STATIC_LIBRARIES += libc libm LOCAL_MODULE := libmiui diff --git a/src/miui/src/libs/miui_graph.c b/src/miui/src/libs/miui_graph.c index 09cd795b..184d397d 100755 --- a/src/miui/src/libs/miui_graph.c +++ b/src/miui/src/libs/miui_graph.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -158,7 +160,6 @@ static void ag_changecolorspace(int r, int g, int b, int a){ } } - int ag_changcolor(char ch1, char ch2, char ch3, char ch4) { int i = 0; @@ -196,7 +197,6 @@ int ag_changcolor(char ch1, char ch2, char ch3, char ch4) ag_changecolorspace(arg[0], arg[1], arg[2], arg[3]); return 0; } - /*********************************[ FUNCTIONS ]********************************/ //-- INITIALIZING AMARULLZ GRAPHIC byte ag_init(){ @@ -210,7 +210,9 @@ byte ag_init(){ //-- Init Info from IO ioctl(ag_fb, FBIOGET_FSCREENINFO, &ag_fbf); ioctl(ag_fb, FBIOGET_VSCREENINFO, &ag_fbv); - +#ifdef PIXEL_FORMAT_BGR565 + ag_fbv.bits_per_pixel = 16; +#endif //-- Init 32 Buffer ag_canvas(&ag_c,ag_fbv.xres,ag_fbv.yres); ag_dp = floor( min(ag_fbv.xres,ag_fbv.yres) / 160); @@ -218,7 +220,7 @@ byte ag_init(){ //-- Init Frame Buffer Size agclp = (ag_fbv.bits_per_pixel>>3); ag_fbsz = (ag_fbv.xres * ag_fbv.yres * ((agclp==3)?4:agclp)); - + //-- Init Frame Buffer miui_debug("ag_fbv.bits_per_pixel = %d\n", ag_fbv.bits_per_pixel); if (ag_fbv.bits_per_pixel==16){ @@ -237,11 +239,12 @@ byte ag_init(){ close(ag_fb); return -1; } + ag_32 = 0; ag_fbuf = (word*) mmap(0,ag_fbf.smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,ag_fb,0); ag_b = (word*) malloc(ag_fbsz); ag_bz = (word*) malloc(ag_fbsz); - + //-- Resolution with Stride ag_16strd = 0; ag_16w = ag_fbf.line_length/2; @@ -279,7 +282,7 @@ byte ag_init(){ } else{ ag_32 = 1; - + //-- Memory Allocation ag_fbuf32 = (byte*) mmap(0,ag_fbf.smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,ag_fb,0); ag_bf32 = (dword*) malloc(ag_fbsz); @@ -602,12 +605,20 @@ void ag_refreshrate(){ //-- Force Refresh Display ag_fbv.yoffset = 0; ag_fbv.activate |= FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; - ioctl(ag_fb, FBIOPUT_VSCREENINFO, &ag_fbv); + ioctl(ag_fb, FBIOPUT_VSCREENINFO, &ag_fbv); +#ifdef NEEDS_VSYNC + int e; + ioctl(ag_fb, MSMFB_OVERLAY_VSYNC_CTRL, &e); +#endif } byte ag_sync_locked = 0; //-- Sync Display void ag_sync(){ +#ifdef NEEDS_VSYNC + int e; + ioctl(ag_fb, MSMFB_OVERLAY_VSYNC_CTRL, &e); +#endif //-- Always On Footer // ag_draw_foot(); ag_isbusy = 0; @@ -632,12 +643,20 @@ void ag_sync(){ } } void ag_sync_force(){ +#ifdef NEEDS_VSYNC + int e; + ioctl(ag_fb, MSMFB_OVERLAY_VSYNC_CTRL, &e); +#endif if (ag_sync_locked) ag_sync_locked = 0; else ag_sync(); } static void *ag_sync_fade_thread(void * cookie){ +#ifdef NEEDS_VSYNC + int e; + ioctl(ag_fb, MSMFB_OVERLAY_VSYNC_CTRL, &e); +#endif miui_debug("pthread %s start...\n", __FUNCTION__); int frame = (int) cookie; ag_isbusy = 0; @@ -701,10 +720,18 @@ static void *ag_sync_fade_thread(void * cookie){ return NULL; } void ag_sync_fade_wait(int frame){ +#ifdef NEEDS_VSYNC + int e; + ioctl(ag_fb, MSMFB_OVERLAY_VSYNC_CTRL, &e); +#endif ag_sync_fade_thread((void *) frame); return; } void ag_sync_fade(int frame){ +#ifdef NEEDS_VSYNC + int e; + ioctl(ag_fb, MSMFB_OVERLAY_VSYNC_CTRL, &e); +#endif pthread_t threadsyncfade; pthread_create(&threadsyncfade,NULL, ag_sync_fade_thread, (void *) frame); pthread_detach(threadsyncfade); diff --git a/src/miui/src/main/backup_ui.c b/src/miui/src/main/backup_ui.c index 4441e9b1..f4d2248c 100755 --- a/src/miui/src/main/backup_ui.c +++ b/src/miui/src/main/backup_ui.c @@ -24,6 +24,13 @@ #define RESTORE_BOOT 15 #define RESTORE_RECOVERY 16 +#ifdef DUALSYSTEM_PARTITIONS +#define BACKUP_SYSTEM1 17 +#define BACKUP_BOOT1 18 +#define RESTORE_SYSTEM1 19 +#define RESTORE_BOOT1 20 +#endif + static struct _menuUnit* p_current = NULL; static struct _menuUnit* backup_menu = NULL; static STATUS backup_restore(char* path) @@ -32,20 +39,32 @@ static STATUS backup_restore(char* path) miui_busy_process(); switch(p_current->result) { case RESTORE_ALL: - miuiIntent_send(INTENT_RESTORE, 7, path, "1", "1", "1", "1", "0", "0"); +#ifdef DUALSYSTEM_PARTITIONS + miuiIntent_send(INTENT_RESTORE, 9, path, "1", "1", "1", "1", "0", "0", "1", "1"); +#else + miuiIntent_send(INTENT_RESTORE, 9, path, "1", "1", "1", "1", "0", "0", "0", "0"); +#endif break; case RESTORE_CACHE: - miuiIntent_send(INTENT_RESTORE, 7, path, "0", "0", "0", "1", "0", "0"); + miuiIntent_send(INTENT_RESTORE, 9, path, "0", "0", "0", "1", "0", "0", "0", "0"); break; case RESTORE_DATA: - miuiIntent_send(INTENT_RESTORE, 7, path, "0", "0", "1", "0", "0", "0"); + miuiIntent_send(INTENT_RESTORE, 9, path, "0", "0", "1", "0", "0", "0", "0", "0"); break; case RESTORE_SYSTEM: - miuiIntent_send(INTENT_RESTORE, 7, path, "0", "1", "0", "0", "0", "0"); + miuiIntent_send(INTENT_RESTORE, 9, path, "0", "1", "0", "0", "0", "0", "0", "0"); break; case RESTORE_BOOT: - miuiIntent_send(INTENT_RESTORE, 7, path, "1", "0", "0", "0", "0", "0"); + miuiIntent_send(INTENT_RESTORE, 9, path, "1", "0", "0", "0", "0", "0", "0", "0"); + break; +#ifdef DUALSYSTEM_PARTITIONS + case RESTORE_SYSTEM1: + miuiIntent_send(INTENT_RESTORE, 9, path, "0", "0", "0", "0", "0", "0", "0", "1"); + break; + case RESTORE_BOOT1: + miuiIntent_send(INTENT_RESTORE, 9, path, "0", "0", "0", "0", "0", "0", "1", "0"); break; +#endif default: miui_error("p->resulte %d should not be the value\n", p_current->result); break; @@ -187,6 +206,14 @@ static STATUS restore_child_show(menuUnit* p) case RESTORE_BOOT: snprintf(path_name,PATH_MAX, "%s/backup/boot", RECOVERY_PATH); break; +#ifdef DUALSYSTEM_PARTITIONS + case RESTORE_SYSTEM1: + snprintf(path_name,PATH_MAX, "%s/backup/system1", RECOVERY_PATH); + break; + case RESTORE_BOOT1: + snprintf(path_name,PATH_MAX, "%s/backup/boot1", RECOVERY_PATH); + break; +#endif default: miui_error("p->resulte %d should not be the value\n", p->result); return MENU_BACK; @@ -198,7 +225,6 @@ static STATUS restore_child_show(menuUnit* p) static STATUS backup_child_show(menuUnit* p) { p_current = p; - miuiIntent_send(INTENT_MOUNT, 1, "/sdcard"); char path_name[PATH_MAX]; static time_t timep; static struct tm *time_tm; @@ -238,6 +264,20 @@ static STATUS backup_child_show(menuUnit* p) time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min); miuiIntent_send(INTENT_ADVANCED_BACKUP, 2 , path_name, "/boot"); break; +#ifdef DUALSYSTEM_PARTITIONS + case BACKUP_SYSTEM1: + snprintf(path_name,PATH_MAX, "%s/backup/system1/%02d%02d%02d-%02d%02d", + RECOVERY_PATH, time_tm->tm_year, + time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min); + miuiIntent_send(INTENT_ADVANCED_BACKUP, 2 , path_name, "/system1"); + break; + case BACKUP_BOOT1: + snprintf(path_name,PATH_MAX, "%s/backup/boot1/%02d%02d%02d-%02d%02d", + RECOVERY_PATH, time_tm->tm_year, + time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min); + miuiIntent_send(INTENT_ADVANCED_BACKUP, 2 , path_name, "/boot1"); + break; +#endif default: miui_error("p->resulte %d should not be the value\n", p->result); break; @@ -258,12 +298,27 @@ struct _menuUnit* advanced_backup_ui_init() menuUnit_set_name(temp, "<~advanced_backup.boot.name>"); menuUnit_set_result(temp, BACKUP_BOOT); menuUnit_set_show(temp, &backup_child_show); +#ifdef DUALSYSTEM_PARTITIONS + temp = common_ui_init(); + assert_if_fail(menuNode_add(p, temp) == RET_OK); + menuUnit_set_name(temp, "<~advanced_backup.boot1.name>"); + menuUnit_set_result(temp, BACKUP_BOOT1); + menuUnit_set_show(temp, &backup_child_show); +#endif //backup system temp = common_ui_init(); assert_if_fail(menuNode_add(p, temp) == RET_OK); menuUnit_set_name(temp, "<~advanced_backup.system.name>"); menuUnit_set_result(temp, BACKUP_SYSTEM); menuUnit_set_show(temp, &backup_child_show); +#ifdef DUALSYSTEM_PARTITIONS + //backup system + temp = common_ui_init(); + assert_if_fail(menuNode_add(p, temp) == RET_OK); + menuUnit_set_name(temp, "<~advanced_backup.system1.name>"); + menuUnit_set_result(temp, BACKUP_SYSTEM1); + menuUnit_set_show(temp, &backup_child_show); +#endif //backup data temp = common_ui_init(); assert_if_fail(menuNode_add(p, temp) == RET_OK); @@ -291,12 +346,28 @@ struct _menuUnit* advanced_restore_ui_init() menuUnit_set_name(temp, "<~advanced_restore.boot.name>"); menuUnit_set_result(temp, RESTORE_BOOT); menuUnit_set_show(temp, &restore_child_show); +#ifdef DUALSYSTEM_PARTITIONS + //restore boot1 + temp = common_ui_init(); + assert_if_fail(menuNode_add(p, temp) == RET_OK); + menuUnit_set_name(temp, "<~advanced_restore.boot1.name>"); + menuUnit_set_result(temp, RESTORE_BOOT1); + menuUnit_set_show(temp, &restore_child_show); +#endif //restore system temp = common_ui_init(); assert_if_fail(menuNode_add(p, temp) == RET_OK); menuUnit_set_name(temp, "<~advanced_restore.system.name>"); menuUnit_set_result(temp, RESTORE_SYSTEM); menuUnit_set_show(temp, &restore_child_show); +#ifdef DUALSYSTEM_PARTITIONS + //restore system + temp = common_ui_init(); + assert_if_fail(menuNode_add(p, temp) == RET_OK); + menuUnit_set_name(temp, "<~advanced_restore.sys.name>"); + menuUnit_set_result(temp, RESTORE_SYSTEM1); + menuUnit_set_show(temp, &restore_child_show); +#endif //restore data temp = common_ui_init(); assert_if_fail(menuNode_add(p, temp) == RET_OK); diff --git a/src/miui/src/main/miui_ui.c b/src/miui/src/main/miui_ui.c index bfb6e4ae..156892b6 100755 --- a/src/miui/src/main/miui_ui.c +++ b/src/miui/src/main/miui_ui.c @@ -174,30 +174,36 @@ static int _miui_setbg_title(CANVAS *win, CANVAS *bg) { static int _miui_draw_battery(CANVAS *win, int x, int y, color fg, color bg) { char batt_name[8]; + float batt_percent; struct stat st; - if (stat(BATTERY_CAPACITY_PATH, &st) >= 0) + if (stat(BATTERY_CAPACITY_PATH, &st) >= 0) { snprintf(batt_name, 8, "%2d", read_int(BATTERY_CAPACITY_PATH)); - else if (stat(BATTERY_CAPACITY_PATH_1, &st) >= 0) + batt_percent = 1.0 * read_int(BATTERY_CAPACITY_PATH) / 100; + } + else if (stat(BATTERY_CAPACITY_PATH_1, &st) >= 0) { snprintf(batt_name, 8, "%2d", read_int(BATTERY_CAPACITY_PATH_1)); + batt_percent = 1.0 * read_int(BATTERY_CAPACITY_PATH_1) / 100; + } else{ miui_error("BATTERY_CAPACITY_PATH error\n"); snprintf(batt_name, 8, "%2d", 0); } - int txtX = x+4; int txtY = y; int txtH = ag_fontheight(0); int txtW = ag_fontheight(0)*2; - int battW = 12*agdp(); - ag_rect(win, txtX, y+1, battW, txtH-3, fg); - ag_rect(win, txtX+1, y+2, battW - 2, txtH-5, bg); + int battW = 10*agdp(); + float fillW = batt_percent * battW; + ag_rect(win, txtX-2, y+1, battW, txtH-3, fg); + ag_rect(win, txtX-1, y+2, battW-2, txtH-5, bg); + ag_rect(win, txtX, y+3, fillW-4, txtH-7, fg); txtX += agdp(); - ag_textf(win, txtW, txtX+1, txtY+1, batt_name, bg, 0); - ag_textf(win, txtW, txtX, txtY, batt_name, fg, 0); + //ag_textf(win, txtW, txtX+1, txtY+1, batt_name, bg, 0); + //ag_textf(win, txtW, txtX, txtY, batt_name, fg, 0); int rectH = agdp() * 3; int rectW = agdp(); txtY += (txtH - rectH)/2; - ag_rect(win, txtX - 3* agdp()+5, txtY, rectW, rectH, fg); + ag_rect(win, txtX - 3* agdp(), txtY, rectW, rectH, fg); return txtH + 2*agdp(); } @@ -218,9 +224,9 @@ static int _miui_setbg_title(CANVAS *win, CANVAS *bg) { ag_textf(win,titW,elmP + 1,elmP+1,bg_title,acfg()->titlebg_g,0); ag_text(win,titW,elmP,elmP,bg_title,acfg()->titlefg,0); //draw battery - _miui_draw_battery(win, agw()/2 + 8*elmP, elmP, acfg()->titlefg, acfg()->titlebg_g); + _miui_draw_battery(win, agw()/2 + 12*elmP, elmP, acfg()->titlefg, acfg()->titlebg_g); //draw time - snprintf(bg_title, 64, "%4d-%02d-%02d %02d:%02d", 1900+p->tm_year, p->tm_mon+1, p->tm_mday, (p->tm_hour + 8) % 24, p->tm_min); + snprintf(bg_title, 64, "%02d:%02d", (p->tm_hour + 8) % 24, p->tm_min); titW = ag_txtwidth(bg_title, 0); int timeX = agw() - titW - elmP; ag_textf(win,titW,timeX + 1,elmP+1,bg_title,acfg()->titlebg_g,0); @@ -658,7 +664,31 @@ STATUS miui_busy_process() int chkH = agh(); int chkY = miui_setbg_title(); int chkW = agw(); - char *text = "Please wait ...."; + char *text = miui_ini_get("text_wait");; + + chkH -= chkY; + int big = 1; + int txtW = ag_txtwidth(text, big); + int txtH = ag_fontheight(big); + int txtX = (agw()/2) - (txtW/2); + int txtY = (agh()/2) - (txtH/2) - (agdp() *2); + ag_rect(&miui_win_bg, 0, chkY, chkW, chkH, acfg()->titlebg_g); + ag_textf(&miui_win_bg, txtW, txtX, txtY, text, acfg()->titlefg, big); + ag_draw(NULL, &miui_win_bg, 0, 0); + ag_sync(); + return RET_OK; +} + +STATUS miui_sideload_process() +{ + //-- Set Busy before everythings ready + ag_setbusy(); + miui_isbgredraw = 1; + + int chkH = agh(); + int chkY = miui_setbg_title(); + int chkW = agw(); + char *text = miui_ini_get("text_wait_sideload");; chkH -= chkY; int big = 1; @@ -750,6 +780,8 @@ char * miui_ini_get(char *item) { else if (strcmp(item,"text_ok") == 0) snprintf(retval,128,"%s",acfg()->text_ok); else if (strcmp(item,"text_next") == 0) snprintf(retval,128,"%s",acfg()->text_next); else if (strcmp(item,"text_back") == 0) snprintf(retval,128,"%s",acfg()->text_back); + else if (strcmp(item,"text_wait") == 0) snprintf(retval,128,"%s",acfg()->text_wait); + else if (strcmp(item,"text_wait_sideload") == 0) snprintf(retval,128,"%s",acfg()->text_wait_sideload); else if (strcmp(item,"text_yes") == 0) snprintf(retval,128,"%s",acfg()->text_yes); else if (strcmp(item,"text_no") == 0) snprintf(retval,128,"%s",acfg()->text_no); @@ -1373,8 +1405,8 @@ STATUS miui_langmenu(char *title_name, char *title_icon) { //-- Check Box ACONTROLP menu1 = acsdmenu(hWin,0,chkY,chkW,chkH,6); //-- Populate Checkbox Items - acsdmenu_add(menu1, "简体中文", "欢迎使用中文恢复系统 syhost制作 @anzhi.com", "@lang.cn"); - acsdmenu_add(menu1, "English", "Welcome to MIUI Recovery by syhost @anzhi.com", "@lang.en"); + acsdmenu_add(menu1, "简体中文", "欢迎使用MIUI Recovery", "@lang.cn"); + acsdmenu_add(menu1, "English", "Welcome to MIUI Recovery", "@lang.en"); //-- Dispatch Message aw_show(hWin); @@ -1844,6 +1876,8 @@ STATUS miui_loadlang(char * name) miui_langloadsave(acfg()->text_ok, 64, "text_ok"); miui_langloadsave(acfg()->text_next, 64, "text_next"); miui_langloadsave(acfg()->text_back, 64, "text_back"); + miui_langloadsave(acfg()->text_wait, 64, "text_wait"); + miui_langloadsave(acfg()->text_wait_sideload, 64, "text_wait_sideload"); miui_langloadsave(acfg()->text_yes, 64, "text_yes"); miui_langloadsave(acfg()->text_no, 64, "text_no"); miui_langloadsave(acfg()->text_about, 64, "text_about"); diff --git a/src/miui/src/main/mount_ui.c b/src/miui/src/main/mount_ui.c index 524716d5..85e49562 100755 --- a/src/miui/src/main/mount_ui.c +++ b/src/miui/src/main/mount_ui.c @@ -7,7 +7,8 @@ #define MOUNT_SYSTEM 3 #define MOUNT_SDCARD 4 #define MOUNT_TOGGLE 5 -#define MOUNT_SDEXT 6 +#define MOUNT_SDEXT 6 +#define MOUNT_SYSTEM1 7 #define MOUNT_DESC_MOUNT "1" #define MOUNT_DESC_UNMOUNT "0" static struct _menuUnit *mount_node; @@ -55,6 +56,20 @@ static STATUS mount_menu_show(menuUnit *p) menuUnit_set_icon(mount_system_node, ICON_DISABLE); menuUnit_set_desc(mount_system_node, MOUNT_DESC_UNMOUNT); } +#ifdef DUALSYSTEM_PARTITIONS + //ensure system1 + miuiIntent_send(INTENT_ISMOUNT, 1, "/system1"); + if (miuiIntent_result_get_int() == 1) + { + menuUnit_set_icon(mount_system_node, ICON_ENABLE); + menuUnit_set_desc(mount_system_node, MOUNT_DESC_MOUNT); + } + else + { + menuUnit_set_icon(mount_system_node, ICON_DISABLE); + menuUnit_set_desc(mount_system_node, MOUNT_DESC_UNMOUNT); + } +#endif //ensure sdcard miuiIntent_send(INTENT_ISMOUNT, 1, "/sdcard"); if (miuiIntent_result_get_int() == 1) @@ -134,6 +149,11 @@ static STATUS mount_child_show(menuUnit *p) case MOUNT_SDEXT: miuiIntent_send(intent_type, 1, "/external_sd"); break; +#ifdef DUALSYSTEM_PARTITIONS + case MOUNT_SYSTEM1: + miuiIntent_send(intent_type, 1, "/system1"); + break; +#endif case MOUNT_TOGGLE: { if (intent_type == INTENT_MOUNT) @@ -191,7 +211,6 @@ struct _menuUnit *mount_ui_init() return_null_if_fail(menuUnit_set_desc(temp, MOUNT_DESC_UNMOUNT) == RET_OK); return_null_if_fail(RET_OK == menuUnit_set_show(temp, &mount_child_show)); mount_data_node = temp; - //mount system temp = common_ui_init(); assert_if_fail(menuNode_add(p, temp) == RET_OK); @@ -201,6 +220,17 @@ struct _menuUnit *mount_ui_init() return_null_if_fail(menuUnit_set_desc(temp, MOUNT_DESC_UNMOUNT) == RET_OK); return_null_if_fail(RET_OK == menuUnit_set_show(temp, &mount_child_show)); mount_system_node = temp; +#ifdef DUALSYSTEM_PARTITIONS + //mount system1 + temp = common_ui_init(); + assert_if_fail(menuNode_add(p, temp) == RET_OK); + return_null_if_fail(menuUnit_set_name(temp, "<~mount.system1.name>") == RET_OK); + return_null_if_fail(menuUnit_set_result(temp, MOUNT_SYSTEM1) == RET_OK); + return_null_if_fail(menuUnit_set_icon(temp, ICON_DISABLE) == RET_OK); + return_null_if_fail(menuUnit_set_desc(temp, MOUNT_DESC_UNMOUNT) == RET_OK); + return_null_if_fail(RET_OK == menuUnit_set_show(temp, &mount_child_show)); + mount_system_node = temp; +#endif //mount sdcard temp = common_ui_init(); assert_if_fail(menuNode_add(p, temp) == RET_OK); diff --git a/src/miui/src/main/power_ui.c b/src/miui/src/main/power_ui.c index d63c36c6..789ee8fe 100755 --- a/src/miui/src/main/power_ui.c +++ b/src/miui/src/main/power_ui.c @@ -7,11 +7,58 @@ #define POWER_RECOVERY 1 #define POWER_BOOTLOADER 2 #define POWER_POWEROFF 3 +#ifdef DUALSYSTEM_PARTITIONS +#define POWER_REBOOT_SYSTEM0 4 +#define POWER_REBOOT_SYSTEM1 5 +extern int is_tdb_enabled(); +static int setbootmode(char* bootmode) { + // open misc-partition + FILE* misc = fopen("/dev/block/platform/msm_sdcc.1/by-name/misc", "wb"); + if (misc == NULL) { + printf("Error opening misc partition.\n"); + return -1; + } + // write bootmode + fseek(misc, 0x1000, SEEK_SET); + if(fputs(bootmode, misc)<0) { + printf("Error writing bootmode to misc partition.\n"); + return -1; + } + + // close + fclose(misc); + return 0; +} +#endif static STATUS power_child_show(menuUnit *p) { //confirm if (RET_YES == miui_confirm(3, p->name, p->desc, p->icon)) { +#ifdef DUALSYSTEM_PARTITIONS + //set truedualboot script + miuiIntent_send(INTENT_UNMOUNT, 1, "/system"); + miuiIntent_send(INTENT_UNMOUNT, 1, "/system1"); + miuiIntent_send(INTENT_SETSYSTEM,1,"0"); + miuiIntent_send(INTENT_MOUNT, 1, "/system"); + miuiIntent_send(INTENT_MOUNT, 1, "/system1"); + __system("rm /system/bin/mount_ext4.sh"); + __system("rm /system1/bin/mount_ext4.sh"); + if (is_tdb_enabled()) { + __system("cp /res/dualsystem/mount_ext4_tdb.sh /system/bin/mount_ext4.sh"); + __system("cp /res/dualsystem/mount_ext4_tdb.sh /system1/bin/mount_ext4.sh"); + } else { + __system("cp /res/dualsystem/mount_ext4_default.sh /system/bin/mount_ext4.sh"); + __system("cp /res/dualsystem/mount_ext4_default.sh /system1/bin/mount_ext4.sh"); + } + __system("chmod 777 /system/bin/mount_ext4.sh"); + __system("chmod 777 /system1/bin/mount_ext4.sh"); +#endif + //disable recovery flash + miuiIntent_send(INTENT_MOUNT, 1, "/system"); + miuiIntent_send(INTENT_MOUNT, 1, "/system1"); + __system("rm /system/etc/install_recovery.sh"); + __system("rm /system1/etc/install_recovery.sh"); switch(p->result) { case POWER_REBOOT: miuiIntent_send(INTENT_REBOOT, 1, "reboot"); @@ -25,6 +72,16 @@ static STATUS power_child_show(menuUnit *p) case POWER_POWEROFF: miuiIntent_send(INTENT_REBOOT, 1, "poweroff"); break; +#ifdef DUALSYSTEM_PARTITIONS + case POWER_REBOOT_SYSTEM0: + setbootmode("boot-system0"); + miuiIntent_send(INTENT_REBOOT, 1, "reboot"); + break; + case POWER_REBOOT_SYSTEM1: + setbootmode("boot-system1"); + miuiIntent_send(INTENT_REBOOT, 1, "reboot"); + break; +#endif default: assert_if_fail(0); break; @@ -80,6 +137,27 @@ struct _menuUnit * power_ui_init() temp->result = POWER_RECOVERY; temp->show = &power_child_show; assert_if_fail(menuNode_add(p, temp) == RET_OK); +#ifdef DUALSYSTEM_PARTITIONS + //reboot to system0 + temp = common_ui_init(); + return_null_if_fail(temp != NULL); + strncpy(temp->name, "<~reboot.system0>", MENU_LEN); + menuUnit_set_title(temp, "<~reboot.system0.title>"); + menuUnit_set_icon(temp, "@reboot"); + temp->result = POWER_REBOOT_SYSTEM0; + temp->show = &power_child_show; + assert_if_fail(menuNode_add(p, temp) == RET_OK); + + //reboot to system1 + temp = common_ui_init(); + return_null_if_fail(temp != NULL); + strncpy(temp->name, "<~reboot.system1>", MENU_LEN); + menuUnit_set_title(temp, "<~reboot.system1.title>"); + menuUnit_set_icon(temp, "@reboot"); + temp->result = POWER_REBOOT_SYSTEM1; + temp->show = &power_child_show; + assert_if_fail(menuNode_add(p, temp) == RET_OK); +#endif //poweroff temp = common_ui_init(); return_null_if_fail(temp != NULL); diff --git a/src/miui/src/main/sd_ui.c b/src/miui/src/main/sd_ui.c index fdea107b..d2cf84e8 100755 --- a/src/miui/src/main/sd_ui.c +++ b/src/miui/src/main/sd_ui.c @@ -21,12 +21,31 @@ int file_install(char *file_name, int file_len, void *data) return_val_if_fail(file_name != NULL, RET_FAIL); return_val_if_fail(strlen(file_name) <= file_len, RET_INVALID_ARG); return_val_if_fail(data != NULL, RET_FAIL); +#ifdef DUALSYSTEM_PARTITIONS + int choose_system_num; + if (is_tdb_enabled()) { + if (RET_YES == miui_confirm(5, "<~choose.system.title>", "<~choose.system.text>", "@alert", "<~choice.system0.name>", "<~choice.system1.name>")) { + miuiIntent_send(INTENT_SETSYSTEM,1,"1"); + } else { + miuiIntent_send(INTENT_SETSYSTEM,1,"2"); + } + + } +#endif struct _menuUnit *p = (pmenuUnit)data; if (RET_YES == miui_confirm(3, p->name, p->desc, p->icon)) { miuiIntent_send(INTENT_INSTALL, 3, file_name, "0", "1"); +#ifdef DUALSYSTEM_PARTITIONS + miuiIntent_send(INTENT_SETSYSTEM,1,"0"); +#endif return 0; } - else return -1; + else { +#ifdef DUALSYSTEM_PARTITIONS + miuiIntent_send(INTENT_SETSYSTEM,1,"0"); +#endif + return -1; + } } //callback funtion file filter, if access ,return 0; others return -1 int file_filter(char *file, int file_len) @@ -66,9 +85,21 @@ static STATUS sd_update_show(menuUnit *p) { char new_path[SD_MAX_PATH] = "/sdcard/update.zip"; int wipe_cache = 0; +#ifdef DUALSYSTEM_PARTITIONS + int choose_system_num; + if (is_tdb_enabled()) { + if (RET_YES == miui_confirm(5, "<~choose.system.title>", "<~choose.system.text>", "@alert", "<~choice.system0.name>", "<~choice.system1.name>")) { + miuiIntent_send(INTENT_SETSYSTEM,1,"1"); + } else { + miuiIntent_send(INTENT_SETSYSTEM,1,"2"); + } + + } +#endif if (RET_YES == miui_confirm(3, p->name, p->desc, p->icon)) { miuiIntent_send(INTENT_INSTALL, 3, new_path, "0", "1"); } + miuiIntent_send(INTENT_SETSYSTEM,1,"0"); return MENU_BACK; } struct _menuUnit * sd_ui_init() diff --git a/src/miui/src/main/tool_ui.c b/src/miui/src/main/tool_ui.c index 58f6237c..a197c9cc 100755 --- a/src/miui/src/main/tool_ui.c +++ b/src/miui/src/main/tool_ui.c @@ -8,6 +8,7 @@ #include "../miui_inter.h" #include "../miui.h" #include "../../../miui_intent.h" +static struct _menuUnit *tdb_node = NULL; static STATUS battary_menu_show(struct _menuUnit* p) { @@ -55,6 +56,95 @@ static STATUS log_menu_show(struct _menuUnit* p) } return MENU_BACK; } +static STATUS sideload_menu_show(struct _menuUnit *p) { + miui_sideload_process(); + miuiIntent_send(INTENT_SIDELOAD, 1, NULL); +#ifdef DUALSYSTEM_PARTITIONS + int choose_system_num; + if (is_tdb_enabled()) { + if (RET_YES == miui_confirm(5, "<~choose.system.title>", "<~choose.system.text>", "@alert", "<~choice.system0.name>", "<~choice.system1.name>")) { + miuiIntent_send(INTENT_SETSYSTEM,1,"1"); + } else { + miuiIntent_send(INTENT_SETSYSTEM,1,"2"); + } + + } +#endif + if (RET_YES == miui_confirm(3, p->name, p->desc, p->icon)) { + miuiIntent_send(INTENT_INSTALL, 3, "/tmp/update.zip", "0", "1"); + } +#ifdef DUALSYSTEM_PARTITIONS + miuiIntent_send(INTENT_SETSYSTEM,1,"0"); +#endif + __system("rm /tmp/update.zip"); + return MENU_BACK; +} +#ifdef DUALSYSTEM_PARTITIONS +int is_tdb_enabled() +{ + struct stat st; + miuiIntent_send(INTENT_MOUNT, 1, "/data"); + return (lstat("/data/.truedualboot",&st)==0); +} +static STATUS enable_or_disable_tdb(struct _menuUnit* p) +{ + if (RET_YES == miui_confirm(3, p->name, p->desc, p->icon)) { + miui_busy_process(); + if(is_tdb_enabled()) { + miuiIntent_send(INTENT_UNMOUNT, 1, "/data"); + miuiIntent_send(INTENT_FORMAT, 1, "/data"); + menuUnit_set_name(tdb_node,"<~tool.enable.tdb>"); + } else { + miuiIntent_send(INTENT_UNMOUNT, 1, "/data"); + miuiIntent_send(INTENT_FORMAT, 1, "/data"); + miuiIntent_send(INTENT_MOUNT, 1, "/data"); + menuUnit_set_name(tdb_node,"<~tool.disable.tdb>"); + FILE * pFile = fopen("/data/.truedualboot","w"); + fclose(pFile); + } + } + return MENU_BACK; +} +static STATUS tool_menu_show(struct _menuUnit* p) +{ + if (is_tdb_enabled()) { + menuUnit_set_name(tdb_node, "<~tool.disable.tdb>"); + menuUnit_set_icon(tdb_node, "@alert"); + } else { + menuUnit_set_name(tdb_node, "<~tool.enable.tdb>"); + menuUnit_set_icon(tdb_node, "@alert"); + } + //show menu + return_val_if_fail(p != NULL, RET_FAIL); + int n = p->get_child_count(p); + return_val_if_fail(n > 0, RET_FAIL); + int selindex = 0; + return_val_if_fail(n >= 1, RET_FAIL); + return_val_if_fail(n < ITEM_COUNT, RET_FAIL); + struct _menuUnit *temp = p->child; + return_val_if_fail(temp != NULL, RET_FAIL); + char **menu_item = malloc(n * sizeof(char *)); + assert_if_fail(menu_item != NULL); + char **icon_item=malloc(n * sizeof(char *)); + assert_if_fail(icon_item != NULL); + char **title_item= malloc(n * sizeof(char *)); + assert_if_fail(title_item != NULL); + int i = 0; + for (i = 0; i < n; i++) + { + menu_item[i] = temp->name; + title_item[i] = temp->title_name; + icon_item[i] = temp->icon; + temp = temp->nextSilbing; + } + selindex = miui_menubox(p->name, menu_item, n); + p->result = selindex; + if (menu_item != NULL) free(menu_item); + if (title_item != NULL) free(title_item); + if (icon_item != NULL) free(icon_item); + return p->result; +} +#endif struct _menuUnit* tool_ui_init() { struct _menuUnit *p = common_ui_init(); @@ -62,6 +152,9 @@ struct _menuUnit* tool_ui_init() menuUnit_set_name(p, "<~tool.name>"); menuUnit_set_title(p, "<~tool.title>"); menuUnit_set_icon(p, "@tool"); +#ifdef DUALSYSTEM_PARTITIONS + menuUnit_set_show(p, &tool_menu_show); +#endif assert_if_fail(menuNode_init(p) != NULL); //batarry wipe struct _menuUnit *temp = common_ui_init(); @@ -83,5 +176,27 @@ struct _menuUnit* tool_ui_init() menuUnit_set_icon(temp, "@tool.permission"); menuUnit_set_show(temp, &permission_menu_show); assert_if_fail(menuNode_add(p, temp) == RET_OK); + + //adb sideload + temp = common_ui_init(); + menuUnit_set_name(temp, "<~tool.sideload.name>"); + menuUnit_set_icon(temp, "@alert"); + menuUnit_set_show(temp, &sideload_menu_show); + menuUnit_set_desc(temp, "<~tool.sideload.desc>"); + assert_if_fail(menuNode_add(p, temp) == RET_OK); +#ifdef DUALSYSTEM_PARTITIONS + //truedualboot + temp = common_ui_init(); + if (is_tdb_enabled()) { + menuUnit_set_name(temp, "<~tool.disable.tdb>"); + menuUnit_set_icon(temp, "@alert"); + } else { + menuUnit_set_name(temp, "<~tool.enable.tdb>"); + menuUnit_set_icon(temp, "@alert"); + } + menuUnit_set_show(temp, &enable_or_disable_tdb); + assert_if_fail(menuNode_add(p, temp) == RET_OK); + tdb_node = temp; +#endif return p; } diff --git a/src/miui/src/main/wipe_ui.c b/src/miui/src/main/wipe_ui.c index 61f56d98..5ab5e916 100755 --- a/src/miui/src/main/wipe_ui.c +++ b/src/miui/src/main/wipe_ui.c @@ -12,15 +12,46 @@ #define FORMAT_BOOT 14 #define FORMAT_SDCARD 15 #define FORMAT_ALL 16 +#ifdef DUALSYSTEM_PARTITIONS +#define FORMAT_SYSTEM1 17 +#define FORMAT_BOOT1 18 +extern int is_tdb_enabled(); +#endif STATUS wipe_item_show(menuUnit *p) { +#ifdef DUALSYSTEM_PARTITIONS +int wipe_system_num; + if (is_tdb_enabled()) { + if (p->result == WIPE_FACTORY) { + if (RET_YES == miui_confirm(5, "<~choose.system.title>", "<~choose.system.text>", "@alert", "<~choice.system0.name>", "<~choice.system1.name>")) { + wipe_system_num = 0; + } else { + wipe_system_num = 1; + } + } + } +#endif if (RET_YES == miui_confirm(3, p->name, p->desc, p->icon)) { miui_busy_process(); switch(p->result) { case WIPE_FACTORY: +#ifdef DUALSYSTEM_PARTITIONS + if (is_tdb_enabled()) { + miuiIntent_send(INTENT_MOUNT, 1, "/data"); + if (wipe_system_num == 0) { + __system("rm -rf /data/system0"); + } else { + __system("rm -rf /data/system1"); + } + } else { + miuiIntent_send(INTENT_WIPE, 1, "/cache"); + miuiIntent_send(INTENT_WIPE, 1, "/data"); + } +#else miuiIntent_send(INTENT_WIPE, 1, "/cache"); miuiIntent_send(INTENT_WIPE, 1, "/data"); +#endif break; case WIPE_DATA: miuiIntent_send(INTENT_WIPE, 1, "/data"); @@ -34,6 +65,11 @@ STATUS wipe_item_show(menuUnit *p) case FORMAT_SYSTEM: miuiIntent_send(INTENT_FORMAT, 1, "/system"); break; +#ifdef DUALSYSTEM_PARTITIONS + case FORMAT_SYSTEM1: + miuiIntent_send(INTENT_FORMAT, 1, "/system1"); + break; +#endif case FORMAT_DATA: miuiIntent_send(INTENT_FORMAT, 1, "/data"); break; @@ -43,6 +79,11 @@ STATUS wipe_item_show(menuUnit *p) case FORMAT_BOOT: miuiIntent_send(INTENT_FORMAT, 1, "/boot"); break; +#ifdef DUALSYSTEM_PARTITIONS + case FORMAT_BOOT1: + miuiIntent_send(INTENT_FORMAT, 1, "/boot1"); + break; +#endif case FORMAT_SDCARD: miuiIntent_send(INTENT_FORMAT, 1, "/sdcard"); break; @@ -67,7 +108,7 @@ STATUS wipe_menu_show(menuUnit *p) int selindex = 0; return_val_if_fail(n >= 1, RET_FAIL); return_val_if_fail(n < ITEM_COUNT, RET_FAIL); - struct _menuUnit *temp = p->child; + struct _menuUnit* temp = p->child; return_val_if_fail(temp != NULL, RET_FAIL); char **menu_item = malloc(n * sizeof(char *)); assert_if_fail(menu_item != NULL); @@ -91,7 +132,7 @@ struct _menuUnit* wipe_ui_init() return_null_if_fail(menuUnit_set_icon(p, "@wipe") == RET_OK); return_null_if_fail(RET_OK == menuUnit_set_show(p, &wipe_menu_show)); return_null_if_fail(menuNode_init(p) != NULL); - //wipe_data/factory reset + //factory reset struct _menuUnit* temp = common_ui_init(); assert_if_fail(menuNode_add(p, temp) == RET_OK); return_null_if_fail(menuUnit_set_name(temp, "<~wipe.factory.name>") == RET_OK); @@ -121,6 +162,14 @@ struct _menuUnit* wipe_ui_init() return_null_if_fail(menuUnit_set_name(temp, "<~format.system.name>") == RET_OK); return_null_if_fail(menuUnit_set_result(temp, FORMAT_SYSTEM) == RET_OK); return_null_if_fail(RET_OK == menuUnit_set_show(temp, &wipe_item_show)); +#ifdef DUALSYSTEM_PARTITIONS + //format system1 + temp = common_ui_init(); + assert_if_fail(menuNode_add(p, temp) == RET_OK); + return_null_if_fail(menuUnit_set_name(temp, "<~format.system1.name>") == RET_OK); + return_null_if_fail(menuUnit_set_result(temp, FORMAT_SYSTEM1) == RET_OK); + return_null_if_fail(RET_OK == menuUnit_set_show(temp, &wipe_item_show)); +#endif //format data temp = common_ui_init(); assert_if_fail(menuNode_add(p, temp) == RET_OK); @@ -139,6 +188,14 @@ struct _menuUnit* wipe_ui_init() return_null_if_fail(menuUnit_set_name(temp, "<~format.boot.name>") == RET_OK); return_null_if_fail(menuUnit_set_result(temp, FORMAT_BOOT) == RET_OK); return_null_if_fail(RET_OK == menuUnit_set_show(temp, &wipe_item_show)); +#ifdef DUALSYSTEM_PARTITIONS + //format BOOT1 + temp = common_ui_init(); + assert_if_fail(menuNode_add(p, temp) == RET_OK); + return_null_if_fail(menuUnit_set_name(temp, "<~format.boot1.name>") == RET_OK); + return_null_if_fail(menuUnit_set_result(temp, FORMAT_BOOT) == RET_OK); + return_null_if_fail(RET_OK == menuUnit_set_show(temp, &wipe_item_show)); +#endif //format SDCARD temp = common_ui_init(); assert_if_fail(menuNode_add(p, temp) == RET_OK); diff --git a/src/miui/src/miui_inter.h b/src/miui/src/miui_inter.h index 61a86579..b8bf397e 100755 --- a/src/miui/src/miui_inter.h +++ b/src/miui/src/miui_inter.h @@ -29,9 +29,12 @@ // #include #include +#include #include #include #include +#include +#include #include #include #include @@ -69,6 +72,8 @@ free(x);x=NULL;} #endif + + // // MIUI ZIP Memory Structure // @@ -689,4 +694,11 @@ int file_scan(char *path, int path_len, char * title, int title_len, fileFun fun #define STRINGIFY(x) #x #define EXPAND(x) STRINGIFY(x) +#ifndef MSMFB_IOCTL_MAGIC +#define MSMFB_IOCTL_MAGIC 'm' +#endif +#ifndef MSMFB_OVERLAY_VSYNC_CTRL +#define MSMFB_OVERLAY_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int) +#endif + #endif // __MIUI_H__ diff --git a/src/miui/src/utils.h b/src/miui/src/utils.h index 883ebae5..b4483d50 100755 --- a/src/miui/src/utils.h +++ b/src/miui/src/utils.h @@ -30,16 +30,16 @@ typedef int u32; // // MIUI Main Configurations // -#define MIUI_NAME "MIUI Recovery by syhost" +#define MIUI_NAME "MIUI Recovery" //rom_version -#define MIUI_VERSION "2.04" +#define MIUI_VERSION "2.05" //rom date -#define MIUI_BUILD "2012-12-02" +#define MIUI_BUILD "2013-07" #define MIUI_BUILD_CN "Weekend" #define MIUI_BUILD_L "Dennis" #define MIUI_BUILD_A "" #define MIUI_BUILD_URL "http://www.micode.net/" -#define MIUI_COPY "(c) 2012 by xiaomi MIUI developers" +#define MIUI_COPY "(c) 2013 by xiaomi MIUI developers" //-- Temporary Dir - Move from /tmp/miui-data to /tmp/miui symlink to /tmp/miui-data for backward compatibility #define MIUI_SYSTMP "/tmp" @@ -184,7 +184,8 @@ typedef struct { char text_ok[64]; // OK char text_next[64]; // Next > char text_back[64]; // < Back - + char text_wait[64]; // Please wait... + char text_wait_sideload[64]; // Please send zip via "adb sideload"... char text_yes[64]; // Yes char text_no[64]; // No char text_about[64]; // About diff --git a/src/miui_intent.h b/src/miui_intent.h index 6458a5b6..5e346a55 100755 --- a/src/miui_intent.h +++ b/src/miui_intent.h @@ -29,7 +29,9 @@ typedef enum _intentType{ INTENT_BACKUP, INTENT_ADVANCED_BACKUP, INTENT_SYSTEM, - INTENT_COPY + INTENT_COPY, + INTENT_SETSYSTEM, + INTENT_SIDELOAD }intentType; #define INTENT_RESULT_LEN 16 diff --git a/src/mount.c b/src/mount.c index d45a3959..2cc7af6c 100755 --- a/src/mount.c +++ b/src/mount.c @@ -39,57 +39,36 @@ * Available state: DISCONNECTED, CONFIGURED, CONNECTED */ #define BOARD_USB_CONFIG_FILE "/sys/class/android_usb/android0/state" - -// USB_STATE_CONFIGURED -#define BOARD_USB_CONFIG_FILE1 "/sys/devices/platform/msm_hsusb/gadget/usb_state" #endif -static int is_usb_connected() -{ +static int is_usb_connected() { char state[255]; - char sel_config_file = 0; int fd = open(BOARD_USB_CONFIG_FILE, O_RDONLY); - if (fd < 0) - { - fd = open(BOARD_USB_CONFIG_FILE1, O_RDONLY); - if (fd < 0) - { - LOGE("Unable to open usb_configuration state file(%s)\n",strerror(errno)); - close(fd); - return 0; - } - else - { - sel_config_file = 1; - } + if (fd < 0) { + LOGE("Unable to open usb_configuration state file(%s)\n", + strerror(errno)); + return 0; } - else - { - sel_config_file = 0; - } - if (read(fd, state, sizeof(state)) < 0) - { - LOGE("Unable to read usb_configuration state file(%s)\n", strerror(errno)); + if (read(fd, state, sizeof(state)) < 0) { + LOGE("Unable to read usb_configuration state file(%s)\n", + strerror(errno)); close(fd); return 0; } state[254] = '\0'; - LOGI("%s: state=%s\n", __func__, state); + LOGE("%s: state=%s\n", __func__, state); + close(fd); - - return state[10*sel_config_file] == 'C'; + return state[0] == 'C'; } -static int mount_usb() -{ +static int mount_usb() { int ret = 0; int fd; char value[PROPERTY_VALUE_MAX]; Volume *vol = volume_for_path("/sdcard"); - Volume *vol_ext = volume_for_path("/external_sd"); - char lunfilename[PATH_MAX]; property_get("sys.usb.state", value, ""); value[PROPERTY_VALUE_MAX - 1] = '\0'; @@ -97,32 +76,17 @@ static int mount_usb() if (strncmp("mass_storage,adb", value, 16)) property_set("sys.usb.config", "mass_storage,adb"); - sprintf(lunfilename, "%s%d/file", acfg()->lun_file, 0); - if ((fd = open(lunfilename, O_WRONLY)) < 0) - { - LOGE("Unable to open ums lunfile 0 (%s)", strerror(errno)); - ret = -1; - goto next; - } - if ((write(fd, vol->device, strlen(vol->device)) < 0) && (!vol->device2 || (write(fd, vol->device2, strlen(vol->device2)) < 0))) - { - LOGE("Unable to write to ums lunfile 0 (%s)", strerror(errno)); - ret = -1; - } - -next: - sprintf(lunfilename, "%s%d/file", acfg()->lun_file, 1); - if ((fd = open(lunfilename, O_WRONLY)) < 0) - { - LOGE("Unable to open ums lunfile 1 (%s)", strerror(errno)); + if ((fd = open(acfg()->lun_file, O_WRONLY)) < 0) { + LOGE("Unable to open ums lunfile (%s)", strerror(errno)); ret = -1; goto out; } - if ((write(fd, vol_ext->device, strlen(vol_ext->device)) < 0) && (!vol_ext->device2 || (write(fd, vol_ext->device2, strlen(vol_ext->device2)) < 0))) - { - LOGE("Unable to write to ums lunfile 1 (%s)", strerror(errno)); + if ((write(fd, vol->device, strlen(vol->device)) < 0) && + (!vol->device2 || (write(fd, vol->device, strlen(vol->device2)) < 0))) { + LOGE("Unable to write to ums lunfile (%s)", strerror(errno)); ret = -1; } + close(fd); out: return ret; @@ -133,36 +97,17 @@ static int umount_usb() { int fd; char ch = 0; char value[PROPERTY_VALUE_MAX]; - char lunfilename[PATH_MAX]; - - sprintf(lunfilename, "%s%d/file", acfg()->lun_file, 0); - if ((fd = open(lunfilename, O_WRONLY)) < 0) - { - LOGE("Unable to open ums lunfile 0 (%s)", strerror(errno)); - ret = -1; - goto next; - } - if (write(fd, &ch, 1) < 0) - { - LOGE("Unable to write to ums lunfile 0 (%s)", strerror(errno)); + if ((fd = open(acfg()->lun_file, O_WRONLY)) < 0) { + LOGE("Unable to open ums lunfile (%s)", strerror(errno)); ret = -1; - } - -next: - sprintf(lunfilename, "%s%d/file", acfg()->lun_file, 1); - if ((fd = open(lunfilename, O_WRONLY)) < 0) - { - LOGE("Unable to open ums lunfile 1 (%s)", strerror(errno)); - ret = -1; - goto next; + goto out; } - if (write(fd, &ch, 1) < 0) - { - LOGE("Unable to write to ums lunfile 1 (%s)", strerror(errno)); + if (write(fd, &ch, 1) < 0) { + LOGE("Unable to write to ums lunfile (%s)", strerror(errno)); ret = -1; - } + } close(fd); out: @@ -187,7 +132,6 @@ intentResult* intent_toggle(int argc, char *argv[]) { umount_usb(); ensure_path_unmounted("/sdcard"); - ensure_path_unmounted("/external_sd"); return miuiIntent_result_set(result, "ok"); } //wait for usb connected @@ -200,8 +144,6 @@ intentResult* intent_toggle(int argc, char *argv[]) LOGE("USB not connect\n"); umount_usb(); ensure_path_unmounted("/sdcard"); - ensure_path_unmounted("/external_sd"); return miuiIntent_result_set(result, "ok"); } - diff --git a/src/nandroid.c b/src/nandroid.c index 09488b6c..85fc4d3b 100755 --- a/src/nandroid.c +++ b/src/nandroid.c @@ -336,6 +336,9 @@ int nandroid_backup(const char* backup_path) if (0 != (ret = nandroid_backup_partition(backup_path, "/boot"))) return ret; + if (0 != (ret = nandroid_backup_partition(backup_path, "/boot1"))) + return ret; + if (0 != (ret = nandroid_backup_partition(backup_path, "/recovery"))) return ret; @@ -355,6 +358,9 @@ int nandroid_backup(const char* backup_path) if (0 != (ret = nandroid_backup_partition(backup_path, "/system"))) return ret; + if (0 != (ret = nandroid_backup_partition(backup_path, "/system1"))) + return ret; + if (0 != (ret = nandroid_backup_partition(backup_path, "/data"))) return ret; @@ -603,7 +609,7 @@ static int nandroid_restore_partition(const char* backup_path, const char* root) return nandroid_restore_partition_extended(backup_path, root, 1); } -int nandroid_restore(const char* backup_path, int restore_boot, int restore_system, int restore_data, int restore_cache, int restore_sdext, int restore_wimax) +int nandroid_restore(const char* backup_path, int restore_boot, int restore_system, int restore_data, int restore_cache, int restore_sdext, int restore_wimax, int restore_boot1, int restore_system1) { ui_set_background(BACKGROUND_ICON_INSTALLING); ui_show_indeterminate_progress(); @@ -623,6 +629,8 @@ int nandroid_restore(const char* backup_path, int restore_boot, int restore_syst if (restore_boot && NULL != volume_for_path("/boot") && 0 != (ret = nandroid_restore_partition(backup_path, "/boot"))) return ret; + if (restore_boot1 && NULL != volume_for_path("/boot1") && 0 != (ret = nandroid_restore_partition(backup_path, "/boot1"))) + return ret; struct stat s; Volume *vol = volume_for_path("/wimax"); @@ -656,6 +664,9 @@ int nandroid_restore(const char* backup_path, int restore_boot, int restore_syst if (restore_system && 0 != (ret = nandroid_restore_partition(backup_path, "/system"))) return ret; + if (restore_system1 && 0 != (ret = nandroid_restore_partition(backup_path, "/system1"))) + return ret; + if (restore_data && 0 != (ret = nandroid_restore_partition(backup_path, "/data"))) return ret; @@ -706,7 +717,7 @@ int nandroid_main(int argc, char** argv) { if (argc != 3) return nandroid_usage(); - return nandroid_restore(argv[2], 1, 1, 1, 1, 1, 0); + return nandroid_restore(argv[2], 1, 1, 1, 1, 1, 0, 0, 0); } return nandroid_usage(); diff --git a/src/nandroid.h b/src/nandroid.h index 6113e84e..77ffd2cd 100755 --- a/src/nandroid.h +++ b/src/nandroid.h @@ -3,7 +3,7 @@ void nandroid_generate_timestamp_path(char* backup_path); int nandroid_backup(const char* backup_path); -int nandroid_restore(const char* backup_path, int restore_boot, int restore_system, int restore_data, int restore_cache, int restore_sdext, int restore_wimax); +int nandroid_restore(const char* backup_path, int restore_boot, int restore_system, int restore_data, int restore_cache, int restore_sdext, int restore_wimax, int restore_boot1, int restore_system1); int nandroid_advanced_backup(const char* backup_path, const char *root); #endif diff --git a/src/recovery.c b/src/recovery.c index 20282852..b316e0f5 100755 --- a/src/recovery.c +++ b/src/recovery.c @@ -38,6 +38,8 @@ #include "miui/src/miui.h" #include "miui_intent.h" #include "mtdutils/mounts.h" +#include "sideload.h" +#include "minadbd/adb.h" #include "nandroid.h" static const struct option OPTIONS[] = { @@ -494,10 +496,10 @@ static intentResult* intent_install(int argc, char *argv[]) */ static intentResult* intent_restore(int argc, char* argv[]) { - return_intent_result_if_fail(argc == 7); + return_intent_result_if_fail(argc == 9); return_intent_result_if_fail(argv != NULL); int result = nandroid_restore(argv[0], atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), - atoi(argv[4]), atoi(argv[5]), atoi(argv[6])); + atoi(argv[4]), atoi(argv[5]), atoi(argv[6]), atoi(argv[7]), atoi(argv[8])); assert_ui_if_fail(result == 0); return miuiIntent_result_set(result, NULL); } @@ -540,6 +542,21 @@ static intentResult* intent_copy(int argc, char* argv[]) copy_log_file(argv[0], argv[1], false); return miuiIntent_result_set(0, NULL); } +static intentResult* intent_setsystem(int argc, char* argv[]) +{ + if (strstr(argv[0], "0") != NULL) { + set_active_system(DUALBOOT_ITEM_BOTH); + } else if (strstr(argv[0], "1") != NULL) { + set_active_system(DUALBOOT_ITEM_SYSTEM0); + } else if (strstr(argv[0], "2") != NULL) { + set_active_system(DUALBOOT_ITEM_SYSTEM1); + } + return miuiIntent_result_set(0, NULL); +} +static intentResult* intent_sideload(int argc, char* argv[]) +{ + return miuiIntent_result_set(start_adb_sideload(), NULL); +} static void print_property(const char *key, const char *name, void *cookie) { printf("%s=%s\n", key, name); @@ -547,6 +564,12 @@ print_property(const char *key, const char *name, void *cookie) { int main(int argc, char **argv) { + + if (argc == 2 && strcmp(argv[1], "adbd") == 0) { + adb_main(); + return 0; + } + time_t start = time(NULL); // If these fail, there's not really anywhere to complain... @@ -572,6 +595,8 @@ main(int argc, char **argv) { miuiIntent_register(INTENT_ADVANCED_BACKUP, &intent_advanced_backup); miuiIntent_register(INTENT_SYSTEM, &intent_system); miuiIntent_register(INTENT_COPY, &intent_copy); + miuiIntent_register(INTENT_SETSYSTEM, &intent_setsystem); + miuiIntent_register(INTENT_SIDELOAD, &intent_sideload); device_ui_init(); load_volume_table(); get_args(&argc, &argv); diff --git a/src/res/dualsystem/mount_ext4_default.sh b/src/res/dualsystem/mount_ext4_default.sh new file mode 100644 index 00000000..f2a0ebaf --- /dev/null +++ b/src/res/dualsystem/mount_ext4_default.sh @@ -0,0 +1,24 @@ +#!/system/bin/sh +export PATH=/system/bin:/system/xbin:$PATH +BLOCK_DEVICE=$1 +MOUNT_POINT=$2 +LOG_FILE="/dev/null" +LOG_LOCATION="/data/.fsck_log/" + +# storage log +if [ "${MOUNT_POINT}" == "/storage_int" ]; then + mkdir ${LOG_LOCATION} + busybox find /data/.fsck_log/ -type f -mtime +7 -exec rm {} \; + TIMESTAMP=`date +%F_%H-%M-%S` + LOG_FILE=${LOG_LOCATION}/storage_${TIMESTAMP}.log +fi + +# mount partition +if [ -e ${BLOCK_DEVICE} ]; then + mount -t ext4 -o nosuid,nodev,barrier=1,noauto_da_alloc ${BLOCK_DEVICE} ${MOUNT_POINT} +fi + +# hide recovery partition +RECOVERY_NODE="$(busybox readlink -f /dev/block/platform/msm_sdcc.1/by-name/recovery)" +busybox mv "${RECOVERY_NODE}" /dev/recovery_moved +busybox mknod -m 0600 "${RECOVERY_NODE}" b 1 3 diff --git a/src/res/dualsystem/mount_ext4_tdb.sh b/src/res/dualsystem/mount_ext4_tdb.sh new file mode 100644 index 00000000..3a168151 --- /dev/null +++ b/src/res/dualsystem/mount_ext4_tdb.sh @@ -0,0 +1,57 @@ +#!/system/bin/sh +export PATH=/system/bin:/system/xbin:$PATH +BLOCK_DEVICE=$1 +MOUNT_POINT=$2 +LOG_FILE="/dev/null" +LOG_LOCATION="/data/.fsck_log/" + +# get syspart-flag from cmdline +set -- $(cat /proc/cmdline) +for x in "$@"; do + case "$x" in + syspart=*) + SYSPART=$(echo "${x#syspart=}") + ;; + esac +done + +# storage log +if [ "${MOUNT_POINT}" == "/storage_int" ]; then + mkdir ${LOG_LOCATION} + busybox find /data/.fsck_log/ -type f -mtime +7 -exec rm {} \; + TIMESTAMP=`date +%F_%H-%M-%S` + LOG_FILE=${LOG_LOCATION}/storage_${TIMESTAMP}.log +fi + +# mount partition +if [ -e ${BLOCK_DEVICE} ]; then + # userdata + if [ "${BLOCK_DEVICE}" == "/dev/block/platform/msm_sdcc.1/by-name/userdata" ];then + if [ "${SYSPART}" == "system" ];then + BINDMOUNT_PATH="/data_root/system0" + elif [ "${SYSPART}" == "system1" ];then + BINDMOUNT_PATH="/data_root/system1" + else + reboot recovery + fi + + # mount /data_root + mkdir -p /data_root + chmod 0755 /data_root + mount -t ext4 -o nosuid,nodev,barrier=1,noauto_da_alloc ${BLOCK_DEVICE} /data_root + + # bind mount + mkdir -p ${BINDMOUNT_PATH} + chmod 0755 ${BINDMOUNT_PATH} + mount -o bind ${BINDMOUNT_PATH} ${MOUNT_POINT} + + # normal mount + else + mount -t ext4 -o nosuid,nodev,barrier=1,noauto_da_alloc ${BLOCK_DEVICE} ${MOUNT_POINT} + fi +fi + +# hide recovery partition +RECOVERY_NODE="$(busybox readlink -f /dev/block/platform/msm_sdcc.1/by-name/recovery)" +busybox mv "${RECOVERY_NODE}" /dev/recovery_moved +busybox mknod -m 0600 "${RECOVERY_NODE}" b 1 3 diff --git a/src/res/langs/cn.lang b/src/res/langs/cn.lang index 79eb2f98..659f2069 100755 --- a/src/res/langs/cn.lang +++ b/src/res/langs/cn.lang @@ -11,6 +11,8 @@ text_quit=退出 text_quit_msg=你确定要退出吗? text_done=完成 global_done=操作完成 +text_wait=请稍候... +text_wait_sideload=请"adb sideload"发送zip... # #-- CUSTOM STRING RESOURCE @@ -19,9 +21,12 @@ lang.name=选择语言 lang.title_name=请选择语言 lang.desc=lang selected default_name=选项 -default_title=选项标题 +default_title=默认标题 default_desc=你确定要这样做吗? - +choice.system0.name=系统一 +choice.system1.name=系统二 +choose.system.title=选择系统 +choose.system.text=选择一个系统来执行该操作. mainmenu.name=主菜单 mainmenu.title_name=主菜单 mainmenu.install.name=从SD卡安装 @@ -51,6 +56,8 @@ reboot.null=重启 reboot.null.title=现在重启 reboot.recovery=重启到recovery reboot.bootloader=重启到bootloader +reboot.system0=重启到系统一 +reboot.system1=重启到系统二 reboot.poweroff=关机 alert.result=错误 @@ -61,6 +68,7 @@ mount.title=挂载各分区和启用USB存储 mount.cache.name=挂载cache分区 mount.data.name=挂载data分区 mount.system.name=挂载system分区 +mount.system1.name=挂载system1分区 mount.sdcard.name=挂载sdcard分区 mount.sdext.name=挂载外置sdcard分区 mount.toggle.name=USB 存储 @@ -69,12 +77,15 @@ wipe.name=擦除和格式化分区 wipe.title=擦除数据操作和格式化分区操作 wipe.cache.name=擦除cache wipe.dalvik-cache.name=擦除dalvik-cache -wipe.factory.name=擦除cache/恢复出厂设置 +wipe.factory.name=清空所有数据 + wipe.data.name=擦除data format.system.name=格式化system分区 +format.system1.name=格式化system1分区 format.data.name=格式化data分区 format.cache.name=格式化cache分区 format.boot.name=格式化boot分区 +format.boot1.name=格式化boot1分区 format.sdcard.name=格式化sdcard format.all.name=全部格式化(不包括boot和sdcard) @@ -86,16 +97,20 @@ advanced_backup.name=高级备份 advanced_backup.cache.name=备份cache advanced_backup.data.name=备份data advanced_backup.system.name=备份system +advanced_backup.system1.name=备份system1 advanced_backup.boot.name=备份boot +advanced_backup.boot1.name=备份boot1 advanced_backup.recovery.name=备份recovery advanced_restore.name=高级恢复 advanced_restore.cache.name=恢复cache advanced_restore.data.name=恢复data advanced_restore.system.name=恢复system +advanced_restore.sys.name=恢复system1 advanced_restore.boot.name=恢复boot +advanced_restore.boot1.name=恢复boot1 advanced_restore.recovery.name=恢复recovery -tool.name=工具 +tool.name=高级选项 tool.title=提供高级的操作 tool.key.name=按键测试 tool.time.name=时间区域设置 @@ -103,6 +118,11 @@ tool.battary.name=电池信息初始化 tool.log.name=拷贝LOG到SD卡 tool.log.desc=是否将日志拷贝到 tool.permission.name=修复权限 +tool.enable.tdb=打开 双系统共存 +tool.disable.tdb=关闭 双系统共存 +tool.tdb.desc=这将清空所有数据! +tool.sideload.name=用sideload安装刷机包 +tool.sideload.desc=已收到刷机包,确认安装? info.name=信息 info.title=关于MIUI RECOVERY的信息 diff --git a/src/res/langs/en.lang b/src/res/langs/en.lang index 7a638835..71e94147 100755 --- a/src/res/langs/en.lang +++ b/src/res/langs/en.lang @@ -12,6 +12,8 @@ text_quit=Quit text_quit_msg=Are you sure to quit? text_done=done global_done=done +text_wait=Please wait... +text_wait_sideload=Please send zip via "adb sideload"... lang.name=选择语言/Select Language @@ -20,7 +22,10 @@ lang.desc=lang selected default_name=default_name default_title=default_title default_desc=Are you sure do it? - +choice.system0.name=system1 +choice.system1.name=system2 +choose.system.title=Choose system +choose.system.text=Choose a system to perform the action. mainmenu.name=MAIN MENU mainmenu.title_name=MAIN MENU mainmenu.install.name=install from SD @@ -49,6 +54,8 @@ reboot.null= reboot reboot.null.title= reboot now reboot.recovery= reboot to recovery reboot.bootloader= reboot to bootloader +reboot.system0=reboot to system1 +reboot.system1=reboot to system2 reboot.poweroff= poweroff alert.result=FAIL! @@ -59,6 +66,7 @@ mount.title=mount and toogle usb storage mount.cache.name=mount cache mount.data.name=mount data mount.system.name=mount system +mount.system1.name=mount system1 mount.sdcard.name=mount sdcard mount.sdcard.name=mount sd external mount.toggle.name=toggle usb storage @@ -67,12 +75,14 @@ wipe.name=wipe or format wipe.title=wipe data or format partation operation wipe.cache.name=wipe cache wipe.dalvik-cache.name=wipe dalvik-cache -wipe.factory.name=wipe cache/factory reset +wipe.factory.name=wipe all wipe.data.name=wipe data format.system.name=format system +format.system1.name=format system1 format.data.name=format data format.cache.name=format cache format.boot.name=format boot +format.boot1.name=format boot1 format.sdcard.name=format sdcard format.all.name=format all(except sdcard and boot) @@ -84,16 +94,20 @@ advanced_backup.name=advanced backup advanced_backup.cache.name=backup cache advanced_backup.data.name=backup data advanced_backup.system.name=backup system +advanced_backup.system1.name=backup system1 advanced_backup.boot.name=backup boot +advanced_backup.boot1.name=backup boot1 advanced_backup.recovery.name=backup recovery advanced_restore.name=advanced restore advanced_restore.cache.name=restore cache advanced_restore.data.name=restore data advanced_restore.system.name=restore system +advanced_restore.sys.name=restore system1 advanced_restore.boot.name=restore boot +advanced_restore.boot1.name=restore boot1 advanced_restore.recovery.name=restore recovery -tool.name=tool +tool.name=advanced tool.title=advanced tools tool.key.name=key test tool.time.name=timer setting @@ -101,6 +115,11 @@ tool.battary.name=wip battary tool.log.name=cope log to sdcard tool.log.desc=are you sure cope log to tool.permission.name=fix permission +tool.enable.tdb=enable truedualboot +tool.disable.tdb=disable truedualboot +tool.tdb.desc=This will wipe all data! +tool.sideload.name=install package via sideload +tool.sideload.desc=package received, confirm install? info.name=info info.title=information of miui recovery diff --git a/src/res/prepare_backup.zip b/src/res/prepare_backup.zip new file mode 100644 index 00000000..f03cab3b Binary files /dev/null and b/src/res/prepare_backup.zip differ diff --git a/src/roots.c b/src/roots.c index 68b2d35d..d2d9ff44 100755 --- a/src/roots.c +++ b/src/roots.c @@ -35,6 +35,9 @@ #include "include/yaffs2/utils/mkyaffs2image.h" #include "include/yaffs2/utils/unyaffs.h" +#ifndef major +# include +#endif int num_volumes; Volume* device_volumes; @@ -144,7 +147,9 @@ void load_volume_table() { device_volumes[num_volumes].fs_type2 = NULL; device_volumes[num_volumes].fs_options = NULL; device_volumes[num_volumes].fs_options2 = NULL; - + int code; + if(code=stat(device, &device_volumes[num_volumes].stat)!=0) + LOGE("stat: Error %d on file %s\n", code, device); if (parse_options(options, device_volumes + num_volumes) != 0) { LOGE("skipping malformed recovery.fstab line: %s\n", original); } else { @@ -605,3 +610,91 @@ int format_unknown_device(const char *device, const char* path, const char *fs_t ensure_path_unmounted(path); return 0; } +int replace_device_node(Volume* vol, struct stat* stat) { + if(stat==NULL) return -1; + + ssize_t len; + char resolved_path[PATH_MAX]; + if((len = readlink(vol->device, resolved_path, sizeof(resolved_path)-1)) != -1) + resolved_path[len] = '\0'; + else sprintf(resolved_path, "%s", vol->device); + + if(ensure_path_unmounted(vol->mount_point)!=0) { + LOGE("replace_device_node: could not unmount device!\n"); + return -1; + } if(unlink(resolved_path)!=0) { + LOGE("replace_device_node: could not delete node!\n"); + return -1; + } if(mknod(resolved_path, stat->st_mode, stat->st_rdev)!=0) { + LOGE("replace_device_node: could not create node!\n"); + return -1; + } + return 0; +} + +int handle_volume_request(Volume* vol0, Volume* vol1, int num) { + if(vol0!=NULL && vol1!=NULL) { + Volume* v0; + Volume* v1; + if(num==DUALBOOT_ITEM_SYSTEM0) { + v0=vol0; + v1=vol0; + } + else if(num==DUALBOOT_ITEM_SYSTEM1) { + v0=vol1; + v1=vol1; + } + else if(num==DUALBOOT_ITEM_BOTH) { + v0=vol0; + v1=vol1; + } + else if(num==DUALBOOT_ITEM_INTERCHANGED) { + v0=vol1; + v1=vol0; + } + else { + LOGE("set_active_system: invalid system number: %d!\n", num); + return -1; + } + + if(replace_device_node(vol0, &v0->stat)!=0) + return -1; + if(replace_device_node(vol1, &v1->stat)!=0) + return -1; + + return 0; + } + else { + LOGE("set_active_system: invalid volumes given!\n"); + return -1; + } +} + +int selected_dualsystem_mode = -1; +int getDualsystemMode() { + return selected_dualsystem_mode; +} + +int set_active_system(int num) { + int i; + char* mount_point; + Volume* system0 = volume_for_path("/system"); + Volume* system1 = volume_for_path("/system1"); + Volume* boot0 = volume_for_path("/boot"); + Volume* boot1 = volume_for_path("/boot1"); + Volume* radio0 = volume_for_path("/radio"); + Volume* radio1 = volume_for_path("/radio1"); + + handle_volume_request(system0, system1, num); + handle_volume_request(boot0, boot1, num); + handle_volume_request(radio0, radio1, num); + + if(ensure_path_unmounted("/data")!=0) { + LOGE("could not unmount /data!\n"); + return -1; + } + + selected_dualsystem_mode = num; + + return 0; +} diff --git a/src/sideload.c b/src/sideload.c new file mode 100644 index 00000000..ed81e14a --- /dev/null +++ b/src/sideload.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "minui/minui.h" +#include "cutils/properties.h" +#include "install.h" +#include "common.h" +#include "recovery_ui.h" +#include "sideload.h" +#include "minadbd/adb.h" + +int finished = 0; + +static void +set_usb_driver(int enabled) { + int fd = open("/sys/class/android_usb/android0/enable", O_WRONLY); + if (fd < 0) { + ui_print("failed to open driver control: %s\n", strerror(errno)); + return; + } + + int status; + if (enabled > 0) { + status = write(fd, "1", 1); + } else { + status = write(fd, "0", 1); + } + + if (status < 0) { + ui_print("failed to set driver control: %s\n", strerror(errno)); + } + + if (close(fd) < 0) { + ui_print("failed to close driver control: %s\n", strerror(errno)); + } +} + +static void +stop_adbd() { + property_set("ctl.stop", "adbd"); + set_usb_driver(0); +} + + +static void +maybe_restart_adbd() { + char value[PROPERTY_VALUE_MAX+1]; + int len = property_get("ro.debuggable", value, NULL); + if (len == 1 && value[0] == '1') { + ui_print("Restarting adbd...\n"); + set_usb_driver(1); + property_set("ctl.start", "adbd"); + } +} + +struct sideload_waiter_data { + pid_t child; +}; + +void *adb_sideload_thread(void* v) { + struct sideload_waiter_data* data = (struct sideload_waiter_data*)v; + + int status; + waitpid(data->child, &status, 0); + LOGI("sideload process finished\n"); + + finished = 1; + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + ui_print("status %d\n", WEXITSTATUS(status)); + } + + LOGI("sideload thread finished\n"); + return NULL; +} + +int start_adb_sideload() { + finished = 0; + stop_adbd(); + set_usb_driver(1); + pid_t child; + if ((child = fork()) == 0) { + execl("/sbin/recovery", "recovery", "adbd", NULL); + _exit(-1); + } + int status; + waitpid(child, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + ui_print("status %d\n", WEXITSTATUS(status)); + } + set_usb_driver(0); + maybe_restart_adbd(); + + return 0; +} diff --git a/src/sideload.h b/src/sideload.h new file mode 100644 index 00000000..a72f70ea --- /dev/null +++ b/src/sideload.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +int start_adb_sideload(); +