diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..4e6ee3b --- /dev/null +++ b/Android.mk @@ -0,0 +1,17 @@ +# Copyright (C) 2010 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. + +ifeq ($(TARGET_BOOTLOADER_BOARD_NAME),s5pc110) + include $(all-subdir-makefiles) +endif diff --git a/BoardConfigCommon.mk b/BoardConfigCommon.mk new file mode 100644 index 0000000..25a9c77 --- /dev/null +++ b/BoardConfigCommon.mk @@ -0,0 +1,106 @@ +# +# 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. + +# BoardConfig.mk +# +# Product-specific compile-time definitions. +# + +# Set this up here so that BoardVendorConfig.mk can override it +BOARD_USES_GENERIC_AUDIO := false + +BOARD_USES_LIBSECRIL_STUB := true + +# ARMv7-A Cortex-A8 architecture +TARGET_CPU_ABI := armeabi-v7a +TARGET_CPU_ABI2 := armeabi +TARGET_ARCH_VARIANT := armv7-a-neon +ARCH_ARM_HAVE_TLS_REGISTER := true +TARGET_GLOBAL_CFLAGS += -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp +TARGET_GLOBAL_CPPFLAGS += -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp +ARCH_ARM_HAVE_TLS_REGISTER := true + +TARGET_NO_BOOTLOADER := true +TARGET_NO_RADIOIMAGE := true + +TARGET_PROVIDES_INIT := true +TARGET_RECOVERY_INITRC := device/samsung/p1-common/recovery.rc + +TARGET_BOARD_PLATFORM := s5pc110 +TARGET_BOARD_PLATFORM_GPU := POWERVR_SGX540_120 +TARGET_BOOTLOADER_BOARD_NAME := s5pc110 + +TARGET_PROVIDES_LIBAUDIO := true + +# Releasetools +TARGET_RELEASETOOL_OTA_FROM_TARGET_SCRIPT := ./device/samsung/p1-common/releasetools/p1_ota_from_target_files +TARGET_RELEASETOOL_IMG_FROM_TARGET_SCRIPT := ./device/samsung/p1-common/releasetools/p1_img_from_target_files + +# Bluetooth +BOARD_HAVE_BLUETOOTH := true +BOARD_HAVE_BLUETOOTH_BCM := true + +# WiFi related defines +BOARD_WPA_SUPPLICANT_DRIVER := WEXT +WPA_SUPPLICANT_VERSION := VER_0_8_X +BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_wext +BOARD_WLAN_DEVICE := bcm4329 +WIFI_DRIVER_MODULE_PATH := "/system/lib/modules/dhd.ko" +WIFI_DRIVER_MODULE_ARG := "firmware_path=/system/etc/wifi/bcm4329_sta.bin nvram_path=/system/etc/wifi/nvram_net.txt dhd_watchdog_ms=10 dhd_poll=1" +WIFI_DRIVER_FW_PATH_AP := "/system/etc/wifi/bcm4329_aps.bin" +WIFI_DRIVER_FW_PATH_STA := "/system/etc/wifi/bcm4329_sta.bin" +WIFI_DRIVER_MODULE_NAME := "dhd" +BOARD_WEXT_NO_COMBO_SCAN := true + +USE_CAMERA_STUB := false +ifeq ($(USE_CAMERA_STUB),false) +BOARD_CAMERA_LIBRARIES := libcamera +endif +BOARD_V4L2_DEVICE := /dev/video1 +BOARD_CAMERA_DEVICE := /dev/video0 +BOARD_SECOND_CAMERA_DEVICE := /dev/video2 + +# OpenGL stuff +BOARD_EGL_CFG := device/samsung/p1-common/prebuilt/lib/egl/egl.cfg +USE_OPENGL_RENDERER := true + +# skia +BOARD_USE_SKIA_LCDTEXT := true + +# Device related defines +BOARD_NAND_PAGE_SIZE := 4096 -s 128 +BOARD_KERNEL_BASE := 0x32000000 +BOARD_KERNEL_PAGESIZE := 4096 +BOARD_KERNEL_CMDLINE := console=ttyFIQ0,115200 init=/init no_console_suspend + +BOARD_BOOTIMAGE_PARTITION_SIZE := 7864320 +BOARD_SYSTEMIMAGE_PARTITION_SIZE := 262144000 +BOARD_USERDATAIMAGE_PARTITION_SIZE := 1319108608 +BOARD_FLASH_BLOCK_SIZE := 4096 + +# Vold +BOARD_VOLD_EMMC_SHARES_DEV_MAJOR := true +TARGET_USE_CUSTOM_LUN_FILE_PATH := "/sys/devices/platform/usb_mass_storage/lun0/file" + +# Recovery +TARGET_USERIMAGES_USE_EXT4 := true +BOARD_HAS_NO_SELECT_BUTTON := true +BOARD_CUSTOM_BOOTIMG_MK := device/samsung/p1-common/shbootimg.mk +TARGET_RECOVERY_PRE_COMMAND := "echo 1 > /cache/.startrecovery; sync;" +BOARD_CUSTOM_GRAPHICS := ../../../device/samsung/p1-common/recovery/graphics.c +BOARD_USES_BML_OVER_MTD := true + +# MTP +BOARD_MTP_DEVICE := "/dev/usb_mtp_gadget" diff --git a/Credits.html b/Credits.html new file mode 100644 index 0000000..133cd67 --- /dev/null +++ b/Credits.html @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + +

+CyanogenMod 9

+

+
+

+

+This +is an unofficial port of +cyanogenmod 9 for Galaxy Tab (P1).

+



+

+

Official +thread : http://forum.xda-developers.com/showthread.php?t=1385153

+

Visit +http://www.cyanogenmod.com +!

+



+

+

This +ROM is free of charge and must not be sold. You are free to copy and +distribute it as long as this file remains unchanged.

+



+

+ +

+Greetings to

+


+

+

+me (cdesai)

+

+angel_666

+

+koxudaxi

+

+Humberos

+

+red_rebel

+

+sbradymobile

+

+jt1134

+

+Techomancer

+

+Cyanogenmod Team

+

+TeamHacksung!

+

+Google!

+

+Samsung

+

+All the Tab community@xda

+

+All the folks who have worked on aries and the tab

+

+All the XDA developers

+

+And anyone else i forgot

+


+

+


+

+

Enjoy +this ROM!

+


+

+


+

+


+

+ + diff --git a/P1Parts/Android.mk b/P1Parts/Android.mk new file mode 100644 index 0000000..bb85b23 --- /dev/null +++ b/P1Parts/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := P1Parts +LOCAL_CERTIFICATE := platform + +# Required so that symbols used by the jni library doesn't get stripped out +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/P1Parts/AndroidManifest.xml b/P1Parts/AndroidManifest.xml new file mode 100644 index 0000000..5f37a8a --- /dev/null +++ b/P1Parts/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/P1Parts/res/drawable/color_tuning_preview.xml b/P1Parts/res/drawable/color_tuning_preview.xml new file mode 100644 index 0000000..2d83c10 --- /dev/null +++ b/P1Parts/res/drawable/color_tuning_preview.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/P1Parts/res/layout/preference_dialog_color_tuning.xml b/P1Parts/res/layout/preference_dialog_color_tuning.xml new file mode 100644 index 0000000..f228541 --- /dev/null +++ b/P1Parts/res/layout/preference_dialog_color_tuning.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/P1Parts/res/values-de/arrays.xml b/P1Parts/res/values-de/arrays.xml new file mode 100644 index 0000000..7339912 --- /dev/null +++ b/P1Parts/res/values-de/arrays.xml @@ -0,0 +1,18 @@ + + + Standard (1,6 Sekunden) + 0,5 Sekunden + 2 Sekunden + 5 Sekunden + 10 Sekunden + 15 Sekunden + 30 Sekunden + Nie + + + + Nur UMTS + Nur HSDPA + HSDPA + HSUPA + + diff --git a/P1Parts/res/values-de/strings.xml b/P1Parts/res/values-de/strings.xml new file mode 100644 index 0000000..b9f9d98 --- /dev/null +++ b/P1Parts/res/values-de/strings.xml @@ -0,0 +1,19 @@ + + + Galaxy-Tab-Einstellungen + + Bildschirm + Farbanpassung + Bildschirmfarben kalibrieren + Rot + Grün + Blau + + Tasten + Beleuchtung + Verzögerung bis zum Abschalten der Tastenbeleuchtung einstellen + + Funk + HSPA + HSDPA/HSUPA aktivieren + diff --git a/P1Parts/res/values-pl/arrays.xml b/P1Parts/res/values-pl/arrays.xml new file mode 100644 index 0000000..4e4b53e --- /dev/null +++ b/P1Parts/res/values-pl/arrays.xml @@ -0,0 +1,35 @@ + + + Domyślnie (1.6 sekundy) + 0.5 sekundy + 2 sekundy + 5 sekund + 10 sekund + 15 sekund + 30 sekund + Nigdy + + + + 1600 + 500 + 2000 + 5000 + 10000 + 15000 + 30000 + -1 + + + + Tylko UMTS + Tylko HSDPA + HSDPA lub HSUPA + + + + 21 + 22 + 23 + + diff --git a/P1Parts/res/values-pl/strings.xml b/P1Parts/res/values-pl/strings.xml new file mode 100644 index 0000000..0105608 --- /dev/null +++ b/P1Parts/res/values-pl/strings.xml @@ -0,0 +1,19 @@ + + + Ustawienia Galaxy Tab + + Wyświetlacz + Modyfikacja kolorów + Kalibruj kolory wyświetlacza + Czerwony + Zielony + Niebieski + + Przyciski dotykowe + Czas podświetlenia + Określ po jakim czasie podświetlenie klawiszy zgaśnie + + Modem + HSPA + Włącz HSDPA/HSUPA + diff --git a/P1Parts/res/values-pt/arrays.xml b/P1Parts/res/values-pt/arrays.xml new file mode 100644 index 0000000..75233fa --- /dev/null +++ b/P1Parts/res/values-pt/arrays.xml @@ -0,0 +1,45 @@ + + + Padrão (1.6 segundos) + 0.5 segundos + 2 segundos + 5 segundos + 10 segundos + 15 segundos + 30 segundos + Nunca + + + + 1600 + 500 + 2000 + 5000 + 10000 + 15000 + 30000 + -1 + + + + UMTS Apenas + HSDPA Apenas + HSDPA + HSUPA + + + + 21 + 22 + 23 + + + + NTSC + PAL + + + + 1 + 2 + + diff --git a/P1Parts/res/values-pt/strings.xml b/P1Parts/res/values-pt/strings.xml new file mode 100644 index 0000000..6e0937e --- /dev/null +++ b/P1Parts/res/values-pt/strings.xml @@ -0,0 +1,27 @@ + + + Configurações do Galaxy Tab + + Tela + Ajuste de Cor + Calibrar as cores da tela + Vermelho + Verde + Azul + + Botões Touch + Tempo Limite da Iluminação + Ajuste o tempo para desligar a iluminação dos Botões Touch + + Radio + HSPA + Ativar HSDPA/HSUPA + + Saída de TV + Saída de TV + Cabo para Saída de TV não conectado + Cabo para Saída de TV conectado, ative para usar + Saída de TV ativada + Sistema de TV + Ajuste seu sistema de TV para a Saída de TV + diff --git a/P1Parts/res/values-ru/arrays.xml b/P1Parts/res/values-ru/arrays.xml new file mode 100644 index 0000000..52766a1 --- /dev/null +++ b/P1Parts/res/values-ru/arrays.xml @@ -0,0 +1,19 @@ + + + По умолчанию (1.6 секунды) + 0.5 секунды + 2 секунды + 5 секунд + 10 секунд + 15 секунд + 30 секунд + Никогда + + + + Только UMTS + Только HSDPA + HSDPA + HSUPA + + + diff --git a/P1Parts/res/values-ru/strings.xml b/P1Parts/res/values-ru/strings.xml new file mode 100644 index 0000000..1a875f8 --- /dev/null +++ b/P1Parts/res/values-ru/strings.xml @@ -0,0 +1,19 @@ + + + Настройки Galaxy Tab + + Экран + Настройки цвета + Калибровка цвета экрана + Красный + Зелёный + Синий + + Сенсорные кнопки + Таймаут подсветки + Как долго работает подсветка сенсорных кнопок + + Радиомодуль + HSPA + Включить HSDPA/HSUPA + diff --git a/P1Parts/res/values-zh-rTW/arrays.xml b/P1Parts/res/values-zh-rTW/arrays.xml new file mode 100644 index 0000000..da23e46 --- /dev/null +++ b/P1Parts/res/values-zh-rTW/arrays.xml @@ -0,0 +1,22 @@ + + + 預設(1.6秒) + 0.5秒 + 2秒 + 5秒 + 10秒 + 15秒 + 30秒 + 永不 + + + + + + 僅 UMTS + 僅 HSDPA + HSDPA+HSUPA + + + + diff --git a/P1Parts/res/values-zh-rTW/strings.xml b/P1Parts/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000..9d2fba7 --- /dev/null +++ b/P1Parts/res/values-zh-rTW/strings.xml @@ -0,0 +1,19 @@ + + + Galaxy Tab 設定 + + 螢幕 + 色彩調整 + 校正螢幕色彩 + + + + + 觸控鍵 + 背光逾時 + 調整觸控鍵背光自動關閉前的延遲時間 + + 行動網路 + HSPA + 啟用 HSDPA/HSUPA + diff --git a/P1Parts/res/values/arrays.xml b/P1Parts/res/values/arrays.xml new file mode 100644 index 0000000..5d32de2 --- /dev/null +++ b/P1Parts/res/values/arrays.xml @@ -0,0 +1,45 @@ + + + Default (1.6 seconds) + 0.5 seconds + 2 seconds + 5 seconds + 10 seconds + 15 seconds + 30 seconds + Never + + + + 1600 + 500 + 2000 + 5000 + 10000 + 15000 + 30000 + -1 + + + + UMTS Only + HSDPA Only + HSDPA + HSUPA + + + + 21 + 22 + 23 + + + + NTSC + PAL + + + + 1 + 2 + + diff --git a/P1Parts/res/values/strings.xml b/P1Parts/res/values/strings.xml new file mode 100644 index 0000000..fa8e314 --- /dev/null +++ b/P1Parts/res/values/strings.xml @@ -0,0 +1,34 @@ + + + Galaxy Tab Settings + + Screen + Color Tuning + Calibrate screen color + Red + Green + Blue + + Touch Keys + Backlight Timeout + Adjust the delay before the touch key backlight automatically turns off + + Radio + HSPA + Enable HSDPA/HSUPA + + TV Out + TV Out + TV Out cable not connected + TV Out cable connected, check to enable + TV Out enabled + TV System + Set your TV system for TV Out + + View Credits + Credits + Loading Credits ...\u2026 + Error loading Credits\u2026 + Unknown + Version + diff --git a/P1Parts/res/xml/main.xml b/P1Parts/res/xml/main.xml new file mode 100644 index 0000000..5214ae4 --- /dev/null +++ b/P1Parts/res/xml/main.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/P1Parts/src/android/hardware/TvOut.java b/P1Parts/src/android/hardware/TvOut.java new file mode 100644 index 0000000..6137c43 --- /dev/null +++ b/P1Parts/src/android/hardware/TvOut.java @@ -0,0 +1,79 @@ +package android.hardware; + +import java.lang.ref.WeakReference; + +import android.graphics.Bitmap; +import android.util.Log; + +public class TvOut { + private static final String TAG = "TvOut"; + + private int mListenerContext; + private int mNativeContext; + + public native void _DisableTvOut(); + + public native void _EnableTvOut(); + + public native void _SetOrientation(int paramInt); + + public native void _SetTvScreenSize(int paramInt); + + public native void _SetTvSystem(int paramInt); + + public native void _TvOutResume(int paramInt); + + public native void _TvOutSetImageString(String paramString); + + public native void _TvOutSuspend(String paramString); + public native void _TvOutHdmiSuspend(String paramString); + + public native boolean _TvoutSubtitleIsEnable(); + + public native boolean _TvoutSubtitlePostBitmap(Bitmap paramBitmap, int paramInt); + + public native boolean _TvoutSubtitleSetStatus(int paramInt); + + public native int _getSubtitleHDMIHeight(); + + public native int _getSubtitleHDMIWidth(); + + public native boolean _isEnabled(); + public native boolean _isHdmiEnabled(); + + public native boolean _isSuspended(); + public native boolean _isHdmiSuspended(); + + public native boolean _isTvoutCableConnected(); + public native boolean _isHdmiCableConnected(); + + private final native void _native_setup(Object paramObject); + + private final native void _release(); + + public native void _setTvoutCableConnected(int paramInt); + public native void _setHdmiCableConnected(int paramInt); + + public native boolean _SetTvoutHdmiStatus(int paramInt); + public native boolean _isHdmiDualEnabled(); + public native void _SetTvoutHdmiDualStatus(int paramInt); + + static { + System.loadLibrary("tvout_jni"); + } + + public TvOut() { + _native_setup(new WeakReference(this)); + } + + public void finalize() { + _release(); + } + + private static void postEventFromNative(Object tvOutRef, int what, int arg1, int arg2, Object obj) { + TvOut tvOut = (TvOut)((WeakReference)tvOutRef).get(); + + Log.d(TAG, "Native Event: " + what + " " + arg1 + " " + arg2); + } + +} diff --git a/P1Parts/src/com/cyanogenmod/P1Parts/ColorTuningPreference.java b/P1Parts/src/com/cyanogenmod/P1Parts/ColorTuningPreference.java new file mode 100644 index 0000000..db063a8 --- /dev/null +++ b/P1Parts/src/com/cyanogenmod/P1Parts/ColorTuningPreference.java @@ -0,0 +1,173 @@ +package com.cyanogenmod.P1Parts; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.preference.DialogPreference; +import android.preference.PreferenceManager; +import android.util.AttributeSet; +import android.view.View; +import android.widget.SeekBar; +import android.widget.TextView; + +/** + * Special preference type that allows configuration of both the ring volume and + * notification volume. + */ +public class ColorTuningPreference extends DialogPreference { + + enum Colors { + RED, + GREEN, + BLUE + }; + + private static final int[] SEEKBAR_ID = new int[] { + R.id.color_red_seekbar, + R.id.color_green_seekbar, + R.id.color_blue_seekbar + }; + + private static final int[] VALUE_DISPLAY_ID = new int[] { + R.id.color_red_value, + R.id.color_green_value, + R.id.color_blue_value + }; + + private static final String[] FILE_PATH = new String[] { + "/sys/devices/virtual/misc/color_tuning/red_multiplier", + "/sys/devices/virtual/misc/color_tuning/green_multiplier", + "/sys/devices/virtual/misc/color_tuning/blue_multiplier" + }; + + private ColorSeekBar mSeekBars[] = new ColorSeekBar[3]; + + private static final int MAX_VALUE = Integer.MAX_VALUE; + + // Track instances to know when to restore original color + // (when the orientation changes, a new dialog is created before the old one is destroyed) + private static int sInstances = 0; + + public ColorTuningPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + setDialogLayoutResource(R.layout.preference_dialog_color_tuning); + } + + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + + sInstances++; + + for (int i = 0; i < SEEKBAR_ID.length; i++) { + SeekBar seekBar = (SeekBar) view.findViewById(SEEKBAR_ID[i]); + TextView valueDisplay = (TextView) view.findViewById(VALUE_DISPLAY_ID[i]); + mSeekBars[i] = new ColorSeekBar(seekBar, valueDisplay, FILE_PATH[i]); + } + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + super.onDialogClosed(positiveResult); + + sInstances--; + + if (positiveResult) { + for (ColorSeekBar csb : mSeekBars) { + csb.save(); + } + } else if (sInstances == 0) { + for (ColorSeekBar csb : mSeekBars) { + csb.reset(); + } + } + } + + /** + * Restore screen color tuning from SharedPreferences. (Write to kernel.) + * @param context The context to read the SharedPreferences from + */ + public static void restore(Context context) { + if (!isSupported()) { + return; + } + + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); + for (String filePath : FILE_PATH) { + int value = sharedPrefs.getInt(filePath, MAX_VALUE); + Utils.writeColor(filePath, value); + } + } + + /** + * Check whether the running kernel supports color tuning or not. + * @return Whether color tuning is supported or not + */ + public static boolean isSupported() { + boolean supported = true; + for (String filePath : FILE_PATH) { + if (!Utils.fileExists(filePath)) { + supported = false; + } + } + + return supported; + } + + class ColorSeekBar implements SeekBar.OnSeekBarChangeListener { + + private String mFilePath; + private int mOriginal; + private SeekBar mSeekBar; + private TextView mValueDisplay; + + public ColorSeekBar(SeekBar seekBar, TextView valueDisplay, String filePath) { + mSeekBar = seekBar; + mValueDisplay = valueDisplay; + mFilePath = filePath; + + // Read original value + SharedPreferences sharedPreferences = getSharedPreferences(); + mOriginal = sharedPreferences.getInt(mFilePath, MAX_VALUE); + + seekBar.setMax(MAX_VALUE); + reset(); + seekBar.setOnSeekBarChangeListener(this); + } + + public void reset() { + mSeekBar.setProgress(mOriginal); + updateValue(mOriginal); + } + + public void save() { + Editor editor = getEditor(); + editor.putInt(mFilePath, mSeekBar.getProgress()); + editor.commit(); + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, + boolean fromUser) { + Utils.writeColor(mFilePath, progress); + updateValue(progress); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // Do nothing + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // Do nothing + } + + private void updateValue(int progress) { + mValueDisplay.setText(String.format("%.3f", (double) progress / MAX_VALUE)); + } + + } + +} diff --git a/P1Parts/src/com/cyanogenmod/P1Parts/Credits.java b/P1Parts/src/com/cyanogenmod/P1Parts/Credits.java new file mode 100644 index 0000000..808cad6 --- /dev/null +++ b/P1Parts/src/com/cyanogenmod/P1Parts/Credits.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2011 The CyanogenMod 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. + */ + +package com.cyanogenmod.P1Parts; + +import com.cyanogenmod.P1Parts.R; + +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Config; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.Toast; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import com.android.internal.app.AlertActivity; +import com.android.internal.app.AlertController; + +public class Credits extends AlertActivity { + + private static final String CREDITS_PATH = "/system/etc/Credits.html"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + InputStreamReader inputReader = null; + StringBuilder data = null; + try { + data = new StringBuilder(2048); + char tmp[] = new char[2048]; + int numRead; + inputReader = new FileReader(CREDITS_PATH); + while ((numRead = inputReader.read(tmp)) >= 0) { + data.append(tmp, 0, numRead); + } + } catch (IOException e) { + showErrorAndFinish(); + return; + } finally { + try { + if (inputReader != null) { + inputReader.close(); + } + } catch (IOException e) { + } + } + + if (TextUtils.isEmpty(data)) { + showErrorAndFinish(); + return; + } + + WebView webView = new WebView(this); + + // Begin the loading. This will be done in a separate thread in WebView. + webView.loadDataWithBaseURL(null, data.toString(), "text/html", "utf-8", null); + webView.setWebViewClient(new WebViewClient() { + @Override + public void onPageFinished(WebView view, String url) { + // Change from 'Loading...' to the real title + mAlert.setTitle(getString(R.string.credits_dialog)); + } + }); + + final AlertController.AlertParams p = mAlertParams; + p.mTitle = getString(R.string.credits_loading); + p.mView = webView; + p.mForceInverseBackground = true; + setupAlert(); + } + + private void showErrorAndFinish() { + Toast.makeText(this, R.string.credits_error, Toast.LENGTH_LONG) + .show(); + finish(); + } + +} diff --git a/P1Parts/src/com/cyanogenmod/P1Parts/Hspa.java b/P1Parts/src/com/cyanogenmod/P1Parts/Hspa.java new file mode 100644 index 0000000..24c8cff --- /dev/null +++ b/P1Parts/src/com/cyanogenmod/P1Parts/Hspa.java @@ -0,0 +1,48 @@ +package com.cyanogenmod.P1Parts; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.PreferenceManager; + +public class Hspa implements OnPreferenceChangeListener { + + private static final String APK_FILE = "/system/app/SamsungServiceMode.apk"; + private Context mCtx; + + public Hspa(Context context) { + mCtx = context; + } + + public static boolean isSupported() { + return Utils.fileExists(APK_FILE); + } + + /** + * Restore HSPA setting from SharedPreferences. (Write to kernel.) + * @param context The context to read the SharedPreferences from + */ + public static void restore(Context context) { + if (!isSupported()) { + return; + } + + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); + sendIntent(context, sharedPrefs.getString(P1Parts.KEY_HSPA, "23")); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + sendIntent(mCtx, (String) newValue); + return true; + } + + private static void sendIntent(Context context, String value) { + Intent i = new Intent("com.cyanogenmod.SamsungServiceMode.EXECUTE"); + i.putExtra("sub_type", 20); // HSPA Setting + i.putExtra("data", value); + context.sendBroadcast(i); + } +} diff --git a/P1Parts/src/com/cyanogenmod/P1Parts/P1Parts.java b/P1Parts/src/com/cyanogenmod/P1Parts/P1Parts.java new file mode 100644 index 0000000..594774c --- /dev/null +++ b/P1Parts/src/com/cyanogenmod/P1Parts/P1Parts.java @@ -0,0 +1,118 @@ +package com.cyanogenmod.P1Parts; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.hardware.TvOut; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.PreferenceActivity; + +public class P1Parts extends PreferenceActivity { + + public static final String KEY_COLOR_TUNING = "color_tuning"; + public static final String KEY_BACKLIGHT_TIMEOUT = "backlight_timeout"; + public static final String KEY_HSPA = "hspa"; + public static final String KEY_TVOUT_ENABLE = "tvout_enable"; + public static final String KEY_TVOUT_SYSTEM = "tvout_system"; + + private ColorTuningPreference mColorTuning; + private ListPreference mBacklightTimeout; + private ListPreference mHspa; + private CheckBoxPreference mTvOutEnable; + private ListPreference mTvOutSystem; + private TvOut mTvOut; + + private BroadcastReceiver mHeadsetReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + int state = intent.getIntExtra("state", 0); + updateTvOutEnable(state != 0); + } + + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.main); + + mColorTuning = (ColorTuningPreference) findPreference(KEY_COLOR_TUNING); + mColorTuning.setEnabled(ColorTuningPreference.isSupported()); + + mBacklightTimeout = (ListPreference) findPreference(KEY_BACKLIGHT_TIMEOUT); + mBacklightTimeout.setEnabled(TouchKeyBacklightTimeout.isSupported()); + mBacklightTimeout.setOnPreferenceChangeListener(new TouchKeyBacklightTimeout()); + + mHspa = (ListPreference) findPreference(KEY_HSPA); + mHspa.setEnabled(Hspa.isSupported()); + mHspa.setOnPreferenceChangeListener(new Hspa(this)); + + mTvOut = new TvOut(); + mTvOutEnable = (CheckBoxPreference) findPreference(KEY_TVOUT_ENABLE); + mTvOutEnable.setChecked(mTvOut._isEnabled()); + + mTvOutEnable.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + boolean enable = (Boolean) newValue; + Intent i = new Intent(P1Parts.this, TvOutService.class); + i.putExtra(TvOutService.EXTRA_COMMAND, enable ? TvOutService.COMMAND_ENABLE : TvOutService.COMMAND_DISABLE); + startService(i); + return true; + } + + }); + + mTvOutSystem = (ListPreference) findPreference(KEY_TVOUT_SYSTEM); + mTvOutSystem.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (mTvOut._isEnabled()) { + int newSystem = Integer.valueOf((String) newValue); + Intent i = new Intent(P1Parts.this, TvOutService.class); + i.putExtra(TvOutService.EXTRA_COMMAND, TvOutService.COMMAND_CHANGE_SYSTEM); + i.putExtra(TvOutService.EXTRA_SYSTEM, newSystem); + startService(i); + } + return true; + } + + }); + } + + @Override + protected void onResume() { + super.onResume(); + registerReceiver(mHeadsetReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); + } + + @Override + protected void onPause() { + super.onPause(); + unregisterReceiver(mHeadsetReceiver); + } + + private void updateTvOutEnable(boolean connected) { + mTvOutEnable.setEnabled(connected); + mTvOutEnable.setSummaryOff(connected ? R.string.tvout_enable_summary : R.string.tvout_enable_summary_nocable); + + if (!connected && mTvOutEnable.isChecked()) { + // Disable on unplug (UI) + mTvOutEnable.setChecked(false); + } + } + + @Override + protected void onDestroy() { + mTvOut.finalize(); + super.onDestroy(); + } + +} diff --git a/P1Parts/src/com/cyanogenmod/P1Parts/Startup.java b/P1Parts/src/com/cyanogenmod/P1Parts/Startup.java new file mode 100644 index 0000000..183c8f8 --- /dev/null +++ b/P1Parts/src/com/cyanogenmod/P1Parts/Startup.java @@ -0,0 +1,16 @@ +package com.cyanogenmod.P1Parts; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class Startup extends BroadcastReceiver { + + @Override + public void onReceive(final Context context, final Intent bootintent) { + ColorTuningPreference.restore(context); + TouchKeyBacklightTimeout.restore(context); + Hspa.restore(context); + } + +} diff --git a/P1Parts/src/com/cyanogenmod/P1Parts/TouchKeyBacklightTimeout.java b/P1Parts/src/com/cyanogenmod/P1Parts/TouchKeyBacklightTimeout.java new file mode 100644 index 0000000..32d6678 --- /dev/null +++ b/P1Parts/src/com/cyanogenmod/P1Parts/TouchKeyBacklightTimeout.java @@ -0,0 +1,36 @@ +package com.cyanogenmod.P1Parts; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.PreferenceManager; + +public class TouchKeyBacklightTimeout implements OnPreferenceChangeListener { + + private static final String FILE = "/sys/class/misc/notification/bl_timeout"; + + public static boolean isSupported() { + return Utils.fileExists(FILE); + } + + /** + * Restore backlight timeout setting from SharedPreferences. (Write to kernel.) + * @param context The context to read the SharedPreferences from + */ + public static void restore(Context context) { + if (!isSupported()) { + return; + } + + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); + Utils.writeValue(FILE, sharedPrefs.getString(P1Parts.KEY_BACKLIGHT_TIMEOUT, "1600")); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + Utils.writeValue(FILE, (String) newValue); + return true; + } + +} diff --git a/P1Parts/src/com/cyanogenmod/P1Parts/TvOutService.java b/P1Parts/src/com/cyanogenmod/P1Parts/TvOutService.java new file mode 100644 index 0000000..f59dc03 --- /dev/null +++ b/P1Parts/src/com/cyanogenmod/P1Parts/TvOutService.java @@ -0,0 +1,146 @@ +package com.cyanogenmod.P1Parts; + +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.hardware.TvOut; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemProperties; +import android.preference.PreferenceManager; +import android.view.Display; +import android.view.IRotationWatcher; +import android.view.IWindowManager; +import android.view.WindowManager; + +public class TvOutService extends Service { + + public static final String EXTRA_COMMAND = "command"; + public static final String EXTRA_SYSTEM = "system"; + public static final String COMMAND_ENABLE = "enable"; + public static final String COMMAND_DISABLE = "disable"; + public static final String COMMAND_CHANGE_SYSTEM = "system"; + + private TvOut mTvOut; + private SharedPreferences mPref; + private int mSystem; + private boolean mWasOn = false; // For enabling on screen on + + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_HEADSET_PLUG.equals(action)) { + int state = intent.getIntExtra("state", 0); + if (state == 0 && mTvOut._isEnabled()) { + // Disable when cable is unplugged + mWasOn = false; + disable(); + stopSelf(); + } + } + else if (Intent.ACTION_SCREEN_ON.equals(action)) { + if (mWasOn) { + SystemProperties.set("ctl.start", "tvouthack"); + mWasOn = false; + } + } + else if (Intent.ACTION_SCREEN_OFF.equals(action)) { + if (mTvOut._isEnabled()) { + mWasOn = true; + SystemProperties.set("ctl.stop", "tvouthack"); + } + } + } + + }; + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + mTvOut = new TvOut(); + mPref = PreferenceManager.getDefaultSharedPreferences(this); + + IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); + try { + wm.watchRotation(new IRotationWatcher.Stub() { + @Override + public void onRotationChanged(int rotation) { + TvOutService.this.onRotationChanged(rotation); + } + }); + } + catch (RemoteException e) { } + + IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_SCREEN_ON); + registerReceiver(mReceiver, filter); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (intent != null) { + String command = intent.getStringExtra("command"); + if (COMMAND_ENABLE.equals(command)) { + mSystem = Integer.parseInt(mPref.getString(P1Parts.KEY_TVOUT_SYSTEM, "2")); // Default = PAL + enable(); + } + else if (COMMAND_DISABLE.equals(command)) { + disable(); + stopSelf(); + } + else if (COMMAND_CHANGE_SYSTEM.equals(command)) { + if (mTvOut._isEnabled()) { + mSystem = intent.getIntExtra(EXTRA_SYSTEM, 2); + disable(); + enable(); + } + } + } + + return START_STICKY; + } + + @Override + public void onDestroy() { + unregisterReceiver(mReceiver); + mTvOut.finalize(); + super.onDestroy(); + } + + public void onRotationChanged(int rotation) { + mTvOut._SetOrientation(rotation); + } + + private void enable() { + mTvOut._SetTvSystem(mSystem); + mTvOut._TvOutSetImageString("TV-out not supported while application running. Phone display only"); + + Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + mTvOut._SetOrientation(display.getRotation()); + + mTvOut._EnableTvOut(); + mTvOut._setTvoutCableConnected(1); + + // Start tvouthack service used to bombard screen refresh messages + SystemProperties.set("ctl.start", "tvouthack"); + } + + private void disable() { + SystemProperties.set("ctl.stop", "tvouthack"); + + mTvOut._DisableTvOut(); + mTvOut._setTvoutCableConnected(0); + } + +} diff --git a/P1Parts/src/com/cyanogenmod/P1Parts/Utils.java b/P1Parts/src/com/cyanogenmod/P1Parts/Utils.java new file mode 100644 index 0000000..110d41d --- /dev/null +++ b/P1Parts/src/com/cyanogenmod/P1Parts/Utils.java @@ -0,0 +1,47 @@ +package com.cyanogenmod.P1Parts; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public class Utils { + + /** + * Write a string value to the specified file. + * @param filename The filename + * @param value The value + */ + public static void writeValue(String filename, String value) { + try { + FileOutputStream fos = new FileOutputStream(new File(filename)); + fos.write(value.getBytes()); + fos.flush(); + fos.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Write the "color value" to the specified file. The value is scaled from + * an integer to an unsigned integer by multiplying by 2. + * @param filename The filename + * @param value The value of max value Integer.MAX + */ + public static void writeColor(String filename, int value) { + writeValue(filename, String.valueOf((long) value * 2)); + } + + /** + * Check if the specified file exists. + * @param filename The filename + * @return Whether the file exists or not + */ + public static boolean fileExists(String filename) { + return new File(filename).exists(); + } + +} diff --git a/bdaddr_read/Android.mk b/bdaddr_read/Android.mk new file mode 100644 index 0000000..46f95cd --- /dev/null +++ b/bdaddr_read/Android.mk @@ -0,0 +1,28 @@ +# Copyright (C) 2010 Ricardo Cerqueira +# Copyright (C) 2011 Pawit Pornkitprasan +# +# 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := bdaddr_read.c + +LOCAL_SHARED_LIBRARIES := libcutils + +LOCAL_MODULE := bdaddr_read + +include $(BUILD_EXECUTABLE) + diff --git a/bdaddr_read/bdaddr_read.c b/bdaddr_read/bdaddr_read.c new file mode 100644 index 0000000..c6e08c9 --- /dev/null +++ b/bdaddr_read/bdaddr_read.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include + +#define LOG_TAG "bdaddr" +#define SAMSUNG_BDADDR_PATH "/efs/imei/bt.txt" +#define BDADDR_PATH "/data/bdaddr" + +/* Read bluetooth MAC from SAMSUNG_BDADDR_PATH (different format), + * write it to BDADDR_PATH, and set ro.bt.bdaddr_path to BDADDR_PATH + * + * Adapted from bdaddr_read.c of thunderg + */ + +int main() { + char tmpbdaddr[23]; // bt_macaddr:xxxxxxxxxxxx + char bdaddr[18]; + int count; + int fd; + + fd = open(SAMSUNG_BDADDR_PATH, O_RDONLY); + if(fd < 0) { + fprintf(stderr, "open(%s) failed\n", SAMSUNG_BDADDR_PATH); + LOGE("Can't open %s\n", SAMSUNG_BDADDR_PATH); + return -1; + } + + count = read(fd, tmpbdaddr, sizeof(tmpbdaddr)); + if (count < 0) { + fprintf(stderr, "read(%s) failed\n", SAMSUNG_BDADDR_PATH); + LOGE("Can't read %s\n", SAMSUNG_BDADDR_PATH); + return -1; + } + else if (count != sizeof(tmpbdaddr)) { + fprintf(stderr, "read(%s) unexpected size %d\n", SAMSUNG_BDADDR_PATH, count); + LOGE("Error reading %s (unexpected size %d)\n", SAMSUNG_BDADDR_PATH, count); + return -1; + } + + count = sprintf(bdaddr, "%2.2s:%2.2s:%2.2s:%2.2s:%2.2s:%2.2s\0", + tmpbdaddr+11,tmpbdaddr+13,tmpbdaddr+15,tmpbdaddr+17,tmpbdaddr+19,tmpbdaddr+21); + + fd = open(BDADDR_PATH, O_WRONLY|O_CREAT|O_TRUNC, 00600|00060|00006); + if (fd < 0) { + fprintf(stderr, "open(%s) failed\n", BDADDR_PATH); + LOGE("Can't open %s\n", BDADDR_PATH); + return -2; + } + write(fd, bdaddr, 18); + close(fd); + property_set("ro.bt.bdaddr_path", BDADDR_PATH); + return 0; +} diff --git a/bml_over_mtd.sh b/bml_over_mtd.sh new file mode 100644 index 0000000..be73e15 --- /dev/null +++ b/bml_over_mtd.sh @@ -0,0 +1,44 @@ +#!/sbin/busybox sh +# +# bml_over_mtd.sh +# Take care of bad blocks while flashing kernel image to boot partition +# + +PARTITION=$1 +PARTITION_START_BLOCK=$2 +RESERVOIRPARTITION=$3 +RESERVOIR_START_BLOCK=$4 +IMAGE=$5 + +# remove old log +rm -rf /sdcard/bml_over_mtd.log + +# everything is logged into /sdcard/bml_over_mtd.log +exec >> /sdcard/bml_over_mtd.log 2>&1 + +set -x +export PATH=/:/sbin:/system/xbin:/system/bin:$PATH + +busybox cat < ../../../vendor/samsung/galaxytab7c/galaxytab7c-vendor-blobs.mk +# Copyright (C) 2010 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. + +# Prebuilt libraries that are needed to build open-source libraries +PRODUCT_COPY_FILES := \\ + vendor/samsung/galaxytab7c/proprietary/libril.so:obj/lib/libril.so \\ + vendor/samsung/galaxytab7c/proprietary/libsecril-client.so:obj/lib/libsecril-client.so + +# radio +PRODUCT_COPY_FILES += \\ + vendor/samsung/galaxytab7c/proprietary/libril.so:system/lib/libril.so \\ + vendor/samsung/galaxytab7c/proprietary/libsecril-client.so:system/lib/libsecril-client.so \\ + vendor/samsung/galaxytab7c/proprietary/libsec-ril40.so:system/lib/libsec-ril40.so \\ + vendor/samsung/galaxytab7c/proprietary/rild:system/bin/rild \\ + vendor/samsung/galaxytab7c/proprietary/pppd_runner:system/bin/pppd_runner + +# gps +PRODUCT_COPY_FILES += \\ + vendor/samsung/galaxytab7c/proprietary/gps.s5pc110.so:system/lib/hw/gps.s5pc110.so \\ + vendor/samsung/galaxytab7c/proprietary/gpsd:system/vendor/bin/gpsd \\ + vendor/samsung/galaxytab7c/proprietary/gps.conf:system/etc/gps.conf + +# sensors +PRODUCT_COPY_FILES += \\ + vendor/samsung/galaxytab7c/proprietary/libakm.so:system/lib/libakm.so \\ + vendor/samsung/galaxytab7c/proprietary/sensors.s5pc110.so:system/lib/hw/sensors.s5pc110.so + +# gfx +PRODUCT_COPY_FILES += \\ + vendor/samsung/galaxytab7c/proprietary/pvrsrvinit:system/bin/pvrsrvinit \\ + vendor/samsung/galaxytab7c/proprietary/libGLES_android.so:system/lib/egl/libGLES_android.so \\ + vendor/samsung/galaxytab7c/proprietary/libEGL_POWERVR_SGX540_120.so:system/vendor/lib/egl/libEGL_POWERVR_SGX540_120.so \\ + vendor/samsung/galaxytab7c/proprietary/libGLESv1_CM_POWERVR_SGX540_120.so:system/vendor/lib/egl/libGLESv1_CM_POWERVR_SGX540_120.so \\ + vendor/samsung/galaxytab7c/proprietary/libGLESv2_POWERVR_SGX540_120.so:system/vendor/lib/egl/libGLESv2_POWERVR_SGX540_120.so \\ + vendor/samsung/galaxytab7c/proprietary/gralloc.s5pc110.so:system/vendor/lib/hw/gralloc.s5pc110.so \\ + vendor/samsung/galaxytab7c/proprietary/libglslcompiler.so:system/vendor/lib/libglslcompiler.so \\ + vendor/samsung/galaxytab7c/proprietary/libIMGegl.so:system/vendor/lib/libIMGegl.so \\ + vendor/samsung/galaxytab7c/proprietary/libpvr2d.so:system/vendor/lib/libpvr2d.so \\ + vendor/samsung/galaxytab7c/proprietary/libpvrANDROID_WSEGL.so:system/vendor/lib/libpvrANDROID_WSEGL.so \\ + vendor/samsung/galaxytab7c/proprietary/libPVRScopeServices.so:system/vendor/lib/libPVRScopeServices.so \\ + vendor/samsung/galaxytab7c/proprietary/libsrv_init.so:system/vendor/lib/libsrv_init.so \\ + vendor/samsung/galaxytab7c/proprietary/libsrv_um.so:system/vendor/lib/libsrv_um.so \\ + vendor/samsung/galaxytab7c/proprietary/libusc.so:system/vendor/lib/libusc.so + +# wifi +PRODUCT_COPY_FILES += \\ + vendor/samsung/galaxytab7c/proprietary/nvram_net.txt:system/etc/wifi/nvram_net.txt \\ + vendor/samsung/galaxytab7c/proprietary/nvram_mfg.txt:system/etc/wifi/nvram_mfg.txt \\ + vendor/samsung/galaxytab7c/proprietary/bcm4329_aps.bin:system/etc/wifi/bcm4329_aps.bin \\ + vendor/samsung/galaxytab7c/proprietary/bcm4329_mfg.bin:system/etc/wifi/bcm4329_mfg.bin \\ + vendor/samsung/galaxytab7c/proprietary/bcm4329_sta.bin:system/etc/wifi/bcm4329_sta.bin + +# low power mode +PRODUCT_COPY_FILES += \\ + vendor/samsung/galaxytab7c/proprietary/charging_mode:system/bin/charging_mode \\ + vendor/samsung/galaxytab7c/proprietary/playlpm:system/bin/playlpm \\ + vendor/samsung/galaxytab7c/proprietary/libQmageDecoder.so:system/lib/libQmageDecoder.so \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_10.qmg:system/media/battery_charging_10.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_100.qmg:system/media/battery_charging_100.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_15.qmg:system/media/battery_charging_15.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_20.qmg:system/media/battery_charging_20.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_25.qmg:system/media/battery_charging_25.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_30.qmg:system/media/battery_charging_30.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_35.qmg:system/media/battery_charging_35.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_40.qmg:system/media/battery_charging_40.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_45.qmg:system/media/battery_charging_45.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_5.qmg:system/media/battery_charging_5.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_50.qmg:system/media/battery_charging_50.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_55.qmg:system/media/battery_charging_55.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_60.qmg:system/media/battery_charging_60.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_65.qmg:system/media/battery_charging_65.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_70.qmg:system/media/battery_charging_70.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_75.qmg:system/media/battery_charging_75.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_80.qmg:system/media/battery_charging_80.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_85.qmg:system/media/battery_charging_85.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_90.qmg:system/media/battery_charging_90.qmg \\ + vendor/samsung/galaxytab7c/proprietary/battery_charging_95.qmg:system/media/battery_charging_95.qmg \\ + vendor/samsung/galaxytab7c/proprietary/chargingwarning_disconnected.qmg:system/media/chargingwarning_disconnected.qmg \\ + vendor/samsung/galaxytab7c/proprietary/chargingwarning_temp.qmg:system/media/chargingwarning_temp.qmg \\ + vendor/samsung/galaxytab7c/proprietary/usb_not_charging.qmg:system/media/usb_not_charging.qmg + +# bluetooth +PRODUCT_COPY_FILES += \\ + vendor/samsung/galaxytab7c/proprietary/BCM4329B1_002.002.023.0534.0571.hcd:system/bin/BCM4329B1_002.002.023.0534.0571.hcd + +EOF + + +./setup-makefiles.sh diff --git a/include/hal_public.h b/include/hal_public.h new file mode 100644 index 0000000..60f33a9 --- /dev/null +++ b/include/hal_public.h @@ -0,0 +1,171 @@ +/* Copyright (c) Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HAL_PUBLIC_H +#define HAL_PUBLIC_H + +/* Authors of third party hardware composer (HWC) modules will need to include + * this header to access functionality in the gralloc and framebuffer HALs. + */ + +#include + +#define ALIGN(x,a) (((x) + (a) - 1L) & ~((a) - 1L)) +#define HW_ALIGN 32 + +/* This can be tuned down as appropriate for the SOC. + * + * IMG formats are usually a single sub-alloc. + * Some OEM video formats are two sub-allocs (Y, UV planes). + * Future OEM video formats might be three sub-allocs (Y, U, V planes). + */ +#define MAX_SUB_ALLOCS 3 + +typedef struct +{ + native_handle_t base; + + /* These fields can be sent cross process. They are also valid + * to duplicate within the same process. + * + * A table is stored within psPrivateData on gralloc_module_t (this + * is obviously per-process) which maps stamps to a mapped + * PVRSRV_CLIENT_MEM_INFO in that process. Each map entry has a lock + * count associated with it, satisfying the requirements of the + * Android API. This also prevents us from leaking maps/allocations. + * + * This table has entries inserted either by alloc() + * (alloc_device_t) or map() (gralloc_module_t). Entries are removed + * by free() (alloc_device_t) and unmap() (gralloc_module_t). + * + * As a special case for framebuffer_device_t, framebuffer_open() + * will add and framebuffer_close() will remove from this table. + */ + +#define IMG_NATIVE_HANDLE_NUMFDS MAX_SUB_ALLOCS + /* The `fd' field is used to "export" a meminfo to another process. + * Therefore, it is allocated by alloc_device_t, and consumed by + * gralloc_module_t. The framebuffer_device_t does not need a handle, + * and the special value IMG_FRAMEBUFFER_FD is used instead. + */ + int fd[MAX_SUB_ALLOCS]; + +#define IMG_NATIVE_HANDLE_NUMINTS ((sizeof(unsigned long long) / sizeof(int)) + 5) + /* A KERNEL unique identifier for any exported kernel meminfo. Each + * exported kernel meminfo will have a unique stamp, but note that in + * userspace, several meminfos across multiple processes could have + * the same stamp. As the native_handle can be dup(2)'d, there could be + * multiple handles with the same stamp but different file descriptors. + */ + unsigned long long ui64Stamp; + + /* This is used for buffer usage validation when locking a buffer, + * and also in WSEGL (for the composition bypass feature). + */ + int usage; + + //int dummy; + /* In order to do efficient cache flushes we need the buffer dimensions + * and format. These are available on the ANativeWindowBuffer, + * but the platform doesn't pass them down to the graphics HAL. + * + * These fields are also used in the composition bypass. In this + * capacity, these are the "real" values for the backing allocation. + */ + int iWidth; + int iHeight; + int iFormat; + unsigned int uiBpp; +} +__attribute__((aligned(sizeof(int)),packed)) IMG_native_handle_t; + +typedef struct +{ + framebuffer_device_t base; + + /* The HWC was loaded. post() is no longer responsible for presents */ + int bBypassPost; + + /* Custom-blit components in lieu of overlay hardware */ + int (*Blit)(framebuffer_device_t *device, buffer_handle_t src, + buffer_handle_t dest, int w, int h, int x, int y); + + /* HWC path for present posts */ + int (*Post2)(framebuffer_device_t *fb, buffer_handle_t *buffers, + int num_buffers, void *data, int data_length); +} +IMG_framebuffer_device_public_t; + +typedef struct IMG_gralloc_module_public_t +{ + gralloc_module_t base; + + /* If the framebuffer has been opened, this will point to the + * framebuffer device data required by the allocator, WSEGL + * modules and composerhal. + */ + IMG_framebuffer_device_public_t *psFrameBufferDevice; + + int (*GetPhyAddrs)(struct IMG_gralloc_module_public_t const* module, + buffer_handle_t handle, + unsigned int auiPhyAddr[MAX_SUB_ALLOCS]); + /* Custom-blit components in lieu of overlay hardware */ + int (*Blit)(struct IMG_gralloc_module_public_t const *module, + buffer_handle_t src, + void *dest[MAX_SUB_ALLOCS], int format); + + int (*Blit2)(struct IMG_gralloc_module_public_t const *module, + buffer_handle_t src, buffer_handle_t dest, + int w, int h, int x, int y); +} +IMG_gralloc_module_public_t; + +typedef struct +{ + int l, t, w, h; +} +IMG_write_lock_rect_t; + +typedef struct IMG_buffer_format_public_t +{ + /* Buffer formats are returned as a linked list */ + struct IMG_buffer_format_public_t *psNext; + + /* HAL_PIXEL_FORMAT_... enumerant */ + int iHalPixelFormat; + + /* WSEGL_PIXELFORMAT_... enumerant */ + int iWSEGLPixelFormat; + + /* Friendly name for format */ + const char *const szName; + + /* Bits (not bytes) per pixel */ + unsigned int uiBpp; + + /* GPU output format (creates EGLConfig for format) */ + int bGPURenderable; +} +IMG_buffer_format_public_t; + +#endif /* HAL_PUBLIC_H */ diff --git a/include/s3c_bc.h b/include/s3c_bc.h new file mode 100755 index 0000000..e8ea490 --- /dev/null +++ b/include/s3c_bc.h @@ -0,0 +1,63 @@ +/*!**************************************************************************** +@File s3c_bc.h + +@Title s3c_bc kernel driver parameters + +@Author Imagination Technologies + Samsung Electronics Co. LTD + +@Date 03/03/2010 + +@Copyright 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. + +@Platform Generic + +@Description s3c_bc kernel driver parameters + +@DoxygenVer + +******************************************************************************/ + +/****************************************************************************** +Modifications :- +$Log: s3c_bc.h $ +******************************************************************************/ +#ifndef __S3C_BC_H__ +#define __S3C_BC_H__ + +#include + +#define S3C_BC_DEVICE_NAME "s3c_bc" + +#define S3C_BC_DEVICE_ID 0 +#define S3C_BC_DEVICE_BUFFER_COUNT 4 /* TODO: Modify this accordingly. */ + +#define S3C_BC_DEVICE_PHYS_PAGE_SIZE 0x1000 /* 4KB */ + +typedef struct S3C_BC_ioctl_package_TAG +{ + int inputparam; + int outputparam; +} S3C_BC_ioctl_package, *PS3C_BC_ioctl_package; + +/*!< Nov 2006: according to ioctl-number.txt 'g' wasn't in use. */ +#define S3C_BC_IOC_GID 'g' + +#define S3C_BC_IOWR(INDEX) _IOWR(S3C_BC_IOC_GID, INDEX, S3C_BC_ioctl_package) + +#define S3C_BC_ioctl_get_physical_base_address S3C_BC_IOWR(0) + +#endif /* __S3C_BC__H__ */ +/****************************************************************************** + End of file (s3c_bc.h) +******************************************************************************/ diff --git a/include/s3c_mem.h b/include/s3c_mem.h new file mode 100755 index 0000000..d51398a --- /dev/null +++ b/include/s3c_mem.h @@ -0,0 +1,56 @@ +/* + * Copyright@ Samsung Electronics Co. LTD + * + * 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 _S3C_MEM_COMMON_H_ +#define _S3C_MEM_COMMON_H_ + +#define MEM_IOCTL_MAGIC 'M' + +#define S3C_MEM_ALLOC _IOWR(MEM_IOCTL_MAGIC, 310, struct s3c_mem_alloc) +#define S3C_MEM_FREE _IOWR(MEM_IOCTL_MAGIC, 311, struct s3c_mem_alloc) + +#define S3C_MEM_SHARE_ALLOC _IOWR(MEM_IOCTL_MAGIC, 314, struct s3c_mem_alloc) +#define S3C_MEM_SHARE_FREE _IOWR(MEM_IOCTL_MAGIC, 315, struct s3c_mem_alloc) + +#define S3C_MEM_CACHEABLE_ALLOC _IOWR(MEM_IOCTL_MAGIC, 316, struct s3c_mem_alloc) +#define S3C_MEM_CACHEABLE_SHARE_ALLOC _IOWR(MEM_IOCTL_MAGIC, 317, struct s3c_mem_alloc) + +#define S3C_MEM_DMA_COPY _IOWR(MEM_IOCTL_MAGIC, 318, struct s3c_mem_dma_param) +#define S3C_MEM_DMA_SET _IOWR(MEM_IOCTL_MAGIC, 319, struct s3c_mem_dma_param) + +#define S3C_MEM_CACHE_INV _IOWR(MEM_IOCTL_MAGIC, 330, struct s3c_mem_dma_param) + + +struct s3c_mem_alloc { + int size; + unsigned int vir_addr; + unsigned int phy_addr; +}; + +struct s3c_mem_dma_param { + int size; + unsigned int src_addr; + unsigned int dst_addr; + int cfg; +}; + +#if 0 +typedef struct _s3c_mem_t{ + int dev_fd; + struct s3c_mem_alloc mem_alloc_info; +}s3c_mem_t; +#endif +#endif // _S3C_MEM_COMMON_H_ diff --git a/include/s5p_fimc.h b/include/s5p_fimc.h new file mode 100755 index 0000000..d2c760c --- /dev/null +++ b/include/s5p_fimc.h @@ -0,0 +1,153 @@ +/* + * Copyright@ Samsung Electronics Co. LTD + * + * 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 _S5P_FIMC_H_ +#define _S5P_FIMC_H_ + +#include + +/* + * G E N E R A L S + * +*/ +#define MIN(x, y) ((x < y) ? x : y) + +/* + * P I X E L F O R M A T G U I D E + * + * The 'x' means 'DO NOT CARE' + * The '*' means 'FIMC SPECIFIC' + * For some fimc formats, we couldn't find equivalent format in the V4L2 FOURCC. + * + * FIMC TYPE PLANES ORDER V4L2_PIX_FMT + * --------------------------------------------------------- + * RGB565 x x V4L2_PIX_FMT_RGB565 + * RGB888 x x V4L2_PIX_FMT_RGB24 + * YUV420 2 LSB_CBCR V4L2_PIX_FMT_NV12 + * YUV420 2 LSB_CRCB V4L2_PIX_FMT_NV21 + * YUV420 2 MSB_CBCR V4L2_PIX_FMT_NV21X* + * YUV420 2 MSB_CRCB V4L2_PIX_FMT_NV12X* + * YUV420 3 x V4L2_PIX_FMT_YUV420 + * YUV422 1 YCBYCR V4L2_PIX_FMT_YUYV + * YUV422 1 YCRYCB V4L2_PIX_FMT_YVYU + * YUV422 1 CBYCRY V4L2_PIX_FMT_UYVY + * YUV422 1 CRYCBY V4L2_PIX_FMT_VYUY* + * YUV422 2 LSB_CBCR V4L2_PIX_FMT_NV16* + * YUV422 2 LSB_CRCB V4L2_PIX_FMT_NV61* + * YUV422 2 MSB_CBCR V4L2_PIX_FMT_NV16X* + * YUV422 2 MSB_CRCB V4L2_PIX_FMT_NV61X* + * YUV422 3 x V4L2_PIX_FMT_YUV422P + * +*/ + +/* + * V 4 L 2 F I M C E X T E N S I O N S + * +*/ +#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') + +/* FOURCC for FIMC specific */ +#define V4L2_PIX_FMT_NV12X v4l2_fourcc('N', '1', '2', 'X') +#define V4L2_PIX_FMT_NV21X v4l2_fourcc('N', '2', '1', 'X') +#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') +#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') +#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') +#define V4L2_PIX_FMT_NV16X v4l2_fourcc('N', '1', '6', 'X') +#define V4L2_PIX_FMT_NV61X v4l2_fourcc('N', '6', '1', 'X') + +#define V4L2_PIX_FMT_NV12T v4l2_fourcc('T', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ + +/* CID extensions */ +#define V4L2_CID_ROTATION (V4L2_CID_PRIVATE_BASE + 0) +#define V4L2_CID_RESERVED_MEM_BASE_ADDR (V4L2_CID_PRIVATE_BASE + 20) +#define V4L2_CID_FIMC_VERSION (V4L2_CID_PRIVATE_BASE + 21) +/* + * U S E R D E F I N E D T Y P E S + * +*/ + +typedef unsigned int dma_addr_t; + +struct fimc_buf { + dma_addr_t base[3]; + size_t length[3]; +}; + +struct fimc_buffer { + void *virt_addr; + void *phys_addr; + size_t length; +}; + +struct yuv_fmt_list { + const char *name; + const char *desc; + unsigned int fmt; + int bpp; + int planes; +}; + +struct img_offset { + int y_h; + int y_v; + int cb_h; + int cb_v; + int cr_h; + int cr_v; +}; + +//------------ STRUCT ---------------------------------------------------------// + +typedef struct +{ + unsigned int full_width; // Source Image Full Width (Virtual screen size) + unsigned int full_height; // Source Image Full Height (Virtual screen size) + unsigned int start_x; // Source Image Start width offset + unsigned int start_y; // Source Image Start height offset + unsigned int width; // Source Image Width + unsigned int height; // Source Image Height + unsigned int buf_addr_phy_rgb_y; // Base Address of the Source Image (RGB or Y): Physical Address + unsigned int buf_addr_phy_cb; // Base Address of the Source Image (CB Component) : Physical Address + unsigned int buf_addr_phy_cr; // Base Address of the Source Image (CR Component) : Physical Address + unsigned int color_space; // Color Space of the Source Image +} s5p_fimc_img_info; + +typedef struct +{ + s5p_fimc_img_info src; + s5p_fimc_img_info dst; +} s5p_fimc_params_t; + +typedef struct _s5p_fimc_t { + int dev_fd; + struct fimc_buffer out_buf; + + s5p_fimc_params_t params; + + int use_ext_out_mem; + unsigned int hw_ver; +}s5p_fimc_t; + +//------------------------ functions for v4l2 ------------------------------// +int fimc_v4l2_set_src(int fd, unsigned int hw_ver, s5p_fimc_img_info *src); +int fimc_v4l2_set_dst(int fd, s5p_fimc_img_info *dst, int rotation, unsigned int addr); +int fimc_v4l2_stream_on(int fd, enum v4l2_buf_type type); +int fimc_v4l2_queue(int fd, struct fimc_buf *fimc_buf); +int fimc_v4l2_dequeue(int fd); +int fimc_v4l2_stream_off(int fd); +int fimc_v4l2_clr_buf(int fd); +int fimc_handle_oneshot(int fd, struct fimc_buf *fimc_buf); +#endif diff --git a/include/sec_format.h b/include/sec_format.h new file mode 100755 index 0000000..99a47bf --- /dev/null +++ b/include/sec_format.h @@ -0,0 +1,43 @@ +/* + * Copyright@ Samsung Electronics Co. LTD + * + * 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 _SEC_FORMAT_H_ +#define _SEC_FORMAT_H_ + +/* enum related to pixel format */ + +enum { + HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x100, + HAL_PIXEL_FORMAT_YCbCr_420_P = 0x101, + HAL_PIXEL_FORMAT_YCbCr_420_I = 0x102, + HAL_PIXEL_FORMAT_CbYCrY_422_I = 0x103, + HAL_PIXEL_FORMAT_CbYCrY_420_I = 0x104, + HAL_PIXEL_FORMAT_YCbCr_422_P = 0x105, + HAL_PIXEL_FORMAT_YCrCb_422_SP = 0x106, + // support custom format for zero copy + HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP = 0x110, + HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP = 0x111, + HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP_TILED = 0x112, + HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_SP = 0x113, + HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_SP = 0x114, + HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_I = 0x115, + HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_I = 0x116, + HAL_PIXEL_FORMAT_CUSTOM_CbYCrY_422_I = 0x117, + HAL_PIXEL_FORMAT_CUSTOM_CrYCbY_422_I = 0x118, + HAL_PIXEL_FORMAT_CUSTOM_MAX +}; + +#endif diff --git a/include/sec_lcd.h b/include/sec_lcd.h new file mode 100755 index 0000000..b5451b7 --- /dev/null +++ b/include/sec_lcd.h @@ -0,0 +1,49 @@ +/* + * Copyright@ Samsung Electronics Co. LTD + * + * 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 _SEC_FB_LCD_ +#define _SEC_FB_LCD_ + +/* + * S T R U C T U R E S F O R C U S T O M I O C T L S + * +*/ +struct secfb_user_window { + int x; + int y; +}; + +/* + * C U S T O M I O C T L S + * +*/ + +#define FBIO_WAITFORVSYNC _IO ('F', 32) +#define SECFB_WIN_POSITION _IOW ('F', 203, struct secfb_user_window) + + +#define DEFAULT_LCD_WIDTH (480) +#define DEFAULT_LCD_HEIGHT (800) +#define DEFAULT_LCD_BPP (32) + +/***************** LCD frame buffer *****************/ +#define FB0_NAME "/dev/fb0" +#define FB1_NAME "/dev/fb1" +#define FB2_NAME "/dev/fb2" +#define FB3_NAME "/dev/fb3" +#define FB4_NAME "/dev/fb4" + +#endif diff --git a/include/sec_utils.h b/include/sec_utils.h new file mode 100644 index 0000000..80b4493 --- /dev/null +++ b/include/sec_utils.h @@ -0,0 +1,331 @@ +/* + * Copyright@ Samsung Electronics Co. LTD + * + * 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 __SAMSUNG_SYSLSI_SEC_COMMON_H__ +#define __SAMSUNG_SYSLSI_SEC_COMMON_H__ + +//---------------------------------------------------------// +// Include +//---------------------------------------------------------// + +#include +#include "sec_format.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif + +//---------------------------------------------------------// +// Common structure // +//---------------------------------------------------------// +struct ADDRS { + unsigned int addr_y; + unsigned int addr_cbcr; + unsigned int buf_idx; + unsigned int reserved; +}; + +//---------------------------------------------------------// +// Common function // +//---------------------------------------------------------// +inline int HAL_PIXEL_FORMAT_2_V4L2_PIX(int HAL_PIXEL_FORMAT) +{ + int V4L2_PIX = -1; + + switch (HAL_PIXEL_FORMAT) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + V4L2_PIX = V4L2_PIX_FMT_RGB32; + break; + + case HAL_PIXEL_FORMAT_RGB_888: + V4L2_PIX = V4L2_PIX_FMT_RGB24; + break; + + case HAL_PIXEL_FORMAT_RGB_565: + V4L2_PIX = V4L2_PIX_FMT_RGB565; + break; + + case HAL_PIXEL_FORMAT_BGRA_8888: + //V4L2_PIX = V4L2_PIX_FMT_BGR32; // this is not proper on fimc. + V4L2_PIX = V4L2_PIX_FMT_RGB32; + break; + + case HAL_PIXEL_FORMAT_RGBA_5551: + V4L2_PIX = V4L2_PIX_FMT_RGB555X; + break; + + case HAL_PIXEL_FORMAT_RGBA_4444: + V4L2_PIX = V4L2_PIX_FMT_RGB444; + break; + + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_YCbCr_420_P: + V4L2_PIX = V4L2_PIX_FMT_YUV420; + break; + + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_SP: + V4L2_PIX = V4L2_PIX_FMT_NV61; + break; + + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP: + V4L2_PIX = V4L2_PIX_FMT_NV12; + break; + + case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_I: + V4L2_PIX = V4L2_PIX_FMT_YUYV; + break; + + case HAL_PIXEL_FORMAT_YCbCr_422_P: + V4L2_PIX = V4L2_PIX_FMT_YUV422P; + break; + + case HAL_PIXEL_FORMAT_CbYCrY_422_I: + case HAL_PIXEL_FORMAT_CUSTOM_CbYCrY_422_I: + V4L2_PIX = V4L2_PIX_FMT_UYVY; + break; + + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_SP: + V4L2_PIX = V4L2_PIX_FMT_NV16; + break; + + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP: + V4L2_PIX = V4L2_PIX_FMT_NV21; + break; + + case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP_TILED: + V4L2_PIX = V4L2_PIX_FMT_NV12T; + break; + + case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_I: + V4L2_PIX = V4L2_PIX_FMT_YVYU; + break; + + case HAL_PIXEL_FORMAT_CUSTOM_CrYCbY_422_I: + V4L2_PIX = V4L2_PIX_FMT_VYUY; + break; + + default: + LOGE("%s::unmatched HAL_PIXEL_FORMAT color_space(0x%x)\n", + __func__, HAL_PIXEL_FORMAT); + break; + } + + return V4L2_PIX; +} + +inline int V4L2_PIX_2_HAL_PIXEL_FORMAT(int V4L2_PIX) +{ + int HAL_PIXEL_FORMAT = -1; + + switch (V4L2_PIX) { + case V4L2_PIX_FMT_RGB32: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_RGBA_8888; + //HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_RGBX_8888; + break; + + case V4L2_PIX_FMT_RGB24: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_RGB_888; + break; + + case V4L2_PIX_FMT_RGB565: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_RGB_565; + break; + + case V4L2_PIX_FMT_BGR32: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_BGRA_8888; + break; + + case V4L2_PIX_FMT_RGB555X: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_RGBA_5551; + break; + + case V4L2_PIX_FMT_RGB444: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_RGBA_4444; + break; + + case V4L2_PIX_FMT_YUV420: + //HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_YV12; + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_YCbCr_420_P; + break; + + case V4L2_PIX_FMT_NV16: + //HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_YCrCb_422_SP; + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_SP; + break; + + case V4L2_PIX_FMT_NV12: + //HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_YCrCb_420_SP; + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP; + break; + + case V4L2_PIX_FMT_YUYV: + //HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_YCbCr_422_I; + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_I; + break; + + case V4L2_PIX_FMT_YUV422P: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_YCbCr_422_P; + break; + + case V4L2_PIX_FMT_UYVY: + //HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_CbYCrY_422_I; + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_CUSTOM_CbYCrY_422_I; + break; + + case V4L2_PIX_FMT_NV21: + //HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_YCbCr_420_SP; + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP; + break; + + case V4L2_PIX_FMT_NV12T: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP_TILED; + break; + + case V4L2_PIX_FMT_NV61: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_SP; + break; + + case V4L2_PIX_FMT_YVYU: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_I; + break; + + case V4L2_PIX_FMT_VYUY: + HAL_PIXEL_FORMAT = HAL_PIXEL_FORMAT_CUSTOM_CrYCbY_422_I; + break; + + default: + LOGE("%s::unmatched V4L2_PIX color_space(%d)\n", + __func__, V4L2_PIX); + break; + } + + return HAL_PIXEL_FORMAT; +} + +#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5) +#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7) +#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13) + +#define GET_32BPP_FRAME_SIZE(w, h) (((w) * (h)) << 2) +#define GET_24BPP_FRAME_SIZE(w, h) (((w) * (h)) * 3) +#define GET_16BPP_FRAME_SIZE(w, h) (((w) * (h)) << 1) + +inline unsigned int FRAME_SIZE(int HAL_PIXEL_FORMAT, int w, int h) +{ + unsigned int frame_size = 0; + unsigned int size = 0; + + switch (HAL_PIXEL_FORMAT) { + // 16bpp + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_RGBA_5551: + //case HAL_PIXEL_FORMAT_ARGB_1555: + //case HAL_PIXEL_FORMAT_BGRA_5551: + //case HAL_PIXEL_FORMAT_ABGR_1555: + + //case HAL_PIXEL_FORMAT_RGBX_5551: + //case HAL_PIXEL_FORMAT_XRGB_1555: + //case HAL_PIXEL_FORMAT_BGRX_5551: + //case HAL_PIXEL_FORMAT_XBGR_1555: + + case HAL_PIXEL_FORMAT_RGBA_4444: + //case HAL_PIXEL_FORMAT_ARGB_4444: + //case HAL_PIXEL_FORMAT_BGRA_4444: + //case HAL_PIXEL_FORMAT_ABGR_4444: + + //case HAL_PIXEL_FORMAT_RGBX_4444: + //case HAL_PIXEL_FORMAT_XRGB_4444: + //case HAL_PIXEL_FORMAT_BGRX_4444: + //case HAL_PIXEL_FORMAT_XBGR_4444: + frame_size = GET_16BPP_FRAME_SIZE(w, h); + break; + + // 24bpp + case HAL_PIXEL_FORMAT_RGB_888: + frame_size = GET_24BPP_FRAME_SIZE(w, h); + break; + + // 32bpp + case HAL_PIXEL_FORMAT_RGBA_8888: + //case HAL_PIXEL_FORMAT_ARGB_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + //case HAL_PIXEL_FORMAT_ABGR_8888: + + case HAL_PIXEL_FORMAT_RGBX_8888: + //case HAL_PIXEL_FORMAT_XRGB_8888: + //case HAL_PIXEL_FORMAT_BGRX_8888: + //case HAL_PIXEL_FORMAT_XBGR_8888: + frame_size = GET_32BPP_FRAME_SIZE(w, h); + break; + + // 12bpp + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_P: + case HAL_PIXEL_FORMAT_YCbCr_420_I: + case HAL_PIXEL_FORMAT_CbYCrY_420_I: + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP: + size = w * h; + // frame_size = width * height * 3 / 2; + // sw5771.park : very curious... + // frame_size = size + ((size / 4) * 2); + frame_size = size + ((size >> 2) << 1); + break; + + case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP_TILED: + frame_size = ALIGN_TO_8KB(ALIGN_TO_128B(w) * ALIGN_TO_32B(h)) + + ALIGN_TO_8KB(ALIGN_TO_128B(w) * ALIGN_TO_32B(h >> 1)); + break; + + // 16bpp + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_YCbCr_422_P: + case HAL_PIXEL_FORMAT_CbYCrY_422_I: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_SP: + case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_I: + case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_I: + case HAL_PIXEL_FORMAT_CUSTOM_CbYCrY_422_I: + case HAL_PIXEL_FORMAT_CUSTOM_CrYCbY_422_I: + frame_size = GET_16BPP_FRAME_SIZE(w, h); + break; + + default: + LOGD("%s::no matching source colorformat(0x%x), w(%d), h(%d) fail\n", + __func__, HAL_PIXEL_FORMAT, w, h); + break; + } + + return frame_size; +} + +#endif //__SAMSUNG_SYSLSI_SEC_COMMON_H__ diff --git a/include/videodev2_samsung.h b/include/videodev2_samsung.h new file mode 100755 index 0000000..f3f32eb --- /dev/null +++ b/include/videodev2_samsung.h @@ -0,0 +1,653 @@ +/* + * Video for Linux Two header file for samsung + * + * Copyright (C) 2009, Samsung Electronics + * + * This header file contains several v4l2 APIs to be proposed to v4l2 + * community and until bein accepted, will be used restrictly in Samsung's + * camera interface driver FIMC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Alternatively, 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 __LINUX_VIDEODEV2_SAMSUNG_H +#define __LINUX_VIDEODEV2_SAMSUNG_H + +/* Values for 'capabilities' field */ +/* Object detection device */ +#define V4L2_CAP_OBJ_RECOGNITION 0x10000000 +/* strobe control */ +#define V4L2_CAP_STROBE 0x20000000 + +#define V4L2_CID_FOCUS_MODE (V4L2_CID_CAMERA_CLASS_BASE + 17) +/* Focus Methods */ +enum v4l2_focus_mode { + V4L2_FOCUS_MODE_AUTO = 0, + V4L2_FOCUS_MODE_MACRO = 1, + V4L2_FOCUS_MODE_MANUAL = 2, + V4L2_FOCUS_MODE_LASTP = 2, +}; + +#define V4L2_CID_ZOOM_MODE (V4L2_CID_CAMERA_CLASS_BASE + 18) +/* Zoom Methods */ +enum v4l2_zoom_mode { + V4L2_ZOOM_MODE_CONTINUOUS = 0, + V4L2_ZOOM_MODE_OPTICAL = 1, + V4L2_ZOOM_MODE_DIGITAL = 2, + V4L2_ZOOM_MODE_LASTP = 2, +}; + +/* Exposure Methods */ +#define V4L2_CID_PHOTOMETRY (V4L2_CID_CAMERA_CLASS_BASE + 19) +enum v4l2_photometry_mode { + V4L2_PHOTOMETRY_MULTISEG = 0, /*Multi Segment */ + V4L2_PHOTOMETRY_CWA = 1, /*Centre Weighted Average */ + V4L2_PHOTOMETRY_SPOT = 2, + V4L2_PHOTOMETRY_AFSPOT = 3, /*Spot metering on focused point */ + V4L2_PHOTOMETRY_LASTP = V4L2_PHOTOMETRY_AFSPOT, +}; + +/* Manual exposure control items menu type: iris, shutter, iso */ +#define V4L2_CID_CAM_APERTURE (V4L2_CID_CAMERA_CLASS_BASE + 20) +#define V4L2_CID_CAM_SHUTTER (V4L2_CID_CAMERA_CLASS_BASE + 21) +#define V4L2_CID_CAM_ISO (V4L2_CID_CAMERA_CLASS_BASE + 22) + +/* Following CIDs are menu type */ +#define V4L2_CID_SCENEMODE (V4L2_CID_CAMERA_CLASS_BASE + 23) +#define V4L2_CID_CAM_STABILIZE (V4L2_CID_CAMERA_CLASS_BASE + 24) +#define V4L2_CID_CAM_MULTISHOT (V4L2_CID_CAMERA_CLASS_BASE + 25) + +/* Control dynamic range */ +#define V4L2_CID_CAM_DR (V4L2_CID_CAMERA_CLASS_BASE + 26) + +/* White balance preset control */ +#define V4L2_CID_WHITE_BALANCE_PRESET (V4L2_CID_CAMERA_CLASS_BASE + 27) + +/* CID extensions */ +#define V4L2_CID_ROTATION (V4L2_CID_PRIVATE_BASE + 0) +#define V4L2_CID_PADDR_Y (V4L2_CID_PRIVATE_BASE + 1) +#define V4L2_CID_PADDR_CB (V4L2_CID_PRIVATE_BASE + 2) +#define V4L2_CID_PADDR_CR (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_PADDR_CBCR (V4L2_CID_PRIVATE_BASE + 4) +#define V4L2_CID_OVERLAY_AUTO (V4L2_CID_PRIVATE_BASE + 5) +#define V4L2_CID_OVERLAY_VADDR0 (V4L2_CID_PRIVATE_BASE + 6) +#define V4L2_CID_OVERLAY_VADDR1 (V4L2_CID_PRIVATE_BASE + 7) +#define V4L2_CID_OVERLAY_VADDR2 (V4L2_CID_PRIVATE_BASE + 8) +#define V4L2_CID_OVLY_MODE (V4L2_CID_PRIVATE_BASE + 9) +#define V4L2_CID_DST_INFO (V4L2_CID_PRIVATE_BASE + 10) +#define V4L2_CID_GET_PHY_SRC_YADDR (V4L2_CID_PRIVATE_BASE + 12) +#define V4L2_CID_GET_PHY_SRC_CADDR (V4L2_CID_PRIVATE_BASE + 13) +#define V4L2_CID_IMAGE_EFFECT_FN (V4L2_CID_PRIVATE_BASE + 16) +#define V4L2_CID_IMAGE_EFFECT_APPLY (V4L2_CID_PRIVATE_BASE + 17) +#define V4L2_CID_IMAGE_EFFECT_CB (V4L2_CID_PRIVATE_BASE + 18) +#define V4L2_CID_IMAGE_EFFECT_CR (V4L2_CID_PRIVATE_BASE + 19) +#define V4L2_CID_RESERVED_MEM_BASE_ADDR (V4L2_CID_PRIVATE_BASE + 20) +#define V4L2_CID_FIMC_VERSION (V4L2_CID_PRIVATE_BASE + 21) + +#define V4L2_CID_STREAM_PAUSE (V4L2_CID_PRIVATE_BASE + 53) + +/* CID Extensions for camera sensor operations */ +#define V4L2_CID_CAM_PREVIEW_ONOFF (V4L2_CID_PRIVATE_BASE + 64) +#define V4L2_CID_CAM_CAPTURE (V4L2_CID_PRIVATE_BASE + 65) +#define V4L2_CID_CAM_JPEG_MEMSIZE (V4L2_CID_PRIVATE_BASE + 66) + +#define V4L2_CID_CAM_DATE_INFO_YEAR (V4L2_CID_PRIVATE_BASE + 14) +#define V4L2_CID_CAM_DATE_INFO_MONTH (V4L2_CID_PRIVATE_BASE + 15) +#define V4L2_CID_CAM_DATE_INFO_DATE (V4L2_CID_PRIVATE_BASE + 22) +#define V4L2_CID_CAM_SENSOR_VER (V4L2_CID_PRIVATE_BASE + 23) +#define V4L2_CID_CAM_FW_MINOR_VER (V4L2_CID_PRIVATE_BASE + 24) +#define V4L2_CID_CAM_FW_MAJOR_VER (V4L2_CID_PRIVATE_BASE + 25) +#define V4L2_CID_CAM_PRM_MINOR_VER (V4L2_CID_PRIVATE_BASE + 26) +#define V4L2_CID_CAM_PRM_MAJOR_VER (V4L2_CID_PRIVATE_BASE + 27) +#define V4L2_CID_CAM_FW_VER (V4L2_CID_PRIVATE_BASE + 28) +#define V4L2_CID_CAM_SET_FW_ADDR (V4L2_CID_PRIVATE_BASE + 29) +#define V4L2_CID_CAM_SET_FW_SIZE (V4L2_CID_PRIVATE_BASE + 30) +#define V4L2_CID_CAM_UPDATE_FW (V4L2_CID_PRIVATE_BASE + 31) +#define V4L2_CID_CAM_JPEG_MAIN_SIZE (V4L2_CID_PRIVATE_BASE + 32) +#define V4L2_CID_CAM_JPEG_MAIN_OFFSET (V4L2_CID_PRIVATE_BASE + 33) +#define V4L2_CID_CAM_JPEG_THUMB_SIZE (V4L2_CID_PRIVATE_BASE + 34) +#define V4L2_CID_CAM_JPEG_THUMB_OFFSET (V4L2_CID_PRIVATE_BASE + 35) +#define V4L2_CID_CAM_JPEG_POSTVIEW_OFFSET (V4L2_CID_PRIVATE_BASE + 36) +#define V4L2_CID_CAM_JPEG_QUALITY (V4L2_CID_PRIVATE_BASE + 37) +#define V4L2_CID_CAM_SENSOR_MAKER (V4L2_CID_PRIVATE_BASE + 38) +#define V4L2_CID_CAM_SENSOR_OPTICAL (V4L2_CID_PRIVATE_BASE + 39) +#define V4L2_CID_CAM_AF_VER_LOW (V4L2_CID_PRIVATE_BASE + 40) +#define V4L2_CID_CAM_AF_VER_HIGH (V4L2_CID_PRIVATE_BASE + 41) +#define V4L2_CID_CAM_GAMMA_RG_LOW (V4L2_CID_PRIVATE_BASE + 42) +#define V4L2_CID_CAM_GAMMA_RG_HIGH (V4L2_CID_PRIVATE_BASE + 43) +#define V4L2_CID_CAM_GAMMA_BG_LOW (V4L2_CID_PRIVATE_BASE + 44) +#define V4L2_CID_CAM_GAMMA_BG_HIGH (V4L2_CID_PRIVATE_BASE + 45) +#define V4L2_CID_CAM_DUMP_FW (V4L2_CID_PRIVATE_BASE + 46) +#define V4L2_CID_CAM_GET_DUMP_SIZE (V4L2_CID_PRIVATE_BASE + 47) +#define V4L2_CID_CAMERA_VT_MODE (V4L2_CID_PRIVATE_BASE + 48) +#define V4L2_CID_CAMERA_VGA_BLUR (V4L2_CID_PRIVATE_BASE + 49) +#define V4L2_CID_CAMERA_CAPTURE (V4L2_CID_PRIVATE_BASE + 50) + +#define V4L2_CID_MAIN_SW_DATE_INFO_YEAR (V4L2_CID_PRIVATE_BASE + 54) +#define V4L2_CID_MAIN_SW_DATE_INFO_MONTH (V4L2_CID_PRIVATE_BASE + 55) +#define V4L2_CID_MAIN_SW_DATE_INFO_DATE (V4L2_CID_PRIVATE_BASE + 56) +#define V4L2_CID_MAIN_SW_FW_MINOR_VER (V4L2_CID_PRIVATE_BASE + 57) +#define V4L2_CID_MAIN_SW_FW_MAJOR_VER (V4L2_CID_PRIVATE_BASE + 58) +#define V4L2_CID_MAIN_SW_PRM_MINOR_VER (V4L2_CID_PRIVATE_BASE + 59) +#define V4L2_CID_MAIN_SW_PRM_MAJOR_VER (V4L2_CID_PRIVATE_BASE + 60) + +enum v4l2_blur { + BLUR_LEVEL_0 = 0, + BLUR_LEVEL_1, + BLUR_LEVEL_2, + BLUR_LEVEL_3, + BLUR_LEVEL_MAX, +}; + +#define V4L2_CID_CAMERA_SCENE_MODE (V4L2_CID_PRIVATE_BASE + 70) +enum v4l2_scene_mode { + SCENE_MODE_BASE = 0, + SCENE_MODE_NONE, + SCENE_MODE_PORTRAIT, + SCENE_MODE_NIGHTSHOT, + SCENE_MODE_BACK_LIGHT, + SCENE_MODE_LANDSCAPE, + SCENE_MODE_SPORTS, + SCENE_MODE_PARTY_INDOOR, + SCENE_MODE_BEACH_SNOW, + SCENE_MODE_SUNSET, + SCENE_MODE_DUST_DAWN, + SCENE_MODE_FALL_COLOR, + SCENE_MODE_FIREWORKS, + SCENE_MODE_TEXT, + SCENE_MODE_CANDLE_LIGHT, + SCENE_MODE_MAX, +}; + +#define V4L2_CID_CAMERA_FLASH_MODE (V4L2_CID_PRIVATE_BASE + 71) +enum v4l2_flash_mode { + FLASH_MODE_BASE = 0, + FLASH_MODE_OFF, + FLASH_MODE_AUTO, + FLASH_MODE_ON, + FLASH_MODE_TORCH, + FLASH_MODE_MAX, +}; + +#define V4L2_CID_CAMERA_BRIGHTNESS (V4L2_CID_PRIVATE_BASE + 72) +enum v4l2_ev_mode { + EV_MINUS_4 = 0, + EV_MINUS_3, + EV_MINUS_2, + EV_MINUS_1, + EV_DEFAULT, + EV_PLUS_1, + EV_PLUS_2, + EV_PLUS_3, + EV_PLUS_4, + EV_MAX, +}; + +#define V4L2_CID_CAMERA_WHITE_BALANCE (V4L2_CID_PRIVATE_BASE + 73) +enum v4l2_wb_mode { + WHITE_BALANCE_BASE = 0, + WHITE_BALANCE_AUTO, + WHITE_BALANCE_SUNNY, + WHITE_BALANCE_DAYLIGHT, + WHITE_BALANCE_CLOUDY_DAYLIGHT, + WHITE_BALANCE_INCANDESCENT, + WHITE_BALANCE_TUNGSTEN, + WHITE_BALANCE_FLUORESCENT, + WHITE_BALANCE_MAX, +}; + +#define V4L2_CID_CAMERA_EFFECT (V4L2_CID_PRIVATE_BASE + 74) +enum v4l2_effect_mode { + IMAGE_EFFECT_BASE = 0, + IMAGE_EFFECT_NONE, + IMAGE_EFFECT_BNW, + IMAGE_EFFECT_SEPIA, + IMAGE_EFFECT_AQUA, + IMAGE_EFFECT_ANTIQUE, + IMAGE_EFFECT_NEGATIVE, + IMAGE_EFFECT_SHARPEN, + IMAGE_EFFECT_MAX, +}; + +#define V4L2_CID_CAMERA_ISO (V4L2_CID_PRIVATE_BASE + 75) +enum v4l2_iso_mode { + ISO_AUTO = 0, + ISO_50, + ISO_100, + ISO_200, + ISO_400, + ISO_800, + ISO_1600, + ISO_SPORTS, + ISO_NIGHT, + ISO_MOVIE, + ISO_MAX, +}; + +#define V4L2_CID_CAMERA_METERING (V4L2_CID_PRIVATE_BASE + 76) +enum v4l2_metering_mode { + METERING_BASE = 0, + METERING_MATRIX, + METERING_CENTER, + METERING_SPOT, + METERING_MAX, +}; + +#define V4L2_CID_CAMERA_CONTRAST (V4L2_CID_PRIVATE_BASE + 77) +enum v4l2_contrast_mode { + CONTRAST_MINUS_2 = 0, + CONTRAST_MINUS_1, + CONTRAST_DEFAULT, + CONTRAST_PLUS_1, + CONTRAST_PLUS_2, + CONTRAST_MAX, +}; + +#define V4L2_CID_CAMERA_SATURATION (V4L2_CID_PRIVATE_BASE + 78) +enum v4l2_saturation_mode { + SATURATION_MINUS_2 = 0, + SATURATION_MINUS_1, + SATURATION_DEFAULT, + SATURATION_PLUS_1, + SATURATION_PLUS_2, + SATURATION_MAX, +}; + +#define V4L2_CID_CAMERA_SHARPNESS (V4L2_CID_PRIVATE_BASE + 79) +enum v4l2_sharpness_mode { + SHARPNESS_MINUS_2 = 0, + SHARPNESS_MINUS_1, + SHARPNESS_DEFAULT, + SHARPNESS_PLUS_1, + SHARPNESS_PLUS_2, + SHARPNESS_MAX, +}; + +#define V4L2_CID_CAMERA_WDR (V4L2_CID_PRIVATE_BASE + 80) +enum v4l2_wdr_mode { + WDR_OFF = 0, + WDR_ON, + WDR_MAX, +}; + +#define V4L2_CID_CAMERA_ANTI_SHAKE (V4L2_CID_PRIVATE_BASE + 81) +enum v4l2_anti_shake_mode { + ANTI_SHAKE_OFF = 0, + ANTI_SHAKE_STILL_ON, + ANTI_SHAKE_MOVIE_ON, + ANTI_SHAKE_MAX, +}; + +#define V4L2_CID_CAMERA_TOUCH_AF_START_STOP (V4L2_CID_PRIVATE_BASE + 82) +enum v4l2_touch_af { + TOUCH_AF_STOP = 0, + TOUCH_AF_START, + TOUCH_AF_MAX, +}; + +#define V4L2_CID_CAMERA_SMART_AUTO (V4L2_CID_PRIVATE_BASE + 83) +enum v4l2_smart_auto { + SMART_AUTO_OFF = 0, + SMART_AUTO_ON, + SMART_AUTO_MAX, +}; + +#define V4L2_CID_CAMERA_VINTAGE_MODE (V4L2_CID_PRIVATE_BASE + 84) +enum v4l2_vintage_mode { + VINTAGE_MODE_BASE = 0, + VINTAGE_MODE_OFF, + VINTAGE_MODE_NORMAL, + VINTAGE_MODE_WARM, + VINTAGE_MODE_COOL, + VINTAGE_MODE_BNW, + VINTAGE_MODE_MAX, +}; + +#define V4L2_CID_CAMERA_JPEG_QUALITY (V4L2_CID_PRIVATE_BASE + 85) +enum JPEG_QUALITY{ + JPEG_QUALITY_ECONOMY = 0, + JPEG_QUALITY_NORMAL = 50, + JPEG_QUALITY_SUPERFINE = 100, + JPEG_QUALITY_MAX, +}; + +#define V4L2_CID_CAMERA_GPS_LATITUDE (V4L2_CID_CAMERA_CLASS_BASE + 30) +#define V4L2_CID_CAMERA_GPS_LONGITUDE (V4L2_CID_CAMERA_CLASS_BASE + 31) +#define V4L2_CID_CAMERA_GPS_TIMESTAMP (V4L2_CID_CAMERA_CLASS_BASE + 32) +#define V4L2_CID_CAMERA_GPS_ALTITUDE (V4L2_CID_CAMERA_CLASS_BASE + 33) +#define V4L2_CID_CAMERA_EXIF_TIME_INFO (V4L2_CID_CAMERA_CLASS_BASE + 34) +#define V4L2_CID_CAMERA_ZOOM (V4L2_CID_PRIVATE_BASE + 90) +enum v4l2_zoom_level { + ZOOM_LEVEL_0 = 0, + ZOOM_LEVEL_1, + ZOOM_LEVEL_2, + ZOOM_LEVEL_3, + ZOOM_LEVEL_4, + ZOOM_LEVEL_5, + ZOOM_LEVEL_6, + ZOOM_LEVEL_7, + ZOOM_LEVEL_8, + ZOOM_LEVEL_9, + ZOOM_LEVEL_10, + ZOOM_LEVEL_11, + ZOOM_LEVEL_12, + ZOOM_LEVEL_MAX, +}; + +#define V4L2_CID_CAMERA_FACE_DETECTION (V4L2_CID_PRIVATE_BASE + 91) +enum v4l2_face_detection { + FACE_DETECTION_OFF = 0, + FACE_DETECTION_ON, + FACE_DETECTION_NOLINE, + FACE_DETECTION_ON_BEAUTY, + FACE_DETECTION_MAX, +}; + +#define V4L2_CID_CAMERA_SMART_AUTO_STATUS (V4L2_CID_PRIVATE_BASE + 92) +enum v4l2_smart_auto_status { + SMART_AUTO_STATUS_AUTO = 0, + SMART_AUTO_STATUS_LANDSCAPE, + SMART_AUTO_STATUS_PORTRAIT, + SMART_AUTO_STATUS_MACRO, + SMART_AUTO_STATUS_NIGHT, + SMART_AUTO_STATUS_PORTRAIT_NIGHT, + SMART_AUTO_STATUS_BACKLIT, + SMART_AUTO_STATUS_PORTRAIT_BACKLIT, + SMART_AUTO_STATUS_ANTISHAKE, + SMART_AUTO_STATUS_PORTRAIT_ANTISHAKE, + SMART_AUTO_STATUS_MAX, +}; + +#define V4L2_CID_CAMERA_SET_AUTO_FOCUS (V4L2_CID_PRIVATE_BASE + 93) +enum v4l2_auto_focus { + AUTO_FOCUS_OFF = 0, + AUTO_FOCUS_ON, + AUTO_FOCUS_STATUS, + AUTO_FOCUS_MAX, +}; + +#define V4L2_CID_CAMERA_BEAUTY_SHOT (V4L2_CID_PRIVATE_BASE + 94) +enum v4l2_beauty_shot { + BEAUTY_SHOT_OFF = 0, + BEAUTY_SHOT_ON, + BEAUTY_SHOT_MAX, +}; + +#define V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK (V4L2_CID_PRIVATE_BASE + 95) +enum v4l2_ae_awb_lockunlock { + AE_UNLOCK_AWB_UNLOCK = 0, + AE_LOCK_AWB_UNLOCK, + AE_UNLOCK_AWB_LOCK, + AE_LOCK_AWB_LOCK, + AE_AWB_MAX +}; + +#define V4L2_CID_CAMERA_FACEDETECT_LOCKUNLOCK (V4L2_CID_PRIVATE_BASE + 96) +enum v4l2_face_lock { + FACE_LOCK_OFF = 0, + FACE_LOCK_ON, + FIRST_FACE_TRACKING, + FACE_LOCK_MAX, +}; + +#define V4L2_CID_CAMERA_OBJECT_POSITION_X (V4L2_CID_PRIVATE_BASE + 97) +#define V4L2_CID_CAMERA_OBJECT_POSITION_Y (V4L2_CID_PRIVATE_BASE + 98) +#define V4L2_CID_CAMERA_FOCUS_MODE (V4L2_CID_PRIVATE_BASE + 99) +enum v4l2_focusmode { + FOCUS_MODE_AUTO = 0, + FOCUS_MODE_MACRO, + FOCUS_MODE_FACEDETECT, + FOCUS_MODE_AUTO_DEFAULT, + FOCUS_MODE_MACRO_DEFAULT, + FOCUS_MODE_FACEDETECT_DEFAULT, + FOCUS_MODE_INFINITY, + FOCUS_MODE_MAX, +}; + +#define V4L2_CID_CAMERA_OBJ_TRACKING_STATUS (V4L2_CID_PRIVATE_BASE + 100) +enum v4l2_obj_tracking_status { + OBJECT_TRACKING_STATUS_BASE = 0, + OBJECT_TRACKING_STATUS_PROGRESSING, + OBJECT_TRACKING_STATUS_SUCCESS, + OBJECT_TRACKING_STATUS_FAIL, + OBJECT_TRACKING_STATUS_MISSING, + OBJECT_TRACKING_STATUS_MAX, +}; + +#define V4L2_CID_CAMERA_OBJ_TRACKING_START_STOP (V4L2_CID_PRIVATE_BASE + 101) +enum v4l2_ot_start_stop { + OT_STOP = 0, + OT_START, + OT_MAX, +}; + +#define V4L2_CID_CAMERA_CAF_START_STOP (V4L2_CID_PRIVATE_BASE + 102) +enum v4l2_caf_start_stop { + CAF_STOP = 0, + CAF_START, + CAF_MAX, +}; + +#define V4L2_CID_CAMERA_AUTO_FOCUS_RESULT (V4L2_CID_PRIVATE_BASE + 103) +#define V4L2_CID_CAMERA_FRAME_RATE (V4L2_CID_PRIVATE_BASE + 104) +enum v4l2_frame_rate { + FRAME_RATE_AUTO = 0, + FRAME_RATE_7 = 7, + FRAME_RATE_15 = 15, + FRAME_RATE_30 = 30, + FRAME_RATE_60 = 60, + FRAME_RATE_120 = 120, + FRAME_RATE_MAX +}; + +#define V4L2_CID_CAMERA_ANTI_BANDING (V4L2_CID_PRIVATE_BASE + 105) +enum v4l2_anti_banding { + ANTI_BANDING_AUTO = 0, + ANTI_BANDING_50HZ = 1, + ANTI_BANDING_60HZ = 2, + ANTI_BANDING_OFF = 3, +}; + +#define V4L2_CID_CAMERA_SET_GAMMA (V4L2_CID_PRIVATE_BASE + 106) +enum v4l2_gamma_mode { + GAMMA_OFF = 0, + GAMMA_ON = 1, + GAMMA_MAX, +}; + +#define V4L2_CID_CAMERA_SET_SLOW_AE (V4L2_CID_PRIVATE_BASE + 107) +enum v4l2_slow_ae_mode { + SLOW_AE_OFF = 0, + SLOW_AE_ON, + SLOW_AE_MAX, +}; + +#define V4L2_CID_CAMERA_BATCH_REFLECTION (V4L2_CID_PRIVATE_BASE + 108) +#define V4L2_CID_CAMERA_EXIF_ORIENTATION (V4L2_CID_PRIVATE_BASE + 109) + +#define V4L2_CID_CAMERA_RESET (V4L2_CID_PRIVATE_BASE + 111) +#define V4L2_CID_CAMERA_CHECK_DATALINE (V4L2_CID_PRIVATE_BASE + 112) +#define V4L2_CID_CAMERA_CHECK_DATALINE_STOP (V4L2_CID_PRIVATE_BASE + 113) +#define V4L2_CID_CAMERA_GET_ISO (V4L2_CID_PRIVATE_BASE + 114) +#define V4L2_CID_CAMERA_GET_SHT_TIME (V4L2_CID_PRIVATE_BASE + 115) +#define V4L2_CID_CAMERA_SENSOR_MODE (V4L2_CID_PRIVATE_BASE + 116) +#define V4L2_CID_ESD_INT (V4L2_CID_PRIVATE_BASE + 117) +#define V4L2_CID_CAMERA_GET_FLASH_ONOFF (V4L2_CID_PRIVATE_BASE + 118) +#define V4L2_CID_CAMERA_APP_CHECK (V4L2_CID_PRIVATE_BASE + 119) +#define V4L2_CID_CAMERA_CHECK_FLIP (V4L2_CID_PRIVATE_BASE + 120) + +#define V4L2_CID_CAM_SENSOR_TYPE (V4L2_CID_PRIVATE_BASE + 121) +enum v4l2_camera_id { + CAMERA_ID_BACK = 0, + CAMERA_ID_FRONT = 1, + CAMERA_ID_MAX = 2, +}; + +/* Pixel format FOURCC depth Description */ +/* 12 Y/CbCr 4:2:0 64x32 macroblocks */ +#define V4L2_PIX_FMT_NV12T v4l2_fourcc('T', 'V', '1', '2') + +/* + * * V4L2 extention for digital camera + * */ +/* Strobe flash light */ +enum v4l2_strobe_control { + /* turn off the flash light */ + V4L2_STROBE_CONTROL_OFF = 0, + /* turn on the flash light */ + V4L2_STROBE_CONTROL_ON = 1, + /* act guide light before splash */ + V4L2_STROBE_CONTROL_AFGUIDE = 2, + /* charge the flash light */ + V4L2_STROBE_CONTROL_CHARGE = 3, +}; + +enum v4l2_strobe_conf { + V4L2_STROBE_OFF = 0, /* Always off */ + V4L2_STROBE_ON = 1, /* Always splashes */ + /* Auto control presets */ + V4L2_STROBE_AUTO = 2, + V4L2_STROBE_REDEYE_REDUCTION = 3, + V4L2_STROBE_SLOW_SYNC = 4, + V4L2_STROBE_FRONT_CURTAIN = 5, + V4L2_STROBE_REAR_CURTAIN = 6, + /* Extra manual control presets */ + /* keep turned on until turning off */ + V4L2_STROBE_PERMANENT = 7, + V4L2_STROBE_EXTERNAL = 8, +}; + +enum v4l2_strobe_status { + V4L2_STROBE_STATUS_OFF = 0, + /* while processing configurations */ + V4L2_STROBE_STATUS_BUSY = 1, + V4L2_STROBE_STATUS_ERR = 2, + V4L2_STROBE_STATUS_CHARGING = 3, + V4L2_STROBE_STATUS_CHARGED = 4, +}; + +/* capabilities field */ +/* No strobe supported */ +#define V4L2_STROBE_CAP_NONE 0x0000 +/* Always flash off mode */ +#define V4L2_STROBE_CAP_OFF 0x0001 +/* Always use flash light mode */ +#define V4L2_STROBE_CAP_ON 0x0002 +/* Flashlight works automatic */ +#define V4L2_STROBE_CAP_AUTO 0x0004 +/* Red-eye reduction */ +#define V4L2_STROBE_CAP_REDEYE 0x0008 +/* Slow sync */ +#define V4L2_STROBE_CAP_SLOWSYNC 0x0010 +/* Front curtain */ +#define V4L2_STROBE_CAP_FRONT_CURTAIN 0x0020 +/* Rear curtain */ +#define V4L2_STROBE_CAP_REAR_CURTAIN 0x0040 +/* keep turned on until turning off */ +#define V4L2_STROBE_CAP_PERMANENT 0x0080 +/* use external strobe */ +#define V4L2_STROBE_CAP_EXTERNAL 0x0100 + +/* Set mode and Get status */ +struct v4l2_strobe { + /* off/on/charge:0/1/2 */ + enum v4l2_strobe_control control; + /* supported strobe capabilities */ + __u32 capabilities; + enum v4l2_strobe_conf mode; + enum v4l2_strobe_status status; /* read only */ + /* default is 0 and range of value varies from each models */ + __u32 flash_ev; + __u32 reserved[4]; +}; + +#define VIDIOC_S_STROBE _IOWR('V', 83, struct v4l2_strobe) +#define VIDIOC_G_STROBE _IOR('V', 84, struct v4l2_strobe) + +/* Object recognition and collateral actions */ +enum v4l2_recog_mode { + V4L2_RECOGNITION_MODE_OFF = 0, + V4L2_RECOGNITION_MODE_ON = 1, + V4L2_RECOGNITION_MODE_LOCK = 2, +}; + +enum v4l2_recog_action { + V4L2_RECOGNITION_ACTION_NONE = 0, /* only recognition */ + V4L2_RECOGNITION_ACTION_BLINK = 1, /* Capture on blinking */ + V4L2_RECOGNITION_ACTION_SMILE = 2, /* Capture on smiling */ +}; + +enum v4l2_recog_pattern { + V4L2_RECOG_PATTERN_FACE = 0, /* Face */ + V4L2_RECOG_PATTERN_HUMAN = 1, /* Human */ + V4L2_RECOG_PATTERN_CHAR = 2, /* Character */ +}; + +struct v4l2_recog_rect { + enum v4l2_recog_pattern p; /* detected pattern */ + struct v4l2_rect o; /* detected area */ + __u32 reserved[4]; +}; + +struct v4l2_recog_data { + __u8 detect_cnt; /* detected object counter */ + struct v4l2_rect o; /* detected area */ + __u32 reserved[4]; +}; + +struct v4l2_recognition { + enum v4l2_recog_mode mode; + + /* Which pattern to detect */ + enum v4l2_recog_pattern pattern; + + /* How many object to detect */ + __u8 obj_num; + + /* select detected object */ + __u32 detect_idx; + + /* read only :Get object coordination */ + struct v4l2_recog_data data; + + enum v4l2_recog_action action; + __u32 reserved[4]; +}; + +#define VIDIOC_S_RECOGNITION _IOWR('V', 85, struct v4l2_recognition) +#define VIDIOC_G_RECOGNITION _IOR('V', 86, struct v4l2_recognition) + +/* We use this struct as the v4l2_streamparm raw_data for + * VIDIOC_G_PARM and VIDIOC_S_PARM + */ +struct sec_cam_parm { + struct v4l2_captureparm capture; + int contrast; + int effects; + int brightness; + int flash_mode; + int focus_mode; + int iso; + int metering; + int saturation; + int scene_mode; + int sharpness; + int white_balance; +}; + +#endif /* __LINUX_VIDEODEV2_SAMSUNG_H */ diff --git a/init.p1.usb.rc b/init.p1.usb.rc new file mode 100755 index 0000000..a8f5413 --- /dev/null +++ b/init.p1.usb.rc @@ -0,0 +1,6 @@ +on property:sys.usb.config=mass_storage + setprop sys.usb.state $sys.usb.config + +on property:sys.usb.config=mass_storage,adb + start adbd + setprop sys.usb.state $sys.usb.config diff --git a/libaudio/Android.mk b/libaudio/Android.mk new file mode 100644 index 0000000..5c998d6 --- /dev/null +++ b/libaudio/Android.mk @@ -0,0 +1,52 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= aplay.c alsa_pcm.c alsa_mixer.c +LOCAL_MODULE:= aplay +LOCAL_SHARED_LIBRARIES:= libc libcutils +LOCAL_MODULE_TAGS:= debug +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= arec.c alsa_pcm.c +LOCAL_MODULE:= arec +LOCAL_SHARED_LIBRARIES:= libc libcutils +LOCAL_MODULE_TAGS:= debug +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= amix.c alsa_mixer.c +LOCAL_MODULE:= amix +LOCAL_SHARED_LIBRARIES := libc libcutils +LOCAL_MODULE_TAGS:= debug +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= AudioHardware.cpp alsa_mixer.c alsa_pcm.c +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE:= audio.primary.s5pc110 +LOCAL_MODULE_TAGS := optional +LOCAL_STATIC_LIBRARIES := libmedia_helper +LOCAL_WHOLE_STATIC_LIBRARIES := libaudiohw_legacy +LOCAL_SHARED_LIBRARIES:= libc libcutils libutils libmedia libhardware_legacy + +ifeq ($(TARGET_SIMULATOR),true) + LOCAL_LDLIBS += -ldl +else + LOCAL_SHARED_LIBRARIES += libdl +endif + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= AudioPolicyManager.cpp +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE:= audio_policy.s5pc110 +LOCAL_MODULE_TAGS := optional +LOCAL_STATIC_LIBRARIES := libmedia_helper +LOCAL_WHOLE_STATIC_LIBRARIES:= libaudiopolicy_legacy +LOCAL_SHARED_LIBRARIES:= libc libcutils libutils libmedia +ifeq ($(BOARD_HAVE_BLUETOOTH),true) + LOCAL_CFLAGS += -DWITH_A2DP +endif +include $(BUILD_SHARED_LIBRARY) diff --git a/libaudio/AudioHardware.cpp b/libaudio/AudioHardware.cpp new file mode 100644 index 0000000..d50a7c3 --- /dev/null +++ b/libaudio/AudioHardware.cpp @@ -0,0 +1,1961 @@ +/* +** Copyright 2010, 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 "AudioHardware" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AudioHardware.h" +#include +#include + +extern "C" { +#include "alsa_audio.h" +} + + +namespace android_audio_legacy { + +const uint32_t AudioHardware::inputSamplingRates[] = { + 8000, 11025, 16000, 22050, 44100 +}; + +// trace driver operations for dump +// +//#define DRIVER_TRACE + +enum { + DRV_NONE, + DRV_PCM_OPEN, + DRV_PCM_CLOSE, + DRV_PCM_WRITE, + DRV_PCM_READ, + DRV_MIXER_OPEN, + DRV_MIXER_CLOSE, + DRV_MIXER_GET, + DRV_MIXER_SEL +}; + +#ifdef DRIVER_TRACE +#define TRACE_DRIVER_IN(op) mDriverOp = op; +#define TRACE_DRIVER_OUT mDriverOp = DRV_NONE; +#else +#define TRACE_DRIVER_IN(op) +#define TRACE_DRIVER_OUT +#endif + +// ---------------------------------------------------------------------------- + +const char *AudioHardware::inputPathNameDefault = "Default"; +const char *AudioHardware::inputPathNameCamcorder = "Camcorder"; +const char *AudioHardware::inputPathNameVoiceRecognition = "Voice Recognition"; +const char *AudioHardware::inputPathNameVoiceCommunication = "Voice Communication"; + +AudioHardware::AudioHardware() : + mInit(false), + mMicMute(false), + mPcm(NULL), + mMixer(NULL), + mPcmOpenCnt(0), + mMixerOpenCnt(0), + mInCallAudioMode(false), + mInputSource(AUDIO_SOURCE_DEFAULT), + mBluetoothNrec(true), + mTTYMode(TTY_MODE_OFF), + mDriverOp(DRV_NONE) +{ + mInit = true; +} + +AudioHardware::~AudioHardware() +{ + for (size_t index = 0; index < mInputs.size(); index++) { + closeInputStream(mInputs[index].get()); + } + mInputs.clear(); + closeOutputStream((AudioStreamOut*)mOutput.get()); + + if (mMixer) { + TRACE_DRIVER_IN(DRV_MIXER_CLOSE) + mixer_close(mMixer); + TRACE_DRIVER_OUT + } + if (mPcm) { + TRACE_DRIVER_IN(DRV_PCM_CLOSE) + pcm_close(mPcm); + TRACE_DRIVER_OUT + } + + mInit = false; +} + +status_t AudioHardware::initCheck() +{ + return mInit ? NO_ERROR : NO_INIT; +} + +AudioStreamOut* AudioHardware::openOutputStream( + uint32_t devices, int *format, uint32_t *channels, + uint32_t *sampleRate, status_t *status) +{ + sp out; + status_t rc; + + { // scope for the lock + Mutex::Autolock lock(mLock); + + // only one output stream allowed + if (mOutput != 0) { + if (status) { + *status = INVALID_OPERATION; + } + return NULL; + } + + out = new AudioStreamOutALSA(); + + rc = out->set(this, devices, format, channels, sampleRate); + if (rc == NO_ERROR) { + mOutput = out; + } + } + + if (rc != NO_ERROR) { + if (out != 0) { + out.clear(); + } + } + if (status) { + *status = rc; + } + + return out.get(); +} + +void AudioHardware::closeOutputStream(AudioStreamOut* out) { + sp spOut; + { + Mutex::Autolock lock(mLock); + if (mOutput == 0 || mOutput.get() != out) { + LOGW("Attempt to close invalid output stream"); + return; + } + spOut = mOutput; + mOutput.clear(); + } + spOut.clear(); +} + +AudioStreamIn* AudioHardware::openInputStream( + uint32_t devices, int *format, uint32_t *channels, + uint32_t *sampleRate, status_t *status, + AudioSystem::audio_in_acoustics acoustic_flags) +{ + // check for valid input source + if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) { + if (status) { + *status = BAD_VALUE; + } + return NULL; + } + + status_t rc = NO_ERROR; + sp in; + + { // scope for the lock + Mutex::Autolock lock(mLock); + + in = new AudioStreamInALSA(); + rc = in->set(this, devices, format, channels, sampleRate, acoustic_flags); + if (rc == NO_ERROR) { + mInputs.add(in); + } + } + + if (rc != NO_ERROR) { + if (in != 0) { + in.clear(); + } + } + if (status) { + *status = rc; + } + + LOGV("AudioHardware::openInputStream()%p", in.get()); + return in.get(); +} + +void AudioHardware::closeInputStream(AudioStreamIn* in) { + + sp spIn; + { + Mutex::Autolock lock(mLock); + + ssize_t index = mInputs.indexOf((AudioStreamInALSA *)in); + if (index < 0) { + LOGW("Attempt to close invalid input stream"); + return; + } + spIn = mInputs[index]; + mInputs.removeAt(index); + } + LOGV("AudioHardware::closeInputStream()%p", in); + spIn.clear(); +} + + +status_t AudioHardware::setMode(int mode) +{ + sp spOut; + sp spIn; + status_t status; + + // Mutex acquisition order is always out -> in -> hw + AutoMutex lock(mLock); + + spOut = mOutput; + while (spOut != 0) { + if (!spOut->checkStandby()) { + int cnt = spOut->prepareLock(); + mLock.unlock(); + spOut->lock(); + mLock.lock(); + // make sure that another thread did not change output state while the + // mutex is released + if ((spOut == mOutput) && (cnt == spOut->standbyCnt())) { + break; + } + spOut->unlock(); + spOut = mOutput; + } else { + spOut.clear(); + } + } + // spOut is not 0 here only if the output is active + + spIn = getActiveInput_l(); + while (spIn != 0) { + int cnt = spIn->prepareLock(); + mLock.unlock(); + spIn->lock(); + mLock.lock(); + // make sure that another thread did not change input state while the + // mutex is released + if ((spIn == getActiveInput_l()) && (cnt == spIn->standbyCnt())) { + break; + } + spIn->unlock(); + spIn = getActiveInput_l(); + } + // spIn is not 0 here only if the input is active + + int prevMode = mMode; + status = AudioHardwareBase::setMode(mode); + LOGV("setMode() : new %d, old %d", mMode, prevMode); + if (status == NO_ERROR) { + if (mMode == AudioSystem::MODE_IN_CALL && !mInCallAudioMode) { + if (spOut != 0) { + LOGV("setMode() in call force output standby"); + spOut->doStandby_l(); + } + if (spIn != 0) { + LOGV("setMode() in call force input standby"); + spIn->doStandby_l(); + } + + LOGV("setMode() openPcmOut_l()"); + openPcmOut_l(); + openMixer_l(); + setInputSource_l(AUDIO_SOURCE_DEFAULT); + mInCallAudioMode = true; + } + if (mMode == AudioSystem::MODE_NORMAL && mInCallAudioMode) { + setInputSource_l(mInputSource); + if (mMixer != NULL) { + TRACE_DRIVER_IN(DRV_MIXER_GET) + struct mixer_ctl *ctl= mixer_get_control(mMixer, "Playback Path", 0); + TRACE_DRIVER_OUT + if (ctl != NULL) { + LOGV("setMode() reset Playback Path to SPK"); + TRACE_DRIVER_IN(DRV_MIXER_SEL) + mixer_ctl_select(ctl, "SPK"); + TRACE_DRIVER_OUT + } + } + LOGV("setMode() closePcmOut_l()"); + closeMixer_l(); + closePcmOut_l(); + + if (spOut != 0) { + LOGV("setMode() off call force output standby"); + spOut->doStandby_l(); + } + if (spIn != 0) { + LOGV("setMode() off call force input standby"); + spIn->doStandby_l(); + } + + mInCallAudioMode = false; + } + } + + if (spIn != 0) { + spIn->unlock(); + } + if (spOut != 0) { + spOut->unlock(); + } + + return status; +} + +status_t AudioHardware::setMicMute(bool state) +{ + LOGV("setMicMute(%d) mMicMute %d", state, mMicMute); + sp spIn; + { + AutoMutex lock(mLock); + if (mMicMute != state) { + mMicMute = state; + spIn = getActiveInput_l(); + } + } + + if (spIn != 0) { + spIn->standby(); + } + + return NO_ERROR; +} + +status_t AudioHardware::getMicMute(bool* state) +{ + *state = mMicMute; + return NO_ERROR; +} + +status_t AudioHardware::setParameters(const String8& keyValuePairs) +{ + AudioParameter param = AudioParameter(keyValuePairs); + String8 value; + String8 key; + const char BT_NREC_KEY[] = "bt_headset_nrec"; + const char BT_NREC_VALUE_ON[] = "on"; + const char TTY_MODE_KEY[] = "tty_mode"; + const char TTY_MODE_VALUE_OFF[] = "tty_off"; + const char TTY_MODE_VALUE_VCO[] = "tty_vco"; + const char TTY_MODE_VALUE_HCO[] = "tty_hco"; + const char TTY_MODE_VALUE_FULL[] = "tty_full"; + + key = String8(BT_NREC_KEY); + if (param.get(key, value) == NO_ERROR) { + if (value == BT_NREC_VALUE_ON) { + mBluetoothNrec = true; + } else { + mBluetoothNrec = false; + LOGD("Turning noise reduction and echo cancellation off for BT " + "headset"); + } + param.remove(String8(BT_NREC_KEY)); + } + + key = String8(TTY_MODE_KEY); + if (param.get(key, value) == NO_ERROR) { + int ttyMode; + if (value == TTY_MODE_VALUE_OFF) { + ttyMode = TTY_MODE_OFF; + } else if (value == TTY_MODE_VALUE_VCO) { + ttyMode = TTY_MODE_VCO; + } else if (value == TTY_MODE_VALUE_HCO) { + ttyMode = TTY_MODE_HCO; + } else if (value == TTY_MODE_VALUE_FULL) { + ttyMode = TTY_MODE_FULL; + } else { + return BAD_VALUE; + } + + if (ttyMode != mTTYMode) { + LOGV("new tty mode %d", ttyMode); + mTTYMode = ttyMode; + if (mOutput != 0 && mMode == AudioSystem::MODE_IN_CALL) { + setIncallPath_l(mOutput->device()); + } + } + param.remove(String8(TTY_MODE_KEY)); + } + + return NO_ERROR; +} + +String8 AudioHardware::getParameters(const String8& keys) +{ + AudioParameter request = AudioParameter(keys); + AudioParameter reply = AudioParameter(); + + LOGV("getParameters() %s", keys.string()); + + return reply.toString(); +} + +size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) +{ + if (format != AudioSystem::PCM_16_BIT) { + LOGW("getInputBufferSize bad format: %d", format); + return 0; + } + if (channelCount < 1 || channelCount > 2) { + LOGW("getInputBufferSize bad channel count: %d", channelCount); + return 0; + } + if (sampleRate != 8000 && sampleRate != 11025 && sampleRate != 16000 && + sampleRate != 22050 && sampleRate != 44100) { + LOGW("getInputBufferSize bad sample rate: %d", sampleRate); + return 0; + } + + return AudioStreamInALSA::getBufferSize(sampleRate, channelCount); +} + + +status_t AudioHardware::setVoiceVolume(float volume) +{ + LOGD("### setVoiceVolume: %f", volume); + + AutoMutex lock(mLock); + + uint32_t device = AudioSystem::DEVICE_OUT_EARPIECE; + if (mOutput != 0) { + device = mOutput->device(); + } + if (mMixer != NULL) { + struct mixer_ctl *ctl; + const char* name; + TRACE_DRIVER_IN(DRV_MIXER_GET) + switch (device) { + case AudioSystem::DEVICE_OUT_WIRED_HEADSET: + case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE: + name = "Playback Headset Volume"; + break; + default: + name = "Playback Spkr Volume"; + break; + } + ctl= mixer_get_control(mMixer, name, 0); + TRACE_DRIVER_OUT + + if (ctl != NULL) { + LOGV("setVoiceVolume() set %s to %f", name, volume); + TRACE_DRIVER_IN(DRV_MIXER_SET) + mixer_ctl_set(ctl, volume * 100); + TRACE_DRIVER_OUT + } + } + + return NO_ERROR; +} + +status_t AudioHardware::setMasterVolume(float volume) +{ + LOGV("Set master volume to %f.\n", volume); + // We return an error code here to let the audioflinger do in-software + // volume on top of the maximum volume that we set through the SND API. + // return error - software mixer will handle it + + return -1; +} + +static const int kDumpLockRetries = 50; +static const int kDumpLockSleep = 20000; + +static bool tryLock(Mutex& mutex) +{ + bool locked = false; + for (int i = 0; i < kDumpLockRetries; ++i) { + if (mutex.tryLock() == NO_ERROR) { + locked = true; + break; + } + usleep(kDumpLockSleep); + } + return locked; +} + +status_t AudioHardware::dump(int fd, const Vector& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + bool locked = tryLock(mLock); + if (!locked) { + snprintf(buffer, SIZE, "\n\tAudioHardware maybe deadlocked\n"); + } else { + mLock.unlock(); + } + + snprintf(buffer, SIZE, "\tInit %s\n", (mInit) ? "OK" : "Failed"); + result.append(buffer); + snprintf(buffer, SIZE, "\tMic Mute %s\n", (mMicMute) ? "ON" : "OFF"); + result.append(buffer); + snprintf(buffer, SIZE, "\tmPcm: %p\n", mPcm); + result.append(buffer); + snprintf(buffer, SIZE, "\tmPcmOpenCnt: %d\n", mPcmOpenCnt); + result.append(buffer); + snprintf(buffer, SIZE, "\tmMixer: %p\n", mMixer); + result.append(buffer); + snprintf(buffer, SIZE, "\tmMixerOpenCnt: %d\n", mMixerOpenCnt); + result.append(buffer); + snprintf(buffer, SIZE, "\tIn Call Audio Mode %s\n", + (mInCallAudioMode) ? "ON" : "OFF"); + result.append(buffer); + snprintf(buffer, SIZE, "\tInput source %d\n", mInputSource); + result.append(buffer); + snprintf(buffer, SIZE, "\tmDriverOp: %d\n", mDriverOp); + result.append(buffer); + + snprintf(buffer, SIZE, "\n\tmOutput %p dump:\n", mOutput.get()); + result.append(buffer); + write(fd, result.string(), result.size()); + if (mOutput != 0) { + mOutput->dump(fd, args); + } + + snprintf(buffer, SIZE, "\n\t%d inputs opened:\n", mInputs.size()); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < mInputs.size(); i++) { + snprintf(buffer, SIZE, "\t- input %d dump:\n", i); + write(fd, buffer, strlen(buffer)); + mInputs[i]->dump(fd, args); + } + + return NO_ERROR; +} + +status_t AudioHardware::setIncallPath_l(uint32_t device) +{ + LOGV("setIncallPath_l: device %x", device); + + if (mMixer != NULL) { + TRACE_DRIVER_IN(DRV_MIXER_GET) + struct mixer_ctl *ctl= mixer_get_control(mMixer, "Voice Call Path", 0); + TRACE_DRIVER_OUT + LOGE_IF(ctl == NULL, "setIncallPath_l() could not get mixer ctl"); + if (ctl != NULL) { + LOGV("setIncallPath_l() Voice Call Path, (%x)", device); + const char *router = getVoiceRouteFromDevice(device); + TRACE_DRIVER_IN(DRV_MIXER_SEL) + mixer_ctl_select(ctl,router); + TRACE_DRIVER_OUT + } + } + return NO_ERROR; +} + +struct pcm *AudioHardware::openPcmOut_l() +{ + LOGD("openPcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt); + if (mPcmOpenCnt++ == 0) { + if (mPcm != NULL) { + LOGE("openPcmOut_l() mPcmOpenCnt == 0 and mPcm == %p\n", mPcm); + mPcmOpenCnt--; + return NULL; + } + unsigned flags = PCM_OUT; + + flags |= (AUDIO_HW_OUT_PERIOD_MULT - 1) << PCM_PERIOD_SZ_SHIFT; + flags |= (AUDIO_HW_OUT_PERIOD_CNT - PCM_PERIOD_CNT_MIN) << PCM_PERIOD_CNT_SHIFT; + + TRACE_DRIVER_IN(DRV_PCM_OPEN) + mPcm = pcm_open(flags); + TRACE_DRIVER_OUT + if (!pcm_ready(mPcm)) { + LOGE("openPcmOut_l() cannot open pcm_out driver: %s\n", pcm_error(mPcm)); + TRACE_DRIVER_IN(DRV_PCM_CLOSE) + pcm_close(mPcm); + TRACE_DRIVER_OUT + mPcmOpenCnt--; + mPcm = NULL; + } + } + return mPcm; +} + +void AudioHardware::closePcmOut_l() +{ + LOGD("closePcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt); + if (mPcmOpenCnt == 0) { + LOGE("closePcmOut_l() mPcmOpenCnt == 0"); + return; + } + + if (--mPcmOpenCnt == 0) { + TRACE_DRIVER_IN(DRV_PCM_CLOSE) + pcm_close(mPcm); + TRACE_DRIVER_OUT + mPcm = NULL; + } +} + +struct mixer *AudioHardware::openMixer_l() +{ + LOGV("openMixer_l() mMixerOpenCnt: %d", mMixerOpenCnt); + if (mMixerOpenCnt++ == 0) { + if (mMixer != NULL) { + LOGE("openMixer_l() mMixerOpenCnt == 0 and mMixer == %p\n", mMixer); + mMixerOpenCnt--; + return NULL; + } + TRACE_DRIVER_IN(DRV_MIXER_OPEN) + mMixer = mixer_open(); + TRACE_DRIVER_OUT + if (mMixer == NULL) { + LOGE("openMixer_l() cannot open mixer"); + mMixerOpenCnt--; + return NULL; + } + } + return mMixer; +} + +void AudioHardware::closeMixer_l() +{ + LOGV("closeMixer_l() mMixerOpenCnt: %d", mMixerOpenCnt); + if (mMixerOpenCnt == 0) { + LOGE("closeMixer_l() mMixerOpenCnt == 0"); + return; + } + + if (--mMixerOpenCnt == 0) { + TRACE_DRIVER_IN(DRV_MIXER_CLOSE) + mixer_close(mMixer); + TRACE_DRIVER_OUT + mMixer = NULL; + } +} + +const char *AudioHardware::getOutputRouteFromDevice(uint32_t device) +{ + switch (device) { + case AudioSystem::DEVICE_OUT_EARPIECE: + case AudioSystem::DEVICE_OUT_SPEAKER: + if (mMode == AudioSystem::MODE_RINGTONE) return "RING_SPK"; + else return "SPK"; + case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE: + if (mMode == AudioSystem::MODE_RINGTONE) return "RING_NO_MIC"; + else return "HP_NO_MIC"; + case AudioSystem::DEVICE_OUT_WIRED_HEADSET: + if (mMode == AudioSystem::MODE_RINGTONE) return "RING_HP"; + else return "HP"; + case (AudioSystem::DEVICE_OUT_SPEAKER|AudioSystem::DEVICE_OUT_WIRED_HEADPHONE): + case (AudioSystem::DEVICE_OUT_SPEAKER|AudioSystem::DEVICE_OUT_WIRED_HEADSET): + if (mMode == AudioSystem::MODE_RINGTONE) return "RING_SPK_HP"; + else return "SPK_HP"; + case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO: + case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET: + case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT: + return "BT"; + default: + return "OFF"; + } +} + +const char *AudioHardware::getVoiceRouteFromDevice(uint32_t device) +{ + switch (device) { + case AudioSystem::DEVICE_OUT_EARPIECE: + case AudioSystem::DEVICE_OUT_SPEAKER: + return "SPK"; + case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE: + case AudioSystem::DEVICE_OUT_WIRED_HEADSET: + switch (mTTYMode) { + case TTY_MODE_VCO: + return "TTY_VCO"; + case TTY_MODE_HCO: + return "TTY_HCO"; + case TTY_MODE_FULL: + return "TTY_FULL"; + case TTY_MODE_OFF: + default: + if (device == AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) { + return "HP_NO_MIC"; + } else { + return "HP"; + } + } + case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO: + case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET: + case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT: + return "BT"; + default: + return "OFF"; + } +} + +const char *AudioHardware::getInputRouteFromDevice(uint32_t device) +{ + if (mMicMute) { + return "MIC OFF"; + } + + switch (device) { + case AudioSystem::DEVICE_IN_BUILTIN_MIC: + return "Main Mic"; + case AudioSystem::DEVICE_IN_WIRED_HEADSET: + return "Hands Free Mic"; + case AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET: + return "BT Sco Mic"; + default: + return "MIC OFF"; + } +} + +uint32_t AudioHardware::getInputSampleRate(uint32_t sampleRate) +{ + uint32_t i; + uint32_t prevDelta; + uint32_t delta; + + for (i = 0, prevDelta = 0xFFFFFFFF; i < sizeof(inputSamplingRates)/sizeof(uint32_t); i++, prevDelta = delta) { + delta = abs(sampleRate - inputSamplingRates[i]); + if (delta > prevDelta) break; + } + // i is always > 0 here + return inputSamplingRates[i-1]; +} + +// getActiveInput_l() must be called with mLock held +sp AudioHardware::getActiveInput_l() +{ + sp< AudioHardware::AudioStreamInALSA> spIn; + + for (size_t i = 0; i < mInputs.size(); i++) { + // return first input found not being in standby mode + // as only one input can be in this state + if (!mInputs[i]->checkStandby()) { + spIn = mInputs[i]; + break; + } + } + + return spIn; +} + +status_t AudioHardware::setInputSource_l(audio_source source) +{ + LOGV("setInputSource_l(%d)", source); + if (source != mInputSource) { + if ((source == AUDIO_SOURCE_DEFAULT) || (mMode != AudioSystem::MODE_IN_CALL)) { + if (mMixer) { + TRACE_DRIVER_IN(DRV_MIXER_GET) + struct mixer_ctl *ctl= mixer_get_control(mMixer, "Input Source", 0); + TRACE_DRIVER_OUT + if (ctl == NULL) { + return NO_INIT; + } + const char* sourceName; + switch (source) { + case AUDIO_SOURCE_DEFAULT: // intended fall-through + case AUDIO_SOURCE_MIC: + sourceName = inputPathNameDefault; + break; + case AUDIO_SOURCE_VOICE_COMMUNICATION: + sourceName = inputPathNameVoiceCommunication; + break; + case AUDIO_SOURCE_CAMCORDER: + sourceName = inputPathNameCamcorder; + break; + case AUDIO_SOURCE_VOICE_RECOGNITION: + sourceName = inputPathNameVoiceRecognition; + break; + case AUDIO_SOURCE_VOICE_UPLINK: // intended fall-through + case AUDIO_SOURCE_VOICE_DOWNLINK: // intended fall-through + case AUDIO_SOURCE_VOICE_CALL: // intended fall-through + default: + return NO_INIT; + } + LOGV("mixer_ctl_select, Input Source, (%s)", sourceName); + TRACE_DRIVER_IN(DRV_MIXER_SEL) + mixer_ctl_select(ctl, sourceName); + TRACE_DRIVER_OUT + } + } + mInputSource = source; + } + + return NO_ERROR; +} + + +//------------------------------------------------------------------------------ +// AudioStreamOutALSA +//------------------------------------------------------------------------------ + +AudioHardware::AudioStreamOutALSA::AudioStreamOutALSA() : + mHardware(0), mPcm(0), mMixer(0), mRouteCtl(0), + mStandby(true), mDevices(0), mChannels(AUDIO_HW_OUT_CHANNELS), + mSampleRate(AUDIO_HW_OUT_SAMPLERATE), mBufferSize(AUDIO_HW_OUT_PERIOD_BYTES), + mDriverOp(DRV_NONE), mStandbyCnt(0), mSleepReq(false) +{ +} + +status_t AudioHardware::AudioStreamOutALSA::set( + AudioHardware* hw, 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; + + mHardware = hw; + mDevices = devices; + + // 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; + + mChannels = lChannels; + mSampleRate = lRate; + mBufferSize = AUDIO_HW_OUT_PERIOD_BYTES; + + return NO_ERROR; +} + +AudioHardware::AudioStreamOutALSA::~AudioStreamOutALSA() +{ + standby(); +} + +ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t bytes) +{ + // LOGV("AudioStreamOutALSA::write(%p, %u)", buffer, bytes); + status_t status = NO_INIT; + const uint8_t* p = static_cast(buffer); + int ret; + + if (mHardware == NULL) return NO_INIT; + + if (mSleepReq) { + // 10ms are always shorter than the time to reconfigure the audio path + // which is the only condition when mSleepReq would be true. + usleep(10000); + } + + { // scope for the lock + + AutoMutex lock(mLock); + + if (mStandby) { + AutoMutex hwLock(mHardware->lock()); + + LOGD("AudioStreamOutALSA::write: AudioHardware pcm playback is exiting standby."); + acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock"); + + sp spIn = mHardware->getActiveInput_l(); + while (spIn != 0) { + int cnt = spIn->prepareLock(); + mHardware->lock().unlock(); + // Mutex acquisition order is always out -> in -> hw + spIn->lock(); + mHardware->lock().lock(); + // make sure that another thread did not change input state + // while the mutex is released + if ((spIn == mHardware->getActiveInput_l()) && + (cnt == spIn->standbyCnt())) { + LOGV("AudioStreamOutALSA::write() force input standby"); + spIn->close_l(); + break; + } + spIn->unlock(); + spIn = mHardware->getActiveInput_l(); + } + // spIn is not 0 here only if the input was active and has been + // closed above + + // open output before input + open_l(); + + if (spIn != 0) { + if (spIn->open_l() != NO_ERROR) { + spIn->doStandby_l(); + } + spIn->unlock(); + } + if (mPcm == NULL) { + release_wake_lock("AudioOutLock"); + goto Error; + } + mStandby = false; + } + + TRACE_DRIVER_IN(DRV_PCM_WRITE) + ret = pcm_write(mPcm,(void*) p, bytes); + TRACE_DRIVER_OUT + + if (ret == 0) { + return bytes; + } + LOGW("write error: %d", errno); + status = -errno; + } +Error: + + standby(); + + // Simulate audio output timing in case of error + usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate()); + + return status; +} + +status_t AudioHardware::AudioStreamOutALSA::standby() +{ + if (mHardware == NULL) return NO_INIT; + + AutoMutex lock(mLock); + + { // scope for the AudioHardware lock + AutoMutex hwLock(mHardware->lock()); + + doStandby_l(); + } + + return NO_ERROR; +} + +void AudioHardware::AudioStreamOutALSA::doStandby_l() +{ + mStandbyCnt++; + + if (!mStandby) { + LOGD("AudioHardware pcm playback is going to standby."); + release_wake_lock("AudioOutLock"); + mStandby = true; + } + + close_l(); +} + +void AudioHardware::AudioStreamOutALSA::close_l() +{ + if (mMixer) { + mHardware->closeMixer_l(); + mMixer = NULL; + mRouteCtl = NULL; + } + if (mPcm) { + mHardware->closePcmOut_l(); + mPcm = NULL; + } +} + +status_t AudioHardware::AudioStreamOutALSA::open_l() +{ + LOGV("open pcm_out driver"); + mPcm = mHardware->openPcmOut_l(); + if (mPcm == NULL) { + return NO_INIT; + } + + mMixer = mHardware->openMixer_l(); + if (mMixer) { + LOGV("open playback normal"); + TRACE_DRIVER_IN(DRV_MIXER_GET) + mRouteCtl = mixer_get_control(mMixer, "Playback Path", 0); + TRACE_DRIVER_OUT + } + if (mHardware->mode() != AudioSystem::MODE_IN_CALL) { + const char *route = mHardware->getOutputRouteFromDevice(mDevices); + LOGV("write() wakeup setting route %s", route); + if (mRouteCtl) { + TRACE_DRIVER_IN(DRV_MIXER_SEL) + mixer_ctl_select(mRouteCtl, route); + TRACE_DRIVER_OUT + } + } + return NO_ERROR; +} + +status_t AudioHardware::AudioStreamOutALSA::dump(int fd, const Vector& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + bool locked = tryLock(mLock); + if (!locked) { + snprintf(buffer, SIZE, "\n\t\tAudioStreamOutALSA maybe deadlocked\n"); + } else { + mLock.unlock(); + } + + snprintf(buffer, SIZE, "\t\tmHardware: %p\n", mHardware); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmPcm: %p\n", mPcm); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmMixer: %p\n", mMixer); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmRouteCtl: %p\n", mRouteCtl); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tStandby %s\n", (mStandby) ? "ON" : "OFF"); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmDevices: 0x%08x\n", mDevices); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmChannels: 0x%08x\n", mChannels); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmSampleRate: %d\n", mSampleRate); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmBufferSize: %d\n", mBufferSize); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmDriverOp: %d\n", mDriverOp); + result.append(buffer); + + ::write(fd, result.string(), result.size()); + + return NO_ERROR; +} + +bool AudioHardware::AudioStreamOutALSA::checkStandby() +{ + return mStandby; +} + +status_t AudioHardware::AudioStreamOutALSA::setParameters(const String8& keyValuePairs) +{ + AudioParameter param = AudioParameter(keyValuePairs); + + status_t status = NO_ERROR; + int device; + LOGD("AudioStreamOutALSA::setParameters() %s", keyValuePairs.string()); + + if (mHardware == NULL) return NO_INIT; + + { + AutoMutex lock(mLock); + + if (param.getInt(String8(AudioParameter::keyRouting), device) == NO_ERROR) + { + if (device != 0) { + AutoMutex hwLock(mHardware->lock()); + + if (mDevices != (uint32_t)device) { + mDevices = (uint32_t)device; + + if (mHardware->mode() != AudioSystem::MODE_IN_CALL) { + doStandby_l(); + } + } + if (mHardware->mode() == AudioSystem::MODE_IN_CALL) { + mHardware->setIncallPath_l(device); + } + } + param.remove(String8(AudioParameter::keyRouting)); + } + } + + if (param.size()) { + status = BAD_VALUE; + } + + return status; +} + +String8 AudioHardware::AudioStreamOutALSA::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)mDevices); + } + + LOGV("AudioStreamOutALSA::getParameters() %s", param.toString().string()); + return param.toString(); +} + +status_t AudioHardware::AudioStreamOutALSA::getRenderPosition(uint32_t *dspFrames) +{ + //TODO + return INVALID_OPERATION; +} + +int AudioHardware::AudioStreamOutALSA::prepareLock() +{ + // request sleep next time write() is called so that caller can acquire + // mLock + mSleepReq = true; + return mStandbyCnt; +} + +void AudioHardware::AudioStreamOutALSA::lock() +{ + mLock.lock(); + mSleepReq = false; +} + +void AudioHardware::AudioStreamOutALSA::unlock() { + mLock.unlock(); +} + +//------------------------------------------------------------------------------ +// AudioStreamInALSA +//------------------------------------------------------------------------------ + +AudioHardware::AudioStreamInALSA::AudioStreamInALSA() : + mHardware(0), mPcm(0), mMixer(0), mRouteCtl(0), + mStandby(true), mDevices(0), mChannels(AUDIO_HW_IN_CHANNELS), mChannelCount(1), + mSampleRate(AUDIO_HW_IN_SAMPLERATE), mBufferSize(AUDIO_HW_IN_PERIOD_BYTES), + mDownSampler(NULL), mReadStatus(NO_ERROR), mDriverOp(DRV_NONE), + mStandbyCnt(0), mSleepReq(false) +{ +} + +status_t AudioHardware::AudioStreamInALSA::set( + AudioHardware* hw, uint32_t devices, int *pFormat, + uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics) +{ + if (pFormat == 0 || *pFormat != AUDIO_HW_IN_FORMAT) { + *pFormat = AUDIO_HW_IN_FORMAT; + return BAD_VALUE; + } + if (pRate == 0) { + return BAD_VALUE; + } + uint32_t rate = AudioHardware::getInputSampleRate(*pRate); + if (rate != *pRate) { + *pRate = rate; + return BAD_VALUE; + } + + if (pChannels == 0 || (*pChannels != AudioSystem::CHANNEL_IN_MONO && + *pChannels != AudioSystem::CHANNEL_IN_STEREO)) { + *pChannels = AUDIO_HW_IN_CHANNELS; + return BAD_VALUE; + } + + mHardware = hw; + + LOGV("AudioStreamInALSA::set(%d, %d, %u)", *pFormat, *pChannels, *pRate); + + mBufferSize = getBufferSize(*pRate, AudioSystem::popCount(*pChannels)); + mDevices = devices; + mChannels = *pChannels; + mChannelCount = AudioSystem::popCount(mChannels); + mSampleRate = rate; + if (mSampleRate != AUDIO_HW_OUT_SAMPLERATE) { + mDownSampler = new AudioHardware::DownSampler(mSampleRate, + mChannelCount, + AUDIO_HW_IN_PERIOD_SZ, + this); + status_t status = mDownSampler->initCheck(); + if (status != NO_ERROR) { + delete mDownSampler; + LOGW("AudioStreamInALSA::set() downsampler init failed: %d", status); + return status; + } + + mPcmIn = new int16_t[AUDIO_HW_IN_PERIOD_SZ * mChannelCount]; + } + return NO_ERROR; +} + +AudioHardware::AudioStreamInALSA::~AudioStreamInALSA() +{ + standby(); + if (mDownSampler != NULL) { + delete mDownSampler; + if (mPcmIn != NULL) { + delete[] mPcmIn; + } + } +} + +ssize_t AudioHardware::AudioStreamInALSA::read(void* buffer, ssize_t bytes) +{ + // LOGV("AudioStreamInALSA::read(%p, %u)", buffer, bytes); + status_t status = NO_INIT; + int ret; + + if (mHardware == NULL) return NO_INIT; + + if (mSleepReq) { + // 10ms are always shorter than the time to reconfigure the audio path + // which is the only condition when mSleepReq would be true. + usleep(10000); + } + + { // scope for the lock + AutoMutex lock(mLock); + + if (mStandby) { + AutoMutex hwLock(mHardware->lock()); + + LOGD("AudioHardware pcm capture is exiting standby."); + acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioInLock"); + + sp spOut = mHardware->output(); + while (spOut != 0) { + if (!spOut->checkStandby()) { + int cnt = spOut->prepareLock(); + mHardware->lock().unlock(); + mLock.unlock(); + // Mutex acquisition order is always out -> in -> hw + spOut->lock(); + mLock.lock(); + mHardware->lock().lock(); + // make sure that another thread did not change output state + // while the mutex is released + if ((spOut == mHardware->output()) && (cnt == spOut->standbyCnt())) { + LOGV("AudioStreamInALSA::read() force output standby"); + spOut->close_l(); + break; + } + spOut->unlock(); + spOut = mHardware->output(); + } else { + spOut.clear(); + } + } + // spOut is not 0 here only if the output was active and has been + // closed above + + // open output before input + if (spOut != 0) { + if (spOut->open_l() != NO_ERROR) { + spOut->doStandby_l(); + } + spOut->unlock(); + } + + open_l(); + + if (mPcm == NULL) { + release_wake_lock("AudioInLock"); + goto Error; + } + mStandby = false; + } + + + if (mDownSampler != NULL) { + size_t frames = bytes / frameSize(); + size_t framesIn = 0; + mReadStatus = 0; + do { + size_t outframes = frames - framesIn; + mDownSampler->resample( + (int16_t *)buffer + (framesIn * mChannelCount), + &outframes); + framesIn += outframes; + } while ((framesIn < frames) && mReadStatus == 0); + ret = mReadStatus; + bytes = framesIn * frameSize(); + } else { + TRACE_DRIVER_IN(DRV_PCM_READ) + ret = pcm_read(mPcm, buffer, bytes); + TRACE_DRIVER_OUT + } + + if (ret == 0) { + return bytes; + } + + LOGW("read error: %d", ret); + status = ret; + } + +Error: + + standby(); + + // Simulate audio output timing in case of error + usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate()); + + return status; +} + +status_t AudioHardware::AudioStreamInALSA::standby() +{ + if (mHardware == NULL) return NO_INIT; + + AutoMutex lock(mLock); + + { // scope for AudioHardware lock + AutoMutex hwLock(mHardware->lock()); + + doStandby_l(); + } + return NO_ERROR; +} + +void AudioHardware::AudioStreamInALSA::doStandby_l() +{ + mStandbyCnt++; + + if (!mStandby) { + LOGD("AudioHardware pcm capture is going to standby."); + release_wake_lock("AudioInLock"); + mStandby = true; + } + close_l(); +} + +void AudioHardware::AudioStreamInALSA::close_l() +{ + if (mMixer) { + mHardware->closeMixer_l(); + mMixer = NULL; + mRouteCtl = NULL; + } + + if (mPcm) { + TRACE_DRIVER_IN(DRV_PCM_CLOSE) + pcm_close(mPcm); + TRACE_DRIVER_OUT + mPcm = NULL; + } +} + +status_t AudioHardware::AudioStreamInALSA::open_l() +{ + unsigned flags = PCM_IN; + if (mChannels == AudioSystem::CHANNEL_IN_MONO) { + flags |= PCM_MONO; + } + flags |= (AUDIO_HW_IN_PERIOD_MULT - 1) << PCM_PERIOD_SZ_SHIFT; + flags |= (AUDIO_HW_IN_PERIOD_CNT - PCM_PERIOD_CNT_MIN) + << PCM_PERIOD_CNT_SHIFT; + + LOGV("open pcm_in driver"); + TRACE_DRIVER_IN(DRV_PCM_OPEN) + mPcm = pcm_open(flags); + TRACE_DRIVER_OUT + if (!pcm_ready(mPcm)) { + LOGE("cannot open pcm_in driver: %s\n", pcm_error(mPcm)); + TRACE_DRIVER_IN(DRV_PCM_CLOSE) + pcm_close(mPcm); + TRACE_DRIVER_OUT + mPcm = NULL; + return NO_INIT; + } + + if (mDownSampler != NULL) { + mInPcmInBuf = 0; + mDownSampler->reset(); + } + + mMixer = mHardware->openMixer_l(); + if (mMixer) { + TRACE_DRIVER_IN(DRV_MIXER_GET) + mRouteCtl = mixer_get_control(mMixer, "Capture MIC Path", 0); + TRACE_DRIVER_OUT + } + + if (mHardware->mode() != AudioSystem::MODE_IN_CALL) { + const char *route = mHardware->getInputRouteFromDevice(mDevices); + LOGV("read() wakeup setting route %s", route); + if (mRouteCtl) { + TRACE_DRIVER_IN(DRV_MIXER_SEL) + mixer_ctl_select(mRouteCtl, route); + TRACE_DRIVER_OUT + } + } + + return NO_ERROR; +} + +status_t AudioHardware::AudioStreamInALSA::dump(int fd, const Vector& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + bool locked = tryLock(mLock); + if (!locked) { + snprintf(buffer, SIZE, "\n\t\tAudioStreamInALSA maybe deadlocked\n"); + } else { + mLock.unlock(); + } + + snprintf(buffer, SIZE, "\t\tmHardware: %p\n", mHardware); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmPcm: %p\n", mPcm); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmMixer: %p\n", mMixer); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tStandby %s\n", (mStandby) ? "ON" : "OFF"); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmDevices: 0x%08x\n", mDevices); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmChannels: 0x%08x\n", mChannels); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmSampleRate: %d\n", mSampleRate); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmBufferSize: %d\n", mBufferSize); + result.append(buffer); + snprintf(buffer, SIZE, "\t\tmDriverOp: %d\n", mDriverOp); + result.append(buffer); + write(fd, result.string(), result.size()); + + return NO_ERROR; +} + +bool AudioHardware::AudioStreamInALSA::checkStandby() +{ + return mStandby; +} + +status_t AudioHardware::AudioStreamInALSA::setParameters(const String8& keyValuePairs) +{ + AudioParameter param = AudioParameter(keyValuePairs); + status_t status = NO_ERROR; + int value; + + LOGD("AudioStreamInALSA::setParameters() %s", keyValuePairs.string()); + + if (mHardware == NULL) return NO_INIT; + + { + AutoMutex lock(mLock); + + if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR) { + AutoMutex hwLock(mHardware->lock()); + + mHardware->openMixer_l(); + mHardware->setInputSource_l((audio_source)value); + mHardware->closeMixer_l(); + + param.remove(String8(AudioParameter::keyInputSource)); + } + + if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) + { + if (value != 0) { + AutoMutex hwLock(mHardware->lock()); + + if (mDevices != (uint32_t)value) { + mDevices = (uint32_t)value; + if (mHardware->mode() != AudioSystem::MODE_IN_CALL) { + doStandby_l(); + } + } + } + param.remove(String8(AudioParameter::keyRouting)); + } + } + + + if (param.size()) { + status = BAD_VALUE; + } + + return status; + +} + +String8 AudioHardware::AudioStreamInALSA::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)mDevices); + } + + LOGV("AudioStreamInALSA::getParameters() %s", param.toString().string()); + return param.toString(); +} + +status_t AudioHardware::AudioStreamInALSA::getNextBuffer(AudioHardware::BufferProvider::Buffer* buffer) +{ + if (mPcm == NULL) { + buffer->raw = NULL; + buffer->frameCount = 0; + mReadStatus = NO_INIT; + return NO_INIT; + } + + if (mInPcmInBuf == 0) { + TRACE_DRIVER_IN(DRV_PCM_READ) + mReadStatus = pcm_read(mPcm,(void*) mPcmIn, AUDIO_HW_IN_PERIOD_SZ * frameSize()); + TRACE_DRIVER_OUT + if (mReadStatus != 0) { + buffer->raw = NULL; + buffer->frameCount = 0; + return mReadStatus; + } + mInPcmInBuf = AUDIO_HW_IN_PERIOD_SZ; + } + + buffer->frameCount = (buffer->frameCount > mInPcmInBuf) ? mInPcmInBuf : buffer->frameCount; + buffer->i16 = mPcmIn + (AUDIO_HW_IN_PERIOD_SZ - mInPcmInBuf) * mChannelCount; + + return mReadStatus; +} + +void AudioHardware::AudioStreamInALSA::releaseBuffer(Buffer* buffer) +{ + mInPcmInBuf -= buffer->frameCount; +} + +size_t AudioHardware::AudioStreamInALSA::getBufferSize(uint32_t sampleRate, int channelCount) +{ + size_t ratio; + + switch (sampleRate) { + case 8000: + case 11025: + ratio = 4; + break; + case 16000: + case 22050: + ratio = 2; + break; + case 44100: + default: + ratio = 1; + break; + } + + return (AUDIO_HW_IN_PERIOD_SZ*channelCount*sizeof(int16_t)) / ratio ; +} + +int AudioHardware::AudioStreamInALSA::prepareLock() +{ + // request sleep next time read() is called so that caller can acquire + // mLock + mSleepReq = true; + return mStandbyCnt; +} + +void AudioHardware::AudioStreamInALSA::lock() +{ + mLock.lock(); + mSleepReq = false; +} + +void AudioHardware::AudioStreamInALSA::unlock() { + mLock.unlock(); +} + +//------------------------------------------------------------------------------ +// DownSampler +//------------------------------------------------------------------------------ + +/* + * 2.30 fixed point FIR filter coefficients for conversion 44100 -> 22050. + * (Works equivalently for 22010 -> 11025 or any other halving, of course.) + * + * Transition band from about 18 kHz, passband ripple < 0.1 dB, + * stopband ripple at about -55 dB, linear phase. + * + * Design and display in MATLAB or Octave using: + * + * filter = fir1(19, 0.5); filter = round(filter * 2**30); freqz(filter * 2**-30); + */ +static const int32_t filter_22khz_coeff[] = { + 2089257, 2898328, -5820678, -10484531, + 19038724, 30542725, -50469415, -81505260, + 152544464, 478517512, 478517512, 152544464, + -81505260, -50469415, 30542725, 19038724, + -10484531, -5820678, 2898328, 2089257, +}; +#define NUM_COEFF_22KHZ (sizeof(filter_22khz_coeff) / sizeof(filter_22khz_coeff[0])) +#define OVERLAP_22KHZ (NUM_COEFF_22KHZ - 2) + +/* + * Convolution of signals A and reverse(B). (In our case, the filter response + * is symmetric, so the reversing doesn't matter.) + * A is taken to be in 0.16 fixed-point, and B is taken to be in 2.30 fixed-point. + * The answer will be in 16.16 fixed-point, unclipped. + * + * This function would probably be the prime candidate for SIMD conversion if + * you want more speed. + */ +int32_t fir_convolve(const int16_t* a, const int32_t* b, int num_samples) +{ + int32_t sum = 1 << 13; + for (int i = 0; i < num_samples; ++i) { + sum += a[i] * (b[i] >> 16); + } + return sum >> 14; +} + +/* Clip from 16.16 fixed-point to 0.16 fixed-point. */ +int16_t clip(int32_t x) +{ + if (x < -32768) { + return -32768; + } else if (x > 32767) { + return 32767; + } else { + return x; + } +} + +/* + * Convert a chunk from 44 kHz to 22 kHz. Will update num_samples_in and num_samples_out + * accordingly, since it may leave input samples in the buffer due to overlap. + * + * Input and output are taken to be in 0.16 fixed-point. + */ +void resample_2_1(int16_t* input, int16_t* output, int* num_samples_in, int* num_samples_out) +{ + if (*num_samples_in < (int)NUM_COEFF_22KHZ) { + *num_samples_out = 0; + return; + } + + int odd_smp = *num_samples_in & 0x1; + int num_samples = *num_samples_in - odd_smp - OVERLAP_22KHZ; + + for (int i = 0; i < num_samples; i += 2) { + output[i / 2] = clip(fir_convolve(input + i, filter_22khz_coeff, NUM_COEFF_22KHZ)); + } + + memmove(input, input + num_samples, (OVERLAP_22KHZ + odd_smp) * sizeof(*input)); + *num_samples_out = num_samples / 2; + *num_samples_in = OVERLAP_22KHZ + odd_smp; +} + +/* + * 2.30 fixed point FIR filter coefficients for conversion 22050 -> 16000, + * or 11025 -> 8000. + * + * Transition band from about 14 kHz, passband ripple < 0.1 dB, + * stopband ripple at about -50 dB, linear phase. + * + * Design and display in MATLAB or Octave using: + * + * filter = fir1(23, 16000 / 22050); filter = round(filter * 2**30); freqz(filter * 2**-30); + */ +static const int32_t filter_16khz_coeff[] = { + 2057290, -2973608, 1880478, 4362037, + -14639744, 18523609, -1609189, -38502470, + 78073125, -68353935, -59103896, 617555440, + 617555440, -59103896, -68353935, 78073125, + -38502470, -1609189, 18523609, -14639744, + 4362037, 1880478, -2973608, 2057290, +}; +#define NUM_COEFF_16KHZ (sizeof(filter_16khz_coeff) / sizeof(filter_16khz_coeff[0])) +#define OVERLAP_16KHZ (NUM_COEFF_16KHZ - 1) + +/* + * Convert a chunk from 22 kHz to 16 kHz. Will update num_samples_in and + * num_samples_out accordingly, since it may leave input samples in the buffer + * due to overlap. + * + * This implementation is rather ad-hoc; it first low-pass filters the data + * into a temporary buffer, and then converts chunks of 441 input samples at a + * time into 320 output samples by simple linear interpolation. A better + * implementation would use a polyphase filter bank to do these two operations + * in one step. + * + * Input and output are taken to be in 0.16 fixed-point. + */ + +#define RESAMPLE_16KHZ_SAMPLES_IN 441 +#define RESAMPLE_16KHZ_SAMPLES_OUT 320 + +void resample_441_320(int16_t* input, int16_t* output, int* num_samples_in, int* num_samples_out) +{ + const int num_blocks = (*num_samples_in - OVERLAP_16KHZ) / RESAMPLE_16KHZ_SAMPLES_IN; + if (num_blocks < 1) { + *num_samples_out = 0; + return; + } + + for (int i = 0; i < num_blocks; ++i) { + uint32_t tmp[RESAMPLE_16KHZ_SAMPLES_IN]; + for (int j = 0; j < RESAMPLE_16KHZ_SAMPLES_IN; ++j) { + tmp[j] = fir_convolve(input + i * RESAMPLE_16KHZ_SAMPLES_IN + j, + filter_16khz_coeff, + NUM_COEFF_16KHZ); + } + + const float step_float = (float)RESAMPLE_16KHZ_SAMPLES_IN / (float)RESAMPLE_16KHZ_SAMPLES_OUT; + const uint32_t step = (uint32_t)(step_float * 32768.0f + 0.5f); // 17.15 fixed point + + uint32_t in_sample_num = 0; // 17.15 fixed point + for (int j = 0; j < RESAMPLE_16KHZ_SAMPLES_OUT; ++j, in_sample_num += step) { + const uint32_t whole = in_sample_num >> 15; + const uint32_t frac = (in_sample_num & 0x7fff); // 0.15 fixed point + const int32_t s1 = tmp[whole]; + const int32_t s2 = tmp[whole + 1]; + *output++ = clip(s1 + (((s2 - s1) * (int32_t)frac) >> 15)); + } + + } + + const int samples_consumed = num_blocks * RESAMPLE_16KHZ_SAMPLES_IN; + memmove(input, input + samples_consumed, (*num_samples_in - samples_consumed) * sizeof(*input)); + *num_samples_in -= samples_consumed; + *num_samples_out = RESAMPLE_16KHZ_SAMPLES_OUT * num_blocks; +} + + +AudioHardware::DownSampler::DownSampler(uint32_t outSampleRate, + uint32_t channelCount, + uint32_t frameCount, + AudioHardware::BufferProvider* provider) + : mStatus(NO_INIT), mProvider(provider), mSampleRate(outSampleRate), + mChannelCount(channelCount), mFrameCount(frameCount), + mInLeft(NULL), mInRight(NULL), mTmpLeft(NULL), mTmpRight(NULL), + mTmp2Left(NULL), mTmp2Right(NULL), mOutLeft(NULL), mOutRight(NULL) + +{ + LOGV("AudioHardware::DownSampler() cstor %p SR %d channels %d frames %d", + this, mSampleRate, mChannelCount, mFrameCount); + + if (mSampleRate != 8000 && mSampleRate != 11025 && mSampleRate != 16000 && + mSampleRate != 22050) { + LOGW("AudioHardware::DownSampler cstor: bad sampling rate: %d", mSampleRate); + return; + } + + mInLeft = new int16_t[mFrameCount]; + mInRight = new int16_t[mFrameCount]; + mTmpLeft = new int16_t[mFrameCount]; + mTmpRight = new int16_t[mFrameCount]; + mTmp2Left = new int16_t[mFrameCount]; + mTmp2Right = new int16_t[mFrameCount]; + mOutLeft = new int16_t[mFrameCount]; + mOutRight = new int16_t[mFrameCount]; + + mStatus = NO_ERROR; +} + +AudioHardware::DownSampler::~DownSampler() +{ + if (mInLeft) delete[] mInLeft; + if (mInRight) delete[] mInRight; + if (mTmpLeft) delete[] mTmpLeft; + if (mTmpRight) delete[] mTmpRight; + if (mTmp2Left) delete[] mTmp2Left; + if (mTmp2Right) delete[] mTmp2Right; + if (mOutLeft) delete[] mOutLeft; + if (mOutRight) delete[] mOutRight; +} + +void AudioHardware::DownSampler::reset() +{ + mInInBuf = 0; + mInTmpBuf = 0; + mInTmp2Buf = 0; + mOutBufPos = 0; + mInOutBuf = 0; +} + + +int AudioHardware::DownSampler::resample(int16_t* out, size_t *outFrameCount) +{ + if (mStatus != NO_ERROR) { + return mStatus; + } + + if (out == NULL || outFrameCount == NULL) { + return BAD_VALUE; + } + + int16_t *outLeft = mTmp2Left; + int16_t *outRight = mTmp2Left; + if (mSampleRate == 22050) { + outLeft = mTmpLeft; + outRight = mTmpRight; + } else if (mSampleRate == 8000){ + outLeft = mOutLeft; + outRight = mOutRight; + } + + int outFrames = 0; + int remaingFrames = *outFrameCount; + + if (mInOutBuf) { + int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames; + + for (int i = 0; i < frames; ++i) { + out[i] = outLeft[mOutBufPos + i]; + } + if (mChannelCount == 2) { + for (int i = 0; i < frames; ++i) { + out[i * 2] = outLeft[mOutBufPos + i]; + out[i * 2 + 1] = outRight[mOutBufPos + i]; + } + } + remaingFrames -= frames; + mInOutBuf -= frames; + mOutBufPos += frames; + outFrames += frames; + } + + while (remaingFrames) { + LOGW_IF((mInOutBuf != 0), "mInOutBuf should be 0 here"); + + AudioHardware::BufferProvider::Buffer buf; + buf.frameCount = mFrameCount - mInInBuf; + int ret = mProvider->getNextBuffer(&buf); + if (buf.raw == NULL) { + *outFrameCount = outFrames; + return ret; + } + + for (size_t i = 0; i < buf.frameCount; ++i) { + mInLeft[i + mInInBuf] = buf.i16[i]; + } + if (mChannelCount == 2) { + for (size_t i = 0; i < buf.frameCount; ++i) { + mInLeft[i + mInInBuf] = buf.i16[i * 2]; + mInRight[i + mInInBuf] = buf.i16[i * 2 + 1]; + } + } + mInInBuf += buf.frameCount; + mProvider->releaseBuffer(&buf); + + /* 44010 -> 22050 */ + { + int samples_in_left = mInInBuf; + int samples_out_left; + resample_2_1(mInLeft, mTmpLeft + mInTmpBuf, &samples_in_left, &samples_out_left); + + if (mChannelCount == 2) { + int samples_in_right = mInInBuf; + int samples_out_right; + resample_2_1(mInRight, mTmpRight + mInTmpBuf, &samples_in_right, &samples_out_right); + } + + mInInBuf = samples_in_left; + mInTmpBuf += samples_out_left; + mInOutBuf = samples_out_left; + } + + if (mSampleRate == 11025 || mSampleRate == 8000) { + /* 22050 - > 11025 */ + int samples_in_left = mInTmpBuf; + int samples_out_left; + resample_2_1(mTmpLeft, mTmp2Left + mInTmp2Buf, &samples_in_left, &samples_out_left); + + if (mChannelCount == 2) { + int samples_in_right = mInTmpBuf; + int samples_out_right; + resample_2_1(mTmpRight, mTmp2Right + mInTmp2Buf, &samples_in_right, &samples_out_right); + } + + + mInTmpBuf = samples_in_left; + mInTmp2Buf += samples_out_left; + mInOutBuf = samples_out_left; + + if (mSampleRate == 8000) { + /* 11025 -> 8000*/ + int samples_in_left = mInTmp2Buf; + int samples_out_left; + resample_441_320(mTmp2Left, mOutLeft, &samples_in_left, &samples_out_left); + + if (mChannelCount == 2) { + int samples_in_right = mInTmp2Buf; + int samples_out_right; + resample_441_320(mTmp2Right, mOutRight, &samples_in_right, &samples_out_right); + } + + mInTmp2Buf = samples_in_left; + mInOutBuf = samples_out_left; + } else { + mInTmp2Buf = 0; + } + + } else if (mSampleRate == 16000) { + /* 22050 -> 16000*/ + int samples_in_left = mInTmpBuf; + int samples_out_left; + resample_441_320(mTmpLeft, mTmp2Left, &samples_in_left, &samples_out_left); + + if (mChannelCount == 2) { + int samples_in_right = mInTmpBuf; + int samples_out_right; + resample_441_320(mTmpRight, mTmp2Right, &samples_in_right, &samples_out_right); + } + + mInTmpBuf = samples_in_left; + mInOutBuf = samples_out_left; + } else { + mInTmpBuf = 0; + } + + int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames; + + for (int i = 0; i < frames; ++i) { + out[outFrames + i] = outLeft[i]; + } + if (mChannelCount == 2) { + for (int i = 0; i < frames; ++i) { + out[(outFrames + i) * 2] = outLeft[i]; + out[(outFrames + i) * 2 + 1] = outRight[i]; + } + } + remaingFrames -= frames; + outFrames += frames; + mOutBufPos = frames; + mInOutBuf -= frames; + } + + return 0; +} + + + + + + + +//------------------------------------------------------------------------------ +// Factory +//------------------------------------------------------------------------------ + +extern "C" AudioHardwareInterface* createAudioHardware(void) { + return new AudioHardware(); +} + +}; // namespace android_audio_legacy diff --git a/libaudio/AudioHardware.h b/libaudio/AudioHardware.h new file mode 100644 index 0000000..f77028c --- /dev/null +++ b/libaudio/AudioHardware.h @@ -0,0 +1,357 @@ +/* +** 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_HARDWARE_H +#define ANDROID_AUDIO_HARDWARE_H + +#include +#include + +#include +#include + +#include +#include + +extern "C" { + struct pcm; + struct mixer; + struct mixer_ctl; +}; + +namespace android_audio_legacy { + +using namespace android; + +// TODO: determine actual audio DSP and hardware latency +// Additionnal latency introduced by audio DSP and hardware in ms +#define AUDIO_HW_OUT_LATENCY_MS 0 +// Default audio output sample rate +#define AUDIO_HW_OUT_SAMPLERATE 44100 +// Default audio output channel mask +#define AUDIO_HW_OUT_CHANNELS (AudioSystem::CHANNEL_OUT_STEREO) +// Default audio output sample format +#define AUDIO_HW_OUT_FORMAT (AudioSystem::PCM_16_BIT) +// Kernel pcm out buffer size in frames at 44.1kHz +#define AUDIO_HW_OUT_PERIOD_MULT 8 // (8 * 128 = 1024 frames) +#define AUDIO_HW_OUT_PERIOD_SZ (PCM_PERIOD_SZ_MIN * AUDIO_HW_OUT_PERIOD_MULT) +#define AUDIO_HW_OUT_PERIOD_CNT 4 +// Default audio output buffer size in bytes +#define AUDIO_HW_OUT_PERIOD_BYTES (AUDIO_HW_OUT_PERIOD_SZ * 2 * sizeof(int16_t)) + +// Default audio input sample rate +#define AUDIO_HW_IN_SAMPLERATE 8000 +// Default audio input channel mask +#define AUDIO_HW_IN_CHANNELS (AudioSystem::CHANNEL_IN_MONO) +// Default audio input sample format +#define AUDIO_HW_IN_FORMAT (AudioSystem::PCM_16_BIT) +// Number of buffers in audio driver for input +#define AUDIO_HW_NUM_IN_BUF 2 +// Kernel pcm in buffer size in frames at 44.1kHz (before resampling) +#define AUDIO_HW_IN_PERIOD_MULT 16 // (16 * 128 = 2048 frames) +#define AUDIO_HW_IN_PERIOD_SZ (PCM_PERIOD_SZ_MIN * AUDIO_HW_IN_PERIOD_MULT) +#define AUDIO_HW_IN_PERIOD_CNT 2 +// Default audio input buffer size in bytes (8kHz mono) +#define AUDIO_HW_IN_PERIOD_BYTES ((AUDIO_HW_IN_PERIOD_SZ*sizeof(int16_t))/8) + + +class AudioHardware : public AudioHardwareBase +{ + class AudioStreamOutALSA; + class AudioStreamInALSA; +public: + + // input path names used to translate from input sources to driver paths + static const char *inputPathNameDefault; + static const char *inputPathNameCamcorder; + static const char *inputPathNameVoiceRecognition; + static const char *inputPathNameVoiceCommunication; + + AudioHardware(); + virtual ~AudioHardware(); + virtual status_t initCheck(); + + virtual status_t setVoiceVolume(float volume); + virtual status_t setMasterVolume(float volume); + + virtual status_t setMode(int mode); + + 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 AudioStreamOut* openOutputStream( + uint32_t devices, int *format=0, uint32_t *channels=0, + uint32_t *sampleRate=0, status_t *status=0); + + virtual AudioStreamIn* openInputStream( + uint32_t devices, int *format, uint32_t *channels, + uint32_t *sampleRate, status_t *status, + AudioSystem::audio_in_acoustics acoustics); + + virtual void closeOutputStream(AudioStreamOut* out); + virtual void closeInputStream(AudioStreamIn* in); + + virtual size_t getInputBufferSize( + uint32_t sampleRate, int format, int channelCount); + + int mode() { return mMode; } + const char *getOutputRouteFromDevice(uint32_t device); + const char *getInputRouteFromDevice(uint32_t device); + const char *getVoiceRouteFromDevice(uint32_t device); + + status_t setIncallPath_l(uint32_t device); + + status_t setInputSource_l(audio_source source); + + static uint32_t getInputSampleRate(uint32_t sampleRate); + sp getActiveInput_l(); + + Mutex& lock() { return mLock; } + + struct pcm *openPcmOut_l(); + void closePcmOut_l(); + + struct mixer *openMixer_l(); + void closeMixer_l(); + + sp output() { return mOutput; } + +protected: + virtual status_t dump(int fd, const Vector& args); + +private: + + enum tty_modes { + TTY_MODE_OFF, + TTY_MODE_VCO, + TTY_MODE_HCO, + TTY_MODE_FULL + }; + + bool mInit; + bool mMicMute; + sp mOutput; + SortedVector < sp > mInputs; + Mutex mLock; + struct pcm* mPcm; + struct mixer* mMixer; + uint32_t mPcmOpenCnt; + uint32_t mMixerOpenCnt; + bool mInCallAudioMode; + + audio_source mInputSource; + bool mBluetoothNrec; + int mTTYMode; + + // trace driver operations for dump + int mDriverOp; + + static uint32_t checkInputSampleRate(uint32_t sampleRate); + static const uint32_t inputSamplingRates[]; + + class AudioStreamOutALSA : public AudioStreamOut, public RefBase + { + public: + AudioStreamOutALSA(); + virtual ~AudioStreamOutALSA(); + status_t set(AudioHardware* mHardware, + uint32_t devices, + int *pFormat, + uint32_t *pChannels, + uint32_t *pRate); + virtual uint32_t sampleRate() + const { return mSampleRate; } + virtual size_t bufferSize() + const { return mBufferSize; } + virtual uint32_t channels() + const { return mChannels; } + virtual int format() + const { return AUDIO_HW_OUT_FORMAT; } + virtual uint32_t latency() + const { return (1000 * AUDIO_HW_OUT_PERIOD_CNT * + (bufferSize()/frameSize()))/sampleRate() + + AUDIO_HW_OUT_LATENCY_MS; } + 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(); + bool checkStandby(); + + virtual status_t dump(int fd, const Vector& args); + virtual status_t setParameters(const String8& keyValuePairs); + virtual String8 getParameters(const String8& keys); + uint32_t device() { return mDevices; } + virtual status_t getRenderPosition(uint32_t *dspFrames); + + void doStandby_l(); + void close_l(); + status_t open_l(); + int standbyCnt() { return mStandbyCnt; } + + int prepareLock(); + void lock(); + void unlock(); + + private: + + Mutex mLock; + AudioHardware* mHardware; + struct pcm *mPcm; + struct mixer *mMixer; + struct mixer_ctl *mRouteCtl; + const char *next_route; + bool mStandby; + uint32_t mDevices; + uint32_t mChannels; + uint32_t mSampleRate; + size_t mBufferSize; + // trace driver operations for dump + int mDriverOp; + int mStandbyCnt; + bool mSleepReq; + }; + + class DownSampler; + + class BufferProvider + { + public: + + struct Buffer { + union { + void* raw; + short* i16; + int8_t* i8; + }; + size_t frameCount; + }; + + virtual ~BufferProvider() {} + + virtual status_t getNextBuffer(Buffer* buffer) = 0; + virtual void releaseBuffer(Buffer* buffer) = 0; + }; + + class DownSampler { + public: + DownSampler(uint32_t outSampleRate, + uint32_t channelCount, + uint32_t frameCount, + BufferProvider* provider); + + virtual ~DownSampler(); + + void reset(); + status_t initCheck() { return mStatus; } + int resample(int16_t* out, size_t *outFrameCount); + + private: + status_t mStatus; + BufferProvider* mProvider; + uint32_t mSampleRate; + uint32_t mChannelCount; + uint32_t mFrameCount; + int16_t *mInLeft; + int16_t *mInRight; + int16_t *mTmpLeft; + int16_t *mTmpRight; + int16_t *mTmp2Left; + int16_t *mTmp2Right; + int16_t *mOutLeft; + int16_t *mOutRight; + int mInInBuf; + int mInTmpBuf; + int mInTmp2Buf; + int mOutBufPos; + int mInOutBuf; + }; + + + class AudioStreamInALSA : public AudioStreamIn, public BufferProvider, public RefBase + { + + public: + AudioStreamInALSA(); + virtual ~AudioStreamInALSA(); + status_t set(AudioHardware* hw, + uint32_t devices, + int *pFormat, + uint32_t *pChannels, + uint32_t *pRate, + AudioSystem::audio_in_acoustics acoustics); + virtual size_t bufferSize() const { return mBufferSize; } + virtual uint32_t channels() const { return mChannels; } + virtual int format() const { return AUDIO_HW_IN_FORMAT; } + virtual uint32_t sampleRate() const { return mSampleRate; } + 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(); + bool checkStandby(); + virtual status_t setParameters(const String8& keyValuePairs); + virtual String8 getParameters(const String8& keys); + virtual unsigned int getInputFramesLost() const { return 0; } + uint32_t device() { return mDevices; } + void doStandby_l(); + void close_l(); + status_t open_l(); + int standbyCnt() { return mStandbyCnt; } + + static size_t getBufferSize(uint32_t sampleRate, int channelCount); + + // BufferProvider + virtual status_t getNextBuffer(BufferProvider::Buffer* buffer); + virtual void releaseBuffer(BufferProvider::Buffer* buffer); + + // Stubs (ICS) + virtual status_t addAudioEffect(effect_handle_t effect) { return INVALID_OPERATION; } + virtual status_t removeAudioEffect(effect_handle_t effect) { return INVALID_OPERATION; } + + int prepareLock(); + void lock(); + void unlock(); + + private: + Mutex mLock; + AudioHardware* mHardware; + struct pcm *mPcm; + struct mixer *mMixer; + struct mixer_ctl *mRouteCtl; + const char *next_route; + bool mStandby; + uint32_t mDevices; + uint32_t mChannels; + uint32_t mChannelCount; + uint32_t mSampleRate; + size_t mBufferSize; + DownSampler *mDownSampler; + status_t mReadStatus; + size_t mInPcmInBuf; + int16_t *mPcmIn; + // trace driver operations for dump + int mDriverOp; + int mStandbyCnt; + bool mSleepReq; + }; + +}; + +}; // namespace android_audio_legacy + +#endif diff --git a/libaudio/AudioPolicyManager.cpp b/libaudio/AudioPolicyManager.cpp new file mode 100644 index 0000000..7557400 --- /dev/null +++ b/libaudio/AudioPolicyManager.cpp @@ -0,0 +1,46 @@ +/* + * 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 "AudioPolicyManager" +#define LOG_NDEBUG 0 +#include +#include "AudioPolicyManager.h" +#include + +namespace android_audio_legacy { + + + +// ---------------------------------------------------------------------------- +// AudioPolicyManager for crespo platform +// Common audio policy manager code is implemented in AudioPolicyManagerBase class +// ---------------------------------------------------------------------------- + +// --- class factory + + +extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) +{ + return new AudioPolicyManager(clientInterface); +} + +extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface) +{ + delete interface; +} + + +}; // namespace android_audio_legacy diff --git a/libaudio/AudioPolicyManager.h b/libaudio/AudioPolicyManager.h new file mode 100644 index 0000000..d660e78 --- /dev/null +++ b/libaudio/AudioPolicyManager.h @@ -0,0 +1,46 @@ +/* + * 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 + + +namespace android_audio_legacy { + +class AudioPolicyManager: public AudioPolicyManagerBase +{ + +public: + AudioPolicyManager(AudioPolicyClientInterface *clientInterface) + : AudioPolicyManagerBase(clientInterface) {} + + virtual ~AudioPolicyManager() {} + +protected: + // true is current platform implements a back microphone + virtual bool hasBackMicrophone() const { return false; } +#ifdef WITH_A2DP + // true is current platform supports duplication of notifications and ringtones over A2DP output + virtual bool a2dpUsedForSonification() const { return true; } +#endif + +}; +}; diff --git a/libaudio/alsa_audio.h b/libaudio/alsa_audio.h new file mode 100644 index 0000000..3cb86d9 --- /dev/null +++ b/libaudio/alsa_audio.h @@ -0,0 +1,77 @@ +/* +** Copyright 2010, 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 _AUDIO_H_ +#define _AUDIO_H_ + +struct pcm; + +#define PCM_OUT 0x00000000 +#define PCM_IN 0x10000000 + +#define PCM_STEREO 0x00000000 +#define PCM_MONO 0x01000000 + +#define PCM_44100HZ 0x00000000 +#define PCM_48000HZ 0x00100000 +#define PCM_8000HZ 0x00200000 +#define PCM_RATE_MASK 0x00F00000 + +#define PCM_PERIOD_CNT_MIN 2 +#define PCM_PERIOD_CNT_SHIFT 16 +#define PCM_PERIOD_CNT_MASK (0xF << PCM_PERIOD_CNT_SHIFT) +#define PCM_PERIOD_SZ_MIN 128 +#define PCM_PERIOD_SZ_SHIFT 12 +#define PCM_PERIOD_SZ_MASK (0xF << PCM_PERIOD_SZ_SHIFT) + +/* Acquire/release a pcm channel. + * Returns non-zero on error + */ +struct pcm *pcm_open(unsigned flags); +int pcm_close(struct pcm *pcm); +int pcm_ready(struct pcm *pcm); + +/* Returns a human readable reason for the last error. */ +const char *pcm_error(struct pcm *pcm); + +/* Returns the buffer size (int bytes) that should be used for pcm_write. + * This will be 1/2 of the actual fifo size. + */ +unsigned pcm_buffer_size(struct pcm *pcm); + +/* Write data to the fifo. + * Will start playback on the first write or on a write that + * occurs after a fifo underrun. + */ +int pcm_write(struct pcm *pcm, void *data, unsigned count); +int pcm_read(struct pcm *pcm, void *data, unsigned count); + +struct mixer; +struct mixer_ctl; + +struct mixer *mixer_open(void); +void mixer_close(struct mixer *mixer); +void mixer_dump(struct mixer *mixer); + +struct mixer_ctl *mixer_get_control(struct mixer *mixer, + const char *name, unsigned index); +struct mixer_ctl *mixer_get_nth_control(struct mixer *mixer, unsigned n); + +int mixer_ctl_set(struct mixer_ctl *ctl, unsigned percent); +int mixer_ctl_select(struct mixer_ctl *ctl, const char *value); +void mixer_ctl_print(struct mixer_ctl *ctl); + +#endif diff --git a/libaudio/alsa_mixer.c b/libaudio/alsa_mixer.c new file mode 100644 index 0000000..3036ef8 --- /dev/null +++ b/libaudio/alsa_mixer.c @@ -0,0 +1,371 @@ +/* +** Copyright 2010, 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 __force +#define __bitwise +#define __user +#include "asound.h" + +#include "alsa_audio.h" + +static const char *elem_iface_name(snd_ctl_elem_iface_t n) +{ + switch (n) { + case SNDRV_CTL_ELEM_IFACE_CARD: return "CARD"; + case SNDRV_CTL_ELEM_IFACE_HWDEP: return "HWDEP"; + case SNDRV_CTL_ELEM_IFACE_MIXER: return "MIXER"; + case SNDRV_CTL_ELEM_IFACE_PCM: return "PCM"; + case SNDRV_CTL_ELEM_IFACE_RAWMIDI: return "MIDI"; + case SNDRV_CTL_ELEM_IFACE_TIMER: return "TIMER"; + case SNDRV_CTL_ELEM_IFACE_SEQUENCER: return "SEQ"; + default: return "???"; + } +} + +static const char *elem_type_name(snd_ctl_elem_type_t n) +{ + switch (n) { + case SNDRV_CTL_ELEM_TYPE_NONE: return "NONE"; + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL"; + case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT32"; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM"; + case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTES"; + case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958"; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64"; + default: return "???"; + } +} + + +struct mixer_ctl { + struct mixer *mixer; + struct snd_ctl_elem_info *info; + char **ename; +}; + +struct mixer { + int fd; + struct snd_ctl_elem_info *info; + struct mixer_ctl *ctl; + unsigned count; +}; + +void mixer_close(struct mixer *mixer) +{ + unsigned n,m; + + if (mixer->fd >= 0) + close(mixer->fd); + + if (mixer->ctl) { + for (n = 0; n < mixer->count; n++) { + if (mixer->ctl[n].ename) { + unsigned max = mixer->ctl[n].info->value.enumerated.items; + for (m = 0; m < max; m++) + free(mixer->ctl[n].ename[m]); + free(mixer->ctl[n].ename); + } + } + free(mixer->ctl); + } + + if (mixer->info) + free(mixer->info); + + free(mixer); +} + +struct mixer *mixer_open(void) +{ + struct snd_ctl_elem_list elist; + struct snd_ctl_elem_info tmp; + struct snd_ctl_elem_id *eid = NULL; + struct mixer *mixer = NULL; + unsigned n, m; + int fd; + + fd = open("/dev/snd/controlC0", O_RDWR); + if (fd < 0) + return 0; + + memset(&elist, 0, sizeof(elist)); + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) + goto fail; + + mixer = calloc(1, sizeof(*mixer)); + if (!mixer) + goto fail; + + mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl)); + mixer->info = calloc(elist.count, sizeof(struct snd_ctl_elem_info)); + if (!mixer->ctl || !mixer->info) + goto fail; + + eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id)); + if (!eid) + goto fail; + + mixer->count = elist.count; + mixer->fd = fd; + elist.space = mixer->count; + elist.pids = eid; + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) + goto fail; + + for (n = 0; n < mixer->count; n++) { + struct snd_ctl_elem_info *ei = mixer->info + n; + ei->id.numid = eid[n].numid; + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0) + goto fail; + mixer->ctl[n].info = ei; + mixer->ctl[n].mixer = mixer; + if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { + char **enames = calloc(ei->value.enumerated.items, sizeof(char*)); + if (!enames) + goto fail; + mixer->ctl[n].ename = enames; + for (m = 0; m < ei->value.enumerated.items; m++) { + memset(&tmp, 0, sizeof(tmp)); + tmp.id.numid = ei->id.numid; + tmp.value.enumerated.item = m; + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0) + goto fail; + enames[m] = strdup(tmp.value.enumerated.name); + if (!enames[m]) + goto fail; + } + } + } + + free(eid); + return mixer; + +fail: + if (eid) + free(eid); + if (mixer) + mixer_close(mixer); + else if (fd >= 0) + close(fd); + return 0; +} + +void mixer_dump(struct mixer *mixer) +{ + unsigned n, m; + + printf(" id iface dev sub idx num perms type name\n"); + for (n = 0; n < mixer->count; n++) { + struct snd_ctl_elem_info *ei = mixer->info + n; + + printf("%4d %5s %3d %3d %3d %3d %c%c%c%c%c%c%c%c%c %-6s %s", + ei->id.numid, elem_iface_name(ei->id.iface), + ei->id.device, ei->id.subdevice, ei->id.index, + ei->count, + (ei->access & SNDRV_CTL_ELEM_ACCESS_READ) ? 'r' : ' ', + (ei->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ? 'w' : ' ', + (ei->access & SNDRV_CTL_ELEM_ACCESS_VOLATILE) ? 'V' : ' ', + (ei->access & SNDRV_CTL_ELEM_ACCESS_TIMESTAMP) ? 'T' : ' ', + (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) ? 'R' : ' ', + (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) ? 'W' : ' ', + (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) ? 'C' : ' ', + (ei->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) ? 'I' : ' ', + (ei->access & SNDRV_CTL_ELEM_ACCESS_LOCK) ? 'L' : ' ', + elem_type_name(ei->type), + ei->id.name); + switch (ei->type) { + case SNDRV_CTL_ELEM_TYPE_INTEGER: + printf(ei->value.integer.step ? + " { %ld-%ld, %ld }\n" : " { %ld-%ld }", + ei->value.integer.min, + ei->value.integer.max, + ei->value.integer.step); + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + printf(ei->value.integer64.step ? + " { %lld-%lld, %lld }\n" : " { %lld-%lld }", + ei->value.integer64.min, + ei->value.integer64.max, + ei->value.integer64.step); + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: { + unsigned m; + printf(" { %s=0", mixer->ctl[n].ename[0]); + for (m = 1; m < ei->value.enumerated.items; m++) + printf(", %s=%d", mixer->ctl[n].ename[m],m); + printf(" }"); + break; + } + } + printf("\n"); + } +} + +struct mixer_ctl *mixer_get_control(struct mixer *mixer, + const char *name, unsigned index) +{ + unsigned n; + for (n = 0; n < mixer->count; n++) { + if (mixer->info[n].id.index == index) { + if (!strcmp(name, (char*) mixer->info[n].id.name)) { + return mixer->ctl + n; + } + } + } + return 0; +} + +struct mixer_ctl *mixer_get_nth_control(struct mixer *mixer, unsigned n) +{ + if (n < mixer->count) + return mixer->ctl + n; + return 0; +} + +void mixer_ctl_print(struct mixer_ctl *ctl) +{ + struct snd_ctl_elem_value ev; + unsigned n; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev)) + return; + printf("%s:", ctl->info->id.name); + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + for (n = 0; n < ctl->info->count; n++) + printf(" %s", ev.value.integer.value[n] ? "ON" : "OFF"); + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER: { + for (n = 0; n < ctl->info->count; n++) + printf(" %ld", ev.value.integer.value[n]); + break; + } + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + for (n = 0; n < ctl->info->count; n++) + printf(" %lld", ev.value.integer64.value[n]); + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + for (n = 0; n < ctl->info->count; n++) { + unsigned v = ev.value.enumerated.item[n]; + printf(" %d (%s)", v, + (v < ctl->info->value.enumerated.items) ? ctl->ename[v] : "???"); + } + break; + default: + printf(" ???"); + } + printf("\n"); +} + +static long scale_int(struct snd_ctl_elem_info *ei, unsigned _percent) +{ + long percent; + long range; + + if (_percent > 100) + percent = 100; + else + percent = (long) _percent; + + range = (ei->value.integer.max - ei->value.integer.min); + + return ei->value.integer.min + (range * percent) / 100LL; +} + +static long long scale_int64(struct snd_ctl_elem_info *ei, unsigned _percent) +{ + long long percent; + long long range; + + if (_percent > 100) + percent = 100; + else + percent = (long) _percent; + + range = (ei->value.integer.max - ei->value.integer.min) * 100LL; + + return ei->value.integer.min + (range / percent); +} + +int mixer_ctl_set(struct mixer_ctl *ctl, unsigned percent) +{ + struct snd_ctl_elem_value ev; + unsigned n; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + for (n = 0; n < ctl->info->count; n++) + ev.value.integer.value[n] = !!percent; + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER: { + long value = scale_int(ctl->info, percent); + for (n = 0; n < ctl->info->count; n++) + ev.value.integer.value[n] = value; + break; + } + case SNDRV_CTL_ELEM_TYPE_INTEGER64: { + long long value = scale_int64(ctl->info, percent); + for (n = 0; n < ctl->info->count; n++) + ev.value.integer64.value[n] = value; + break; + } + default: + errno = EINVAL; + return -1; + } + + return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); +} + +int mixer_ctl_select(struct mixer_ctl *ctl, const char *value) +{ + unsigned n, max; + struct snd_ctl_elem_value ev; + + if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) { + errno = EINVAL; + return -1; + } + + max = ctl->info->value.enumerated.items; + for (n = 0; n < max; n++) { + if (!strcmp(value, ctl->ename[n])) { + memset(&ev, 0, sizeof(ev)); + ev.value.enumerated.item[0] = n; + ev.id.numid = ctl->info->id.numid; + if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev) < 0) + return -1; + return 0; + } + } + + errno = EINVAL; + return -1; +} diff --git a/libaudio/alsa_pcm.c b/libaudio/alsa_pcm.c new file mode 100644 index 0000000..7f9cdc0 --- /dev/null +++ b/libaudio/alsa_pcm.c @@ -0,0 +1,405 @@ +/* +** Copyright 2010, 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 "alsa_pcm" +#define LOG_NDEBUG 0 +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "alsa_audio.h" + +#define __force +#define __bitwise +#define __user +#include "asound.h" + +#define DEBUG 0 + +/* alsa parameter manipulation cruft */ + +#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL + +static inline int param_is_mask(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && + (p <= SNDRV_PCM_HW_PARAM_LAST_MASK); +} + +static inline int param_is_interval(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) && + (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL); +} + +static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n) +{ + return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]); +} + +static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n) +{ + return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]); +} + +static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit) +{ + if (bit >= SNDRV_MASK_MAX) + return; + if (param_is_mask(n)) { + struct snd_mask *m = param_to_mask(p, n); + m->bits[0] = 0; + m->bits[1] = 0; + m->bits[bit >> 5] |= (1 << (bit & 31)); + } +} + +static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned val) +{ + if (param_is_interval(n)) { + struct snd_interval *i = param_to_interval(p, n); + i->min = val; + } +} + +static void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned val) +{ + if (param_is_interval(n)) { + struct snd_interval *i = param_to_interval(p, n); + i->max = val; + } +} + +static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned val) +{ + if (param_is_interval(n)) { + struct snd_interval *i = param_to_interval(p, n); + i->min = val; + i->max = val; + i->integer = 1; + } +} + +static void param_init(struct snd_pcm_hw_params *p) +{ + int n; + memset(p, 0, sizeof(*p)); + for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK; + n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) { + struct snd_mask *m = param_to_mask(p, n); + m->bits[0] = ~0; + m->bits[1] = ~0; + } + for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; + n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) { + struct snd_interval *i = param_to_interval(p, n); + i->min = 0; + i->max = ~0; + } +} + +/* debugging gunk */ + +#if DEBUG +static const char *param_name[PARAM_MAX+1] = { + [SNDRV_PCM_HW_PARAM_ACCESS] = "access", + [SNDRV_PCM_HW_PARAM_FORMAT] = "format", + [SNDRV_PCM_HW_PARAM_SUBFORMAT] = "subformat", + + [SNDRV_PCM_HW_PARAM_SAMPLE_BITS] = "sample_bits", + [SNDRV_PCM_HW_PARAM_FRAME_BITS] = "frame_bits", + [SNDRV_PCM_HW_PARAM_CHANNELS] = "channels", + [SNDRV_PCM_HW_PARAM_RATE] = "rate", + [SNDRV_PCM_HW_PARAM_PERIOD_TIME] = "period_time", + [SNDRV_PCM_HW_PARAM_PERIOD_SIZE] = "period_size", + [SNDRV_PCM_HW_PARAM_PERIOD_BYTES] = "period_bytes", + [SNDRV_PCM_HW_PARAM_PERIODS] = "periods", + [SNDRV_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time", + [SNDRV_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size", + [SNDRV_PCM_HW_PARAM_BUFFER_BYTES] = "buffer_bytes", + [SNDRV_PCM_HW_PARAM_TICK_TIME] = "tick_time", +}; + +static void param_dump(struct snd_pcm_hw_params *p) +{ + int n; + + for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK; + n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) { + struct snd_mask *m = param_to_mask(p, n); + LOGV("%s = %08x%08x\n", param_name[n], + m->bits[1], m->bits[0]); + } + for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; + n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) { + struct snd_interval *i = param_to_interval(p, n); + LOGV("%s = (%d,%d) omin=%d omax=%d int=%d empty=%d\n", + param_name[n], i->min, i->max, i->openmin, + i->openmax, i->integer, i->empty); + } + LOGV("info = %08x\n", p->info); + LOGV("msbits = %d\n", p->msbits); + LOGV("rate = %d/%d\n", p->rate_num, p->rate_den); + LOGV("fifo = %d\n", (int) p->fifo_size); +} + +static void info_dump(struct snd_pcm_info *info) +{ + LOGV("device = %d\n", info->device); + LOGV("subdevice = %d\n", info->subdevice); + LOGV("stream = %d\n", info->stream); + LOGV("card = %d\n", info->card); + LOGV("id = '%s'\n", info->id); + LOGV("name = '%s'\n", info->name); + LOGV("subname = '%s'\n", info->subname); + LOGV("dev_class = %d\n", info->dev_class); + LOGV("dev_subclass = %d\n", info->dev_subclass); + LOGV("subdevices_count = %d\n", info->subdevices_count); + LOGV("subdevices_avail = %d\n", info->subdevices_avail); +} +#else +static void param_dump(struct snd_pcm_hw_params *p) {} +static void info_dump(struct snd_pcm_info *info) {} +#endif + +#define PCM_ERROR_MAX 128 + +struct pcm { + int fd; + unsigned flags; + int running:1; + int underruns; + unsigned buffer_size; + char error[PCM_ERROR_MAX]; +}; + +unsigned pcm_buffer_size(struct pcm *pcm) +{ + return pcm->buffer_size; +} + +const char* pcm_error(struct pcm *pcm) +{ + return pcm->error; +} + +static int oops(struct pcm *pcm, int e, const char *fmt, ...) +{ + va_list ap; + int sz; + + va_start(ap, fmt); + vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap); + va_end(ap); + sz = strlen(pcm->error); + + if (errno) + snprintf(pcm->error + sz, PCM_ERROR_MAX - sz, + ": %s", strerror(e)); + return -1; +} + +int pcm_write(struct pcm *pcm, void *data, unsigned count) +{ + struct snd_xferi x; + + if (pcm->flags & PCM_IN) + return -EINVAL; + + x.buf = data; + x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4); + + for (;;) { + if (!pcm->running) { + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) + return oops(pcm, errno, "cannot prepare channel"); + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) + return oops(pcm, errno, "cannot write initial data"); + pcm->running = 1; + return 0; + } + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { + pcm->running = 0; + if (errno == EPIPE) { + /* we failed to make our window -- try to restart */ + pcm->underruns++; + continue; + } + return oops(pcm, errno, "cannot write stream data"); + } + return 0; + } +} + +int pcm_read(struct pcm *pcm, void *data, unsigned count) +{ + struct snd_xferi x; + + if (!(pcm->flags & PCM_IN)) + return -EINVAL; + + x.buf = data; + x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4); + +// LOGV("read() %d frames", x.frames); + for (;;) { + if (!pcm->running) { + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) + return oops(pcm, errno, "cannot prepare channel"); + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) + return oops(pcm, errno, "cannot start channel"); + pcm->running = 1; + } + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { + pcm->running = 0; + if (errno == EPIPE) { + /* we failed to make our window -- try to restart */ + pcm->underruns++; + continue; + } + return oops(pcm, errno, "cannot read stream data"); + } +// LOGV("read() got %d frames", x.frames); + return 0; + } +} + +static struct pcm bad_pcm = { + .fd = -1, +}; + +int pcm_close(struct pcm *pcm) +{ + if (pcm == &bad_pcm) + return 0; + + if (pcm->fd >= 0) + close(pcm->fd); + pcm->running = 0; + pcm->buffer_size = 0; + pcm->fd = -1; + return 0; +} + +struct pcm *pcm_open(unsigned flags) +{ + const char *dname; + struct pcm *pcm; + struct snd_pcm_info info; + struct snd_pcm_hw_params params; + struct snd_pcm_sw_params sparams; + unsigned period_sz; + unsigned period_cnt; + + LOGV("pcm_open(0x%08x)",flags); + + pcm = calloc(1, sizeof(struct pcm)); + if (!pcm) + return &bad_pcm; + + if (flags & PCM_IN) { + dname = "/dev/snd/pcmC0D0c"; + } else { + dname = "/dev/snd/pcmC0D0p"; + } + + LOGV("pcm_open() period sz multiplier %d", + ((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1); + period_sz = 128 * (((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1); + LOGV("pcm_open() period cnt %d", + ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN); + period_cnt = ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN; + + pcm->flags = flags; + pcm->fd = open(dname, O_RDWR); + if (pcm->fd < 0) { + oops(pcm, errno, "cannot open device '%s'"); + return pcm; + } + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { + oops(pcm, errno, "cannot get info - %s"); + goto fail; + } + info_dump(&info); + + LOGV("pcm_open() period_cnt %d period_sz %d channels %d", + period_cnt, period_sz, (flags & PCM_MONO) ? 1 : 2); + + param_init(¶ms); + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_ACCESS_RW_INTERLEAVED); + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_FORMAT_S16_LE); + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT, + SNDRV_PCM_SUBFORMAT_STD); + param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, period_sz); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS, + (flags & PCM_MONO) ? 16 : 32); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS, + (flags & PCM_MONO) ? 1 : 2); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, period_cnt); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, 44100); + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { + oops(pcm, errno, "cannot set hw params"); + goto fail; + } + param_dump(¶ms); + + memset(&sparams, 0, sizeof(sparams)); + sparams.tstamp_mode = SNDRV_PCM_TSTAMP_NONE; + sparams.period_step = 1; + sparams.avail_min = 1; + sparams.start_threshold = period_cnt * period_sz; + sparams.stop_threshold = period_cnt * period_sz; + sparams.xfer_align = period_sz / 2; /* needed for old kernels */ + sparams.silence_size = 0; + sparams.silence_threshold = 0; + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { + oops(pcm, errno, "cannot set sw params"); + goto fail; + } + + pcm->buffer_size = period_cnt * period_sz; + pcm->underruns = 0; + return pcm; + +fail: + close(pcm->fd); + pcm->fd = -1; + return pcm; +} + +int pcm_ready(struct pcm *pcm) +{ + return pcm->fd >= 0; +} diff --git a/libaudio/amix.c b/libaudio/amix.c new file mode 100644 index 0000000..d978caa --- /dev/null +++ b/libaudio/amix.c @@ -0,0 +1,78 @@ +/* +** Copyright 2010, 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 "alsa_audio.h" + + +struct mixer_ctl *get_ctl(struct mixer *mixer, char *name) +{ + char *p; + unsigned idx = 0; + + if (isdigit(name[0])) + return mixer_get_nth_control(mixer, atoi(name) - 1); + + p = strrchr(name, '#'); + if (p) { + *p++ = 0; + idx = atoi(p); + } + + return mixer_get_control(mixer, name, idx); +} + +int main(int argc, char **argv) +{ + struct mixer *mixer; + struct mixer_ctl *ctl; + int r; + + mixer = mixer_open(); + if (!mixer) + return -1; + + if (argc == 1) { + mixer_dump(mixer); + return 0; + } + + ctl = get_ctl(mixer, argv[1]); + argc -= 2; + argv += 2; + + if (!ctl) { + fprintf(stderr,"can't find control\n"); + return -1; + } + + if (argc) { + if (isdigit(argv[0][0])) + r = mixer_ctl_set(ctl, atoi(argv[0])); + else + r = mixer_ctl_select(ctl, argv[0]); + if (r) + fprintf(stderr,"oops: %s\n", strerror(errno)); + } else { + mixer_ctl_print(ctl); + } + return 0; +} diff --git a/libaudio/aplay.c b/libaudio/aplay.c new file mode 100644 index 0000000..0ac0ac0 --- /dev/null +++ b/libaudio/aplay.c @@ -0,0 +1,140 @@ +/* +** Copyright 2010, 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 "alsa_audio.h" + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; + +int play_file(unsigned rate, unsigned channels, int fd, unsigned count) +{ + struct pcm *pcm; + struct mixer *mixer; + struct pcm_ctl *ctl = NULL; + unsigned bufsize; + char *data; + unsigned flags = PCM_OUT; + + if (channels == 1) + flags |= PCM_MONO; + else + flags |= PCM_STEREO; + + pcm = pcm_open(flags); + if (!pcm_ready(pcm)) { + pcm_close(pcm); + return -1; + } + + mixer = mixer_open(); + if (mixer) + ctl = mixer_get_control(mixer,"Playback Path", 0); + + bufsize = pcm_buffer_size(pcm); + data = malloc(bufsize); + if (!data) { + fprintf(stderr,"could not allocate %d bytes\n", count); + return -1; + } + + while (read(fd, data, bufsize) == bufsize) { + if (pcm_write(pcm, data, bufsize)) + break; + + /* HACK: remove */ + if (ctl) { + //mixer_ctl_select(ctl, "SPK"); + ctl = 0; + } + } + pcm_close(pcm); + return 0; +} + +int play_wav(const char *fn) +{ + struct wav_header hdr; + unsigned rate, channels; + int fd; + fd = open(fn, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "aplay: cannot open '%s'\n", fn); + return -1; + } + if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + fprintf(stderr, "aplay: cannot read header\n"); + return -1; + } + fprintf(stderr,"aplay: %d ch, %d hz, %d bit, %s\n", + hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample, + hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown"); + + if ((hdr.riff_id != ID_RIFF) || + (hdr.riff_fmt != ID_WAVE) || + (hdr.fmt_id != ID_FMT)) { + fprintf(stderr, "aplay: '%s' is not a riff/wave file\n", fn); + return -1; + } + if ((hdr.audio_format != FORMAT_PCM) || + (hdr.fmt_sz != 16)) { + fprintf(stderr, "aplay: '%s' is not pcm format\n", fn); + return -1; + } + if (hdr.bits_per_sample != 16) { + fprintf(stderr, "aplay: '%s' is not 16bit per sample\n", fn); + return -1; + } + + return play_file(hdr.sample_rate, hdr.num_channels, fd, hdr.data_sz); +} + +int main(int argc, char **argv) +{ + if (argc != 2) { + fprintf(stderr,"usage: aplay \n"); + return -1; + } + + return play_wav(argv[1]); +} + diff --git a/libaudio/arec.c b/libaudio/arec.c new file mode 100644 index 0000000..b1e9eda --- /dev/null +++ b/libaudio/arec.c @@ -0,0 +1,128 @@ +/* +** Copyright 2010, 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 "alsa_audio.h" + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; + +int record_file(unsigned rate, unsigned channels, int fd, unsigned count) +{ + struct pcm *pcm; + unsigned avail, xfer, bufsize; + char *data, *next; + int r; + + pcm = pcm_open(PCM_IN|PCM_MONO); + if (!pcm_ready(pcm)) { + pcm_close(pcm); + goto fail; + } + + bufsize = pcm_buffer_size(pcm); + + data = malloc(bufsize); + if (!data) { + fprintf(stderr,"could not allocate %d bytes\n", count); + return -1; + } + + while (!pcm_read(pcm, data, bufsize)) { + if (write(fd, data, bufsize) != bufsize) { + fprintf(stderr,"could not write %d bytes\n", bufsize); + return -1; + } + } + + close(fd); + pcm_close(pcm); + return 0; + +fail: + fprintf(stderr,"pcm error: %s\n", pcm_error(pcm)); + return -1; +} + +int rec_wav(const char *fn) +{ + struct wav_header hdr; + unsigned rate, channels; + int fd; + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); + if (fd < 0) { + fprintf(stderr, "arec: cannot open '%s'\n", fn); + return -1; + } + + hdr.riff_id = ID_RIFF; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.audio_format = FORMAT_PCM; + hdr.fmt_sz = 16; + hdr.bits_per_sample = 16; + hdr.num_channels = 1; + hdr.data_sz = 0; + hdr.sample_rate = 44100; + + if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + fprintf(stderr, "arec: cannot write header\n"); + return -1; + } + fprintf(stderr,"arec: %d ch, %d hz, %d bit, %s\n", + hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample, + hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown"); + + + return record_file(hdr.sample_rate, hdr.num_channels, fd, hdr.data_sz); +} + +int main(int argc, char **argv) +{ + if (argc != 2) { + fprintf(stderr,"usage: arec \n"); + return -1; + } + + return rec_wav(argv[1]); +} + diff --git a/libaudio/asound.h b/libaudio/asound.h new file mode 100644 index 0000000..6a17f29 --- /dev/null +++ b/libaudio/asound.h @@ -0,0 +1,814 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef __SOUND_ASOUND_H +#define __SOUND_ASOUND_H + +#include + +#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor)) +#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff) +#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff) +#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff) +#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion))) + +struct snd_aes_iec958 { + unsigned char status[24]; + unsigned char subcode[147]; + unsigned char pad; + unsigned char dig_subframe[4]; +}; + +#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1) + +enum { + SNDRV_HWDEP_IFACE_OPL2 = 0, + SNDRV_HWDEP_IFACE_OPL3, + SNDRV_HWDEP_IFACE_OPL4, + SNDRV_HWDEP_IFACE_SB16CSP, + SNDRV_HWDEP_IFACE_EMU10K1, + SNDRV_HWDEP_IFACE_YSS225, + SNDRV_HWDEP_IFACE_ICS2115, + SNDRV_HWDEP_IFACE_SSCAPE, + SNDRV_HWDEP_IFACE_VX, + SNDRV_HWDEP_IFACE_MIXART, + SNDRV_HWDEP_IFACE_USX2Y, + SNDRV_HWDEP_IFACE_EMUX_WAVETABLE, + SNDRV_HWDEP_IFACE_BLUETOOTH, + SNDRV_HWDEP_IFACE_USX2Y_PCM, + SNDRV_HWDEP_IFACE_PCXHR, + SNDRV_HWDEP_IFACE_SB_RC, + SNDRV_HWDEP_IFACE_HDA, + SNDRV_HWDEP_IFACE_USB_STREAM, + + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM +}; + +struct snd_hwdep_info { + unsigned int device; + int card; + unsigned char id[64]; + unsigned char name[80]; + int iface; + unsigned char reserved[64]; +}; + +struct snd_hwdep_dsp_status { + unsigned int version; + unsigned char id[32]; + unsigned int num_dsps; + unsigned int dsp_loaded; + unsigned int chip_ready; + unsigned char reserved[16]; +}; + +struct snd_hwdep_dsp_image { + unsigned int index; + unsigned char name[64]; + unsigned char __user *image; + size_t length; + unsigned long driver_data; +}; + +#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int) +#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info) +#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status) +#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image) + +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10) + +typedef unsigned long snd_pcm_uframes_t; +typedef signed long snd_pcm_sframes_t; + +enum { + SNDRV_PCM_CLASS_GENERIC = 0, + SNDRV_PCM_CLASS_MULTI, + SNDRV_PCM_CLASS_MODEM, + SNDRV_PCM_CLASS_DIGITIZER, + + SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER, +}; + +enum { + SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0, + SNDRV_PCM_SUBCLASS_MULTI_MIX, + + SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX, +}; + +enum { + SNDRV_PCM_STREAM_PLAYBACK = 0, + SNDRV_PCM_STREAM_CAPTURE, + SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE, +}; + +typedef int __bitwise snd_pcm_access_t; +#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0) +#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1) +#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2) +#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3) +#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4) +#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED + +typedef int __bitwise snd_pcm_format_t; +#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0) +#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1) +#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2) +#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3) +#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4) +#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5) +#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6) +#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) +#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) +#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) +#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10) +#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11) +#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12) +#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13) +#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14) +#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15) +#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16) +#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17) +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18) +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19) +#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20) +#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21) +#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22) +#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23) +#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24) +#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31) +#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) +#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) +#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34) +#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35) +#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36) +#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37) +#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38) +#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39) +#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40) +#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) +#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) +#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) +#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_U18_3BE + +#ifdef SNDRV_LITTLE_ENDIAN +#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE +#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE +#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE +#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE +#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE +#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE +#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE +#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE +#endif +#ifdef SNDRV_BIG_ENDIAN +#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE +#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE +#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE +#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE +#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE +#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE +#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE +#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE +#endif + +typedef int __bitwise snd_pcm_subformat_t; +#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0) +#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD + +#define SNDRV_PCM_INFO_MMAP 0x00000001 +#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 +#define SNDRV_PCM_INFO_DOUBLE 0x00000004 +#define SNDRV_PCM_INFO_BATCH 0x00000010 +#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 +#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 +#define SNDRV_PCM_INFO_COMPLEX 0x00000400 +#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000 +#define SNDRV_PCM_INFO_OVERRANGE 0x00020000 +#define SNDRV_PCM_INFO_RESUME 0x00040000 +#define SNDRV_PCM_INFO_PAUSE 0x00080000 +#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 +#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 +#define SNDRV_PCM_INFO_SYNC_START 0x00400000 +#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 + +typedef int __bitwise snd_pcm_state_t; +#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) +#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) +#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) +#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3) +#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4) +#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) +#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6) +#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) +#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) +#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED + +enum { + SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, + SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000, + SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000, +}; + +union snd_pcm_sync_id { + unsigned char id[16]; + unsigned short id16[8]; + unsigned int id32[4]; +}; + +struct snd_pcm_info { + unsigned int device; + unsigned int subdevice; + int stream; + int card; + unsigned char id[64]; + unsigned char name[80]; + unsigned char subname[32]; + int dev_class; + int dev_subclass; + unsigned int subdevices_count; + unsigned int subdevices_avail; + union snd_pcm_sync_id sync; + unsigned char reserved[64]; +}; + +typedef int snd_pcm_hw_param_t; +#define SNDRV_PCM_HW_PARAM_ACCESS 0 +#define SNDRV_PCM_HW_PARAM_FORMAT 1 +#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2 +#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS +#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT + +#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8 +#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9 +#define SNDRV_PCM_HW_PARAM_CHANNELS 10 +#define SNDRV_PCM_HW_PARAM_RATE 11 +#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12 +#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13 +#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14 +#define SNDRV_PCM_HW_PARAM_PERIODS 15 +#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16 +#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17 +#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18 +#define SNDRV_PCM_HW_PARAM_TICK_TIME 19 +#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS +#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME + +#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) + +struct snd_interval { + unsigned int min, max; + unsigned int openmin:1, + openmax:1, + integer:1, + empty:1; +}; + +#define SNDRV_MASK_MAX 256 + +struct snd_mask { + __u32 bits[(SNDRV_MASK_MAX+31)/32]; +}; + +struct snd_pcm_hw_params { + unsigned int flags; + struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - + SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; + struct snd_mask mres[5]; + struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; + struct snd_interval ires[9]; + unsigned int rmask; + unsigned int cmask; + unsigned int info; + unsigned int msbits; + unsigned int rate_num; + unsigned int rate_den; + snd_pcm_uframes_t fifo_size; + unsigned char reserved[64]; +}; + +enum { + SNDRV_PCM_TSTAMP_NONE = 0, + SNDRV_PCM_TSTAMP_ENABLE, + SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE, +}; + +struct snd_pcm_sw_params { + int tstamp_mode; + unsigned int period_step; + unsigned int sleep_min; + snd_pcm_uframes_t avail_min; + snd_pcm_uframes_t xfer_align; + snd_pcm_uframes_t start_threshold; + snd_pcm_uframes_t stop_threshold; + snd_pcm_uframes_t silence_threshold; + snd_pcm_uframes_t silence_size; + snd_pcm_uframes_t boundary; + unsigned char reserved[64]; +}; + +struct snd_pcm_channel_info { + unsigned int channel; + __kernel_off_t offset; + unsigned int first; + unsigned int step; +}; + +struct snd_pcm_status { + snd_pcm_state_t state; + struct timespec trigger_tstamp; + struct timespec tstamp; + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t hw_ptr; + snd_pcm_sframes_t delay; + snd_pcm_uframes_t avail; + snd_pcm_uframes_t avail_max; + snd_pcm_uframes_t overrange; + snd_pcm_state_t suspended_state; + unsigned char reserved[60]; +}; + +struct snd_pcm_mmap_status { + snd_pcm_state_t state; + int pad1; + snd_pcm_uframes_t hw_ptr; + struct timespec tstamp; + snd_pcm_state_t suspended_state; +}; + +struct snd_pcm_mmap_control { + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t avail_min; +}; + +#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0) +#define SNDRV_PCM_SYNC_PTR_APPL (1<<1) +#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) + +struct snd_pcm_sync_ptr { + unsigned int flags; + union { + struct snd_pcm_mmap_status status; + unsigned char reserved[64]; + } s; + union { + struct snd_pcm_mmap_control control; + unsigned char reserved[64]; + } c; +}; + +struct snd_xferi { + snd_pcm_sframes_t result; + void __user *buf; + snd_pcm_uframes_t frames; +}; + +struct snd_xfern { + snd_pcm_sframes_t result; + void __user * __user *bufs; + snd_pcm_uframes_t frames; +}; + +enum { + SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, + SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, + SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, +}; + +#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) +#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) +#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) +#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int) +#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) +#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params) +#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status) +#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) +#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) +#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) +#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) +#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40) +#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41) +#define SNDRV_PCM_IOCTL_START _IO('A', 0x42) +#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43) +#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44) +#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int) +#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47) +#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48) +#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi) +#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi) +#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern) +#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern) +#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int) +#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61) + +#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0) + +enum { + SNDRV_RAWMIDI_STREAM_OUTPUT = 0, + SNDRV_RAWMIDI_STREAM_INPUT, + SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT, +}; + +#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001 +#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002 +#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004 + +struct snd_rawmidi_info { + unsigned int device; + unsigned int subdevice; + int stream; + int card; + unsigned int flags; + unsigned char id[64]; + unsigned char name[80]; + unsigned char subname[32]; + unsigned int subdevices_count; + unsigned int subdevices_avail; + unsigned char reserved[64]; +}; + +struct snd_rawmidi_params { + int stream; + size_t buffer_size; + size_t avail_min; + unsigned int no_active_sensing: 1; + unsigned char reserved[16]; +}; + +struct snd_rawmidi_status { + int stream; + struct timespec tstamp; + size_t avail; + size_t xruns; + unsigned char reserved[16]; +}; + +#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) +#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info) +#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params) +#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status) +#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int) +#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int) + +#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) + +enum { + SNDRV_TIMER_CLASS_NONE = -1, + SNDRV_TIMER_CLASS_SLAVE = 0, + SNDRV_TIMER_CLASS_GLOBAL, + SNDRV_TIMER_CLASS_CARD, + SNDRV_TIMER_CLASS_PCM, + SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM, +}; + +enum { + SNDRV_TIMER_SCLASS_NONE = 0, + SNDRV_TIMER_SCLASS_APPLICATION, + SNDRV_TIMER_SCLASS_SEQUENCER, + SNDRV_TIMER_SCLASS_OSS_SEQUENCER, + SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER, +}; + +#define SNDRV_TIMER_GLOBAL_SYSTEM 0 +#define SNDRV_TIMER_GLOBAL_RTC 1 +#define SNDRV_TIMER_GLOBAL_HPET 2 +#define SNDRV_TIMER_GLOBAL_HRTIMER 3 + +#define SNDRV_TIMER_FLG_SLAVE (1<<0) + +struct snd_timer_id { + int dev_class; + int dev_sclass; + int card; + int device; + int subdevice; +}; + +struct snd_timer_ginfo { + struct snd_timer_id tid; + unsigned int flags; + int card; + unsigned char id[64]; + unsigned char name[80]; + unsigned long reserved0; + unsigned long resolution; + unsigned long resolution_min; + unsigned long resolution_max; + unsigned int clients; + unsigned char reserved[32]; +}; + +struct snd_timer_gparams { + struct snd_timer_id tid; + unsigned long period_num; + unsigned long period_den; + unsigned char reserved[32]; +}; + +struct snd_timer_gstatus { + struct snd_timer_id tid; + unsigned long resolution; + unsigned long resolution_num; + unsigned long resolution_den; + unsigned char reserved[32]; +}; + +struct snd_timer_select { + struct snd_timer_id id; + unsigned char reserved[32]; +}; + +struct snd_timer_info { + unsigned int flags; + int card; + unsigned char id[64]; + unsigned char name[80]; + unsigned long reserved0; + unsigned long resolution; + unsigned char reserved[64]; +}; + +#define SNDRV_TIMER_PSFLG_AUTO (1<<0) +#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1) +#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) + +struct snd_timer_params { + unsigned int flags; + unsigned int ticks; + unsigned int queue_size; + unsigned int reserved0; + unsigned int filter; + unsigned char reserved[60]; +}; + +struct snd_timer_status { + struct timespec tstamp; + unsigned int resolution; + unsigned int lost; + unsigned int overrun; + unsigned int queue; + unsigned char reserved[64]; +}; + +#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) +#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id) +#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int) +#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo) +#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams) +#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus) +#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select) +#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info) +#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params) +#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status) + +#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0) +#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1) +#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) +#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) + +struct snd_timer_read { + unsigned int resolution; + unsigned int ticks; +}; + +enum { + SNDRV_TIMER_EVENT_RESOLUTION = 0, + SNDRV_TIMER_EVENT_TICK, + SNDRV_TIMER_EVENT_START, + SNDRV_TIMER_EVENT_STOP, + SNDRV_TIMER_EVENT_CONTINUE, + SNDRV_TIMER_EVENT_PAUSE, + SNDRV_TIMER_EVENT_EARLY, + SNDRV_TIMER_EVENT_SUSPEND, + SNDRV_TIMER_EVENT_RESUME, + + SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10, + SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10, + SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10, + SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10, + SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10, + SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10, +}; + +struct snd_timer_tread { + int event; + struct timespec tstamp; + unsigned int val; +}; + +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) + +struct snd_ctl_card_info { + int card; + int pad; + unsigned char id[16]; + unsigned char driver[16]; + unsigned char name[32]; + unsigned char longname[80]; + unsigned char reserved_[16]; + unsigned char mixername[80]; + unsigned char components[128]; +}; + +typedef int __bitwise snd_ctl_elem_type_t; +#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0) +#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1) +#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2) +#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3) +#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4) +#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5) +#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6) +#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64 + +typedef int __bitwise snd_ctl_elem_iface_t; +#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0) +#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1) +#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2) +#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3) +#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4) +#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5) +#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6) +#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER + +#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0) +#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1) +#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) +#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3) +#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) +#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) +#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6) +#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) +#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) +#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) +#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) +#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) + +#define SNDRV_CTL_POWER_D0 0x0000 +#define SNDRV_CTL_POWER_D1 0x0100 +#define SNDRV_CTL_POWER_D2 0x0200 +#define SNDRV_CTL_POWER_D3 0x0300 +#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000) +#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001) + +struct snd_ctl_elem_id { + unsigned int numid; + snd_ctl_elem_iface_t iface; + unsigned int device; + unsigned int subdevice; + unsigned char name[44]; + unsigned int index; +}; + +struct snd_ctl_elem_list { + unsigned int offset; + unsigned int space; + unsigned int used; + unsigned int count; + struct snd_ctl_elem_id __user *pids; + unsigned char reserved[50]; +}; + +struct snd_ctl_elem_info { + struct snd_ctl_elem_id id; + snd_ctl_elem_type_t type; + unsigned int access; + unsigned int count; + __kernel_pid_t owner; + union { + struct { + long min; + long max; + long step; + } integer; + struct { + long long min; + long long max; + long long step; + } integer64; + struct { + unsigned int items; + unsigned int item; + char name[64]; + } enumerated; + unsigned char reserved[128]; + } value; + union { + unsigned short d[4]; + unsigned short *d_ptr; + } dimen; + unsigned char reserved[64-4*sizeof(unsigned short)]; +}; + +struct snd_ctl_elem_value { + struct snd_ctl_elem_id id; + unsigned int indirect: 1; + union { + union { + long value[128]; + long *value_ptr; + } integer; + union { + long long value[64]; + long long *value_ptr; + } integer64; + union { + unsigned int item[128]; + unsigned int *item_ptr; + } enumerated; + union { + unsigned char data[512]; + unsigned char *data_ptr; + } bytes; + struct snd_aes_iec958 iec958; + } value; + struct timespec tstamp; + unsigned char reserved[128-sizeof(struct timespec)]; +}; + +struct snd_ctl_tlv { + unsigned int numid; + unsigned int length; + unsigned int tlv[0]; +}; + +#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int) +#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info) +#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list) +#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int) +#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int) +#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info) +#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int) +#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info) +#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info) +#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int) +#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int) +#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int) + +enum sndrv_ctl_event_type { + SNDRV_CTL_EVENT_ELEM = 0, + SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM, +}; + +#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) +#define SNDRV_CTL_EVENT_MASK_INFO (1<<1) +#define SNDRV_CTL_EVENT_MASK_ADD (1<<2) +#define SNDRV_CTL_EVENT_MASK_TLV (1<<3) +#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) + +struct snd_ctl_event { + int type; + union { + struct { + unsigned int mask; + struct snd_ctl_elem_id id; + } elem; + unsigned char data8[60]; + } data; +}; + +#define SNDRV_CTL_NAME_NONE "" +#define SNDRV_CTL_NAME_PLAYBACK "Playback " +#define SNDRV_CTL_NAME_CAPTURE "Capture " + +#define SNDRV_CTL_NAME_IEC958_NONE "" +#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch" +#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume" +#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default" +#define SNDRV_CTL_NAME_IEC958_MASK "Mask" +#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask" +#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask" +#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream" +#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what + +#endif + diff --git a/libcamera/Android.mk b/libcamera/Android.mk new file mode 100644 index 0000000..5304cc5 --- /dev/null +++ b/libcamera/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# HAL module implemenation stored in +# hw/..so +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libs3cjpeg + +LOCAL_SRC_FILES:= \ + SecCamera.cpp SecCameraHWInterface.cpp + +LOCAL_SHARED_LIBRARIES:= libutils libcutils libbinder liblog libcamera_client libhardware +LOCAL_SHARED_LIBRARIES+= libs3cjpeg + +LOCAL_MODULE := camera.s5pc110 + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) + diff --git a/libcamera/NOTICE b/libcamera/NOTICE new file mode 100644 index 0000000..f921593 --- /dev/null +++ b/libcamera/NOTICE @@ -0,0 +1,190 @@ + + 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. + + 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/libcamera/SecCamera.cpp b/libcamera/SecCamera.cpp new file mode 100755 index 0000000..4bd00c6 --- /dev/null +++ b/libcamera/SecCamera.cpp @@ -0,0 +1,2604 @@ +/* + * Copyright 2008, The Android Open Source Project + * Copyright 2010, Samsung Electronics Co. LTD + * Copyright 2011, The CyanogenMod 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. + */ + +/* +************************************ +* Filename: SecCamera.cpp +* Author: Sachin P. Kamat +* Purpose: This file interacts with the Camera and JPEG drivers. +************************************* +*/ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SecCamera" + +#include + +#include +#include +#include +#include +#include "SecCamera.h" +#include "cutils/properties.h" + +using namespace android; + +#define CHECK(return_value) \ + if (return_value < 0) { \ + LOGE("%s::%d fail. errno: %s, m_camera_id = %d\n", \ + __func__, __LINE__, strerror(errno), m_camera_id); \ + return -1; \ + } + + +#define CHECK_PTR(return_value) \ + if (return_value < 0) { \ + LOGE("%s::%d fail, errno: %s, m_camera_id = %d\n", \ + __func__,__LINE__, strerror(errno), m_camera_id); \ + return NULL; \ + } + +#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5) +#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7) +#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13) + +namespace android { + +// ====================================================================== +// Camera controls + +static struct timeval time_start; +static struct timeval time_stop; + +unsigned long measure_time(struct timeval *start, struct timeval *stop) +{ + unsigned long sec, usec, time; + + sec = stop->tv_sec - start->tv_sec; + + if (stop->tv_usec >= start->tv_usec) { + usec = stop->tv_usec - start->tv_usec; + } else { + usec = stop->tv_usec + 1000000 - start->tv_usec; + sec--; + } + + time = (sec * 1000000) + usec; + + return time; +} + +static int get_pixel_depth(unsigned int fmt) +{ + int depth = 0; + + switch (fmt) { + case V4L2_PIX_FMT_NV12: + depth = 12; + break; + case V4L2_PIX_FMT_NV12T: + depth = 12; + break; + case V4L2_PIX_FMT_NV21: + depth = 12; + break; + case V4L2_PIX_FMT_YUV420: + depth = 12; + break; + + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_YUV422P: + depth = 16; + break; + + case V4L2_PIX_FMT_RGB32: + depth = 32; + break; + } + + return depth; +} + +#define ALIGN_W(x) (((x) + 0x7F) & (~0x7F)) // Set as multiple of 128 +#define ALIGN_H(x) (((x) + 0x1F) & (~0x1F)) // Set as multiple of 32 +#define ALIGN_BUF(x) (((x) + 0x1FFF)& (~0x1FFF)) // Set as multiple of 8K + +static int fimc_poll(struct pollfd *events) +{ + int ret; + + /* 10 second delay is because sensor can take a long time + * to do auto focus and capture in dark settings + */ + ret = poll(events, 1, 10000); + if (ret < 0) { + LOGE("ERR(%s):poll error\n", __func__); + return ret; + } + + if (ret == 0) { + LOGE("ERR(%s):No data in 10 secs..\n", __func__); + return ret; + } + + return ret; +} + +int SecCamera::previewPoll(bool preview) +{ + int ret; + + if (preview) { +#ifdef ENABLE_ESD_PREVIEW_CHECK + int status = 0; + + if (!(++m_esd_check_count % 60)) { + status = getCameraSensorESDStatus(); + m_esd_check_count = 0; + if (status) { + LOGE("ERR(%s) ESD status(%d)", __func__, status); + return status; + } + } +#endif + + ret = poll(&m_events_c, 1, 1000); + } else { + ret = poll(&m_events_c2, 1, 1000); + } + + if (ret < 0) { + LOGE("ERR(%s):poll error\n", __func__); + return ret; + } + + if (ret == 0) { + LOGE("ERR(%s):No data in 1 secs.. Camera Device Reset \n", __func__); + return ret; + } + + return ret; +} + +static int fimc_v4l2_querycap(int fp) +{ + struct v4l2_capability cap; + int ret = 0; + + ret = ioctl(fp, VIDIOC_QUERYCAP, &cap); + + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_QUERYCAP failed\n", __func__); + return -1; + } + + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + LOGE("ERR(%s):no capture devices\n", __func__); + return -1; + } + + return ret; +} + +static const __u8* fimc_v4l2_enuminput(int fp, int index) +{ + static struct v4l2_input input; + + input.index = index; + if (ioctl(fp, VIDIOC_ENUMINPUT, &input) != 0) { + LOGE("ERR(%s):No matching index found\n", __func__); + return NULL; + } + LOGI("Name of input channel[%d] is %s\n", input.index, input.name); + + return input.name; +} + + +static int fimc_v4l2_s_input(int fp, int index) +{ + struct v4l2_input input; + int ret; + + input.index = index; + + ret = ioctl(fp, VIDIOC_S_INPUT, &input); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_S_INPUT failed\n", __func__); + return ret; + } + + return ret; +} + +static int fimc_v4l2_s_fmt(int fp, int width, int height, unsigned int fmt, int flag_capture) +{ + struct v4l2_format v4l2_fmt; + struct v4l2_pix_format pixfmt; + int ret; + + v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + memset(&pixfmt, 0, sizeof(pixfmt)); + + pixfmt.width = width; + pixfmt.height = height; + pixfmt.pixelformat = fmt; + + pixfmt.sizeimage = (width * height * get_pixel_depth(fmt)) / 8; + + pixfmt.field = V4L2_FIELD_NONE; + + v4l2_fmt.fmt.pix = pixfmt; + + /* Set up for capture */ + ret = ioctl(fp, VIDIOC_S_FMT, &v4l2_fmt); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_S_FMT failed\n", __func__); + return -1; + } + + return 0; +} + +static int fimc_v4l2_s_fmt_cap(int fp, int width, int height, unsigned int fmt) +{ + struct v4l2_format v4l2_fmt; + struct v4l2_pix_format pixfmt; + int ret; + + memset(&pixfmt, 0, sizeof(pixfmt)); + + v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + pixfmt.width = width; + pixfmt.height = height; + pixfmt.pixelformat = fmt; + if (fmt == V4L2_PIX_FMT_JPEG) { + pixfmt.colorspace = V4L2_COLORSPACE_JPEG; + } + + pixfmt.sizeimage = (width * height * get_pixel_depth(fmt)) / 8; + + v4l2_fmt.fmt.pix = pixfmt; + + //LOGE("ori_w %d, ori_h %d, w %d, h %d\n", width, height, v4l2_fmt.fmt.pix.width, v4l2_fmt.fmt.pix.height); + + /* Set up for capture */ + ret = ioctl(fp, VIDIOC_S_FMT, &v4l2_fmt); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_S_FMT failed\n", __func__); + return ret; + } + + return ret; +} + +static int fimc_v4l2_enum_fmt(int fp, unsigned int fmt) +{ + struct v4l2_fmtdesc fmtdesc; + int found = 0; + + fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmtdesc.index = 0; + + while (ioctl(fp, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { + if (fmtdesc.pixelformat == fmt) { + LOGV("passed fmt = %#x found pixel format[%d]: %s\n", fmt, fmtdesc.index, fmtdesc.description); + found = 1; + break; + } + + fmtdesc.index++; + } + + if (!found) { + LOGE("unsupported pixel format\n"); + return -1; + } + + return 0; +} + +static int fimc_v4l2_reqbufs(int fp, enum v4l2_buf_type type, int nr_bufs) +{ + struct v4l2_requestbuffers req; + int ret; + + req.count = nr_bufs; + req.type = type; + req.memory = V4L2_MEMORY_MMAP; + + ret = ioctl(fp, VIDIOC_REQBUFS, &req); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_REQBUFS failed\n", __func__); + return -1; + } + + return req.count; +} + +static int fimc_v4l2_querybuf(int fp, struct fimc_buffer *buffer, enum v4l2_buf_type type) +{ + struct v4l2_buffer v4l2_buf; + int ret; + + LOGI("%s :", __func__); + + v4l2_buf.type = type; + v4l2_buf.memory = V4L2_MEMORY_MMAP; + v4l2_buf.index = 0; + + ret = ioctl(fp , VIDIOC_QUERYBUF, &v4l2_buf); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_QUERYBUF failed\n", __func__); + return -1; + } + + buffer->length = v4l2_buf.length; + if ((buffer->start = (char *)mmap(0, v4l2_buf.length, + PROT_READ | PROT_WRITE, MAP_SHARED, + fp, v4l2_buf.m.offset)) < 0) { + LOGE("%s %d] mmap() failed\n",__func__, __LINE__); + return -1; + } + + LOGI("%s: buffer->start = %p v4l2_buf.length = %d", + __func__, buffer->start, v4l2_buf.length); + + return 0; +} + +static int fimc_v4l2_streamon(int fp) +{ + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + int ret; + + ret = ioctl(fp, VIDIOC_STREAMON, &type); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_STREAMON failed\n", __func__); + return ret; + } + + return ret; +} + +static int fimc_v4l2_streamoff(int fp) +{ + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + int ret; + + LOGV("%s :", __func__); + ret = ioctl(fp, VIDIOC_STREAMOFF, &type); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_STREAMOFF failed\n", __func__); + return ret; + } + + return ret; +} + +static int fimc_v4l2_qbuf(int fp, int index) +{ + struct v4l2_buffer v4l2_buf; + int ret; + + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2_buf.memory = V4L2_MEMORY_MMAP; + v4l2_buf.index = index; + + ret = ioctl(fp, VIDIOC_QBUF, &v4l2_buf); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_QBUF failed\n", __func__); + return ret; + } + + return 0; +} + +static int fimc_v4l2_dqbuf(int fp) +{ + struct v4l2_buffer v4l2_buf; + int ret; + + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2_buf.memory = V4L2_MEMORY_MMAP; + + ret = ioctl(fp, VIDIOC_DQBUF, &v4l2_buf); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_DQBUF failed, dropped frame\n", __func__); + return ret; + } + + return v4l2_buf.index; +} + +static int fimc_v4l2_g_ctrl(int fp, unsigned int id) +{ + struct v4l2_control ctrl; + int ret; + + ctrl.id = id; + + ret = ioctl(fp, VIDIOC_G_CTRL, &ctrl); + if (ret < 0) { + LOGE("ERR(%s): VIDIOC_G_CTRL(id = 0x%x (%d)) failed, ret = %d\n", + __func__, id, id-V4L2_CID_PRIVATE_BASE, ret); + return ret; + } + + return ctrl.value; +} + +static int fimc_v4l2_s_ctrl(int fp, unsigned int id, unsigned int value) +{ + struct v4l2_control ctrl; + int ret; + + ctrl.id = id; + ctrl.value = value; + + ret = ioctl(fp, VIDIOC_S_CTRL, &ctrl); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_S_CTRL(id = %#x (%d), value = %d) failed ret = %d\n", + __func__, id, id-V4L2_CID_PRIVATE_BASE, value, ret); + + return ret; + } + + return ctrl.value; +} + +static int fimc_v4l2_s_ext_ctrl(int fp, unsigned int id, void *value) +{ + struct v4l2_ext_controls ctrls; + struct v4l2_ext_control ctrl; + int ret; + + ctrl.id = id; + ctrl.reserved = value; + + ctrls.ctrl_class = V4L2_CTRL_CLASS_CAMERA; + ctrls.count = 1; + ctrls.controls = &ctrl; + + ret = ioctl(fp, VIDIOC_S_EXT_CTRLS, &ctrls); + if (ret < 0) + LOGE("ERR(%s):VIDIOC_S_EXT_CTRLS failed\n", __func__); + + return ret; +} + +static int fimc_v4l2_g_parm(int fp, struct v4l2_streamparm *streamparm) +{ + int ret; + + streamparm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret = ioctl(fp, VIDIOC_G_PARM, streamparm); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_G_PARM failed\n", __func__); + return -1; + } + + LOGV("%s : timeperframe: numerator %d, denominator %d\n", __func__, + streamparm->parm.capture.timeperframe.numerator, + streamparm->parm.capture.timeperframe.denominator); + + return 0; +} + +static int fimc_v4l2_s_parm(int fp, struct v4l2_streamparm *streamparm) +{ + int ret; + + streamparm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret = ioctl(fp, VIDIOC_S_PARM, streamparm); + if (ret < 0) { + LOGE("ERR(%s):VIDIOC_S_PARM failed\n", __func__); + return ret; + } + + return 0; +} + +// ====================================================================== +// Constructor & Destructor + +SecCamera::SecCamera() : + m_flag_init(0), + m_camera_id(CAMERA_ID_BACK), + m_cam_fd(-1), + m_cam_fd2(-1), + m_preview_v4lformat(V4L2_PIX_FMT_NV21), + m_preview_width (0), + m_preview_height (0), + m_preview_max_width (MAX_BACK_CAMERA_PREVIEW_WIDTH), + m_preview_max_height (MAX_BACK_CAMERA_PREVIEW_HEIGHT), + m_snapshot_v4lformat(-1), + m_snapshot_width (0), + m_snapshot_height (0), + m_snapshot_max_width (MAX_BACK_CAMERA_SNAPSHOT_WIDTH), + m_snapshot_max_height (MAX_BACK_CAMERA_SNAPSHOT_HEIGHT), + m_angle(-1), + m_zoom_level(-1), + m_object_tracking(-1), + m_vtmode(0), + m_sensor_mode(-1), + m_shot_mode(-1), + m_exif_orientation(-1), + m_blur_level(-1), + m_chk_dataline(-1), + m_camera_af_flag(-1), + m_flag_camera_start(0), + m_jpeg_thumbnail_width (0), + m_jpeg_thumbnail_height(0), + m_jpeg_quality(100) +#ifdef ENABLE_ESD_PREVIEW_CHECK + , + m_esd_check_count(0) +#endif // ENABLE_ESD_PREVIEW_CHECK +{ + m_params = (struct sec_cam_parm*)&m_streamparm.parm.raw_data; + struct v4l2_captureparm capture; + m_params->capture.timeperframe.numerator = 1; + m_params->capture.timeperframe.denominator = 0; + m_params->contrast = -1; + m_params->effects = -1; + m_params->brightness = -1; + m_params->flash_mode = -1; + m_params->focus_mode = -1; + m_params->iso = -1; + m_params->metering = -1; + m_params->saturation = -1; + m_params->scene_mode = -1; + m_params->sharpness = -1; + m_params->white_balance = -1; + + memset(&m_capture_buf, 0, sizeof(m_capture_buf)); + + LOGV("%s :", __func__); +} + +SecCamera::~SecCamera() +{ + LOGV("%s :", __func__); +} + +int SecCamera::initCamera(int index) +{ + LOGV("%s :", __func__); + int ret = 0; + + if (!m_flag_init) { + /* Arun C + * Reset the lense position only during camera starts; don't do + * reset between shot to shot + */ + m_camera_af_flag = -1; + + m_cam_fd = open(CAMERA_DEV_NAME, O_RDWR); + if (m_cam_fd < 0) { + LOGE("ERR(%s):Cannot open %s (error : %s)\n", __func__, CAMERA_DEV_NAME, strerror(errno)); + return -1; + } + LOGV("%s: open(%s) --> m_cam_fd %d", __FUNCTION__, CAMERA_DEV_NAME, m_cam_fd); + + LOGE("initCamera: m_cam_fd(%d), m_jpeg_fd(%d)", m_cam_fd, m_jpeg_fd); + + ret = fimc_v4l2_querycap(m_cam_fd); + CHECK(ret); + if (!fimc_v4l2_enuminput(m_cam_fd, index)) + return -1; + ret = fimc_v4l2_s_input(m_cam_fd, index); + CHECK(ret); + + m_cam_fd2 = open(CAMERA_DEV_NAME2, O_RDWR); + LOGV("%s: open(%s) --> m_cam_fd2 = %d", __FUNCTION__, CAMERA_DEV_NAME2, m_cam_fd2); + if (m_cam_fd2 < 0) { + LOGE("ERR(%s):Cannot open %s (error : %s)\n", __func__, CAMERA_DEV_NAME2, strerror(errno)); + return -1; + } + + LOGE("initCamera: m_cam_fd2(%d)", m_cam_fd2); + + ret = fimc_v4l2_querycap(m_cam_fd2); + CHECK(ret); + if (!fimc_v4l2_enuminput(m_cam_fd2, index)) + return -1; + ret = fimc_v4l2_s_input(m_cam_fd2, index); + CHECK(ret); + + m_camera_id = index; + + switch (m_camera_id) { + case CAMERA_ID_FRONT: + m_preview_max_width = MAX_FRONT_CAMERA_PREVIEW_WIDTH; + m_preview_max_height = MAX_FRONT_CAMERA_PREVIEW_HEIGHT; + m_snapshot_max_width = MAX_FRONT_CAMERA_SNAPSHOT_WIDTH; + m_snapshot_max_height = MAX_FRONT_CAMERA_SNAPSHOT_HEIGHT; + break; + + case CAMERA_ID_BACK: + m_preview_max_width = MAX_BACK_CAMERA_PREVIEW_WIDTH; + m_preview_max_height = MAX_BACK_CAMERA_PREVIEW_HEIGHT; + m_snapshot_max_width = MAX_BACK_CAMERA_SNAPSHOT_WIDTH; + m_snapshot_max_height = MAX_BACK_CAMERA_SNAPSHOT_HEIGHT; + break; + } + + setExifFixedAttribute(); + + m_flag_init = 1; + LOGI("%s : initialized", __FUNCTION__); + } + return 0; +} + +void SecCamera::resetCamera() +{ + LOGV("%s :", __func__); + DeinitCamera(); + initCamera(m_camera_id); +} + +void SecCamera::DeinitCamera() +{ + LOGV("%s :", __func__); + + if (m_flag_init) { + + stopRecord(); + + /* close m_cam_fd after stopRecord() because stopRecord() + * uses m_cam_fd to change frame rate + */ + LOGI("DeinitCamera: m_cam_fd(%d)", m_cam_fd); + if (m_cam_fd > -1) { + close(m_cam_fd); + m_cam_fd = -1; + } + + LOGI("DeinitCamera: m_cam_fd2(%d)", m_cam_fd2); + if (m_cam_fd2 > -1) { + close(m_cam_fd2); + m_cam_fd2 = -1; + } + + m_flag_init = 0; + } + else LOGI("%s : already deinitialized", __FUNCTION__); +} + + +int SecCamera::getCameraFd(void) +{ + return m_cam_fd; +} + +// ====================================================================== +// Preview + +int SecCamera::startPreview(void) +{ + v4l2_streamparm streamparm; + struct sec_cam_parm *parms; + parms = (struct sec_cam_parm*)&streamparm.parm.raw_data; + LOGV("%s :", __func__); + + // aleady started + if (m_flag_camera_start > 0) { + LOGE("ERR(%s):Preview was already started\n", __func__); + return 0; + } + + if (m_cam_fd <= 0) { + LOGE("ERR(%s):Camera was closed\n", __func__); + return -1; + } + + memset(&m_events_c, 0, sizeof(m_events_c)); + m_events_c.fd = m_cam_fd; + m_events_c.events = POLLIN | POLLERR; + + /* enum_fmt, s_fmt sample */ + int ret = fimc_v4l2_enum_fmt(m_cam_fd,m_preview_v4lformat); + CHECK(ret); + + if (m_camera_id == CAMERA_ID_BACK) + ret = fimc_v4l2_s_fmt(m_cam_fd, m_preview_width,m_preview_height,m_preview_v4lformat, 0); + else + ret = fimc_v4l2_s_fmt(m_cam_fd, m_preview_height,m_preview_width,m_preview_v4lformat, 0); + CHECK(ret); + + ret = fimc_v4l2_reqbufs(m_cam_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, MAX_BUFFERS); + CHECK(ret); + + LOGV("%s : m_preview_width: %d m_preview_height: %d m_angle: %d\n", + __func__, m_preview_width, m_preview_height, m_angle); + + ret = fimc_v4l2_s_ctrl(m_cam_fd, + V4L2_CID_CAMERA_CHECK_DATALINE, m_chk_dataline); + CHECK(ret); + + if (m_camera_id == CAMERA_ID_FRONT) { + /* VT mode setting */ + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_VT_MODE, m_vtmode); + CHECK(ret); + + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_CHECK_FLIP, 0); + CHECK(ret); + + } + + /* start with all buffers in queue */ + for (int i = 0; i < MAX_BUFFERS; i++) { + ret = fimc_v4l2_qbuf(m_cam_fd, i); + CHECK(ret); + } + + ret = fimc_v4l2_streamon(m_cam_fd); + CHECK(ret); + + m_flag_camera_start = 1; + + if (m_camera_id == CAMERA_ID_BACK) { + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_SCENE_MODE, m_params->scene_mode); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_WHITE_BALANCE, m_params->white_balance); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_EFFECT, m_params->effects); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FRAME_RATE, m_params->capture.timeperframe.denominator); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_METERING, m_params->metering); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_SATURATION, m_params->saturation); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FOCUS_MODE, m_params->focus_mode); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_CONTRAST, m_params->contrast); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_SENSOR_MODE, 0); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_ISO, m_params->iso); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_BRIGHTNESS, m_params->brightness); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_SHARPNESS, m_params->sharpness); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FLASH_MODE, m_params->flash_mode); + CHECK(ret); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_APP_CHECK, 0); + CHECK(ret); + } + + ret = fimc_v4l2_s_parm(m_cam_fd, &m_streamparm); + CHECK(ret); + + if (m_camera_id == CAMERA_ID_FRONT) { + /* Blur setting */ + LOGV("m_blur_level = %d", m_blur_level); + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_VGA_BLUR, + m_blur_level); + CHECK(ret); + } + + ret = fimc_v4l2_g_ctrl(m_cam_fd, V4L2_CID_ESD_INT); + CHECK_PTR(ret); + + LOGV("%s: got the first frame of the preview\n", __func__); + + return 0; +} + +int SecCamera::stopPreview(void) +{ + int ret; + + LOGV("%s :", __func__); + + if (m_flag_camera_start == 0) { + LOGW("%s: doing nothing because m_flag_camera_start is zero", __func__); + return 0; + } + + if (m_params->flash_mode == FLASH_MODE_TORCH) + setFlashMode(FLASH_MODE_OFF); + + if (m_cam_fd <= 0) { + LOGE("ERR(%s):Camera was closed\n", __func__); + return -1; + } + + ret = fimc_v4l2_streamoff(m_cam_fd); + CHECK(ret); + + m_flag_camera_start = 0; + + return ret; +} + +//Recording +int SecCamera::startRecord(void) +{ + int ret, i; + + LOGV("%s :", __func__); + + // aleady started + if (m_flag_record_start > 0) { + LOGE("ERR(%s):Preview was already started\n", __func__); + return 0; + } + + if (m_cam_fd2 <= 0) { + LOGE("ERR(%s):Camera was closed\n", __func__); + return -1; + } + + /* enum_fmt, s_fmt sample */ + ret = fimc_v4l2_enum_fmt(m_cam_fd2, V4L2_PIX_FMT_NV12T); + CHECK(ret); + + LOGI("%s: m_recording_width = %d, m_recording_height = %d\n", + __func__, m_recording_width, m_recording_height); + + if (m_camera_id == CAMERA_ID_BACK) { + ret = fimc_v4l2_s_fmt(m_cam_fd2, m_recording_width, + m_recording_height, V4L2_PIX_FMT_NV12T, 0); + } + else { + ret = fimc_v4l2_s_fmt(m_cam_fd2, m_recording_height, + m_recording_width, V4L2_PIX_FMT_NV12T, 0); + } + CHECK(ret); + + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FRAME_RATE, + m_params->capture.timeperframe.denominator); + CHECK(ret); + + ret = fimc_v4l2_reqbufs(m_cam_fd2, V4L2_BUF_TYPE_VIDEO_CAPTURE, MAX_BUFFERS); + CHECK(ret); + + /* start with all buffers in queue */ + for (i = 0; i < MAX_BUFFERS; i++) { + ret = fimc_v4l2_qbuf(m_cam_fd2, i); + CHECK(ret); + } + + ret = fimc_v4l2_streamon(m_cam_fd2); + CHECK(ret); + + // Get and throw away the first frame since it is often garbled. + memset(&m_events_c2, 0, sizeof(m_events_c2)); + m_events_c2.fd = m_cam_fd2; + m_events_c2.events = POLLIN | POLLERR; + ret = fimc_poll(&m_events_c2); + CHECK(ret); + + m_flag_record_start = 1; + + return 0; +} + +int SecCamera::stopRecord(void) +{ + int ret; + + LOGV("%s :", __func__); + + if (m_flag_record_start == 0) { + LOGW("%s: doing nothing because m_flag_record_start is zero", __func__); + return 0; + } + + if (m_cam_fd2 <= 0) { + LOGE("ERR(%s):Camera was closed\n", __func__); + return -1; + } + + m_flag_record_start = 0; + + ret = fimc_v4l2_streamoff(m_cam_fd2); + CHECK(ret); + + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FRAME_RATE, + FRAME_RATE_AUTO); + CHECK(ret); + + return 0; +} + +unsigned int SecCamera::getRecPhyAddrY(int index) +{ + unsigned int addr_y; + + addr_y = fimc_v4l2_s_ctrl(m_cam_fd2, V4L2_CID_PADDR_Y, index); + CHECK((int)addr_y); + return addr_y; +} + +unsigned int SecCamera::getRecPhyAddrC(int index) +{ + unsigned int addr_c; + + addr_c = fimc_v4l2_s_ctrl(m_cam_fd2, V4L2_CID_PADDR_CBCR, index); + CHECK((int)addr_c); + return addr_c; +} + +unsigned int SecCamera::getPhyAddrY(int index) +{ + unsigned int addr_y; + + addr_y = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_PADDR_Y, index); + CHECK((int)addr_y); + return addr_y; +} + +unsigned int SecCamera::getPhyAddrC(int index) +{ + unsigned int addr_c; + + addr_c = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_PADDR_CBCR, index); + CHECK((int)addr_c); + return addr_c; +} + +void SecCamera::pausePreview() +{ + fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_STREAM_PAUSE, 0); +} + +int SecCamera::getPreview() +{ + int index; + int ret; + + if (m_flag_camera_start == 0 || previewPoll(true) == 0) { + LOGE("ERR(%s):Start Camera Device Reset \n", __func__); + /* GAUDI Project([arun.c@samsung.com]) 2010.05.20. [Implemented ESD code] */ + /* + * When there is no data for more than 1 second from the camera we inform + * the FIMC driver by calling fimc_v4l2_s_input() with a special value = 1000 + * FIMC driver identify that there is something wrong with the camera + * and it restarts the sensor. + */ + stopPreview(); + /* Reset Only Camera Device */ + ret = fimc_v4l2_querycap(m_cam_fd); + CHECK(ret); + if (fimc_v4l2_enuminput(m_cam_fd, m_camera_id)) + return -1; + ret = fimc_v4l2_s_input(m_cam_fd, 1000); + CHECK(ret); + ret = startPreview(); + if (ret < 0) { + LOGE("ERR(%s): startPreview() return %d\n", __func__, ret); + return 0; + } + } + + index = fimc_v4l2_dqbuf(m_cam_fd); + if (!(0 <= index && index < MAX_BUFFERS)) { + LOGE("ERR(%s):wrong index = %d\n", __func__, index); + return -1; + } + + ret = fimc_v4l2_qbuf(m_cam_fd, index); + CHECK(ret); + + return index; +} + +int SecCamera::getRecordFrame() +{ + if (m_flag_record_start == 0) { + LOGE("%s: m_flag_record_start is 0", __func__); + return -1; + } + + previewPoll(false); + return fimc_v4l2_dqbuf(m_cam_fd2); +} + +int SecCamera::releaseRecordFrame(int index) +{ + if (!m_flag_record_start) { + /* this can happen when recording frames are returned after + * the recording is stopped at the driver level. we don't + * need to return the buffers in this case and we've seen + * cases where fimc could crash if we called qbuf and it + * wasn't expecting it. + */ + LOGI("%s: recording not in progress, ignoring", __func__); + return 0; + } + + return fimc_v4l2_qbuf(m_cam_fd2, index); +} + +int SecCamera::setPreviewSize(int width, int height, int pixel_format) +{ + LOGV("%s(width(%d), height(%d), format(%d))", __func__, width, height, pixel_format); + + int v4lpixelformat = pixel_format; + +#if defined(LOG_NDEBUG) && LOG_NDEBUG == 0 + if (v4lpixelformat == V4L2_PIX_FMT_YUV420) + LOGV("PreviewFormat:V4L2_PIX_FMT_YUV420"); + else if (v4lpixelformat == V4L2_PIX_FMT_NV12) + LOGV("PreviewFormat:V4L2_PIX_FMT_NV12"); + else if (v4lpixelformat == V4L2_PIX_FMT_NV12T) + LOGV("PreviewFormat:V4L2_PIX_FMT_NV12T"); + else if (v4lpixelformat == V4L2_PIX_FMT_NV21) + LOGV("PreviewFormat:V4L2_PIX_FMT_NV21"); + else if (v4lpixelformat == V4L2_PIX_FMT_YUV422P) + LOGV("PreviewFormat:V4L2_PIX_FMT_YUV422P"); + else if (v4lpixelformat == V4L2_PIX_FMT_YUYV) + LOGV("PreviewFormat:V4L2_PIX_FMT_YUYV"); + else if (v4lpixelformat == V4L2_PIX_FMT_RGB565) + LOGV("PreviewFormat:V4L2_PIX_FMT_RGB565"); + else + LOGV("PreviewFormat:UnknownFormat"); +#endif + m_preview_width = width; + m_preview_height = height; + m_preview_v4lformat = v4lpixelformat; + + return 0; +} + +int SecCamera::getPreviewSize(int *width, int *height, int *frame_size) +{ + *width = m_preview_width; + *height = m_preview_height; + *frame_size = m_frameSize(m_preview_v4lformat, m_preview_width, m_preview_height); + + return 0; +} + +int SecCamera::getPreviewMaxSize(int *width, int *height) +{ + *width = m_preview_max_width; + *height = m_preview_max_height; + + return 0; +} + +int SecCamera::getPreviewPixelFormat(void) +{ + return m_preview_v4lformat; +} + + +// ====================================================================== +// Snapshot +/* + * Devide getJpeg() as two funcs, setSnapshotCmd() & getJpeg() because of the shutter sound timing. + * Here, just send the capture cmd to camera ISP to start JPEG capture. + */ +int SecCamera::setSnapshotCmd(void) +{ + LOGV("%s :", __func__); + + int ret = 0; + + LOG_TIME_DEFINE(0) + LOG_TIME_DEFINE(1) + + if (m_cam_fd <= 0) { + LOGE("ERR(%s):Camera was closed\n", __func__); + return 0; + } + + if (m_flag_camera_start > 0) { + LOG_TIME_START(0) + LOGW("WARN(%s):Camera was in preview, should have been stopped\n", __func__); + stopPreview(); + LOG_TIME_END(0) + } + + memset(&m_events_c, 0, sizeof(m_events_c)); + m_events_c.fd = m_cam_fd; + m_events_c.events = POLLIN | POLLERR; + + LOG_TIME_START(1) // prepare + int nframe = 1; + + ret = fimc_v4l2_enum_fmt(m_cam_fd,m_snapshot_v4lformat); + CHECK(ret); + ret = fimc_v4l2_s_fmt_cap(m_cam_fd, m_snapshot_width, m_snapshot_height, V4L2_PIX_FMT_JPEG); + CHECK(ret); + ret = fimc_v4l2_reqbufs(m_cam_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, nframe); + CHECK(ret); + ret = fimc_v4l2_querybuf(m_cam_fd, &m_capture_buf, V4L2_BUF_TYPE_VIDEO_CAPTURE); + CHECK(ret); + + ret = fimc_v4l2_qbuf(m_cam_fd, 0); + CHECK(ret); + + ret = fimc_v4l2_streamon(m_cam_fd); + CHECK(ret); + + LOG_TIME_END(1) + + return 0; +} + +int SecCamera::endSnapshot(void) +{ + int ret; + + LOGI("%s :", __func__); + if (m_capture_buf.start) { + munmap(m_capture_buf.start, m_capture_buf.length); + LOGI("munmap():virt. addr %p size = %d\n", + m_capture_buf.start, m_capture_buf.length); + m_capture_buf.start = NULL; + m_capture_buf.length = 0; + } + return 0; +} + +/* + * Set Jpeg quality & exif info and get JPEG data from camera ISP + */ +unsigned char* SecCamera::getJpeg(int *jpeg_size, unsigned int *phyaddr) +{ + LOGV("%s :", __func__); + + int index, ret = 0; + unsigned char *addr; + + LOG_TIME_DEFINE(2) + + // capture + ret = fimc_poll(&m_events_c); + CHECK_PTR(ret); + index = fimc_v4l2_dqbuf(m_cam_fd); + if (index != 0) { + LOGE("ERR(%s):wrong index = %d\n", __func__, index); + return NULL; + } + + *jpeg_size = fimc_v4l2_g_ctrl(m_cam_fd, V4L2_CID_CAM_JPEG_MAIN_SIZE); + CHECK_PTR(*jpeg_size); + + int main_offset = fimc_v4l2_g_ctrl(m_cam_fd, V4L2_CID_CAM_JPEG_MAIN_OFFSET); + CHECK_PTR(main_offset); + m_postview_offset = fimc_v4l2_g_ctrl(m_cam_fd, V4L2_CID_CAM_JPEG_POSTVIEW_OFFSET); + CHECK_PTR(m_postview_offset); + + ret = fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_STREAM_PAUSE, 0); + CHECK_PTR(ret); + LOGV("\nsnapshot dqueued buffer = %d snapshot_width = %d snapshot_height = %d, size = %d\n\n", + index, m_snapshot_width, m_snapshot_height, *jpeg_size); + + addr = (unsigned char*)(m_capture_buf.start) + main_offset; + *phyaddr = getPhyAddrY(index) + m_postview_offset; + + LOG_TIME_START(2) // post + ret = fimc_v4l2_streamoff(m_cam_fd); + CHECK_PTR(ret); + LOG_TIME_END(2) + + return addr; +} + +int SecCamera::getExif(unsigned char *pExifDst, unsigned char *pThumbSrc) +{ + JpegEncoder jpgEnc; + + LOGV("%s : m_jpeg_thumbnail_width = %d, height = %d", + __func__, m_jpeg_thumbnail_width, m_jpeg_thumbnail_height); + if ((m_jpeg_thumbnail_width > 0) && (m_jpeg_thumbnail_height > 0)) { + int inFormat = JPG_MODESEL_YCBCR; + int outFormat = JPG_422; + switch (m_snapshot_v4lformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12T: + case V4L2_PIX_FMT_YUV420: + outFormat = JPG_420; + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV422P: + outFormat = JPG_422; + break; + } + + if (jpgEnc.setConfig(JPEG_SET_ENCODE_IN_FORMAT, inFormat) != JPG_SUCCESS) + return -1; + + if (jpgEnc.setConfig(JPEG_SET_SAMPING_MODE, outFormat) != JPG_SUCCESS) + return -1; + + if (jpgEnc.setConfig(JPEG_SET_ENCODE_QUALITY, JPG_QUALITY_LEVEL_2) != JPG_SUCCESS) + return -1; + + int thumbWidth, thumbHeight, thumbSrcSize; + getThumbnailConfig(&thumbWidth, &thumbHeight, &thumbSrcSize); + if (jpgEnc.setConfig(JPEG_SET_ENCODE_WIDTH, thumbWidth) != JPG_SUCCESS) + return -1; + + if (jpgEnc.setConfig(JPEG_SET_ENCODE_HEIGHT, thumbHeight) != JPG_SUCCESS) + return -1; + + char *pInBuf = (char *)jpgEnc.getInBuf(thumbSrcSize); + if (pInBuf == NULL) + return -1; + memcpy(pInBuf, pThumbSrc, thumbSrcSize); + + unsigned int thumbSize; + + jpgEnc.encode(&thumbSize, NULL); + + LOGV("%s : enableThumb set to true", __func__); + mExifInfo.enableThumb = true; + } else { + LOGV("%s : enableThumb set to false", __func__); + mExifInfo.enableThumb = false; + } + + unsigned int exifSize; + + setExifChangedAttribute(); + + LOGV("%s: calling jpgEnc.makeExif, mExifInfo.width set to %d, height to %d\n", + __func__, mExifInfo.width, mExifInfo.height); + + jpgEnc.makeExif(pExifDst, &mExifInfo, &exifSize, true); + + return exifSize; +} + +void SecCamera::getPostViewConfig(int *width, int *height, int *size) +{ + if (m_preview_width == 1024) { + *width = BACK_CAMERA_POSTVIEW_WIDE_WIDTH; + *height = BACK_CAMERA_POSTVIEW_HEIGHT; + *size = BACK_CAMERA_POSTVIEW_WIDE_WIDTH * BACK_CAMERA_POSTVIEW_HEIGHT * BACK_CAMERA_POSTVIEW_BPP / 8; + } else { + *width = BACK_CAMERA_POSTVIEW_WIDTH; + *height = BACK_CAMERA_POSTVIEW_HEIGHT; + *size = BACK_CAMERA_POSTVIEW_WIDTH * BACK_CAMERA_POSTVIEW_HEIGHT * BACK_CAMERA_POSTVIEW_BPP / 8; + } + LOGV("[5B] m_preview_width : %d, mPostViewWidth = %d mPostViewHeight = %d mPostViewSize = %d", + m_preview_width, *width, *height, *size); +} + +void SecCamera::getThumbnailConfig(int *width, int *height, int *size) +{ + if (m_camera_id == CAMERA_ID_BACK) { + *width = BACK_CAMERA_THUMBNAIL_WIDTH; + *height = BACK_CAMERA_THUMBNAIL_HEIGHT; + *size = BACK_CAMERA_THUMBNAIL_WIDTH * BACK_CAMERA_THUMBNAIL_HEIGHT + * BACK_CAMERA_THUMBNAIL_BPP / 8; + } else { + *width = FRONT_CAMERA_THUMBNAIL_WIDTH; + *height = FRONT_CAMERA_THUMBNAIL_HEIGHT; + *size = FRONT_CAMERA_THUMBNAIL_WIDTH * FRONT_CAMERA_THUMBNAIL_HEIGHT + * FRONT_CAMERA_THUMBNAIL_BPP / 8; + } +} + +int SecCamera::getPostViewOffset(void) +{ + return m_postview_offset; +} + +int SecCamera::getSnapshotAndJpeg(unsigned char *yuv_buf, unsigned char *jpeg_buf, + unsigned int *output_size) +{ + LOGV("%s :", __func__); + + int index; + //unsigned int addr; + unsigned char *addr; + int ret = 0; + + LOG_TIME_DEFINE(0) + LOG_TIME_DEFINE(1) + LOG_TIME_DEFINE(2) + LOG_TIME_DEFINE(3) + LOG_TIME_DEFINE(4) + LOG_TIME_DEFINE(5) + + //fimc_v4l2_streamoff(m_cam_fd); [zzangdol] remove - it is separate in HWInterface with camera_id + + if (m_cam_fd <= 0) { + LOGE("ERR(%s):Camera was closed\n", __func__); + return -1; + } + + if (m_flag_camera_start > 0) { + LOG_TIME_START(0) + LOGW("WARN(%s):Camera was in preview, should have been stopped\n", __func__); + stopPreview(); + LOG_TIME_END(0) + } + + memset(&m_events_c, 0, sizeof(m_events_c)); + m_events_c.fd = m_cam_fd; + m_events_c.events = POLLIN | POLLERR; + +#if defined(LOG_NDEBUG) && LOG_NDEBUG == 0 + if (m_snapshot_v4lformat == V4L2_PIX_FMT_YUV420) + LOGV("SnapshotFormat:V4L2_PIX_FMT_YUV420"); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_NV12) + LOGV("SnapshotFormat:V4L2_PIX_FMT_NV12"); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_NV12T) + LOGV("SnapshotFormat:V4L2_PIX_FMT_NV12T"); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_NV21) + LOGV("SnapshotFormat:V4L2_PIX_FMT_NV21"); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_YUV422P) + LOGV("SnapshotFormat:V4L2_PIX_FMT_YUV422P"); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_YUYV) + LOGV("SnapshotFormat:V4L2_PIX_FMT_YUYV"); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_UYVY) + LOGV("SnapshotFormat:V4L2_PIX_FMT_UYVY"); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_RGB565) + LOGV("SnapshotFormat:V4L2_PIX_FMT_RGB565"); + else + LOGV("SnapshotFormat:UnknownFormat"); +#endif + + LOG_TIME_START(1) // prepare + int nframe = 1; + + ret = fimc_v4l2_enum_fmt(m_cam_fd,m_snapshot_v4lformat); + CHECK(ret); + // FFC: Swap width and height + ret = fimc_v4l2_s_fmt_cap(m_cam_fd, m_snapshot_height, m_snapshot_width, m_snapshot_v4lformat); + CHECK(ret); + ret = fimc_v4l2_reqbufs(m_cam_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, nframe); + CHECK(ret); + ret = fimc_v4l2_querybuf(m_cam_fd, &m_capture_buf, V4L2_BUF_TYPE_VIDEO_CAPTURE); + CHECK(ret); + + ret = fimc_v4l2_qbuf(m_cam_fd, 0); + CHECK(ret); + + ret = fimc_v4l2_streamon(m_cam_fd); + CHECK(ret); + LOG_TIME_END(1) + + LOG_TIME_START(2) // capture + fimc_poll(&m_events_c); + index = fimc_v4l2_dqbuf(m_cam_fd); + fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_STREAM_PAUSE, 0); + LOGV("\nsnapshot dequeued buffer = %d snapshot_width = %d snapshot_height = %d\n\n", + index, m_snapshot_width, m_snapshot_height); + + LOG_TIME_END(2) + + LOGI("%s : calling memcpy from m_capture_buf", __func__); + memcpy(yuv_buf, (unsigned char*)m_capture_buf.start, m_snapshot_width * m_snapshot_height * 2); + LOG_TIME_START(5) // post + fimc_v4l2_streamoff(m_cam_fd); + LOG_TIME_END(5) + + LOG_CAMERA("getSnapshotAndJpeg intervals : stopPreview(%lu), prepare(%lu)," + " capture(%lu), memcpy(%lu), yuv2Jpeg(%lu), post(%lu) us", + LOG_TIME(0), LOG_TIME(1), LOG_TIME(2), LOG_TIME(3), LOG_TIME(4), LOG_TIME(5)); + /* JPEG encoding */ + JpegEncoder jpgEnc; + int inFormat = JPG_MODESEL_YCBCR; + int outFormat = JPG_422; + + switch (m_snapshot_v4lformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12T: + case V4L2_PIX_FMT_YUV420: + outFormat = JPG_420; + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV422P: + default: + outFormat = JPG_422; + break; + } + + if (jpgEnc.setConfig(JPEG_SET_ENCODE_IN_FORMAT, inFormat) != JPG_SUCCESS) + LOGE("[JPEG_SET_ENCODE_IN_FORMAT] Error\n"); + + if (jpgEnc.setConfig(JPEG_SET_SAMPING_MODE, outFormat) != JPG_SUCCESS) + LOGE("[JPEG_SET_SAMPING_MODE] Error\n"); + + image_quality_type_t jpegQuality; + if (m_jpeg_quality >= 90) + jpegQuality = JPG_QUALITY_LEVEL_1; + else if (m_jpeg_quality >= 80) + jpegQuality = JPG_QUALITY_LEVEL_2; + else if (m_jpeg_quality >= 70) + jpegQuality = JPG_QUALITY_LEVEL_3; + else + jpegQuality = JPG_QUALITY_LEVEL_4; + + if (jpgEnc.setConfig(JPEG_SET_ENCODE_QUALITY, jpegQuality) != JPG_SUCCESS) + LOGE("[JPEG_SET_ENCODE_QUALITY] Error\n"); + if (jpgEnc.setConfig(JPEG_SET_ENCODE_WIDTH, m_snapshot_width) != JPG_SUCCESS) + LOGE("[JPEG_SET_ENCODE_WIDTH] Error\n"); + + if (jpgEnc.setConfig(JPEG_SET_ENCODE_HEIGHT, m_snapshot_height) != JPG_SUCCESS) + LOGE("[JPEG_SET_ENCODE_HEIGHT] Error\n"); + + unsigned int snapshot_size = m_snapshot_width * m_snapshot_height * 2; + unsigned char *pInBuf = (unsigned char *)jpgEnc.getInBuf(snapshot_size); + + if (pInBuf == NULL) { + LOGE("JPEG input buffer is NULL!!\n"); + return -1; + } + memcpy(pInBuf, yuv_buf, snapshot_size); + + setExifChangedAttribute(); + jpgEnc.encode(output_size, NULL); + + uint64_t outbuf_size; + unsigned char *pOutBuf = (unsigned char *)jpgEnc.getOutBuf(&outbuf_size); + + if (pOutBuf == NULL) { + LOGE("JPEG output buffer is NULL!!\n"); + return -1; + } + + memcpy(jpeg_buf, pOutBuf, outbuf_size); + + return 0; +} + + +int SecCamera::setSnapshotSize(int width, int height) +{ + LOGV("%s(width(%d), height(%d))", __func__, width, height); + + m_snapshot_width = width; + m_snapshot_height = height; + + return 0; +} + +int SecCamera::getSnapshotSize(int *width, int *height, int *frame_size) +{ + *width = m_snapshot_width; + *height = m_snapshot_height; + + int frame = 0; + + frame = m_frameSize(m_snapshot_v4lformat, m_snapshot_width, m_snapshot_height); + + // set it big. + if (frame == 0) + frame = m_snapshot_width * m_snapshot_height * BPP; + + *frame_size = frame; + + return 0; +} + +int SecCamera::getSnapshotMaxSize(int *width, int *height) +{ + switch (m_camera_id) { + case CAMERA_ID_FRONT: + m_snapshot_max_width = MAX_FRONT_CAMERA_SNAPSHOT_WIDTH; + m_snapshot_max_height = MAX_FRONT_CAMERA_SNAPSHOT_HEIGHT; + break; + + default: + case CAMERA_ID_BACK: + m_snapshot_max_width = MAX_BACK_CAMERA_SNAPSHOT_WIDTH; + m_snapshot_max_height = MAX_BACK_CAMERA_SNAPSHOT_HEIGHT; + break; + } + + *width = m_snapshot_max_width; + *height = m_snapshot_max_height; + + return 0; +} + +int SecCamera::setSnapshotPixelFormat(int pixel_format) +{ + int v4lpixelformat= pixel_format; + + if (m_snapshot_v4lformat != v4lpixelformat) { + m_snapshot_v4lformat = v4lpixelformat; + } + +#if defined(LOG_NDEBUG) && LOG_NDEBUG == 0 + if (m_snapshot_v4lformat == V4L2_PIX_FMT_YUV420) + LOGE("%s : SnapshotFormat:V4L2_PIX_FMT_YUV420", __func__); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_NV12) + LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_NV12", __func__); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_NV12T) + LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_NV12T", __func__); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_NV21) + LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_NV21", __func__); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_YUV422P) + LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_YUV422P", __func__); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_YUYV) + LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_YUYV", __func__); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_UYVY) + LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_UYVY", __func__); + else if (m_snapshot_v4lformat == V4L2_PIX_FMT_RGB565) + LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_RGB565", __func__); + else + LOGD("SnapshotFormat:UnknownFormat"); +#endif + return 0; +} + +int SecCamera::getSnapshotPixelFormat(void) +{ + return m_snapshot_v4lformat; +} + +// ====================================================================== +// Settings + +int SecCamera::getCameraId(void) +{ + return m_camera_id; +} + +// ----------------------------------- + +int SecCamera::setAutofocus(void) +{ + LOGV("%s :", __func__); + + if (m_cam_fd <= 0) { + LOGE("ERR(%s):Camera was closed\n", __func__); + return -1; + } + + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_ON) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_SET_AUTO_FOCUS", __func__); + return -1; + } + + return 0; +} + +int SecCamera::getAutoFocusResult(void) +{ + int af_result; + + af_result = fimc_v4l2_g_ctrl(m_cam_fd, V4L2_CID_CAMERA_AUTO_FOCUS_RESULT); + + LOGV("%s : returning %d", __func__, af_result); + + return af_result; +} + +int SecCamera::cancelAutofocus(void) +{ + LOGV("%s :", __func__); + + if (m_cam_fd <= 0) { + LOGE("ERR(%s):Camera was closed\n", __func__); + return -1; + } + + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_OFF) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_SET_AUTO_FOCUS", __func__); + return -1; + } + + return 0; +} + +// ----------------------------------- + +int SecCamera::zoomIn(void) +{ + LOGV("%s :", __func__); + return 0; +} + +int SecCamera::zoomOut(void) +{ + LOGV("%s :", __func__); + return 0; +} + +// ----------------------------------- + +int SecCamera::setFrameRate(int frame_rate) +{ + LOGV("%s(FrameRate(%d))", __func__, frame_rate); + + if (frame_rate < FRAME_RATE_AUTO || FRAME_RATE_MAX < frame_rate ) + LOGE("ERR(%s):Invalid frame_rate(%d)", __func__, frame_rate); + + if (m_params->capture.timeperframe.denominator != (unsigned)frame_rate) { + m_params->capture.timeperframe.denominator = frame_rate; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FRAME_RATE, frame_rate) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_FRAME_RATE", __func__); + return -1; + } + } + } + + return 0; +} + +// ----------------------------------- + +int SecCamera::setVerticalMirror(void) +{ + LOGV("%s :", __func__); + + if (m_cam_fd <= 0) { + LOGE("ERR(%s):Camera was closed\n", __func__); + return -1; + } + + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_VFLIP, 0) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_VFLIP", __func__); + return -1; + } + + return 0; +} + +int SecCamera::setHorizontalMirror(void) +{ + LOGV("%s :", __func__); + + if (m_cam_fd <= 0) { + LOGE("ERR(%s):Camera was closed\n", __func__); + return -1; + } + + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_HFLIP, 0) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_HFLIP", __func__); + return -1; + } + + return 0; +} + +// ----------------------------------- + +int SecCamera::setWhiteBalance(int white_balance) +{ + LOGV("%s(white_balance(%d))", __func__, white_balance); + + if (white_balance <= WHITE_BALANCE_BASE || WHITE_BALANCE_MAX <= white_balance) { + LOGE("ERR(%s):Invalid white_balance(%d)", __func__, white_balance); + return -1; + } + + if (m_params->white_balance != white_balance) { + m_params->white_balance = white_balance; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_WHITE_BALANCE, white_balance) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_WHITE_BALANCE", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getWhiteBalance(void) +{ + LOGV("%s : white_balance(%d)", __func__, m_params->white_balance); + return m_params->white_balance; +} + +// ----------------------------------- + +int SecCamera::setBrightness(int brightness) +{ + LOGV("%s(brightness(%d))", __func__, brightness); + + brightness += EV_DEFAULT; + + if (brightness < EV_MINUS_4 || EV_PLUS_4 < brightness) { + LOGE("ERR(%s):Invalid brightness(%d)", __func__, brightness); + return -1; + } + + if (m_params->brightness != brightness) { + m_params->brightness = brightness; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_BRIGHTNESS, brightness) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_BRIGHTNESS", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getBrightness(void) +{ + LOGV("%s : brightness(%d)", __func__, m_params->brightness); + return m_params->brightness; +} + +// ----------------------------------- + +int SecCamera::setImageEffect(int image_effect) +{ + LOGV("%s(image_effect(%d))", __func__, image_effect); + + if (image_effect <= IMAGE_EFFECT_BASE || IMAGE_EFFECT_MAX <= image_effect) { + LOGE("ERR(%s):Invalid image_effect(%d)", __func__, image_effect); + return -1; + } + + if (m_params->effects != image_effect) { + m_params->effects = image_effect; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_EFFECT, image_effect) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_EFFECT", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getImageEffect(void) +{ + LOGV("%s : image_effect(%d)", __func__, m_params->effects); + return m_params->effects; +} + +//====================================================================== +int SecCamera::setSceneMode(int scene_mode) +{ + LOGV("%s(scene_mode(%d))", __func__, scene_mode); + + if (scene_mode <= SCENE_MODE_BASE || SCENE_MODE_MAX <= scene_mode) { + LOGE("ERR(%s):Invalid scene_mode (%d)", __func__, scene_mode); + return -1; + } + + if (m_params->scene_mode != scene_mode) { + m_params->scene_mode = scene_mode; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_SCENE_MODE, scene_mode) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_SCENE_MODE", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getSceneMode(void) +{ + return m_params->scene_mode; +} + +//====================================================================== + +int SecCamera::setFlashMode(int flash_mode) +{ + LOGV("%s(flash_mode(%d))", __func__, flash_mode); + + if (flash_mode <= FLASH_MODE_BASE || FLASH_MODE_MAX <= flash_mode) { + LOGE("ERR(%s):Invalid flash_mode (%d)", __func__, flash_mode); + return -1; + } + + if (m_params->flash_mode != flash_mode) { + m_params->flash_mode = flash_mode; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FLASH_MODE, flash_mode) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_FLASH_MODE", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getFlashMode(void) +{ + return m_params->flash_mode; +} + +//====================================================================== + +int SecCamera::setISO(int iso_value) +{ + LOGV("%s(iso_value(%d))", __func__, iso_value); + if (iso_value < ISO_AUTO || ISO_MAX <= iso_value) { + LOGE("ERR(%s):Invalid iso_value (%d)", __func__, iso_value); + return -1; + } + + if (m_params->iso != iso_value) { + m_params->iso = iso_value; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_ISO, iso_value) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_ISO", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getISO(void) +{ + return m_params->iso; +} + +//====================================================================== + +int SecCamera::setContrast(int contrast_value) +{ + LOGV("%s(contrast_value(%d))", __func__, contrast_value); + + if (contrast_value < CONTRAST_MINUS_2 || CONTRAST_MAX <= contrast_value) { + LOGE("ERR(%s):Invalid contrast_value (%d)", __func__, contrast_value); + return -1; + } + + if (m_params->contrast != contrast_value) { + m_params->contrast = contrast_value; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_CONTRAST, contrast_value) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_CONTRAST", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getContrast(void) +{ + return m_params->contrast; +} + +//====================================================================== + +int SecCamera::setSaturation(int saturation_value) +{ + LOGV("%s(saturation_value(%d))", __func__, saturation_value); + + if (saturation_value saturation != saturation_value) { + m_params->saturation = saturation_value; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_SATURATION, saturation_value) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_SATURATION", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getSaturation(void) +{ + return m_params->saturation; +} + +//====================================================================== + +int SecCamera::setSharpness(int sharpness_value) +{ + LOGV("%s(sharpness_value(%d))", __func__, sharpness_value); + + if (sharpness_value < SHARPNESS_MINUS_2 || SHARPNESS_MAX <= sharpness_value) { + LOGE("ERR(%s):Invalid sharpness_value (%d)", __func__, sharpness_value); + return -1; + } + + if (m_params->sharpness != sharpness_value) { + m_params->sharpness = sharpness_value; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_SHARPNESS, sharpness_value) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_SHARPNESS", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getSharpness(void) +{ + return m_params->sharpness; +} + +//====================================================================== + +int SecCamera::setMetering(int metering_value) +{ + LOGV("%s(metering (%d))", __func__, metering_value); + + if (metering_value <= METERING_BASE || METERING_MAX <= metering_value) { + LOGE("ERR(%s):Invalid metering_value (%d)", __func__, metering_value); + return -1; + } + + if (m_params->metering != metering_value) { + m_params->metering = metering_value; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_METERING, metering_value) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_METERING", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getMetering(void) +{ + return m_params->metering; +} + +//====================================================================== + +int SecCamera::setJpegQuality(int jpeg_quality) +{ + LOGV("%s(jpeg_quality (%d))", __func__, jpeg_quality); + + if (jpeg_quality < JPEG_QUALITY_ECONOMY || JPEG_QUALITY_MAX <= jpeg_quality) { + LOGE("ERR(%s):Invalid jpeg_quality (%d)", __func__, jpeg_quality); + return -1; + } + + if (m_jpeg_quality != jpeg_quality) { + m_jpeg_quality = jpeg_quality; + if (m_flag_camera_start && (m_camera_id == CAMERA_ID_BACK)) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAM_JPEG_QUALITY, jpeg_quality) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAM_JPEG_QUALITY", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getJpegQuality(void) +{ + return m_jpeg_quality; +} + +//====================================================================== + +int SecCamera::setZoom(int zoom_level) +{ + LOGV("%s(zoom_level (%d))", __func__, zoom_level); + + if (zoom_level < ZOOM_LEVEL_0 || ZOOM_LEVEL_MAX <= zoom_level) { + LOGE("ERR(%s):Invalid zoom_level (%d)", __func__, zoom_level); + return -1; + } + + if (m_zoom_level != zoom_level) { + m_zoom_level = zoom_level; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_ZOOM, zoom_level) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_ZOOM", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getZoom(void) +{ + return m_zoom_level; +} + +//====================================================================== + +int SecCamera::setObjectTracking(int object_tracking) +{ + LOGV("%s(object_tracking (%d))", __func__, object_tracking); + + if (object_tracking < OBJECT_TRACKING_OFF || OBJECT_TRACKING_MAX <= object_tracking) { + LOGE("ERR(%s):Invalid object_tracking (%d)", __func__, object_tracking); + return -1; + } + + if (m_object_tracking != object_tracking) { + m_object_tracking = object_tracking; + } + + return 0; +} + +int SecCamera::getObjectTracking(void) +{ + return m_object_tracking; +} + +int SecCamera::getObjectTrackingStatus(void) +{ + int obj_status = 0; + obj_status = fimc_v4l2_g_ctrl(m_cam_fd, V4L2_CID_CAMERA_OBJ_TRACKING_STATUS); + return obj_status; +} + +int SecCamera::setObjectTrackingStartStop(int start_stop) +{ + LOGV("%s(object_tracking_start_stop (%d))", __func__, start_stop); + + if (m_object_tracking_start_stop != start_stop) { + m_object_tracking_start_stop = start_stop; + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_OBJ_TRACKING_START_STOP, start_stop) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_OBJ_TRACKING_START_STOP", __func__); + return -1; + } + } + + return 0; +} + +int SecCamera::setTouchAFStartStop(int start_stop) +{ + LOGV("%s(touch_af_start_stop (%d))", __func__, start_stop); + + if (m_touch_af_start_stop != start_stop) { + m_touch_af_start_stop = start_stop; + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_TOUCH_AF_START_STOP, start_stop) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_TOUCH_AF_START_STOP", __func__); + return -1; + } + } + + return 0; +} + +//====================================================================== + +int SecCamera::setFocusMode(int focus_mode) +{ + LOGV("%s(focus_mode(%d))", __func__, focus_mode); + + if (FOCUS_MODE_MAX <= focus_mode) { + LOGE("ERR(%s):Invalid focus_mode (%d)", __func__, focus_mode); + return -1; + } + + if (m_params->focus_mode != focus_mode) { + m_params->focus_mode = focus_mode; + + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FOCUS_MODE, focus_mode) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_FOCUS_MODE", __func__); + return -1; + } + } + } + + return 0; +} + +int SecCamera::getFocusMode(void) +{ + return m_params->focus_mode; +} + +//====================================================================== + +int SecCamera::setObjectPosition(int x, int y) +{ + LOGV("%s(setObjectPosition(x=%d, y=%d))", __func__, x, y); + + if (m_preview_width ==640) + x = x - 80; + + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_OBJECT_POSITION_X, x) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_OBJECT_POSITION_X", __func__); + return -1; + } + + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_OBJECT_POSITION_Y, y) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_OBJECT_POSITION_Y", __func__); + return -1; + } + + return 0; +} + +//====================================================================== +int SecCamera::setRecordingSize(int width, int height) +{ + LOGV("%s(width(%d), height(%d))", __func__, width, height); + + m_recording_width = width; + m_recording_height = height; + + return 0; +} + +//====================================================================== + +int SecCamera::setExifOrientationInfo(int orientationInfo) +{ + LOGV("%s(orientationInfo(%d))", __func__, orientationInfo); + + if (orientationInfo < 0) { + LOGE("ERR(%s):Invalid orientationInfo (%d)", __func__, orientationInfo); + return -1; + } + m_exif_orientation = orientationInfo; + + return 0; +} + +/*Video call*/ +int SecCamera::setVTmode(int vtmode) +{ + LOGV("%s(vtmode (%d))", __func__, vtmode); + + if (vtmode < VT_MODE_OFF || VT_MODE_MAX <= vtmode) { + LOGE("ERR(%s):Invalid vtmode (%d)", __func__, vtmode); + return -1; + } + + if (m_vtmode != vtmode) { + m_vtmode = vtmode; + } + + return 0; +} + +/* Camcorder fix fps */ +int SecCamera::setSensorMode(int sensor_mode) +{ + LOGV("%s(sensor_mode (%d))", __func__, sensor_mode); + + if (sensor_mode < SENSOR_MODE_CAMERA || SENSOR_MODE_MOVIE < sensor_mode) { + LOGE("ERR(%s):Invalid sensor mode (%d)", __func__, sensor_mode); + return -1; + } + + if (m_sensor_mode != sensor_mode) { + m_sensor_mode = sensor_mode; + } + + return 0; +} + +/* Shot mode */ +/* SINGLE = 0 +* CONTINUOUS = 1 +* PANORAMA = 2 +* SMILE = 3 +* SELF = 6 +*/ +int SecCamera::setShotMode(int shot_mode) +{ + LOGV("%s(shot_mode (%d))", __func__, shot_mode); + if (shot_mode < SHOT_MODE_SINGLE || SHOT_MODE_SELF < shot_mode) { + LOGE("ERR(%s):Invalid shot_mode (%d)", __func__, shot_mode); + return -1; + } + m_shot_mode = shot_mode; + + return 0; +} + +int SecCamera::getVTmode(void) +{ + return m_vtmode; +} + +int SecCamera::setBlur(int blur_level) +{ + LOGV("%s(level (%d))", __func__, blur_level); + + if (blur_level < BLUR_LEVEL_0 || BLUR_LEVEL_MAX <= blur_level) { + LOGE("ERR(%s):Invalid level (%d)", __func__, blur_level); + return -1; + } + + if (m_blur_level != blur_level) { + m_blur_level = blur_level; + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_VGA_BLUR, blur_level) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_VGA_BLUR", __func__); + return -1; + } + } + } + return 0; +} + +int SecCamera::getBlur(void) +{ + return m_blur_level; +} + +int SecCamera::setDataLineCheck(int chk_dataline) +{ + LOGV("%s(chk_dataline (%d))", __func__, chk_dataline); + + if (chk_dataline < CHK_DATALINE_OFF || CHK_DATALINE_MAX <= chk_dataline) { + LOGE("ERR(%s):Invalid chk_dataline (%d)", __func__, chk_dataline); + return -1; + } + + m_chk_dataline = chk_dataline; + + return 0; +} + +int SecCamera::getDataLineCheck(void) +{ + return m_chk_dataline; +} + +int SecCamera::setDataLineCheckStop(void) +{ + LOGV("%s", __func__); + + if (m_flag_camera_start) { + if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_CHECK_DATALINE_STOP, 1) < 0) { + LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_CHECK_DATALINE_STOP", __func__); + return -1; + } + } + return 0; +} + +const __u8* SecCamera::getCameraSensorName(void) +{ + LOGV("%s", __func__); + + return fimc_v4l2_enuminput(m_cam_fd, getCameraId()); +} + +#ifdef ENABLE_ESD_PREVIEW_CHECK +int SecCamera::getCameraSensorESDStatus(void) +{ + LOGV("%s", __func__); + + // 0 : normal operation, 1 : abnormal operation + int status = fimc_v4l2_g_ctrl(m_cam_fd, V4L2_CID_ESD_INT); + + return status; +} +#endif // ENABLE_ESD_PREVIEW_CHECK + +// ====================================================================== +// Jpeg + +int SecCamera::setJpegThumbnailSize(int width, int height) +{ + LOGV("%s(width(%d), height(%d))", __func__, width, height); + + m_jpeg_thumbnail_width = width; + m_jpeg_thumbnail_height = height; + + return 0; +} + +int SecCamera::getJpegThumbnailSize(int *width, int *height) +{ + if (width) + *width = m_jpeg_thumbnail_width; + if (height) + *height = m_jpeg_thumbnail_height; + + return 0; +} + +void SecCamera::setExifFixedAttribute() +{ + char property[PROPERTY_VALUE_MAX]; + + //2 0th IFD TIFF Tags + //3 Maker + property_get("ro.product.brand", property, EXIF_DEF_MAKER); + strncpy((char *)mExifInfo.maker, property, + sizeof(mExifInfo.maker) - 1); + mExifInfo.maker[sizeof(mExifInfo.maker) - 1] = '\0'; + //3 Model + property_get("ro.product.model", property, EXIF_DEF_MODEL); + strncpy((char *)mExifInfo.model, property, + sizeof(mExifInfo.model) - 1); + mExifInfo.model[sizeof(mExifInfo.model) - 1] = '\0'; + //3 Software + property_get("ro.build.id", property, EXIF_DEF_SOFTWARE); + strncpy((char *)mExifInfo.software, property, + sizeof(mExifInfo.software) - 1); + mExifInfo.software[sizeof(mExifInfo.software) - 1] = '\0'; + + //3 YCbCr Positioning + mExifInfo.ycbcr_positioning = EXIF_DEF_YCBCR_POSITIONING; + + //2 0th IFD Exif Private Tags + //3 F Number + mExifInfo.fnumber.num = EXIF_DEF_FNUMBER_NUM; + mExifInfo.fnumber.den = EXIF_DEF_FNUMBER_DEN; + //3 Exposure Program + mExifInfo.exposure_program = EXIF_DEF_EXPOSURE_PROGRAM; + //3 Exif Version + memcpy(mExifInfo.exif_version, EXIF_DEF_EXIF_VERSION, sizeof(mExifInfo.exif_version)); + //3 Aperture + uint32_t av = APEX_FNUM_TO_APERTURE((double)mExifInfo.fnumber.num/mExifInfo.fnumber.den); + mExifInfo.aperture.num = av*EXIF_DEF_APEX_DEN; + mExifInfo.aperture.den = EXIF_DEF_APEX_DEN; + //3 Maximum lens aperture + mExifInfo.max_aperture.num = mExifInfo.aperture.num; + mExifInfo.max_aperture.den = mExifInfo.aperture.den; + //3 Lens Focal Length + if (m_camera_id == CAMERA_ID_BACK) + mExifInfo.focal_length.num = BACK_CAMERA_FOCAL_LENGTH; + else + mExifInfo.focal_length.num = FRONT_CAMERA_FOCAL_LENGTH; + + mExifInfo.focal_length.den = EXIF_DEF_FOCAL_LEN_DEN; + //3 User Comments + strcpy((char *)mExifInfo.user_comment, EXIF_DEF_USERCOMMENTS); + //3 Color Space information + mExifInfo.color_space = EXIF_DEF_COLOR_SPACE; + //3 Exposure Mode + mExifInfo.exposure_mode = EXIF_DEF_EXPOSURE_MODE; + + //2 1th IFD TIFF Tags + mExifInfo.compression_scheme = EXIF_DEF_COMPRESSION; + mExifInfo.x_resolution.num = EXIF_DEF_RESOLUTION_NUM; + mExifInfo.x_resolution.den = EXIF_DEF_RESOLUTION_DEN; + mExifInfo.y_resolution.num = EXIF_DEF_RESOLUTION_NUM; + mExifInfo.y_resolution.den = EXIF_DEF_RESOLUTION_DEN; + mExifInfo.resolution_unit = EXIF_DEF_RESOLUTION_UNIT; +} + +void SecCamera::setExifChangedAttribute() +{ + //2 0th IFD TIFF Tags + //3 Width + mExifInfo.width = m_snapshot_width; + //3 Height + mExifInfo.height = m_snapshot_height; + //3 Orientation + switch (m_exif_orientation) { + case 0: + mExifInfo.orientation = EXIF_ORIENTATION_UP; + break; + case 90: + mExifInfo.orientation = EXIF_ORIENTATION_90; + break; + case 180: + mExifInfo.orientation = EXIF_ORIENTATION_180; + break; + case 270: + mExifInfo.orientation = EXIF_ORIENTATION_270; + break; + default: + mExifInfo.orientation = EXIF_ORIENTATION_UP; + break; + } + //3 Date time + time_t rawtime; + struct tm *timeinfo; + time(&rawtime); + timeinfo = localtime(&rawtime); + strftime((char *)mExifInfo.date_time, 20, "%Y:%m:%d %H:%M:%S", timeinfo); + + //2 0th IFD Exif Private Tags + //3 Exposure Time + int shutterSpeed = fimc_v4l2_g_ctrl(m_cam_fd, + V4L2_CID_CAMERA_GET_SHT_TIME); + /* TBD - front camera needs to be fixed to support this g_ctrl, + it current returns a negative err value, so avoid putting + odd value into exif for now */ + if (shutterSpeed < 0) { + LOGE("%s: error %d getting shutterSpeed, camera_id = %d, using 100", + __func__, shutterSpeed, m_camera_id); + shutterSpeed = 100; + } + mExifInfo.exposure_time.num = 1; + // x us -> 1/x s */ + mExifInfo.exposure_time.den = (uint32_t)(1000000 / shutterSpeed); + + //3 ISO Speed Rating + int iso = fimc_v4l2_g_ctrl(m_cam_fd, V4L2_CID_CAMERA_GET_ISO); + /* TBD - front camera needs to be fixed to support this g_ctrl, + it current returns a negative err value, so avoid putting + odd value into exif for now */ + if (iso < 0) { + LOGE("%s: error %d getting iso, camera_id = %d, using 100", + __func__, iso, m_camera_id); + iso = ISO_100; + } + switch(iso) { + case ISO_50: + mExifInfo.iso_speed_rating = 50; + break; + case ISO_100: + mExifInfo.iso_speed_rating = 100; + break; + case ISO_200: + mExifInfo.iso_speed_rating = 200; + break; + case ISO_400: + mExifInfo.iso_speed_rating = 400; + break; + case ISO_800: + mExifInfo.iso_speed_rating = 800; + break; + case ISO_1600: + mExifInfo.iso_speed_rating = 1600; + break; + default: + mExifInfo.iso_speed_rating = 100; + break; + } + + uint32_t av, tv, bv, sv, ev; + av = APEX_FNUM_TO_APERTURE((double)mExifInfo.fnumber.num / mExifInfo.fnumber.den); + tv = APEX_EXPOSURE_TO_SHUTTER((double)mExifInfo.exposure_time.num / mExifInfo.exposure_time.den); + sv = APEX_ISO_TO_FILMSENSITIVITY(mExifInfo.iso_speed_rating); + bv = av + tv - sv; + ev = av + tv; + LOGD("Shutter speed=%d us, iso=%d\n", shutterSpeed, mExifInfo.iso_speed_rating); + LOGD("AV=%d, TV=%d, SV=%d\n", av, tv, sv); + + //3 Shutter Speed + mExifInfo.shutter_speed.num = tv*EXIF_DEF_APEX_DEN; + mExifInfo.shutter_speed.den = EXIF_DEF_APEX_DEN; + //3 Brightness + mExifInfo.brightness.num = bv*EXIF_DEF_APEX_DEN; + mExifInfo.brightness.den = EXIF_DEF_APEX_DEN; + //3 Exposure Bias + if (m_params->scene_mode == SCENE_MODE_BEACH_SNOW) { + mExifInfo.exposure_bias.num = EXIF_DEF_APEX_DEN; + mExifInfo.exposure_bias.den = EXIF_DEF_APEX_DEN; + } else { + mExifInfo.exposure_bias.num = 0; + mExifInfo.exposure_bias.den = 0; + } + //3 Metering Mode + switch (m_params->metering) { + case METERING_SPOT: + mExifInfo.metering_mode = EXIF_METERING_SPOT; + break; + case METERING_MATRIX: + mExifInfo.metering_mode = EXIF_METERING_AVERAGE; + break; + case METERING_CENTER: + mExifInfo.metering_mode = EXIF_METERING_CENTER; + break; + default : + mExifInfo.metering_mode = EXIF_METERING_AVERAGE; + break; + } + + //3 Flash + int flash = fimc_v4l2_g_ctrl(m_cam_fd, V4L2_CID_CAMERA_GET_FLASH_ONOFF); + if (flash < 0) + mExifInfo.flash = EXIF_DEF_FLASH; + else + mExifInfo.flash = flash; + + //3 White Balance + if (m_params->white_balance == WHITE_BALANCE_AUTO) + mExifInfo.white_balance = EXIF_WB_AUTO; + else + mExifInfo.white_balance = EXIF_WB_MANUAL; + //3 Scene Capture Type + switch (m_params->scene_mode) { + case SCENE_MODE_PORTRAIT: + mExifInfo.scene_capture_type = EXIF_SCENE_PORTRAIT; + break; + case SCENE_MODE_LANDSCAPE: + mExifInfo.scene_capture_type = EXIF_SCENE_LANDSCAPE; + break; + case SCENE_MODE_NIGHTSHOT: + mExifInfo.scene_capture_type = EXIF_SCENE_NIGHT; + break; + default: + mExifInfo.scene_capture_type = EXIF_SCENE_STANDARD; + break; + } + + //2 1th IFD TIFF Tags + mExifInfo.widthThumb = m_jpeg_thumbnail_width; + mExifInfo.heightThumb = m_jpeg_thumbnail_height; +} + +// ====================================================================== +// Conversions + +inline int SecCamera::m_frameSize(int format, int width, int height) +{ + int size = 0; + + switch (format) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + size = (width * height * 3 / 2); + break; + + case V4L2_PIX_FMT_NV12T: + size = ALIGN_TO_8KB(ALIGN_TO_128B(width) * ALIGN_TO_32B(height)) + + ALIGN_TO_8KB(ALIGN_TO_128B(width) * ALIGN_TO_32B(height / 2)); + break; + + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + size = (width * height * 2); + break; + + default : + LOGE("ERR(%s):Invalid V4L2 pixel format(%d)\n", __func__, format); + case V4L2_PIX_FMT_RGB565: + size = (width * height * BPP); + break; + } + + return size; +} + +status_t SecCamera::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + snprintf(buffer, 255, "dump(%d)\n", fd); + result.append(buffer); + ::write(fd, result.string(), result.size()); + return NO_ERROR; +} + +double SecCamera::jpeg_ratio = 0.7; +int SecCamera::interleaveDataSize = 4261248; +int SecCamera::jpegLineLength = 636; + +}; // namespace android diff --git a/libcamera/SecCamera.h b/libcamera/SecCamera.h new file mode 100644 index 0000000..2f219e6 --- /dev/null +++ b/libcamera/SecCamera.h @@ -0,0 +1,503 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** Copyright 2010, Samsung Electronics Co. LTD +** +** 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_CAMERA_SEC_H +#define ANDROID_HARDWARE_CAMERA_SEC_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "JpegEncoder.h" + +namespace android { + +#define ENABLE_ESD_PREVIEW_CHECK + +#if defined(LOG_NDEBUG) && LOG_NDEBUG == 0 +#define LOG_CAMERA LOGD +#define LOG_CAMERA_PREVIEW LOGD + +#define LOG_TIME_DEFINE(n) \ + struct timeval time_start_##n, time_stop_##n; unsigned long log_time_##n = 0; + +#define LOG_TIME_START(n) \ + gettimeofday(&time_start_##n, NULL); + +#define LOG_TIME_END(n) \ + gettimeofday(&time_stop_##n, NULL); log_time_##n = measure_time(&time_start_##n, &time_stop_##n); + +#define LOG_TIME(n) \ + log_time_##n + +#else +#define LOG_CAMERA(...) +#define LOG_CAMERA_PREVIEW(...) +#define LOG_TIME_DEFINE(n) +#define LOG_TIME_START(n) +#define LOG_TIME_END(n) +#define LOG_TIME(n) +#endif + +#define JOIN(x, y) JOIN_AGAIN(x, y) +#define JOIN_AGAIN(x, y) x ## y + +#define FRONT_CAM VGA +#define BACK_CAM S5K4ECGX + +#if !defined (FRONT_CAM) || !defined(BACK_CAM) +#error "Please define the Camera module" +#endif + +#define S5K4ECGX_PREVIEW_WIDTH 1024 +#define S5K4ECGX_PREVIEW_HEIGHT 600 +#define S5K4ECGX_SNAPSHOT_WIDTH 2048 +#define S5K4ECGX_SNAPSHOT_HEIGHT 1536 + +#define S5K4ECGX_POSTVIEW_WIDTH 512 +#define S5K4ECGX_POSTVIEW_WIDE_WIDTH 640 +#define S5K4ECGX_POSTVIEW_HEIGHT 384 +#define S5K4ECGX_POSTVIEW_BPP 16 + +#define S5K4ECGX_THUMBNAIL_WIDTH 320 +#define S5K4ECGX_THUMBNAIL_HEIGHT 240 +#define S5K4ECGX_THUMBNAIL_BPP 16 + +/* focal length of 2.78mm */ +#define S5K4ECGX_FOCAL_LENGTH 278 + +#define VGA_PREVIEW_WIDTH 640 +#define VGA_PREVIEW_HEIGHT 480 +#define VGA_SNAPSHOT_WIDTH 640 +#define VGA_SNAPSHOT_HEIGHT 480 + +#define VGA_THUMBNAIL_WIDTH 160 +#define VGA_THUMBNAIL_HEIGHT 120 +#define VGA_THUMBNAIL_BPP 16 + +/* focal length of 0.9mm */ +#define VGA_FOCAL_LENGTH 90 + +#define MAX_BACK_CAMERA_PREVIEW_WIDTH JOIN(BACK_CAM,_PREVIEW_WIDTH) +#define MAX_BACK_CAMERA_PREVIEW_HEIGHT JOIN(BACK_CAM,_PREVIEW_HEIGHT) +#define MAX_BACK_CAMERA_SNAPSHOT_WIDTH JOIN(BACK_CAM,_SNAPSHOT_WIDTH) +#define MAX_BACK_CAMERA_SNAPSHOT_HEIGHT JOIN(BACK_CAM,_SNAPSHOT_HEIGHT) +#define BACK_CAMERA_POSTVIEW_WIDTH JOIN(BACK_CAM,_POSTVIEW_WIDTH) +#define BACK_CAMERA_POSTVIEW_WIDE_WIDTH JOIN(BACK_CAM,_POSTVIEW_WIDE_WIDTH) +#define BACK_CAMERA_POSTVIEW_HEIGHT JOIN(BACK_CAM,_POSTVIEW_HEIGHT) +#define BACK_CAMERA_POSTVIEW_BPP JOIN(BACK_CAM,_POSTVIEW_BPP) +#define BACK_CAMERA_THUMBNAIL_WIDTH JOIN(BACK_CAM,_THUMBNAIL_WIDTH) +#define BACK_CAMERA_THUMBNAIL_HEIGHT JOIN(BACK_CAM,_THUMBNAIL_HEIGHT) +#define BACK_CAMERA_THUMBNAIL_BPP JOIN(BACK_CAM,_THUMBNAIL_BPP) + +#define BACK_CAMERA_FOCAL_LENGTH JOIN(BACK_CAM,_FOCAL_LENGTH) + +#define MAX_FRONT_CAMERA_PREVIEW_WIDTH JOIN(FRONT_CAM,_PREVIEW_WIDTH) +#define MAX_FRONT_CAMERA_PREVIEW_HEIGHT JOIN(FRONT_CAM,_PREVIEW_HEIGHT) +#define MAX_FRONT_CAMERA_SNAPSHOT_WIDTH JOIN(FRONT_CAM,_SNAPSHOT_WIDTH) +#define MAX_FRONT_CAMERA_SNAPSHOT_HEIGHT JOIN(FRONT_CAM,_SNAPSHOT_HEIGHT) + +#define FRONT_CAMERA_THUMBNAIL_WIDTH JOIN(FRONT_CAM,_THUMBNAIL_WIDTH) +#define FRONT_CAMERA_THUMBNAIL_HEIGHT JOIN(FRONT_CAM,_THUMBNAIL_HEIGHT) +#define FRONT_CAMERA_THUMBNAIL_BPP JOIN(FRONT_CAM,_THUMBNAIL_BPP) +#define FRONT_CAMERA_FOCAL_LENGTH JOIN(FRONT_CAM,_FOCAL_LENGTH) + +#define DEFAULT_JPEG_THUMBNAIL_WIDTH 256 +#define DEFAULT_JPEG_THUMBNAIL_HEIGHT 192 + +#define CAMERA_DEV_NAME "/dev/video0" +#define CAMERA_DEV_NAME2 "/dev/video2" + +#define CAMERA_DEV_NAME_TEMP "/data/videotmp_000" +#define CAMERA_DEV_NAME2_TEMP "/data/videotemp_002" + + +#define BPP 2 +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define MAX_BUFFERS 9 // 11 +/* + * V 4 L 2 F I M C E X T E N S I O N S + * + */ +#define V4L2_CID_ROTATION (V4L2_CID_PRIVATE_BASE + 0) +#define V4L2_CID_PADDR_Y (V4L2_CID_PRIVATE_BASE + 1) +#define V4L2_CID_PADDR_CB (V4L2_CID_PRIVATE_BASE + 2) +#define V4L2_CID_PADDR_CR (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_PADDR_CBCR (V4L2_CID_PRIVATE_BASE + 4) +#define V4L2_CID_STREAM_PAUSE (V4L2_CID_PRIVATE_BASE + 53) + +#define V4L2_CID_CAM_JPEG_MAIN_SIZE (V4L2_CID_PRIVATE_BASE + 32) +#define V4L2_CID_CAM_JPEG_MAIN_OFFSET (V4L2_CID_PRIVATE_BASE + 33) +#define V4L2_CID_CAM_JPEG_THUMB_SIZE (V4L2_CID_PRIVATE_BASE + 34) +#define V4L2_CID_CAM_JPEG_THUMB_OFFSET (V4L2_CID_PRIVATE_BASE + 35) +#define V4L2_CID_CAM_JPEG_POSTVIEW_OFFSET (V4L2_CID_PRIVATE_BASE + 36) +#define V4L2_CID_CAM_JPEG_QUALITY (V4L2_CID_PRIVATE_BASE + 37) + +#define TPATTERN_COLORBAR 1 +#define TPATTERN_HORIZONTAL 2 +#define TPATTERN_VERTICAL 3 + +#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') + +/* FOURCC for FIMC specific */ +#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') +#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') +#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') +#define V4L2_PIX_FMT_NV12T v4l2_fourcc('T', 'V', '1', '2') +/* + * U S E R D E F I N E D T Y P E S + * + */ + +struct fimc_buffer { + void *start; + size_t length; +}; + +struct yuv_fmt_list { + const char *name; + const char *desc; + unsigned int fmt; + int depth; + int planes; +}; + +//s1 [Apply factory standard] +struct camsensor_date_info { + unsigned int year; + unsigned int month; + unsigned int date; +}; + +class SecCamera : public virtual RefBase { +public: + + enum CAMERA_ID { + CAMERA_ID_BACK = 0, + CAMERA_ID_FRONT = 1, + }; + + enum JPEG_QUALITY { + JPEG_QUALITY_ECONOMY = 0, + JPEG_QUALITY_NORMAL = 50, + JPEG_QUALITY_SUPERFINE = 100, + JPEG_QUALITY_MAX, + }; + + enum OBJECT_TRACKING { + OBJECT_TRACKING_OFF, + OBJECT_TRACKING_ON, + OBJECT_TRACKING_MAX, + }; + + /*VT call*/ + enum VT_MODE { + VT_MODE_OFF, + VT_MODE_ON, + VT_MODE_MAX, + }; + + /*Camera sensor mode - Camcorder fix fps*/ + enum SENSOR_MODE { + SENSOR_MODE_CAMERA, + SENSOR_MODE_MOVIE, + }; + + /*Camera Shot mode*/ + enum SHOT_MODE { + SHOT_MODE_SINGLE = 0, + SHOT_MODE_CONTINUOUS = 1, + SHOT_MODE_PANORAMA = 2, + SHOT_MODE_SMILE = 3, + SHOT_MODE_SELF = 6, + }; + + enum CHK_DATALINE { + CHK_DATALINE_OFF, + CHK_DATALINE_ON, + CHK_DATALINE_MAX, + }; + + int m_touch_af_start_stop; + + SecCamera(); + virtual ~SecCamera(); + + static SecCamera* createInstance(void) + { + static SecCamera singleton; + return &singleton; + } + status_t dump(int fd); + + int getCameraId(void); + + int startPreview(void); + int stopPreview(void); + + int startRecord(void); + int stopRecord(void); + int getRecordFrame(void); + int releaseRecordFrame(int index); + unsigned int getRecPhyAddrY(int); + unsigned int getRecPhyAddrC(int); + + int getPreview(void); + int setPreviewSize(int width, int height, int pixel_format); + int getPreviewSize(int *width, int *height, int *frame_size); + int getPreviewMaxSize(int *width, int *height); + int getPreviewPixelFormat(void); + int setPreviewImage(int index, unsigned char *buffer, int size); + + int setSnapshotSize(int width, int height); + int getSnapshotSize(int *width, int *height, int *frame_size); + int getSnapshotMaxSize(int *width, int *height); + int setSnapshotPixelFormat(int pixel_format); + int getSnapshotPixelFormat(void); + + unsigned char* getJpeg(unsigned char *snapshot_data, int snapshot_size, int *size); + unsigned char* yuv2Jpeg(unsigned char *raw_data, int raw_size, + int *jpeg_size, + int width, int height, int pixel_format); + + int setJpegThumbnailSize(int width, int height); + int getJpegThumbnailSize(int *width, int *height); + + int setAutofocus(void); + int zoomIn(void); + int zoomOut(void); + + int setVerticalMirror(void); + int setHorizontalMirror(void); + + int setWhiteBalance(int white_balance); + int getWhiteBalance(void); + + int setBrightness(int brightness); + int getBrightness(void); + + int setImageEffect(int image_effect); + int getImageEffect(void); + + int setSceneMode(int scene_mode); + int getSceneMode(void); + + int setFlashMode(int flash_mode); + int getFlashMode(void); + + int setMetering(int metering_value); + int getMetering(void); + + int setISO(int iso_value); + int getISO(void); + + int setContrast(int contrast_value); + int getContrast(void); + + int setSaturation(int saturation_value); + int getSaturation(void); + + int setSharpness(int sharpness_value); + int getSharpness(void); + + int setJpegQuality(int jpeg_qality); + int getJpegQuality(void); + + int setZoom(int zoom_level); + int getZoom(void); + + int setObjectTracking(int object_tracking); + int getObjectTracking(void); + int getObjectTrackingStatus(void); + + int getAutosceneStatus(void); + + int setFocusMode(int focus_mode); + int getFocusMode(void); + + int cancelAutofocus(void); + int setObjectPosition(int x, int y); + int setObjectTrackingStartStop(int start_stop); + int setTouchAFStartStop(int start_stop); + int getAutoFocusResult(void); + int getPostview(void); + int setRecordingSize(int width, int height); + int setExifOrientationInfo(int orientationInfo); + int setSnapshotCmd(void); + int endSnapshot(void); + int setCameraSensorReset(void); + int setSensorMode(int sensor_mode); /* Camcorder fix fps */ + int setShotMode(int shot_mode); /* Shot mode */ + /*VT call*/ + int setVTmode(int vtmode); + int getVTmode(void); + int setBlur(int blur_level); + int getBlur(void); + int setDataLineCheck(int chk_dataline); + int getDataLineCheck(void); + int setDataLineCheckStop(void); + int setDefultIMEI(int imei); + int getDefultIMEI(void); + const __u8* getCameraSensorName(void); + int previewPoll(bool preview); +#ifdef ENABLE_ESD_PREVIEW_CHECK + int getCameraSensorESDStatus(void); +#endif // ENABLE_ESD_PREVIEW_CHECK + + int setFrameRate(int frame_rate); + unsigned char* getJpeg(int*, unsigned int*); + int getSnapshotAndJpeg(unsigned char *yuv_buf, unsigned char *jpeg_buf, + unsigned int *output_size); + int getExif(unsigned char *pExifDst, unsigned char *pThumbSrc); + + void getPostViewConfig(int*, int*, int*); + void getThumbnailConfig(int *width, int *height, int *size); + + int getPostViewOffset(void); + int getCameraFd(void); + int getJpegFd(void); + void SetJpgAddr(unsigned char *addr); + unsigned int getPhyAddrY(int); + unsigned int getPhyAddrC(int); + void pausePreview(); + int initCamera(int index); + void DeinitCamera(); + static void setJpegRatio(double ratio) + { + if((ratio < 0) || (ratio > 1)) + return; + + jpeg_ratio = ratio; + } + + static double getJpegRatio() + { + return jpeg_ratio; + } + + static void setInterleaveDataSize(int x) + { + interleaveDataSize = x; + } + + static int getInterleaveDataSize() + { + return interleaveDataSize; + } + + static void setJpegLineLength(int x) + { + jpegLineLength = x; + } + + static int getJpegLineLength() + { + return jpegLineLength; + } + + +private: + v4l2_streamparm m_streamparm; + struct sec_cam_parm *m_params; + int m_flag_init; + + int m_camera_id; + + int m_cam_fd; + + int m_cam_fd2; + struct pollfd m_events_c2; + int m_flag_record_start; + + int m_preview_v4lformat; + int m_preview_width; + int m_preview_height; + int m_preview_max_width; + int m_preview_max_height; + + int m_snapshot_v4lformat; + int m_snapshot_width; + int m_snapshot_height; + int m_snapshot_max_width; + int m_snapshot_max_height; + + int m_angle; + int m_zoom_level; + int m_object_tracking; + int m_object_tracking_start_stop; + int m_recording_width; + int m_recording_height; + int m_vtmode; + int m_sensor_mode; /*Camcorder fix fps */ + int m_shot_mode; /* Shot mode */ + int m_exif_orientation; + int m_blur_level; + int m_chk_dataline; + int m_default_imei; + int m_camera_af_flag; + + int m_flag_camera_start; + + int m_jpeg_fd; + int m_jpeg_thumbnail_width; + int m_jpeg_thumbnail_height; + int m_jpeg_quality; + + int m_postview_offset; + +#ifdef ENABLE_ESD_PREVIEW_CHECK + int m_esd_check_count; +#endif // ENABLE_ESD_PREVIEW_CHECK + + exif_attribute_t mExifInfo; + + struct fimc_buffer m_capture_buf; + struct pollfd m_events_c; + + inline int m_frameSize(int format, int width, int height); + + void setExifChangedAttribute(); + void setExifFixedAttribute(); + void resetCamera(); + + static double jpeg_ratio; + static int interleaveDataSize; + static int jpegLineLength; +}; + +extern unsigned long measure_time(struct timeval *start, struct timeval *stop); + +}; // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_SEC_H diff --git a/libcamera/SecCameraHWInterface.cpp b/libcamera/SecCameraHWInterface.cpp new file mode 100755 index 0000000..50da359 --- /dev/null +++ b/libcamera/SecCameraHWInterface.cpp @@ -0,0 +1,2383 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** Copyright 2010, Samsung Electronics Co. LTD +** Copyright 2011, The CyanogenMod 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_NDEBUG 0 +#define LOG_TAG "CameraHardwareSec" +#include + +#include "SecCameraHWInterface.h" +#include +#include +#include +#include +#include + +#define VIDEO_COMMENT_MARKER_H 0xFFBE +#define VIDEO_COMMENT_MARKER_L 0xFFBF +#define VIDEO_COMMENT_MARKER_LENGTH 4 +#define JPEG_EOI_MARKER 0xFFD9 +#define HIBYTE(x) (((x) >> 8) & 0xFF) +#define LOBYTE(x) ((x) & 0xFF) + +#define BACK_CAMERA_AUTO_FOCUS_DISTANCES_STR "0.10,1.20,Infinity" +#define BACK_CAMERA_MACRO_FOCUS_DISTANCES_STR "0.10,0.20,Infinity" +#define BACK_CAMERA_INFINITY_FOCUS_DISTANCES_STR "0.10,1.20,Infinity" +#define FRONT_CAMERA_FOCUS_DISTANCES_STR "0.20,0.25,Infinity" + +// FIXME: +// -- The actual preview color is set to YV12. The preview frames +// returned via preview callback must be generated by color +// conversion if the requested preview color format for the +// preview frames is _not_ YV12. The reason that YV12 is used +// for actual preview is because that is the only color format +// supported by gralloc. Matching the preview cor format with +// gralloc color format improves performance since no color +// conversion is needed for preview. +// +// -- we only support two preview color formats that client +// applications can set: NV21 and YUV420/YV12. + +namespace android { + +struct addrs { + uint32_t type; // make sure that this is 4 byte. + unsigned int addr_y; + unsigned int addr_cbcr; + unsigned int buf_index; + unsigned int reserved; +}; + +struct addrs_cap { + unsigned int addr_y; + unsigned int width; + unsigned int height; +}; + +static const int INITIAL_SKIP_FRAME = 3; +static const int EFFECT_SKIP_FRAME = 1; + +gralloc_module_t const* CameraHardwareSec::mGrallocHal; + +CameraHardwareSec::CameraHardwareSec(int cameraId, camera_device_t *dev) + : + mCaptureInProgress(false), + mParameters(), + mCameraSensorName(NULL), + mSkipFrame(0), + mNotifyCb(0), + mDataCb(0), + mDataCbTimestamp(0), + mCallbackCookie(0), + mMsgEnabled(0), + mRecordRunning(false), + mPostViewWidth(0), + mPostViewHeight(0), + mPostViewSize(0), + mHalDevice(dev) +{ + LOGV("%s :", __func__); + int ret = 0; + + mPreviewWindow = NULL; + mSecCamera = SecCamera::createInstance(); + + mRawHeap = NULL; + mPreviewHeap = NULL; + mRecordHeap = NULL; + + if (!mGrallocHal) { + ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const hw_module_t **)&mGrallocHal); + if (ret) + LOGE("ERR(%s):Fail on loading gralloc HAL", __func__); + } + + ret = mSecCamera->initCamera(cameraId); + if (ret < 0) { + LOGE("ERR(%s):Fail on mSecCamera init", __func__); + } + + mSecCamera->getPostViewConfig(&mPostViewWidth, &mPostViewHeight, &mPostViewSize); + LOGV("mPostViewWidth = %d mPostViewHeight = %d mPostViewSize = %d", + mPostViewWidth,mPostViewHeight,mPostViewSize); + + initDefaultParameters(cameraId); + + mExitAutoFocusThread = false; + mExitPreviewThread = false; + /* whether the PreviewThread is active in preview or stopped. we + * create the thread but it is initially in stopped state. + */ + mPreviewRunning = false; + mPreviewStartDeferred = false; + mPreviewThread = new PreviewThread(this); + mAutoFocusThread = new AutoFocusThread(this); + mPictureThread = new PictureThread(this); +} + +int CameraHardwareSec::getCameraId() const +{ + return mSecCamera->getCameraId(); +} + +void CameraHardwareSec::initDefaultParameters(int cameraId) +{ + if (mSecCamera == NULL) { + LOGE("ERR(%s):mSecCamera object is NULL", __func__); + return; + } + + CameraParameters p; + CameraParameters ip; + + mCameraSensorName = mSecCamera->getCameraSensorName(); + LOGV("CameraSensorName: %s", mCameraSensorName); + + int preview_max_width = 0; + int preview_max_height = 0; + int snapshot_max_width = 0; + int snapshot_max_height = 0; + + if (cameraId == SecCamera::CAMERA_ID_BACK) { + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, + "1024x600,800x600,720x480,176x144"); + p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, + "2048x1536,2048x1232,1600x1200,1600x960,1024x600,800x600"); + } else { + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, + "640x480,320x240,176x144"); + p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, + "640x480"); + } + + p.getSupportedPreviewSizes(mSupportedPreviewSizes); + + // If these fail, then we are using an invalid cameraId and we'll leave the + // sizes at zero to catch the error. + if (mSecCamera->getPreviewMaxSize(&preview_max_width, + &preview_max_height) < 0) + LOGE("getPreviewMaxSize fail (%d / %d) \n", + preview_max_width, preview_max_height); + if (mSecCamera->getSnapshotMaxSize(&snapshot_max_width, + &snapshot_max_height) < 0) + LOGE("getSnapshotMaxSize fail (%d / %d) \n", + snapshot_max_width, snapshot_max_height); + String8 previewColorString; + previewColorString = CameraParameters::PIXEL_FORMAT_YUV420SP; + previewColorString.append(","); + previewColorString.append(CameraParameters::PIXEL_FORMAT_YUV420P); + p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP); + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, previewColorString.string()); + p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, CameraParameters::PIXEL_FORMAT_YUV420P); + p.setPreviewSize(preview_max_width, preview_max_height); + + p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG); + p.setPictureSize(snapshot_max_width, snapshot_max_height); + p.set(CameraParameters::KEY_JPEG_QUALITY, "100"); // maximum quality + p.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS, + CameraParameters::PIXEL_FORMAT_JPEG); + + String8 parameterString; + + if (cameraId == SecCamera::CAMERA_ID_BACK) { + parameterString = CameraParameters::FOCUS_MODE_AUTO; + parameterString.append(","); + parameterString.append(CameraParameters::FOCUS_MODE_INFINITY); + parameterString.append(","); + parameterString.append(CameraParameters::FOCUS_MODE_MACRO); + p.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, + parameterString.string()); + p.set(CameraParameters::KEY_FOCUS_MODE, + CameraParameters::FOCUS_MODE_AUTO); + p.set(CameraParameters::KEY_FOCUS_DISTANCES, + BACK_CAMERA_AUTO_FOCUS_DISTANCES_STR); + p.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, + "320x240,0x0"); + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, "320"); + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, "240"); + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, "30"); + p.setPreviewFrameRate(30); + } else { + parameterString = CameraParameters::FOCUS_MODE_FIXED; + p.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, + parameterString.string()); + p.set(CameraParameters::KEY_FOCUS_MODE, + CameraParameters::FOCUS_MODE_FIXED); + p.set(CameraParameters::KEY_FOCUS_DISTANCES, + FRONT_CAMERA_FOCUS_DISTANCES_STR); + p.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, + "160x120,0x0"); + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, "160"); + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, "120"); + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, "15"); + p.setPreviewFrameRate(15); + } + + parameterString = CameraParameters::EFFECT_NONE; + parameterString.append(","); + parameterString.append(CameraParameters::EFFECT_MONO); + parameterString.append(","); + parameterString.append(CameraParameters::EFFECT_NEGATIVE); + parameterString.append(","); + parameterString.append(CameraParameters::EFFECT_SEPIA); + p.set(CameraParameters::KEY_SUPPORTED_EFFECTS, parameterString.string()); + + if (cameraId == SecCamera::CAMERA_ID_BACK) { + parameterString = CameraParameters::FLASH_MODE_ON; + parameterString.append(","); + parameterString.append(CameraParameters::FLASH_MODE_OFF); + parameterString.append(","); + parameterString.append(CameraParameters::FLASH_MODE_AUTO); + parameterString.append(","); + parameterString.append(CameraParameters::FLASH_MODE_TORCH); + p.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, + parameterString.string()); + p.set(CameraParameters::KEY_FLASH_MODE, + CameraParameters::FLASH_MODE_OFF); + + parameterString = CameraParameters::SCENE_MODE_AUTO; + parameterString.append(","); + parameterString.append(CameraParameters::SCENE_MODE_PORTRAIT); + parameterString.append(","); + parameterString.append(CameraParameters::SCENE_MODE_LANDSCAPE); + parameterString.append(","); + parameterString.append(CameraParameters::SCENE_MODE_NIGHT); + parameterString.append(","); + parameterString.append(CameraParameters::SCENE_MODE_BEACH); + parameterString.append(","); + parameterString.append(CameraParameters::SCENE_MODE_SNOW); + parameterString.append(","); + parameterString.append(CameraParameters::SCENE_MODE_SUNSET); + parameterString.append(","); + parameterString.append(CameraParameters::SCENE_MODE_FIREWORKS); + parameterString.append(","); + parameterString.append(CameraParameters::SCENE_MODE_SPORTS); + parameterString.append(","); + parameterString.append(CameraParameters::SCENE_MODE_PARTY); + parameterString.append(","); + parameterString.append(CameraParameters::SCENE_MODE_CANDLELIGHT); + //p.set(CameraParameters::KEY_SUPPORTED_SCENE_MODES, + // parameterString.string()); + p.set(CameraParameters::KEY_SCENE_MODE, + CameraParameters::SCENE_MODE_AUTO); + + /* we have two ranges, 4-30fps for night mode and + * 15-30fps for all others + */ + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(15000,30000)"); + p.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "15000,30000"); + + p.set(CameraParameters::KEY_FOCAL_LENGTH, "2.78"); + } else { + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(7500,30000)"); + p.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "7500,30000"); + + p.set(CameraParameters::KEY_FOCAL_LENGTH, "0.9"); + } + + parameterString = CameraParameters::WHITE_BALANCE_AUTO; + parameterString.append(","); + parameterString.append(CameraParameters::WHITE_BALANCE_INCANDESCENT); + parameterString.append(","); + parameterString.append(CameraParameters::WHITE_BALANCE_FLUORESCENT); + parameterString.append(","); + parameterString.append(CameraParameters::WHITE_BALANCE_DAYLIGHT); + parameterString.append(","); + parameterString.append(CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT); + p.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE, + parameterString.string()); + + ip.set("sharpness-min", 0); + ip.set("sharpness-max", 4); + ip.set("saturation-min", 0); + ip.set("saturation-max", 4); + ip.set("contrast-min", 0); + ip.set("contrast-max", 4); + + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, "100"); + + p.set(CameraParameters::KEY_ROTATION, 0); + p.set(CameraParameters::KEY_WHITE_BALANCE, CameraParameters::WHITE_BALANCE_AUTO); + + p.set(CameraParameters::KEY_EFFECT, CameraParameters::EFFECT_NONE); + + ip.set("sharpness", SHARPNESS_DEFAULT); + ip.set("contrast", CONTRAST_DEFAULT); + ip.set("saturation", SATURATION_DEFAULT); + ip.set("iso", "auto"); + ip.set("metering", "center"); + + ip.set("chk_dataline", 0); + if (cameraId == SecCamera::CAMERA_ID_FRONT) { + ip.set("vtmode", 0); + ip.set("blur", 0); + } + + p.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "51.2"); + p.set(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, "39.4"); + + p.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, "0"); + p.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, "4"); + p.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, "-4"); + p.set(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, "0.5"); + + mParameters = p; + mInternalParameters = ip; + + /* make sure mSecCamera has all the settings we do. applications + * aren't required to call setParameters themselves (only if they + * want to change something. + */ + setParameters(p); + mSecCamera->setISO(ISO_AUTO); + mSecCamera->setMetering(METERING_CENTER); + mSecCamera->setContrast(CONTRAST_DEFAULT); + mSecCamera->setSharpness(SHARPNESS_DEFAULT); + mSecCamera->setSaturation(SATURATION_DEFAULT); + if (cameraId == SecCamera::CAMERA_ID_BACK) + mSecCamera->setFrameRate(30); + else + mSecCamera->setFrameRate(15); +} + +CameraHardwareSec::~CameraHardwareSec() +{ + LOGV("%s", __func__); + mSecCamera->DeinitCamera(); +} + +status_t CameraHardwareSec::setPreviewWindow(preview_stream_ops *w) +{ + int min_bufs; + + mPreviewWindow = w; + LOGV("%s: mPreviewWindow %p", __func__, mPreviewWindow); + + if (!w) { + LOGE("preview window is NULL!"); + return OK; + } + + mPreviewLock.lock(); + + if (mPreviewRunning && !mPreviewStartDeferred) { + LOGI("stop preview (window change)"); + stopPreviewInternal(); + } + + if (w->get_min_undequeued_buffer_count(w, &min_bufs)) { + LOGE("%s: could not retrieve min undequeued buffer count", __func__); + return INVALID_OPERATION; + } + + if (min_bufs >= kBufferCount) { + LOGE("%s: min undequeued buffer count %d is too high (expecting at most %d)", __func__, + min_bufs, kBufferCount - 1); + } + + LOGV("%s: setting buffer count to %d", __func__, kBufferCount); + if (w->set_buffer_count(w, kBufferCount)) { + LOGE("%s: could not set buffer count", __func__); + return INVALID_OPERATION; + } + + int preview_width; + int preview_height; + mParameters.getPreviewSize(&preview_width, &preview_height); + int hal_pixel_format = HAL_PIXEL_FORMAT_YV12; + + const char *str_preview_format = mParameters.getPreviewFormat(); + LOGV("%s: preview format %s", __func__, str_preview_format); + + if (w->set_usage(w, GRALLOC_USAGE_SW_WRITE_OFTEN)) { + LOGE("%s: could not set usage on gralloc buffer", __func__); + return INVALID_OPERATION; + } + + if (w->set_buffers_geometry(w, + preview_width, preview_height, + hal_pixel_format)) { + LOGE("%s: could not set buffers geometry to %s", + __func__, str_preview_format); + return INVALID_OPERATION; + } + + if (mPreviewRunning && mPreviewStartDeferred) { + LOGV("start/resume preview"); + status_t ret = startPreviewInternal(); + if (ret == OK) { + mPreviewStartDeferred = false; + mPreviewCondition.signal(); + } + } + mPreviewLock.unlock(); + + return OK; +} + +void CameraHardwareSec::setCallbacks(camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user) +{ + mNotifyCb = notify_cb; + mDataCb = data_cb; + mDataCbTimestamp = data_cb_timestamp; + mGetMemoryCb = get_memory; + mCallbackCookie = user; +} + +void CameraHardwareSec::enableMsgType(int32_t msgType) +{ + LOGV("%s : msgType = 0x%x, mMsgEnabled before = 0x%x", + __func__, msgType, mMsgEnabled); + mMsgEnabled |= msgType; + + LOGV("%s : mMsgEnabled = 0x%x", __func__, mMsgEnabled); +} + +void CameraHardwareSec::disableMsgType(int32_t msgType) +{ + LOGV("%s : msgType = 0x%x, mMsgEnabled before = 0x%x", + __func__, msgType, mMsgEnabled); + mMsgEnabled &= ~msgType; + LOGV("%s : mMsgEnabled = 0x%x", __func__, mMsgEnabled); +} + +bool CameraHardwareSec::msgTypeEnabled(int32_t msgType) +{ + return (mMsgEnabled & msgType); +} + +// --------------------------------------------------------------------------- +void CameraHardwareSec::setSkipFrame(int frame) +{ + Mutex::Autolock lock(mSkipFrameLock); + if (frame < mSkipFrame) + return; + + mSkipFrame = frame; +} + +int CameraHardwareSec::previewThreadWrapper() +{ + LOGI("%s: starting", __func__); + while (1) { + mPreviewLock.lock(); + while (!mPreviewRunning) { + LOGI("%s: calling mSecCamera->stopPreview() and waiting", __func__); + mSecCamera->stopPreview(); + /* signal that we're stopping */ + mPreviewStoppedCondition.signal(); + mPreviewCondition.wait(mPreviewLock); + LOGI("%s: return from wait", __func__); + } + mPreviewLock.unlock(); + + if (mExitPreviewThread) { + LOGI("%s: exiting", __func__); + mSecCamera->stopPreview(); + return 0; + } + previewThread(); + } +} + +int CameraHardwareSec::previewThread() +{ + int index; + nsecs_t timestamp; + unsigned int phyYAddr; + unsigned int phyCAddr; + struct addrs *addrs; + + index = mSecCamera->getPreview(); + if (index < 0) { + LOGE("ERR(%s):Fail on SecCamera->getPreview()", __func__); + return UNKNOWN_ERROR; + } + +// LOGV("%s: index %d", __func__, index); + + mSkipFrameLock.lock(); + if (mSkipFrame > 0) { + mSkipFrame--; + mSkipFrameLock.unlock(); + LOGV("%s: index %d skipping frame", __func__, index); + return NO_ERROR; + } + mSkipFrameLock.unlock(); + + timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + + phyYAddr = mSecCamera->getPhyAddrY(index); + phyCAddr = mSecCamera->getPhyAddrC(index); + + if (phyYAddr == 0xffffffff || phyCAddr == 0xffffffff) { + LOGE("ERR(%s):Fail on SecCamera getPhyAddr Y addr = %0x C addr = %0x", + __func__, phyYAddr, phyCAddr); + return UNKNOWN_ERROR; + } + + int width, height, frame_size, offset; + + mSecCamera->getPreviewSize(&width, &height, &frame_size); + + offset = frame_size * index; + + if (mPreviewWindow && mGrallocHal) { + buffer_handle_t *buf_handle; + int stride; + if (0 != mPreviewWindow->dequeue_buffer(mPreviewWindow, &buf_handle, &stride)) { + LOGE("Could not dequeue gralloc buffer!\n"); + goto callbacks; + } + + void *vaddr; + if (!mGrallocHal->lock(mGrallocHal, + *buf_handle, + GRALLOC_USAGE_SW_WRITE_OFTEN, + 0, 0, width, height, &vaddr)) { + char *frame = ((char *)mPreviewHeap->data) + offset; + + // the code below assumes YUV, not RGB + { + int h; + char *src = frame; + char *ptr = (char *)vaddr; + + // Copy the Y plane, while observing the stride + for (h = 0; h < height; h++) { + memcpy(ptr, src, width); + ptr += stride; + src += width; + } + + { + // U + char *v = ptr; + ptr += stride * height / 4; + for (h = 0; h < height / 2; h++) { + memcpy(ptr, src, width / 2); + ptr += stride / 2; + src += width / 2; + } + // V + ptr = v; + for (h = 0; h < height / 2; h++) { + memcpy(ptr, src, width / 2); + ptr += stride / 2; + src += width / 2; + } + } + } + + mGrallocHal->unlock(mGrallocHal, *buf_handle); + } + else + LOGE("%s: could not obtain gralloc buffer", __func__); + + if (0 != mPreviewWindow->enqueue_buffer(mPreviewWindow, buf_handle)) { + LOGE("Could not enqueue gralloc buffer!\n"); + goto callbacks; + } + } + +callbacks: + // Notify the client of a new frame. + if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) { + const char * preview_format = mParameters.getPreviewFormat(); + if (!strcmp(preview_format, CameraParameters::PIXEL_FORMAT_YUV420SP)) { + // Color conversion from YUV420 to NV21 + char *vu = ((char *)mPreviewHeap->data) + offset + width * height; + const int uv_size = (width * height) >> 1; + char saved_uv[uv_size]; + memcpy(saved_uv, vu, uv_size); + char *u = saved_uv; + char *v = u + (uv_size >> 1); + + int h = 0; + while (h < width * height / 4) { + *vu++ = *v++; + *vu++ = *u++; + ++h; + } + } + mDataCb(CAMERA_MSG_PREVIEW_FRAME, mPreviewHeap, index, NULL, mCallbackCookie); + } + + Mutex::Autolock lock(mRecordLock); + if (mRecordRunning == true) { + index = mSecCamera->getRecordFrame(); + if (index < 0) { + LOGE("ERR(%s):Fail on SecCamera->getRecord()", __func__); + return UNKNOWN_ERROR; + } + + phyYAddr = mSecCamera->getRecPhyAddrY(index); + phyCAddr = mSecCamera->getRecPhyAddrC(index); + + if (phyYAddr == 0xffffffff || phyCAddr == 0xffffffff) { + LOGE("ERR(%s):Fail on SecCamera getRectPhyAddr Y addr = %0x C addr = %0x", __func__, + phyYAddr, phyCAddr); + return UNKNOWN_ERROR; + } + + addrs = (struct addrs *)mRecordHeap->data; + + addrs[index].type = kMetadataBufferTypeCameraSource; + addrs[index].addr_y = phyYAddr; + addrs[index].addr_cbcr = phyCAddr; + addrs[index].buf_index = index; + + // Notify the client of a new frame. + if (mMsgEnabled & CAMERA_MSG_VIDEO_FRAME) { + mDataCbTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, + mRecordHeap, index, mCallbackCookie); + } else { + mSecCamera->releaseRecordFrame(index); + } + } + + return NO_ERROR; +} + +status_t CameraHardwareSec::startPreview() +{ + int ret = 0; //s1 [Apply factory standard] + + LOGV("%s :", __func__); + + if (waitCaptureCompletion() != NO_ERROR) { + return TIMED_OUT; + } + + mPreviewLock.lock(); + if (mPreviewRunning) { + // already running + LOGE("%s : preview thread already running", __func__); + mPreviewLock.unlock(); + return INVALID_OPERATION; + } + + mPreviewRunning = true; + mPreviewStartDeferred = false; + + if (!mPreviewWindow) { + LOGI("%s : deferring", __func__); + mPreviewStartDeferred = true; + mPreviewLock.unlock(); + return NO_ERROR; + } + + ret = startPreviewInternal(); + if (ret == OK) + mPreviewCondition.signal(); + + mPreviewLock.unlock(); + return ret; +} + +status_t CameraHardwareSec::startPreviewInternal() +{ + LOGV("%s", __func__); + + int ret = mSecCamera->startPreview(); + LOGV("%s : mSecCamera->startPreview() returned %d", __func__, ret); + + if (ret < 0) { + LOGE("ERR(%s):Fail on mSecCamera->startPreview()", __func__); + return UNKNOWN_ERROR; + } + + setSkipFrame(INITIAL_SKIP_FRAME); + + int width, height, frame_size; + + mSecCamera->getPreviewSize(&width, &height, &frame_size); + + LOGD("mPreviewHeap(fd(%d), size(%d), width(%d), height(%d))", + mSecCamera->getCameraFd(), frame_size, width, height); + if (mPreviewHeap) { + mPreviewHeap->release(mPreviewHeap); + mPreviewHeap = 0; + } + + mPreviewHeap = mGetMemoryCb((int)mSecCamera->getCameraFd(), + frame_size, + kBufferCount, + 0); // no cookie + + mSecCamera->getPostViewConfig(&mPostViewWidth, &mPostViewHeight, &mPostViewSize); + LOGV("CameraHardwareSec: mPostViewWidth = %d mPostViewHeight = %d mPostViewSize = %d", + mPostViewWidth,mPostViewHeight,mPostViewSize); + + return NO_ERROR; +} + +void CameraHardwareSec::stopPreviewInternal() +{ + LOGV("%s :", __func__); + + /* request that the preview thread stop. */ + if (mPreviewRunning) { + mPreviewRunning = false; + if (!mPreviewStartDeferred) { + mPreviewCondition.signal(); + /* wait until preview thread is stopped */ + mPreviewStoppedCondition.wait(mPreviewLock); + } + else + LOGV("%s : preview running but deferred, doing nothing", __func__); + } else + LOGI("%s : preview not running, doing nothing", __func__); +} + +void CameraHardwareSec::stopPreview() +{ + LOGV("%s :", __func__); + + /* request that the preview thread stop. */ + mPreviewLock.lock(); + stopPreviewInternal(); + mPreviewLock.unlock(); +} + +bool CameraHardwareSec::previewEnabled() +{ + Mutex::Autolock lock(mPreviewLock); + LOGV("%s : %d", __func__, mPreviewRunning); + return mPreviewRunning; +} + +// --------------------------------------------------------------------------- + +status_t CameraHardwareSec::startRecording() +{ + LOGV("%s :", __func__); + + Mutex::Autolock lock(mRecordLock); + + if (mRecordHeap) { + mRecordHeap->release(mRecordHeap); + mRecordHeap = 0; + } + mRecordHeap = mGetMemoryCb(-1, sizeof(struct addrs), kBufferCount, NULL); + if (!mRecordHeap) { + LOGE("ERR(%s): Record heap creation fail", __func__); + return UNKNOWN_ERROR; + } + + if (mRecordRunning == false) { + if (mSecCamera->startRecord() < 0) { + LOGE("ERR(%s):Fail on mSecCamera->startRecord()", __func__); + return UNKNOWN_ERROR; + } + mRecordRunning = true; + } + return NO_ERROR; +} + +void CameraHardwareSec::stopRecording() +{ + LOGV("%s :", __func__); + + Mutex::Autolock lock(mRecordLock); + + if (mRecordRunning == true) { + if (mSecCamera->stopRecord() < 0) { + LOGE("ERR(%s):Fail on mSecCamera->stopRecord()", __func__); + return; + } + mRecordRunning = false; + } +} + +bool CameraHardwareSec::recordingEnabled() +{ + LOGV("%s :", __func__); + + return mRecordRunning; +} + +void CameraHardwareSec::releaseRecordingFrame(const void *opaque) +{ + struct addrs *addrs = (struct addrs *)opaque; + mSecCamera->releaseRecordFrame(addrs->buf_index); +} + +// --------------------------------------------------------------------------- + +int CameraHardwareSec::autoFocusThread() +{ + int count =0; + int af_status =0 ; + + LOGV("%s : starting", __func__); + + /* block until we're told to start. we don't want to use + * a restartable thread and requestExitAndWait() in cancelAutoFocus() + * because it would cause deadlock between our callbacks and the + * caller of cancelAutoFocus() which both want to grab the same lock + * in CameraServices layer. + */ + mFocusLock.lock(); + /* check early exit request */ + if (mExitAutoFocusThread) { + mFocusLock.unlock(); + LOGV("%s : exiting on request0", __func__); + return NO_ERROR; + } + mFocusCondition.wait(mFocusLock); + /* check early exit request */ + if (mExitAutoFocusThread) { + mFocusLock.unlock(); + LOGV("%s : exiting on request1", __func__); + return NO_ERROR; + } + mFocusLock.unlock(); + + LOGV("%s : calling setAutoFocus", __func__); + if (mSecCamera->setAutofocus() < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setAutofocus()", __func__); + return UNKNOWN_ERROR; + } + + af_status = mSecCamera->getAutoFocusResult(); + + if (af_status == 0x01) { + LOGV("%s : AF Success!!", __func__); + if (mMsgEnabled & CAMERA_MSG_FOCUS) + mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie); + } else if (af_status == 0x02) { + LOGV("%s : AF Cancelled !!", __func__); + if (mMsgEnabled & CAMERA_MSG_FOCUS) { + /* CAMERA_MSG_FOCUS only takes a bool. true for + * finished and false for failure. cancel is still + * considered a true result. + */ + mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie); + } + } else { + LOGV("%s : AF Fail !!", __func__); + LOGV("%s : mMsgEnabled = 0x%x", __func__, mMsgEnabled); + if (mMsgEnabled & CAMERA_MSG_FOCUS) + mNotifyCb(CAMERA_MSG_FOCUS, false, 0, mCallbackCookie); + } + + LOGV("%s : exiting with no error", __func__); + return NO_ERROR; +} + +status_t CameraHardwareSec::autoFocus() +{ + LOGV("%s :", __func__); + /* signal autoFocusThread to run once */ + mFocusCondition.signal(); + return NO_ERROR; +} + +/* 2009.10.14 by icarus for added interface */ +status_t CameraHardwareSec::cancelAutoFocus() +{ + LOGV("%s :", __func__); + + // cancelAutoFocus should be allowed after preview is started. But if + // the preview is deferred, cancelAutoFocus will fail. Ignore it if that is + // the case. + if (mPreviewRunning && mPreviewStartDeferred) return NO_ERROR; + + if (mSecCamera->cancelAutofocus() < 0) { + LOGE("ERR(%s):Fail on mSecCamera->cancelAutofocus()", __func__); + return UNKNOWN_ERROR; + } + + return NO_ERROR; +} + +int CameraHardwareSec::save_jpeg( unsigned char *real_jpeg, int jpeg_size) +{ + FILE *yuv_fp = NULL; + char filename[100], *buffer = NULL; + + /* file create/open, note to "wb" */ + yuv_fp = fopen("/data/camera_dump.jpeg", "wb"); + if (yuv_fp == NULL) { + LOGE("Save jpeg file open error"); + return -1; + } + + LOGV("[BestIQ] real_jpeg size ========> %d\n", jpeg_size); + buffer = (char *) malloc(jpeg_size); + if (buffer == NULL) { + LOGE("Save YUV] buffer alloc failed"); + if (yuv_fp) + fclose(yuv_fp); + + return -1; + } + + memcpy(buffer, real_jpeg, jpeg_size); + + fflush(stdout); + + fwrite(buffer, 1, jpeg_size, yuv_fp); + + fflush(yuv_fp); + + if (yuv_fp) + fclose(yuv_fp); + if (buffer) + free(buffer); + + return 0; +} + +void CameraHardwareSec::save_postview(const char *fname, uint8_t *buf, uint32_t size) +{ + int nw; + int cnt = 0; + uint32_t written = 0; + + LOGD("opening file [%s]\n", fname); + int fd = open(fname, O_RDWR | O_CREAT); + if (fd < 0) { + LOGE("failed to create file [%s]: %s", fname, strerror(errno)); + return; + } + + LOGD("writing %d bytes to file [%s]\n", size, fname); + while (written < size) { + nw = ::write(fd, buf + written, size - written); + if (nw < 0) { + LOGE("failed to write to file %d [%s]: %s",written,fname, strerror(errno)); + break; + } + written += nw; + cnt++; + } + LOGD("done writing %d bytes to file [%s] in %d passes\n",size, fname, cnt); + ::close(fd); +} + +bool CameraHardwareSec::scaleDownYuv422(char *srcBuf, uint32_t srcWidth, uint32_t srcHeight, + char *dstBuf, uint32_t dstWidth, uint32_t dstHeight) +{ + int32_t step_x, step_y; + int32_t iXsrc, iXdst; + int32_t x, y, src_y_start_pos, dst_pos, src_pos; + + if (dstWidth % 2 != 0 || dstHeight % 2 != 0){ + LOGE("scale_down_yuv422: invalid width, height for scaling"); + return false; + } + + step_x = srcWidth / dstWidth; + step_y = srcHeight / dstHeight; + + dst_pos = 0; + for (uint32_t y = 0; y < dstHeight; y++) { + src_y_start_pos = (y * step_y * (srcWidth * 2)); + + for (uint32_t x = 0; x < dstWidth; x += 2) { + src_pos = src_y_start_pos + (x * (step_x * 2)); + + dstBuf[dst_pos++] = srcBuf[src_pos ]; + dstBuf[dst_pos++] = srcBuf[src_pos + 1]; + dstBuf[dst_pos++] = srcBuf[src_pos + 2]; + dstBuf[dst_pos++] = srcBuf[src_pos + 3]; + } + } + + return true; +} + +bool CameraHardwareSec::YUY2toNV21(void *srcBuf, void *dstBuf, uint32_t srcWidth, uint32_t srcHeight) +{ + int32_t x, y, src_y_start_pos, dst_cbcr_pos, dst_pos, src_pos; + unsigned char *srcBufPointer = (unsigned char *)srcBuf; + unsigned char *dstBufPointer = (unsigned char *)dstBuf; + + dst_pos = 0; + dst_cbcr_pos = srcWidth*srcHeight; + for (uint32_t y = 0; y < srcHeight; y++) { + src_y_start_pos = (y * (srcWidth * 2)); + + for (uint32_t x = 0; x < (srcWidth * 2); x += 2) { + src_pos = src_y_start_pos + x; + + dstBufPointer[dst_pos++] = srcBufPointer[src_pos]; + } + } + for (uint32_t y = 0; y < srcHeight; y += 2) { + src_y_start_pos = (y * (srcWidth * 2)); + + for (uint32_t x = 0; x < (srcWidth * 2); x += 4) { + src_pos = src_y_start_pos + x; + + dstBufPointer[dst_cbcr_pos++] = srcBufPointer[src_pos + 3]; + dstBufPointer[dst_cbcr_pos++] = srcBufPointer[src_pos + 1]; + } + } + + return true; +} + +int CameraHardwareSec::pictureThread() +{ + LOGV("%s :", __func__); + + int jpeg_size = 0; + int ret = NO_ERROR; + unsigned char *jpeg_data = NULL; + int postview_offset = 0; + unsigned char *postview_data = NULL; + + unsigned char *addr = NULL; + int mPostViewWidth, mPostViewHeight, mPostViewSize; + int mThumbWidth, mThumbHeight, mThumbSize; + int cap_width, cap_height, cap_frame_size; + int JpegImageSize, JpegExifSize; + + unsigned int output_size = 0; + + mSecCamera->getPostViewConfig(&mPostViewWidth, &mPostViewHeight, &mPostViewSize); + mSecCamera->getThumbnailConfig(&mThumbWidth, &mThumbHeight, &mThumbSize); + int postviewHeapSize = mPostViewSize; + mSecCamera->getSnapshotSize(&cap_width, &cap_height, &cap_frame_size); + int mJpegHeapSize; + if (mSecCamera->getCameraId() == SecCamera::CAMERA_ID_BACK) + mJpegHeapSize = cap_frame_size * SecCamera::getJpegRatio(); + else + mJpegHeapSize = cap_frame_size; + + LOG_TIME_DEFINE(0) + LOG_TIME_START(0) +// sp buffer = new MemoryBase(mRawHeap, 0, mPostViewSize + 8); + + struct addrs_cap *addrs = (struct addrs_cap *)mRawHeap->data; + + addrs[0].width = mPostViewWidth; + addrs[0].height = mPostViewHeight; + LOGV("[5B] mPostViewWidth = %d mPostViewHeight = %d\n",mPostViewWidth,mPostViewHeight); + + camera_memory_t *JpegHeap = mGetMemoryCb(-1, mJpegHeapSize, 1, 0); + sp PostviewHeap = new MemoryHeapBase(mPostViewSize); + sp ThumbnailHeap = new MemoryHeapBase(mThumbSize); + + LOG_TIME_DEFINE(1) + LOG_TIME_START(1) + + int picture_size, picture_width, picture_height; + mSecCamera->getSnapshotSize(&picture_width, &picture_height, &picture_size); + int picture_format = mSecCamera->getSnapshotPixelFormat(); + + unsigned int phyAddr; + + // Modified the shutter sound timing for Jpeg capture + if (mSecCamera->getCameraId() == SecCamera::CAMERA_ID_BACK) + mSecCamera->setSnapshotCmd(); + if (mMsgEnabled & CAMERA_MSG_SHUTTER) { + mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie); + } + + if (mSecCamera->getCameraId() == SecCamera::CAMERA_ID_BACK){ + jpeg_data = mSecCamera->getJpeg(&jpeg_size, &phyAddr); + if (jpeg_data == NULL) { + LOGE("ERR(%s):Fail on SecCamera->getSnapshot()", __func__); + ret = UNKNOWN_ERROR; + goto out; + } + } else { + if (mSecCamera->getSnapshotAndJpeg((unsigned char*)PostviewHeap->base(), + (unsigned char*)JpegHeap->data, &output_size) < 0) { + ret = UNKNOWN_ERROR; + goto out; + } + LOGI("snapshotandjpeg done\n"); + } + + LOG_TIME_END(1) + LOG_CAMERA("getSnapshotAndJpeg interval: %lu us", LOG_TIME(1)); + + if (mSecCamera->getCameraId() == SecCamera::CAMERA_ID_BACK) { + // TODO: copy postview to PostviewHeap->base() + memcpy(JpegHeap->data, jpeg_data, jpeg_size); + JpegImageSize = jpeg_size; + } else { + JpegImageSize = static_cast(output_size); + } + scaleDownYuv422((char *)PostviewHeap->base(), mPostViewWidth, mPostViewHeight, + (char *)ThumbnailHeap->base(), mThumbWidth, mThumbHeight); + + memcpy(mRawHeap->data, PostviewHeap->base(), postviewHeapSize); + + if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) { + mDataCb(CAMERA_MSG_RAW_IMAGE, mRawHeap, 0, NULL, mCallbackCookie); + } else if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE_NOTIFY) { + mNotifyCb(CAMERA_MSG_RAW_IMAGE_NOTIFY, 0, 0, mCallbackCookie); + } + + if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) { + camera_memory_t *ExifHeap = + mGetMemoryCb(-1, EXIF_FILE_SIZE + JPG_STREAM_BUF_SIZE, 1, 0); + JpegExifSize = mSecCamera->getExif((unsigned char *)ExifHeap->data, + (unsigned char *)ThumbnailHeap->base()); + + LOGV("JpegExifSize=%d", JpegExifSize); + + if (JpegExifSize < 0) { + ret = UNKNOWN_ERROR; + ExifHeap->release(ExifHeap); + goto out; + } + + camera_memory_t *mem = mGetMemoryCb(-1, JpegImageSize + JpegExifSize, 1, 0); + uint8_t *ptr = (uint8_t *) mem->data; + memcpy(ptr, JpegHeap->data, 2); ptr += 2; + memcpy(ptr, ExifHeap->data, JpegExifSize); ptr += JpegExifSize; + memcpy(ptr, (uint8_t *) JpegHeap->data + 2, JpegImageSize - 2); + mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, 0, NULL, mCallbackCookie); + mem->release(mem); + ExifHeap->release(ExifHeap); + } + + LOG_TIME_END(0) + LOG_CAMERA("pictureThread interval: %lu us", LOG_TIME(0)); + + LOGV("%s : pictureThread end", __func__); + +out: + JpegHeap->release(JpegHeap); + mSecCamera->endSnapshot(); + mCaptureLock.lock(); + mCaptureInProgress = false; + mCaptureCondition.broadcast(); + mCaptureLock.unlock(); + + return ret; +} + +status_t CameraHardwareSec::waitCaptureCompletion() { + // 5 seconds timeout + nsecs_t endTime = 5000000000LL + systemTime(SYSTEM_TIME_MONOTONIC); + Mutex::Autolock lock(mCaptureLock); + while (mCaptureInProgress) { + nsecs_t remainingTime = endTime - systemTime(SYSTEM_TIME_MONOTONIC); + if (remainingTime <= 0) { + LOGE("Timed out waiting picture thread."); + return TIMED_OUT; + } + LOGD("Waiting for picture thread to complete."); + mCaptureCondition.waitRelative(mCaptureLock, remainingTime); + } + return NO_ERROR; +} + +status_t CameraHardwareSec::takePicture() +{ + LOGV("%s :", __func__); + + stopPreview(); + + if (!mRawHeap) { + int rawHeapSize = mPostViewSize; + LOGV("mRawHeap : MemoryHeapBase(previewHeapSize(%d))", rawHeapSize); + mRawHeap = mGetMemoryCb(-1, rawHeapSize, 1, 0); + if (!mRawHeap) { + LOGE("ERR(%s): Raw heap creation fail", __func__); + } + } + + if (waitCaptureCompletion() != NO_ERROR) { + return TIMED_OUT; + } + + if (mPictureThread->run("CameraPictureThread", PRIORITY_DEFAULT) != NO_ERROR) { + LOGE("%s : couldn't run picture thread", __func__); + return INVALID_OPERATION; + } + mCaptureLock.lock(); + mCaptureInProgress = true; + mCaptureLock.unlock(); + + return NO_ERROR; +} + +status_t CameraHardwareSec::cancelPicture() +{ + LOGV("%s", __func__); + + if (mPictureThread.get()) { + LOGV("%s: waiting for picture thread to exit", __func__); + mPictureThread->requestExitAndWait(); + LOGV("%s: picture thread has exited", __func__); + } + + return NO_ERROR; +} + +bool CameraHardwareSec::CheckVideoStartMarker(unsigned char *pBuf) +{ + if (!pBuf) { + LOGE("CheckVideoStartMarker() => pBuf is NULL\n"); + return false; + } + + if (HIBYTE(VIDEO_COMMENT_MARKER_H) == * pBuf && LOBYTE(VIDEO_COMMENT_MARKER_H) == *(pBuf + 1) && + HIBYTE(VIDEO_COMMENT_MARKER_L) == *(pBuf + 2) && LOBYTE(VIDEO_COMMENT_MARKER_L) == *(pBuf + 3)) + return true; + + return false; +} + +bool CameraHardwareSec::CheckEOIMarker(unsigned char *pBuf) +{ + if (!pBuf) { + LOGE("CheckEOIMarker() => pBuf is NULL\n"); + return false; + } + + // EOI marker [FF D9] + if (HIBYTE(JPEG_EOI_MARKER) == *pBuf && LOBYTE(JPEG_EOI_MARKER) == *(pBuf + 1)) + return true; + + return false; +} + +bool CameraHardwareSec::FindEOIMarkerInJPEG(unsigned char *pBuf, int dwBufSize, int *pnJPEGsize) +{ + if (NULL == pBuf || 0 >= dwBufSize) { + LOGE("FindEOIMarkerInJPEG() => There is no contents."); + return false; + } + + unsigned char *pBufEnd = pBuf + dwBufSize; + + while (pBuf < pBufEnd) { + if (CheckEOIMarker(pBuf++)) + return true; + + (*pnJPEGsize)++; + } + + return false; +} + +status_t CameraHardwareSec::dump(int fd) const +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + const Vector args; + + if (mSecCamera != 0) { + mSecCamera->dump(fd); + mParameters.dump(fd, args); + mInternalParameters.dump(fd, args); + snprintf(buffer, 255, " preview running(%s)\n", mPreviewRunning?"true": "false"); + result.append(buffer); + } else { + result.append("No camera client yet.\n"); + } + write(fd, result.string(), result.size()); + return NO_ERROR; +} + +bool CameraHardwareSec::isSupportedPreviewSize(const int width, + const int height) const +{ + unsigned int i; + + for (i = 0; i < mSupportedPreviewSizes.size(); i++) { + if (mSupportedPreviewSizes[i].width == width && + mSupportedPreviewSizes[i].height == height) + return true; + } + + return false; +} + +bool CameraHardwareSec::isSupportedParameter(const char * const parm, + const char * const supported_parm) const +{ + const char *pStart; + const char *pEnd; + + if (!parm || !supported_parm) + return false; + + pStart = supported_parm; + + while (true) { + pEnd = strchr(pStart, ','); + if (!pEnd) { + if (!strcmp(parm, pStart)) + return true; + else + return false; + } + if (!strncmp(parm, pStart, pEnd - pStart)) { + return true; + } + pStart = pEnd + 1; + } + /* NOTREACHED */ +} + +status_t CameraHardwareSec::setParameters(const CameraParameters& params) +{ + LOGV("%s :", __func__); + + status_t ret = NO_ERROR; + + /* if someone calls us while picture thread is running, it could screw + * up the sensor quite a bit so return error. + */ + if (waitCaptureCompletion() != NO_ERROR) { + return TIMED_OUT; + } + + // preview size + int new_preview_width = 0; + int new_preview_height = 0; + params.getPreviewSize(&new_preview_width, &new_preview_height); + const char *new_str_preview_format = params.getPreviewFormat(); + LOGV("%s : new_preview_width x new_preview_height = %dx%d, format = %s", + __func__, new_preview_width, new_preview_height, new_str_preview_format); + + if (strcmp(new_str_preview_format, CameraParameters::PIXEL_FORMAT_YUV420SP) && + strcmp(new_str_preview_format, CameraParameters::PIXEL_FORMAT_YUV420P)) { + LOGE("Unsupported preview color format: %s", new_str_preview_format); + return BAD_VALUE; + } + + if (0 < new_preview_width && 0 < new_preview_height && + new_str_preview_format != NULL && + isSupportedPreviewSize(new_preview_width, new_preview_height)) { + int new_preview_format = V4L2_PIX_FMT_YUV420; + + int current_preview_width, current_preview_height, current_frame_size; + mSecCamera->getPreviewSize(¤t_preview_width, + ¤t_preview_height, + ¤t_frame_size); + int current_pixel_format = mSecCamera->getPreviewPixelFormat(); + + if (current_preview_width != new_preview_width || + current_preview_height != new_preview_height || + current_pixel_format != new_preview_format) { + if (mSecCamera->setPreviewSize(new_preview_width, new_preview_height, + new_preview_format) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setPreviewSize(width(%d), height(%d), format(%d))", + __func__, new_preview_width, new_preview_height, new_preview_format); + ret = UNKNOWN_ERROR; + } else { + if (mPreviewWindow) { + if (mPreviewRunning && !mPreviewStartDeferred) { + LOGE("ERR(%s): preview is running, cannot change size and format!", + __func__); + ret = INVALID_OPERATION; + } + + LOGV("%s: mPreviewWindow (%p) set_buffers_geometry", __func__, mPreviewWindow); + LOGV("%s: mPreviewWindow->set_buffers_geometry (%p)", __func__, + mPreviewWindow->set_buffers_geometry); + mPreviewWindow->set_buffers_geometry(mPreviewWindow, + new_preview_width, new_preview_height, + new_preview_format); + LOGV("%s: DONE mPreviewWindow (%p) set_buffers_geometry", __func__, mPreviewWindow); + } + + mParameters.setPreviewSize(new_preview_width, new_preview_height); + mParameters.setPreviewFormat(new_str_preview_format); + } + } + else LOGV("%s: preview size and format has not changed", __func__); + } else { + LOGE("%s: Invalid preview size(%dx%d)", + __func__, new_preview_width, new_preview_height); + + ret = INVALID_OPERATION; + } + + int new_picture_width = 0; + int new_picture_height = 0; + + params.getPictureSize(&new_picture_width, &new_picture_height); + LOGV("%s : new_picture_width x new_picture_height = %dx%d", __func__, new_picture_width, new_picture_height); + if (0 < new_picture_width && 0 < new_picture_height) { + LOGV("%s: setSnapshotSize", __func__); + if (mSecCamera->setSnapshotSize(new_picture_width, new_picture_height) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setSnapshotSize(width(%d), height(%d))", + __func__, new_picture_width, new_picture_height); + ret = UNKNOWN_ERROR; + } else { + mParameters.setPictureSize(new_picture_width, new_picture_height); + } + } + + // picture format + const char *new_str_picture_format = params.getPictureFormat(); + LOGV("%s : new_str_picture_format %s", __func__, new_str_picture_format); + if (new_str_picture_format != NULL) { + int new_picture_format = 0; + + if (!strcmp(new_str_picture_format, CameraParameters::PIXEL_FORMAT_RGB565)) + new_picture_format = V4L2_PIX_FMT_RGB565; + else if (!strcmp(new_str_picture_format, CameraParameters::PIXEL_FORMAT_RGBA8888)) + new_picture_format = V4L2_PIX_FMT_RGB32; + else if (!strcmp(new_str_picture_format, CameraParameters::PIXEL_FORMAT_YUV420SP)) + new_picture_format = V4L2_PIX_FMT_NV21; + else if (!strcmp(new_str_picture_format, "yuv420sp_custom")) + new_picture_format = V4L2_PIX_FMT_NV12T; + else if (!strcmp(new_str_picture_format, "yuv420p")) + new_picture_format = V4L2_PIX_FMT_YUV420; + else if (!strcmp(new_str_picture_format, "yuv422i")) + new_picture_format = V4L2_PIX_FMT_YUYV; + else if (!strcmp(new_str_picture_format, "uyv422i_custom")) //Zero copy UYVY format + new_picture_format = V4L2_PIX_FMT_UYVY; + else if (!strcmp(new_str_picture_format, "uyv422i")) //Non-zero copy UYVY format + new_picture_format = V4L2_PIX_FMT_UYVY; + else if (!strcmp(new_str_picture_format, CameraParameters::PIXEL_FORMAT_JPEG)) + new_picture_format = V4L2_PIX_FMT_YUYV; + else if (!strcmp(new_str_picture_format, "yuv422p")) + new_picture_format = V4L2_PIX_FMT_YUV422P; + else + new_picture_format = V4L2_PIX_FMT_NV21; //for 3rd party + + if (mSecCamera->setSnapshotPixelFormat(new_picture_format) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setSnapshotPixelFormat(format(%d))", __func__, new_picture_format); + ret = UNKNOWN_ERROR; + } else { + mParameters.setPictureFormat(new_str_picture_format); + } + } + + //JPEG image quality + int new_jpeg_quality = params.getInt(CameraParameters::KEY_JPEG_QUALITY); + LOGV("%s : new_jpeg_quality %d", __func__, new_jpeg_quality); + /* we ignore bad values */ + if (new_jpeg_quality >=1 && new_jpeg_quality <= 100) { + if (mSecCamera->setJpegQuality(new_jpeg_quality) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setJpegQuality(quality(%d))", __func__, new_jpeg_quality); + ret = UNKNOWN_ERROR; + } else { + mParameters.set(CameraParameters::KEY_JPEG_QUALITY, new_jpeg_quality); + } + } + + // JPEG thumbnail size + int new_jpeg_thumbnail_width = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH); + int new_jpeg_thumbnail_height= params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT); + if (0 <= new_jpeg_thumbnail_width && 0 <= new_jpeg_thumbnail_height) { + if (mSecCamera->setJpegThumbnailSize(new_jpeg_thumbnail_width, new_jpeg_thumbnail_height) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setJpegThumbnailSize(width(%d), height(%d))", __func__, new_jpeg_thumbnail_width, new_jpeg_thumbnail_height); + ret = UNKNOWN_ERROR; + } else { + mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, new_jpeg_thumbnail_width); + mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, new_jpeg_thumbnail_height); + } + } + + // frame rate + int new_frame_rate = params.getPreviewFrameRate(); + /* ignore any fps request, we're determine fps automatically based + * on scene mode. don't return an error because it causes CTS failure. + */ + if (new_frame_rate != mParameters.getPreviewFrameRate()) { + LOGW("WARN(%s): request for preview frame %d not allowed, != %d\n", + __func__, new_frame_rate, mParameters.getPreviewFrameRate()); + } + + // rotation + int new_rotation = params.getInt(CameraParameters::KEY_ROTATION); + LOGV("%s : new_rotation %d", __func__, new_rotation); + if (0 <= new_rotation) { + LOGV("%s : set orientation:%d\n", __func__, new_rotation); + if (mSecCamera->setExifOrientationInfo(new_rotation) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setExifOrientationInfo(%d)", __func__, new_rotation); + ret = UNKNOWN_ERROR; + } else { + mParameters.set(CameraParameters::KEY_ROTATION, new_rotation); + } + } + + // brightness + int new_exposure_compensation = params.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION); + int max_exposure_compensation = params.getInt(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION); + int min_exposure_compensation = params.getInt(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION); + LOGV("%s : new_exposure_compensation %d", __func__, new_exposure_compensation); + if ((min_exposure_compensation <= new_exposure_compensation) && + (max_exposure_compensation >= new_exposure_compensation)) { + if (mSecCamera->setBrightness(new_exposure_compensation) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setBrightness(brightness(%d))", __func__, new_exposure_compensation); + ret = UNKNOWN_ERROR; + } else { + mParameters.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, new_exposure_compensation); + } + } + + // whitebalance + const char *new_white_str = params.get(CameraParameters::KEY_WHITE_BALANCE); + LOGV("%s : new_white_str %s", __func__, new_white_str); + if (new_white_str != NULL) { + int new_white = -1; + + if (!strcmp(new_white_str, CameraParameters::WHITE_BALANCE_AUTO)) + new_white = WHITE_BALANCE_AUTO; + else if (!strcmp(new_white_str, + CameraParameters::WHITE_BALANCE_DAYLIGHT)) + new_white = WHITE_BALANCE_SUNNY; + else if (!strcmp(new_white_str, + CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT)) + new_white = WHITE_BALANCE_CLOUDY_DAYLIGHT; + else if (!strcmp(new_white_str, + CameraParameters::WHITE_BALANCE_FLUORESCENT)) + new_white = WHITE_BALANCE_FLUORESCENT; + else if (!strcmp(new_white_str, + CameraParameters::WHITE_BALANCE_INCANDESCENT)) + new_white = WHITE_BALANCE_TUNGSTEN; + else { + LOGE("ERR(%s):Invalid white balance(%s)", __func__, new_white_str); //twilight, shade, warm_flourescent + ret = UNKNOWN_ERROR; + } + + if (0 <= new_white) { + if (mSecCamera->setWhiteBalance(new_white) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setWhiteBalance(white(%d))", __func__, new_white); + ret = UNKNOWN_ERROR; + } else { + mParameters.set(CameraParameters::KEY_WHITE_BALANCE, new_white_str); + } + } + } + + // scene mode + const char *new_scene_mode_str = params.get(CameraParameters::KEY_SCENE_MODE); + const char *current_scene_mode_str = mParameters.get(CameraParameters::KEY_SCENE_MODE); + + // fps range + int new_min_fps = 0; + int new_max_fps = 0; + int current_min_fps, current_max_fps; + params.getPreviewFpsRange(&new_min_fps, &new_max_fps); + mParameters.getPreviewFpsRange(¤t_min_fps, ¤t_max_fps); + /* our fps range is determined by the sensor, reject any request + * that isn't exactly what we're already at. + * but the check is performed when requesting only changing fps range + */ + if (new_scene_mode_str && current_scene_mode_str) { + if (!strcmp(new_scene_mode_str, current_scene_mode_str)) { + if ((new_min_fps != current_min_fps) || (new_max_fps != current_max_fps)) { + LOGW("%s : requested new_min_fps = %d, new_max_fps = %d not allowed", + __func__, new_min_fps, new_max_fps); + LOGE("%s : current_min_fps = %d, current_max_fps = %d", + __func__, current_min_fps, current_max_fps); + ret = UNKNOWN_ERROR; + } + } + } else { + /* Check basic validation if scene mode is different */ + if ((new_min_fps > new_max_fps) || + (new_min_fps < 0) || (new_max_fps < 0)) + ret = UNKNOWN_ERROR; + } + + const char *new_focus_mode_str = params.get(CameraParameters::KEY_FOCUS_MODE); + + if (mSecCamera->getCameraId() == SecCamera::CAMERA_ID_BACK) { + int new_scene_mode = -1; + + const char *new_flash_mode_str = params.get(CameraParameters::KEY_FLASH_MODE); + + // fps range is (15000,30000) by default. + mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(15000,30000)"); + mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, + "15000,30000"); + + if (!strcmp(new_scene_mode_str, CameraParameters::SCENE_MODE_AUTO)) { + new_scene_mode = SCENE_MODE_NONE; + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, "on,off,auto,torch"); + } else { + // defaults for non-auto scene modes + if (mSecCamera->getCameraId() == SecCamera::CAMERA_ID_BACK) { + new_focus_mode_str = CameraParameters::FOCUS_MODE_AUTO; + } + new_flash_mode_str = CameraParameters::FLASH_MODE_OFF; + + if (!strcmp(new_scene_mode_str, + CameraParameters::SCENE_MODE_PORTRAIT)) { + new_scene_mode = SCENE_MODE_PORTRAIT; + new_flash_mode_str = CameraParameters::FLASH_MODE_AUTO; + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, "auto"); + } else if (!strcmp(new_scene_mode_str, + CameraParameters::SCENE_MODE_LANDSCAPE)) { + new_scene_mode = SCENE_MODE_LANDSCAPE; + new_flash_mode_str = CameraParameters::FLASH_MODE_OFF; + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, "off"); + } else if (!strcmp(new_scene_mode_str, + CameraParameters::SCENE_MODE_SPORTS)) { + new_scene_mode = SCENE_MODE_SPORTS; + new_flash_mode_str = CameraParameters::FLASH_MODE_OFF; + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, "off"); + } else if (!strcmp(new_scene_mode_str, + CameraParameters::SCENE_MODE_PARTY)) { + new_scene_mode = SCENE_MODE_PARTY_INDOOR; + new_flash_mode_str = CameraParameters::FLASH_MODE_AUTO; + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, "auto"); + } else if ((!strcmp(new_scene_mode_str, + CameraParameters::SCENE_MODE_BEACH)) || + (!strcmp(new_scene_mode_str, + CameraParameters::SCENE_MODE_SNOW))) { + new_scene_mode = SCENE_MODE_BEACH_SNOW; + new_flash_mode_str = CameraParameters::FLASH_MODE_OFF; + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, "off"); + } else if (!strcmp(new_scene_mode_str, + CameraParameters::SCENE_MODE_SUNSET)) { + new_scene_mode = SCENE_MODE_SUNSET; + new_flash_mode_str = CameraParameters::FLASH_MODE_OFF; + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, "off"); + } else if (!strcmp(new_scene_mode_str, + CameraParameters::SCENE_MODE_NIGHT)) { + new_scene_mode = SCENE_MODE_NIGHTSHOT; + mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(4000,30000)"); + mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, + "4000,30000"); + new_flash_mode_str = CameraParameters::FLASH_MODE_OFF; + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, "off"); + } else if (!strcmp(new_scene_mode_str, + CameraParameters::SCENE_MODE_FIREWORKS)) { + new_scene_mode = SCENE_MODE_FIREWORKS; + new_flash_mode_str = CameraParameters::FLASH_MODE_OFF; + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, "off"); + } else if (!strcmp(new_scene_mode_str, + CameraParameters::SCENE_MODE_CANDLELIGHT)) { + new_scene_mode = SCENE_MODE_CANDLE_LIGHT; + new_flash_mode_str = CameraParameters::FLASH_MODE_OFF; + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, "off"); + } else { + LOGE("%s::unmatched scene_mode(%s)", + __func__, new_scene_mode_str); //action, night-portrait, theatre, steadyphoto + ret = UNKNOWN_ERROR; + } + } + + // focus mode + if (new_focus_mode_str != NULL) { + int new_focus_mode = -1; + + if (!strcmp(new_focus_mode_str, + CameraParameters::FOCUS_MODE_AUTO)) { + new_focus_mode = FOCUS_MODE_AUTO; + mParameters.set(CameraParameters::KEY_FOCUS_DISTANCES, + BACK_CAMERA_AUTO_FOCUS_DISTANCES_STR); + } + else if (!strcmp(new_focus_mode_str, + CameraParameters::FOCUS_MODE_MACRO)) { + new_focus_mode = FOCUS_MODE_MACRO; + mParameters.set(CameraParameters::KEY_FOCUS_DISTANCES, + BACK_CAMERA_MACRO_FOCUS_DISTANCES_STR); + } + else if (!strcmp(new_focus_mode_str, + CameraParameters::FOCUS_MODE_INFINITY)) { + new_focus_mode = FOCUS_MODE_INFINITY; + mParameters.set(CameraParameters::KEY_FOCUS_DISTANCES, + BACK_CAMERA_INFINITY_FOCUS_DISTANCES_STR); + } + else { + LOGE("%s::unmatched focus_mode(%s)", __func__, new_focus_mode_str); + ret = UNKNOWN_ERROR; + } + + if (0 <= new_focus_mode) { + if (mSecCamera->setFocusMode(new_focus_mode) < 0) { + LOGE("%s::mSecCamera->setFocusMode(%d) fail", __func__, new_focus_mode); + ret = UNKNOWN_ERROR; + } else { + mParameters.set(CameraParameters::KEY_FOCUS_MODE, new_focus_mode_str); + } + } + } + + // flash.. + if (new_flash_mode_str != NULL) { + int new_flash_mode = -1; + + if (!strcmp(new_flash_mode_str, CameraParameters::FLASH_MODE_OFF)) + new_flash_mode = FLASH_MODE_OFF; + else if (!strcmp(new_flash_mode_str, CameraParameters::FLASH_MODE_AUTO)) + new_flash_mode = FLASH_MODE_AUTO; + else if (!strcmp(new_flash_mode_str, CameraParameters::FLASH_MODE_ON)) + new_flash_mode = FLASH_MODE_ON; + else if (!strcmp(new_flash_mode_str, CameraParameters::FLASH_MODE_TORCH)) + new_flash_mode = FLASH_MODE_TORCH; + else { + LOGE("%s::unmatched flash_mode(%s)", __func__, new_flash_mode_str); //red-eye + ret = UNKNOWN_ERROR; + } + if (0 <= new_flash_mode) { + if (mSecCamera->setFlashMode(new_flash_mode) < 0) { + LOGE("%s::mSecCamera->setFlashMode(%d) fail", __func__, new_flash_mode); + ret = UNKNOWN_ERROR; + } else { + mParameters.set(CameraParameters::KEY_FLASH_MODE, new_flash_mode_str); + } + } + } + + // scene.. + if (0 <= new_scene_mode) { + if (mSecCamera->setSceneMode(new_scene_mode) < 0) { + LOGE("%s::mSecCamera->setSceneMode(%d) fail", __func__, new_scene_mode); + ret = UNKNOWN_ERROR; + } else { + mParameters.set(CameraParameters::KEY_SCENE_MODE, new_scene_mode_str); + } + } + } else { + if (!isSupportedParameter(new_focus_mode_str, + mParameters.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES))) { + LOGE("%s: Unsupported focus mode: %s", __func__, new_focus_mode_str); + ret = UNKNOWN_ERROR; + } + } + + // --------------------------------------------------------------------------- + + // image effect + const char *new_image_effect_str = params.get(CameraParameters::KEY_EFFECT); + if (new_image_effect_str != NULL) { + + int new_image_effect = -1; + + if (!strcmp(new_image_effect_str, CameraParameters::EFFECT_NONE)) + new_image_effect = IMAGE_EFFECT_NONE; + else if (!strcmp(new_image_effect_str, CameraParameters::EFFECT_MONO)) + new_image_effect = IMAGE_EFFECT_BNW; + else if (!strcmp(new_image_effect_str, CameraParameters::EFFECT_SEPIA)) + new_image_effect = IMAGE_EFFECT_SEPIA; + else if (!strcmp(new_image_effect_str, CameraParameters::EFFECT_AQUA)) + new_image_effect = IMAGE_EFFECT_AQUA; + else if (!strcmp(new_image_effect_str, CameraParameters::EFFECT_NEGATIVE)) + new_image_effect = IMAGE_EFFECT_NEGATIVE; + else { + //posterize, whiteboard, blackboard, solarize + LOGE("ERR(%s):Invalid effect(%s)", __func__, new_image_effect_str); + ret = UNKNOWN_ERROR; + } + + if (new_image_effect >= 0) { + if (mSecCamera->setImageEffect(new_image_effect) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setImageEffect(effect(%d))", __func__, new_image_effect); + ret = UNKNOWN_ERROR; + } else { + const char *old_image_effect_str = mParameters.get(CameraParameters::KEY_EFFECT); + + if (old_image_effect_str) { + if (strcmp(old_image_effect_str, new_image_effect_str)) { + setSkipFrame(EFFECT_SKIP_FRAME); + } + } + + mParameters.set(CameraParameters::KEY_EFFECT, new_image_effect_str); + } + } + } + + //vt mode + int new_vtmode = mInternalParameters.getInt("vtmode"); + if (0 <= new_vtmode) { + if (mSecCamera->setVTmode(new_vtmode) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setVTMode(%d)", __func__, new_vtmode); + ret = UNKNOWN_ERROR; + } + } + + //contrast + int new_contrast = mInternalParameters.getInt("contrast"); + + if (0 <= new_contrast) { + if (mSecCamera->setContrast(new_contrast) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setContrast(%d)", __func__, new_contrast); + ret = UNKNOWN_ERROR; + } + } + + // Recording size + int new_recording_width = mInternalParameters.getInt("recording-size-width"); + int new_recording_height= mInternalParameters.getInt("recording-size-height"); + + if (0 < new_recording_width && 0 < new_recording_height) { + if (mSecCamera->setRecordingSize(new_recording_width, new_recording_height) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setRecordingSize(width(%d), height(%d))", __func__, new_recording_width, new_recording_height); + ret = UNKNOWN_ERROR; + } + } else { + if (mSecCamera->setRecordingSize(new_preview_width, new_preview_height) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setRecordingSize(width(%d), height(%d))", __func__, new_preview_width, new_preview_height); + ret = UNKNOWN_ERROR; + } + } + + /*Camcorder fix fps*/ + int new_sensor_mode = mInternalParameters.getInt("cam_mode"); + + if (0 <= new_sensor_mode) { + if (mSecCamera->setSensorMode(new_sensor_mode) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setSensorMode(%d)", __func__, new_sensor_mode); + ret = UNKNOWN_ERROR; + } + } else { + new_sensor_mode=0; + } + + /*Shot mode*/ + int new_shot_mode = mInternalParameters.getInt("shot_mode"); + + if (0 <= new_shot_mode) { + if (mSecCamera->setShotMode(new_shot_mode) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setShotMode(%d)", __func__, new_shot_mode); + ret = UNKNOWN_ERROR; + } + } else { + new_shot_mode=0; + } + + //blur for Video call + int new_blur_level = mInternalParameters.getInt("blur"); + + if (0 <= new_blur_level) { + if (mSecCamera->setBlur(new_blur_level) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setBlur(%d)", __func__, new_blur_level); + ret = UNKNOWN_ERROR; + } + } + + + // chk_dataline + int new_dataline = mInternalParameters.getInt("chk_dataline"); + + if (0 <= new_dataline) { + if (mSecCamera->setDataLineCheck(new_dataline) < 0) { + LOGE("ERR(%s):Fail on mSecCamera->setDataLineCheck(%d)", __func__, new_dataline); + ret = UNKNOWN_ERROR; + } + } + LOGV("%s return ret = %d", __func__, ret); + + return ret; +} + +CameraParameters CameraHardwareSec::getParameters() const +{ + LOGV("%s :", __func__); + return mParameters; +} + +status_t CameraHardwareSec::sendCommand(int32_t command, int32_t arg1, int32_t arg2) +{ + return BAD_VALUE; +} + +void CameraHardwareSec::release() +{ + LOGV("%s", __func__); + + /* shut down any threads we have that might be running. do it here + * instead of the destructor. we're guaranteed to be on another thread + * than the ones below. if we used the destructor, since the threads + * have a reference to this object, we could wind up trying to wait + * for ourself to exit, which is a deadlock. + */ + if (mPreviewThread != NULL) { + /* this thread is normally already in it's threadLoop but blocked + * on the condition variable or running. signal it so it wakes + * up and can exit. + */ + mPreviewThread->requestExit(); + mExitPreviewThread = true; + mPreviewRunning = true; /* let it run so it can exit */ + mPreviewCondition.signal(); + mPreviewThread->requestExitAndWait(); + mPreviewThread.clear(); + } + if (mAutoFocusThread != NULL) { + /* this thread is normally already in it's threadLoop but blocked + * on the condition variable. signal it so it wakes up and can exit. + */ + mFocusLock.lock(); + mAutoFocusThread->requestExit(); + mExitAutoFocusThread = true; + mFocusCondition.signal(); + mFocusLock.unlock(); + mAutoFocusThread->requestExitAndWait(); + mAutoFocusThread.clear(); + } + if (mPictureThread != NULL) { + mPictureThread->requestExitAndWait(); + mPictureThread.clear(); + } + + if (mRawHeap) { + mRawHeap->release(mRawHeap); + mRawHeap = 0; + } + if (mPreviewHeap) { + mPreviewHeap->release(mPreviewHeap); + mPreviewHeap = 0; + } + if (mRecordHeap) { + mRecordHeap->release(mRecordHeap); + mRecordHeap = 0; + } + + /* close after all the heaps are cleared since those + * could have dup'd our file descriptor. + */ + mSecCamera->DeinitCamera(); +} + +status_t CameraHardwareSec::storeMetaDataInBuffers(bool enable) +{ + // FIXME: + // metadata buffer mode can be turned on or off. + // Samsung needs to fix this. + if (!enable) { + LOGE("Non-metadata buffer mode is not supported!"); + return INVALID_OPERATION; + } + return OK; +} + +static CameraInfo sCameraInfo[] = { + { + CAMERA_FACING_BACK, + 90, /* orientation */ + }, + { + CAMERA_FACING_FRONT, + 270, /* orientation */ + } +}; + +/** Close this device */ + +static camera_device_t *g_cam_device; + +static int HAL_camera_device_close(struct hw_device_t* device) +{ + LOGI("%s", __func__); + if (device) { + camera_device_t *cam_device = (camera_device_t *)device; + delete static_cast(cam_device->priv); + free(cam_device); + g_cam_device = 0; + } + return 0; +} + +static inline CameraHardwareSec *obj(struct camera_device *dev) +{ + return reinterpret_cast(dev->priv); +} + +/** Set the preview_stream_ops to which preview frames are sent */ +static int HAL_camera_device_set_preview_window(struct camera_device *dev, + struct preview_stream_ops *buf) +{ + LOGV("%s", __func__); + return obj(dev)->setPreviewWindow(buf); +} + +/** Set the notification and data callbacks */ +static void HAL_camera_device_set_callbacks(struct camera_device *dev, + camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void* user) +{ + LOGV("%s", __func__); + obj(dev)->setCallbacks(notify_cb, data_cb, data_cb_timestamp, + get_memory, + user); +} + +/** + * The following three functions all take a msg_type, which is a bitmask of + * the messages defined in include/ui/Camera.h + */ + +/** + * Enable a message, or set of messages. + */ +static void HAL_camera_device_enable_msg_type(struct camera_device *dev, int32_t msg_type) +{ + LOGV("%s", __func__); + obj(dev)->enableMsgType(msg_type); +} + +/** + * Disable a message, or a set of messages. + * + * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera + * HAL should not rely on its client to call releaseRecordingFrame() to + * release video recording frames sent out by the cameral HAL before and + * after the disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera HAL + * clients must not modify/access any video recording frame after calling + * disableMsgType(CAMERA_MSG_VIDEO_FRAME). + */ +static void HAL_camera_device_disable_msg_type(struct camera_device *dev, int32_t msg_type) +{ + LOGV("%s", __func__); + obj(dev)->disableMsgType(msg_type); +} + +/** + * Query whether a message, or a set of messages, is enabled. Note that + * this is operates as an AND, if any of the messages queried are off, this + * will return false. + */ +static int HAL_camera_device_msg_type_enabled(struct camera_device *dev, int32_t msg_type) +{ + LOGV("%s", __func__); + return obj(dev)->msgTypeEnabled(msg_type); +} + +/** + * Start preview mode. + */ +static int HAL_camera_device_start_preview(struct camera_device *dev) +{ + LOGV("%s", __func__); + return obj(dev)->startPreview(); +} + +/** + * Stop a previously started preview. + */ +static void HAL_camera_device_stop_preview(struct camera_device *dev) +{ + LOGV("%s", __func__); + obj(dev)->stopPreview(); +} + +/** + * Returns true if preview is enabled. + */ +static int HAL_camera_device_preview_enabled(struct camera_device *dev) +{ + LOGV("%s", __func__); + return obj(dev)->previewEnabled(); +} + +/** + * Request the camera HAL to store meta data or real YUV data in the video + * buffers sent out via CAMERA_MSG_VIDEO_FRAME for a recording session. If + * it is not called, the default camera HAL behavior is to store real YUV + * data in the video buffers. + * + * This method should be called before startRecording() in order to be + * effective. + * + * If meta data is stored in the video buffers, it is up to the receiver of + * the video buffers to interpret the contents and to find the actual frame + * data with the help of the meta data in the buffer. How this is done is + * outside of the scope of this method. + * + * Some camera HALs may not support storing meta data in the video buffers, + * but all camera HALs should support storing real YUV data in the video + * buffers. If the camera HAL does not support storing the meta data in the + * video buffers when it is requested to do do, INVALID_OPERATION must be + * returned. It is very useful for the camera HAL to pass meta data rather + * than the actual frame data directly to the video encoder, since the + * amount of the uncompressed frame data can be very large if video size is + * large. + * + * @param enable if true to instruct the camera HAL to store + * meta data in the video buffers; false to instruct + * the camera HAL to store real YUV data in the video + * buffers. + * + * @return OK on success. + */ +static int HAL_camera_device_store_meta_data_in_buffers(struct camera_device *dev, int enable) +{ + LOGV("%s", __func__); + return obj(dev)->storeMetaDataInBuffers(enable); +} + +/** + * Start record mode. When a record image is available, a + * CAMERA_MSG_VIDEO_FRAME message is sent with the corresponding + * frame. Every record frame must be released by a camera HAL client via + * releaseRecordingFrame() before the client calls + * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls + * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's + * responsibility to manage the life-cycle of the video recording frames, + * and the client must not modify/access any video recording frames. + */ +static int HAL_camera_device_start_recording(struct camera_device *dev) +{ + LOGV("%s", __func__); + return obj(dev)->startRecording(); +} + +/** + * Stop a previously started recording. + */ +static void HAL_camera_device_stop_recording(struct camera_device *dev) +{ + LOGV("%s", __func__); + obj(dev)->stopRecording(); +} + +/** + * Returns true if recording is enabled. + */ +static int HAL_camera_device_recording_enabled(struct camera_device *dev) +{ + LOGV("%s", __func__); + return obj(dev)->recordingEnabled(); +} + +/** + * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME. + * + * It is camera HAL client's responsibility to release video recording + * frames sent out by the camera HAL before the camera HAL receives a call + * to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives the call to + * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's + * responsibility to manage the life-cycle of the video recording frames. + */ +static void HAL_camera_device_release_recording_frame(struct camera_device *dev, + const void *opaque) +{ + LOGV("%s", __func__); + obj(dev)->releaseRecordingFrame(opaque); +} + +/** + * Start auto focus, the notification callback routine is called with + * CAMERA_MSG_FOCUS once when focusing is complete. autoFocus() will be + * called again if another auto focus is needed. + */ +static int HAL_camera_device_auto_focus(struct camera_device *dev) +{ + LOGV("%s", __func__); + return obj(dev)->autoFocus(); +} + +/** + * Cancels auto-focus function. If the auto-focus is still in progress, + * this function will cancel it. Whether the auto-focus is in progress or + * not, this function will return the focus position to the default. If + * the camera does not support auto-focus, this is a no-op. + */ +static int HAL_camera_device_cancel_auto_focus(struct camera_device *dev) +{ + LOGV("%s", __func__); + return obj(dev)->cancelAutoFocus(); +} + +/** + * Take a picture. + */ +static int HAL_camera_device_take_picture(struct camera_device *dev) +{ + LOGV("%s", __func__); + return obj(dev)->takePicture(); +} + +/** + * Cancel a picture that was started with takePicture. Calling this method + * when no picture is being taken is a no-op. + */ +static int HAL_camera_device_cancel_picture(struct camera_device *dev) +{ + LOGV("%s", __func__); + return obj(dev)->cancelPicture(); +} + +/** + * Set the camera parameters. This returns BAD_VALUE if any parameter is + * invalid or not supported. + */ +static int HAL_camera_device_set_parameters(struct camera_device *dev, + const char *parms) +{ + LOGV("%s", __func__); + String8 str(parms); + CameraParameters p(str); + return obj(dev)->setParameters(p); +} + +/** Return the camera parameters. */ +char *HAL_camera_device_get_parameters(struct camera_device *dev) +{ + LOGV("%s", __func__); + String8 str; + CameraParameters parms = obj(dev)->getParameters(); + str = parms.flatten(); + return strdup(str.string()); +} + +void HAL_camera_device_put_parameters(struct camera_device *dev, char *parms) +{ + LOGV("%s", __func__); + free(parms); +} + +/** + * Send command to camera driver. + */ +static int HAL_camera_device_send_command(struct camera_device *dev, + int32_t cmd, int32_t arg1, int32_t arg2) +{ + LOGV("%s", __func__); + return obj(dev)->sendCommand(cmd, arg1, arg2); +} + +/** + * Release the hardware resources owned by this object. Note that this is + * *not* done in the destructor. + */ +static void HAL_camera_device_release(struct camera_device *dev) +{ + LOGV("%s", __func__); + obj(dev)->release(); +} + +/** + * Dump state of the camera hardware + */ +static int HAL_camera_device_dump(struct camera_device *dev, int fd) +{ + LOGV("%s", __func__); + return obj(dev)->dump(fd); +} + +static int HAL_getNumberOfCameras() +{ + LOGV("%s", __func__); + return sizeof(sCameraInfo) / sizeof(sCameraInfo[0]); +} + +static int HAL_getCameraInfo(int cameraId, struct camera_info *cameraInfo) +{ + LOGV("%s", __func__); + memcpy(cameraInfo, &sCameraInfo[cameraId], sizeof(CameraInfo)); + return 0; +} + +#define SET_METHOD(m) m : HAL_camera_device_##m + +static camera_device_ops_t camera_device_ops = { + SET_METHOD(set_preview_window), + SET_METHOD(set_callbacks), + SET_METHOD(enable_msg_type), + SET_METHOD(disable_msg_type), + SET_METHOD(msg_type_enabled), + SET_METHOD(start_preview), + SET_METHOD(stop_preview), + SET_METHOD(preview_enabled), + SET_METHOD(store_meta_data_in_buffers), + SET_METHOD(start_recording), + SET_METHOD(stop_recording), + SET_METHOD(recording_enabled), + SET_METHOD(release_recording_frame), + SET_METHOD(auto_focus), + SET_METHOD(cancel_auto_focus), + SET_METHOD(take_picture), + SET_METHOD(cancel_picture), + SET_METHOD(set_parameters), + SET_METHOD(get_parameters), + SET_METHOD(put_parameters), + SET_METHOD(send_command), + SET_METHOD(release), + SET_METHOD(dump), +}; + +#undef SET_METHOD + +static int HAL_camera_device_open(const struct hw_module_t* module, + const char *id, + struct hw_device_t** device) +{ + LOGV("%s", __func__); + + int cameraId = atoi(id); + if (cameraId < 0 || cameraId >= HAL_getNumberOfCameras()) { + LOGE("Invalid camera ID %s", id); + return -EINVAL; + } + + if (g_cam_device) { + if (obj(g_cam_device)->getCameraId() == cameraId) { + LOGV("returning existing camera ID %s", id); + goto done; + } else { + LOGE("Cannot open camera %d. camera %d is already running!", + cameraId, obj(g_cam_device)->getCameraId()); + return -ENOSYS; + } + } + + g_cam_device = (camera_device_t *)malloc(sizeof(camera_device_t)); + if (!g_cam_device) + return -ENOMEM; + + g_cam_device->common.tag = HARDWARE_DEVICE_TAG; + g_cam_device->common.version = 1; + g_cam_device->common.module = const_cast(module); + g_cam_device->common.close = HAL_camera_device_close; + + g_cam_device->ops = &camera_device_ops; + + LOGI("%s: open camera %s", __func__, id); + + g_cam_device->priv = new CameraHardwareSec(cameraId, g_cam_device); + +done: + *device = (hw_device_t *)g_cam_device; + LOGI("%s: opened camera %s (%p)", __func__, id, *device); + return 0; +} + +static hw_module_methods_t camera_module_methods = { + open : HAL_camera_device_open +}; + +extern "C" { + struct camera_module HAL_MODULE_INFO_SYM = { + common : { + tag : HARDWARE_MODULE_TAG, + version_major : 1, + version_minor : 0, + id : CAMERA_HARDWARE_MODULE_ID, + name : "GalaxyTab camera HAL", + author : "Samsung Corporation", + methods : &camera_module_methods, + }, + get_number_of_cameras : HAL_getNumberOfCameras, + get_camera_info : HAL_getCameraInfo + }; +} + +}; // namespace android diff --git a/libcamera/SecCameraHWInterface.h b/libcamera/SecCameraHWInterface.h new file mode 100644 index 0000000..e99aff6 --- /dev/null +++ b/libcamera/SecCameraHWInterface.h @@ -0,0 +1,214 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** Copyright 2010, Samsung Electronics Co. LTD +** +** 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_CAMERA_HARDWARE_SEC_H +#define ANDROID_HARDWARE_CAMERA_HARDWARE_SEC_H + +#include "SecCamera.h" +#include +#include +#include +#include +#include +#include +#include + +namespace android { + class CameraHardwareSec : public virtual RefBase { +public: + virtual void setCallbacks(camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user); + + virtual void enableMsgType(int32_t msgType); + virtual void disableMsgType(int32_t msgType); + virtual bool msgTypeEnabled(int32_t msgType); + + virtual status_t startPreview(); + virtual void stopPreview(); + virtual bool previewEnabled(); + + virtual status_t startRecording(); + virtual void stopRecording(); + virtual bool recordingEnabled(); + virtual void releaseRecordingFrame(const void *opaque); + + virtual status_t autoFocus(); + virtual status_t cancelAutoFocus(); + virtual status_t takePicture(); + virtual status_t cancelPicture(); + virtual status_t dump(int fd) const; + virtual status_t setParameters(const CameraParameters& params); + virtual CameraParameters getParameters() const; + virtual status_t sendCommand(int32_t command, int32_t arg1, int32_t arg2); + virtual status_t setPreviewWindow(preview_stream_ops *w); + virtual status_t storeMetaDataInBuffers(bool enable); + virtual void release(); + + inline int getCameraId() const; + + CameraHardwareSec(int cameraId, camera_device_t *dev); + virtual ~CameraHardwareSec(); +private: + status_t startPreviewInternal(); + void stopPreviewInternal(); + + static const int kBufferCount = MAX_BUFFERS; + static const int kBufferCountForRecord = MAX_BUFFERS; + + class PreviewThread : public Thread { + CameraHardwareSec *mHardware; + public: + PreviewThread(CameraHardwareSec *hw): + Thread(false), + mHardware(hw) { } + virtual void onFirstRef() { + run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY); + } + virtual bool threadLoop() { + mHardware->previewThreadWrapper(); + return false; + } + }; + + class PictureThread : public Thread { + CameraHardwareSec *mHardware; + public: + PictureThread(CameraHardwareSec *hw): + Thread(false), + mHardware(hw) { } + virtual bool threadLoop() { + mHardware->pictureThread(); + return false; + } + }; + + class AutoFocusThread : public Thread { + CameraHardwareSec *mHardware; + public: + AutoFocusThread(CameraHardwareSec *hw): Thread(false), mHardware(hw) { } + virtual void onFirstRef() { + run("CameraAutoFocusThread", PRIORITY_DEFAULT); + } + virtual bool threadLoop() { + mHardware->autoFocusThread(); + return true; + } + }; + + void initDefaultParameters(int cameraId); + void initHeapLocked(); + + sp mPreviewThread; + int previewThread(); + int previewThreadWrapper(); + + sp mAutoFocusThread; + int autoFocusThread(); + + sp mPictureThread; + int pictureThread(); + bool mCaptureInProgress; + + int save_jpeg(unsigned char *real_jpeg, int jpeg_size); + void save_postview(const char *fname, uint8_t *buf, + uint32_t size); + int decodeInterleaveData(unsigned char *pInterleaveData, + int interleaveDataSize, + int yuvWidth, + int yuvHeight, + int *pJpegSize, + void *pJpegData, + void *pYuvData); + bool YUY2toNV21(void *srcBuf, void *dstBuf, uint32_t srcWidth, uint32_t srcHeight); + bool scaleDownYuv422(char *srcBuf, uint32_t srcWidth, + uint32_t srcHight, char *dstBuf, + uint32_t dstWidth, uint32_t dstHight); + + bool CheckVideoStartMarker(unsigned char *pBuf); + bool CheckEOIMarker(unsigned char *pBuf); + bool FindEOIMarkerInJPEG(unsigned char *pBuf, + int dwBufSize, int *pnJPEGsize); + bool SplitFrame(unsigned char *pFrame, int dwSize, + int dwJPEGLineLength, int dwVideoLineLength, + int dwVideoHeight, void *pJPEG, + int *pdwJPEGSize, void *pVideo, + int *pdwVideoSize); + void setSkipFrame(int frame); + bool isSupportedPreviewSize(const int width, + const int height) const; + bool isSupportedParameter(const char * const parm, + const char * const supported_parm) const; + status_t waitCaptureCompletion(); + /* used by auto focus thread to block until it's told to run */ + mutable Mutex mFocusLock; + mutable Condition mFocusCondition; + bool mExitAutoFocusThread; + + /* used by preview thread to block until it's told to run */ + mutable Mutex mPreviewLock; + mutable Condition mPreviewCondition; + mutable Condition mPreviewStoppedCondition; + bool mPreviewRunning; + bool mPreviewStartDeferred; + bool mExitPreviewThread; + + preview_stream_ops *mPreviewWindow; + + /* used to guard mCaptureInProgress */ + mutable Mutex mCaptureLock; + mutable Condition mCaptureCondition; + + CameraParameters mParameters; + CameraParameters mInternalParameters; + + camera_memory_t *mPreviewHeap; + camera_memory_t *mRawHeap; + camera_memory_t *mRecordHeap; + + SecCamera *mSecCamera; + const __u8 *mCameraSensorName; + + mutable Mutex mSkipFrameLock; + int mSkipFrame; + + camera_notify_callback mNotifyCb; + camera_data_callback mDataCb; + camera_data_timestamp_callback mDataCbTimestamp; + camera_request_memory mGetMemoryCb; + void *mCallbackCookie; + + int32_t mMsgEnabled; + + bool mRecordRunning; + mutable Mutex mRecordLock; + int mPostViewWidth; + int mPostViewHeight; + int mPostViewSize; + + Vector mSupportedPreviewSizes; + + camera_device_t *mHalDevice; + static gralloc_module_t const* mGrallocHal; +}; + +}; // namespace android + +#endif diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk new file mode 100644 index 0000000..223326b --- /dev/null +++ b/libhwcomposer/Android.mk @@ -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. + +LOCAL_PATH:= $(call my-dir) +# HAL module implemenation, not prelinked and stored in +# hw/..so + +include $(CLEAR_VARS) +LOCAL_PRELINK_MODULE := false +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_SHARED_LIBRARIES := liblog libcutils libEGL libGLESv1_CM libhardware +LOCAL_CFLAGS += -DLOG_TAG=\"hwcomposer\" + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../include + +LOCAL_SRC_FILES := SecHWCUtils.cpp SecHWC.cpp + +LOCAL_MODULE := hwcomposer.s5pc110 +LOCAL_MODULE_TAGS := optional +include $(BUILD_SHARED_LIBRARY) + diff --git a/libhwcomposer/SecHWC.cpp b/libhwcomposer/SecHWC.cpp new file mode 100644 index 0000000..31c0b2c --- /dev/null +++ b/libhwcomposer/SecHWC.cpp @@ -0,0 +1,567 @@ +/* + * Copyright (C) 2010 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. + */ + +/* + * + * @author Rama, Meka(v.meka@samsung.com) + Sangwoo, Park(sw5771.park@samsung.com) + Jamie Oh (jung-min.oh@samsung.com) + * @date 2011-07-28 + * + */ + +#include +#include +#include +#include +#include "SecHWCUtils.h" + +static IMG_gralloc_module_public_t *gpsGrallocModule; + +static int hwc_device_open(const struct hw_module_t* module, const char* name, + struct hw_device_t** device); + +static struct hw_module_methods_t hwc_module_methods = { + open: hwc_device_open +}; + +hwc_module_t HAL_MODULE_INFO_SYM = { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: HWC_HARDWARE_MODULE_ID, + name: "Samsung S5PC11X hwcomposer module", + author: "SAMSUNG", + methods: &hwc_module_methods, + } +}; + +static void dump_layer(hwc_layer_t const* l) { + LOGD("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}, {%d,%d,%d,%d}", + l->compositionType, l->flags, l->handle, l->transform, l->blending, + l->sourceCrop.left, + l->sourceCrop.top, + l->sourceCrop.right, + l->sourceCrop.bottom, + l->displayFrame.left, + l->displayFrame.top, + l->displayFrame.right, + l->displayFrame.bottom); +} + +static int set_src_dst_info(hwc_layer_t *cur, + struct hwc_win_info_t *win, + struct sec_img *src_img, + struct sec_img *dst_img, + struct sec_rect *src_rect, + struct sec_rect *dst_rect, + int win_idx) +{ + IMG_native_handle_t *prev_handle = (IMG_native_handle_t *)(cur->handle); + + // set src image + src_img->w = prev_handle->iWidth; + src_img->h = prev_handle->iHeight; + src_img->format = prev_handle->iFormat; + src_img->base = NULL; + src_img->offset = 0; + src_img->mem_id =0; + + src_img->mem_type = HWC_PHYS_MEM_TYPE; + src_img->w = (src_img->w + 15) & (~15); + src_img->h = (src_img->h + 1) & (~1) ; + + //set src rect + src_rect->x = SEC_MAX(cur->sourceCrop.left, 0); + src_rect->y = SEC_MAX(cur->sourceCrop.top, 0); + src_rect->w = SEC_MAX(cur->sourceCrop.right - cur->sourceCrop.left, 0); + src_rect->w = SEC_MIN(src_rect->w, src_img->w - src_rect->x); + src_rect->h = SEC_MAX(cur->sourceCrop.bottom - cur->sourceCrop.top, 0); + src_rect->h = SEC_MIN(src_rect->h, src_img->h - src_rect->y); + + //set dst image + dst_img->w = win->lcd_info.xres; + dst_img->h = win->lcd_info.yres; + + switch (win->lcd_info.bits_per_pixel) { + case 32: + dst_img->format = HAL_PIXEL_FORMAT_RGBX_8888; + break; + default: + dst_img->format = HAL_PIXEL_FORMAT_RGB_565; + break; + } + + dst_img->base = win->addr[win->buf_index]; + dst_img->offset = 0; + dst_img->mem_id = 0; + dst_img->mem_type = HWC_PHYS_MEM_TYPE; + + //set dst rect + //fimc dst image will be stored from left top corner + dst_rect->x = 0; + dst_rect->y = 0; + dst_rect->w = win->rect_info.w; + dst_rect->h = win->rect_info.h; + + LOGV("%s::sr_x %d sr_y %d sr_w %d sr_h %d dr_x %d dr_y %d dr_w %d dr_h %d ", + __func__, src_rect->x, src_rect->y, src_rect->w, src_rect->h, + dst_rect->x, dst_rect->y, dst_rect->w, dst_rect->h); + + return 0; +} + +static int get_hwc_compos_decision(hwc_layer_t* cur) +{ + if(cur->flags & HWC_SKIP_LAYER || !cur->handle) { + LOGV("%s::is_skip_layer %d cur->handle %x", + __func__, cur->flags & HWC_SKIP_LAYER, (uint32_t)cur->handle); + return HWC_FRAMEBUFFER; + } + + IMG_native_handle_t *prev_handle = (IMG_native_handle_t *)(cur->handle); + int compositionType = HWC_FRAMEBUFFER; + + /* check here....if we have any resolution constraints */ + if (((cur->sourceCrop.right - cur->sourceCrop.left) < 16) || + ((cur->sourceCrop.bottom - cur->sourceCrop.top) < 8)) + return compositionType; + + if ((cur->transform == HAL_TRANSFORM_ROT_90) || + (cur->transform == HAL_TRANSFORM_ROT_270)) { + if(((cur->displayFrame.right - cur->displayFrame.left) < 4)|| + ((cur->displayFrame.bottom - cur->displayFrame.top) < 8)) + return compositionType; + } else if (((cur->displayFrame.right - cur->displayFrame.left) < 8) || + ((cur->displayFrame.bottom - cur->displayFrame.top) < 4)) + return compositionType; + + if((prev_handle->usage & GRALLOC_USAGE_PHYS_CONTIG) && + (cur->blending == HWC_BLENDING_NONE)) + compositionType = HWC_OVERLAY; + else + compositionType = HWC_FRAMEBUFFER; + + LOGV("%s::compositionType %d bpp %d format %x usage %x", + __func__,compositionType, prev_handle->uiBpp, prev_handle->iFormat, + prev_handle->usage & GRALLOC_USAGE_PHYS_CONTIG); + + return compositionType; +} + +static int assign_overlay_window(struct hwc_context_t *ctx, + hwc_layer_t *cur, + int win_idx, + int layer_idx) +{ + struct hwc_win_info_t *win; + sec_rect rect; + int ret = 0; + + if(NUM_OF_WIN <= win_idx) + return -1; + + win = &ctx->win[win_idx]; + + rect.x = SEC_MAX(cur->displayFrame.left, 0); + rect.y = SEC_MAX(cur->displayFrame.top, 0); + rect.w = SEC_MIN(cur->displayFrame.right - rect.x, win->lcd_info.xres - rect.x); + rect.h = SEC_MIN(cur->displayFrame.bottom - rect.y, win->lcd_info.yres - rect.y); + win->set_win_flag = 0; + + if((rect.x != win->rect_info.x) || (rect.y != win->rect_info.y) || + (rect.w != win->rect_info.w) || (rect.h != win->rect_info.h)){ + win->rect_info.x = rect.x; + win->rect_info.y = rect.y; + win->rect_info.w = rect.w; + win->rect_info.h = rect.h; + win->set_win_flag = 1; + win->layer_prev_buf = 0; + } + + win->layer_index = layer_idx; + win->status = HWC_WIN_RESERVED; + + LOGV("%s:: win_x %d win_y %d win_w %d win_h %d lay_idx %d win_idx %d", + __func__, win->rect_info.x, win->rect_info.y, win->rect_info.w, + win->rect_info.h, win->layer_index, win_idx ); + + return 0; +} + +static void reset_win_rect_info(hwc_win_info_t *win) +{ + win->rect_info.x = 0; + win->rect_info.y = 0; + win->rect_info.w = 0; + win->rect_info.h = 0; + return; +} + +static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) +{ + + struct hwc_context_t* ctx = (struct hwc_context_t*)dev; + int overlay_win_cnt = 0; + int compositionType = 0; + int ret; + + //if geometry is not changed, there is no need to do any work here + if( !list || (!(list->flags & HWC_GEOMETRY_CHANGED))) + return 0; + + //all the windows are free here.... + for (int i = 0; i < NUM_OF_WIN; i++) { + ctx->win[i].status = HWC_WIN_FREE; + ctx->win[i].buf_index = 0; + } + ctx->num_of_hwc_layer = 0; + ctx->num_of_fb_layer = 0; + LOGV("%s:: hwc_prepare list->numHwLayers %d", __func__, list->numHwLayers); + + for (int i = 0; i < list->numHwLayers ; i++) { + hwc_layer_t* cur = &list->hwLayers[i]; + + if (overlay_win_cnt < NUM_OF_WIN) { + compositionType = get_hwc_compos_decision(cur); + + if (compositionType == HWC_FRAMEBUFFER) { + cur->compositionType = HWC_FRAMEBUFFER; + ctx->num_of_fb_layer++; + } else { + ret = assign_overlay_window(ctx, cur, overlay_win_cnt, i); + if (ret != 0) { + cur->compositionType = HWC_FRAMEBUFFER; + ctx->num_of_fb_layer++; + continue; + } + + cur->compositionType = HWC_OVERLAY; + cur->hints = HWC_HINT_CLEAR_FB; + overlay_win_cnt++; + ctx->num_of_hwc_layer++; + } + } else { + cur->compositionType = HWC_FRAMEBUFFER; + ctx->num_of_fb_layer++; + } + } + + if(list->numHwLayers != (ctx->num_of_fb_layer + ctx->num_of_hwc_layer)) + LOGV("%s:: numHwLayers %d num_of_fb_layer %d num_of_hwc_layer %d ", + __func__, list->numHwLayers, ctx->num_of_fb_layer, + ctx->num_of_hwc_layer); + + if (overlay_win_cnt < NUM_OF_WIN) { + //turn off the free windows + for (int i = overlay_win_cnt; i < NUM_OF_WIN; i++) { + window_hide(&ctx->win[i]); + reset_win_rect_info(&ctx->win[i]); + } + } + return 0; +} + +static int hwc_set(hwc_composer_device_t *dev, + hwc_display_t dpy, + hwc_surface_t sur, + hwc_layer_list_t* list) +{ + struct hwc_context_t *ctx = (struct hwc_context_t *)dev; + unsigned int phyAddr[MAX_NUM_PLANES]; + int skipped_window_mask = 0; + hwc_layer_t* cur; + struct hwc_win_info_t *win; + int ret; + struct sec_img src_img; + struct sec_img dst_img; + struct sec_rect src_rect; + struct sec_rect dst_rect; + + + if (dpy == NULL && sur == NULL && list == NULL) { + // release our resources, the screen is turning off + // in our case, there is nothing to do. + ctx->num_of_fb_layer_prev = 0; + return 0; + } + + bool need_swap_buffers = ctx->num_of_fb_layer > 0; + + /* + * H/W composer documentation states: + * There is an implicit layer containing opaque black + * pixels behind all the layers in the list. + * It is the responsibility of the hwcomposer module to make + * sure black pixels are output (or blended from). + * + * Since we're using a blitter, we need to erase the frame-buffer when + * switching to all-overlay mode. + * + */ + if (ctx->num_of_hwc_layer && + ctx->num_of_fb_layer==0 && ctx->num_of_fb_layer_prev) { + /* we're clearing the screen using GLES here, this is very + * hack-ish, ideal we would use the fimc (if it can do it) */ + glDisable(GL_SCISSOR_TEST); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + glEnable(GL_SCISSOR_TEST); + need_swap_buffers = true; + } + + ctx->num_of_fb_layer_prev = ctx->num_of_fb_layer; + + if (need_swap_buffers || !list) { + EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); + if (!sucess) { + return HWC_EGL_ERROR; + } + } + + if (!list) { + /* turn off the all windows */ + for (int i = 0; i < NUM_OF_WIN; i++) { + window_hide(&ctx->win[i]); + reset_win_rect_info(&ctx->win[i]); + ctx->win[i].status = HWC_WIN_FREE; + } + ctx->num_of_hwc_layer = 0; + return 0; + } + + if(ctx->num_of_hwc_layer > NUM_OF_WIN) + ctx->num_of_hwc_layer = NUM_OF_WIN; + + /* compose hardware layers here */ + for (uint32_t i = 0; i < ctx->num_of_hwc_layer; i++) { + win = &ctx->win[i]; + if (win->status == HWC_WIN_RESERVED) { + cur = &list->hwLayers[win->layer_index]; + + if (cur->compositionType == HWC_OVERLAY) { + + ret = gpsGrallocModule->GetPhyAddrs(gpsGrallocModule, + cur->handle, phyAddr); + if (ret) { + LOGE("%s::GetPhyAddrs fail : ret=%d\n", __func__, ret); + skipped_window_mask |= (1 << i); + continue; + } + + /* initialize the src & dist context for fimc */ + set_src_dst_info (cur, win, &src_img, &dst_img, &src_rect, + &dst_rect, i); + + ret = runFimc(ctx, &src_img, &src_rect, &dst_img, &dst_rect, + phyAddr, cur->transform); + if (ret < 0){ + LOGE("%s::runFimc fail : ret=%d\n", __func__, ret); + skipped_window_mask |= (1 << i); + continue; + } + + if (win->set_win_flag == 1) { + /* turnoff the window and set the window position with new conf... */ + if (window_set_pos(win) < 0) { + LOGE("%s::window_set_pos is failed : %s", __func__, + strerror(errno)); + skipped_window_mask |= (1 << i); + continue; + } + win->set_win_flag = 0; + } + + /* is the frame didn't change, it needs to be composited + * because something else below it could have changed, however + * it doesn't need to be swapped. + */ + if (win->layer_prev_buf != (uint32_t)cur->handle) { + win->layer_prev_buf = (uint32_t)cur->handle; + window_pan_display(win); + win->buf_index = (win->buf_index + 1) % NUM_OF_WIN_BUF; + } + + if(win->power_state == 0) + window_show(win); + + } else { + LOGE("%s:: error : layer %d compositionType should have been \ + HWC_OVERLAY", __func__, win->layer_index); + skipped_window_mask |= (1 << i); + continue; + } + } else { + LOGE("%s:: error : window status should have been HWC_WIN_RESERVED \ + by now... ", __func__); + skipped_window_mask |= (1 << i); + continue; + } + } + + if (skipped_window_mask) { + //turn off the free windows + for (int i = 0; i < NUM_OF_WIN; i++) { + if (skipped_window_mask & (1 << i)) + window_hide(&ctx->win[i]); + } + } + + return 0; +} + +static int hwc_device_close(struct hw_device_t *dev) +{ + struct hwc_context_t* ctx = (struct hwc_context_t*)dev; + int ret = 0; + int i; + + if (ctx) { + if (destroyFimc(&ctx->fimc) < 0) { + LOGE("%s::destroyFimc fail", __func__); + ret = -1; + } + + for (i = 0; i < NUM_OF_WIN; i++) { + if (window_close(&ctx->win[i]) < 0) { + LOGE("%s::window_close() fail", __func__); + ret = -1; + } + } + + free(ctx); + } + return ret; +} + +static int hwc_device_open(const struct hw_module_t* module, const char* name, + struct hw_device_t** device) +{ + int status = 0; + struct hwc_win_info_t *win; + + if(hw_get_module(GRALLOC_HARDWARE_MODULE_ID, + (const hw_module_t**)&gpsGrallocModule)) + return -EINVAL; + + if(strcmp(gpsGrallocModule->base.common.author, "Imagination Technologies")) + return -EINVAL; + + if (strcmp(name, HWC_HARDWARE_COMPOSER)) + return -EINVAL; + + struct hwc_context_t *dev; + dev = (hwc_context_t*)malloc(sizeof(*dev)); + + /* initialize our state here */ + memset(dev, 0, sizeof(*dev)); + + /* initialize the procs */ + dev->device.common.tag = HARDWARE_DEVICE_TAG; + dev->device.common.version = 0; + dev->device.common.module = const_cast(module); + dev->device.common.close = hwc_device_close; + + dev->device.prepare = hwc_prepare; + dev->device.set = hwc_set; + + *device = &dev->device.common; + + /* initializing */ + memset(&(dev->fimc), 0, sizeof(s5p_fimc_t)); + dev->fimc.dev_fd = -1; + + /* open WIN0 & WIN1 here */ + for (int i = 0; i < NUM_OF_WIN; i++) { + if (window_open(&(dev->win[i]), i) < 0) { + LOGE("%s:: Failed to open window %d device ", __func__, i); + status = -EINVAL; + goto err; + } + } + + /* get default window config */ + if (window_get_global_lcd_info(&dev->lcd_info) < 0) { + LOGE("%s::window_get_global_lcd_info is failed : %s", + __func__, strerror(errno)); + status = -EINVAL; + goto err; + } + + dev->lcd_info.yres_virtual = dev->lcd_info.yres * NUM_OF_WIN_BUF; + + /* initialize the window context */ + for (int i = 0; i < NUM_OF_WIN; i++) { + win = &dev->win[i]; + memcpy(&win->lcd_info, &dev->lcd_info, sizeof(struct fb_var_screeninfo)); + memcpy(&win->var_info, &dev->lcd_info, sizeof(struct fb_var_screeninfo)); + + win->rect_info.x = 0; + win->rect_info.y = 0; + win->rect_info.w = win->var_info.xres; + win->rect_info.h = win->var_info.yres; + + if (window_set_pos(win) < 0) { + LOGE("%s::window_set_pos is failed : %s", + __func__, strerror(errno)); + status = -EINVAL; + goto err; + } + + if (window_get_info(win) < 0) { + LOGE("%s::window_get_info is failed : %s", + __func__, strerror(errno)); + status = -EINVAL; + goto err; + } + + win->size = win->fix_info.line_length * win->var_info.yres; + + if (!win->fix_info.smem_start){ + LOGE("%s:: win-%d failed to get the reserved memory", __func__, i); + status = -EINVAL; + goto err; + } + + for (int j = 0; j < NUM_OF_WIN_BUF; j++) { + win->addr[j] = win->fix_info.smem_start + (win->size * j); + LOGI("%s::win-%d add[%d] %x ", __func__, i, j, win->addr[j]); + } + } + + /* open pp */ + if (createFimc(&dev->fimc) < 0) { + LOGE("%s::creatFimc() fail", __func__); + status = -EINVAL; + goto err; + } + + LOGD("%s:: success\n", __func__); + + return 0; + +err: + if (destroyFimc(&dev->fimc) < 0) + LOGE("%s::destroyFimc() fail", __func__); + + for (int i = 0; i < NUM_OF_WIN; i++) { + if (window_close(&dev->win[i]) < 0) + LOGE("%s::window_close() fail", __func__); + } + + return status; +} diff --git a/libhwcomposer/SecHWCUtils.cpp b/libhwcomposer/SecHWCUtils.cpp new file mode 100644 index 0000000..4a5b7b4 --- /dev/null +++ b/libhwcomposer/SecHWCUtils.cpp @@ -0,0 +1,890 @@ +/* + * Copyright (C) 2010 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. + */ + +/* + * + * @author Rama, Meka(v.meka@samsung.com) + Sangwoo, Park(sw5771.park@samsung.com) + Jamie Oh (jung-min.oh@samsung.com) + * @date 2011-07-28 + * + */ + +#include "SecHWCUtils.h" + +int window_open(struct hwc_win_info_t *win, int id) +{ + char name[64]; + + char const * const device_template = "/dev/graphics/fb%u"; + /* window & FB maping + fb0 -> win-id : 2 + fb1 -> win-id : 3 + fb2 -> win-id : 4 + fb3 -> win-id : 0 + fb4 -> win_id : 1 + it is pre assumed that ...win0 or win1 is used here.. + */ + switch (id) { + case 0: + case 1: + case 2: + break; + default: + LOGE("%s::id(%d) is weird", __func__, id); + goto error; + } + + snprintf(name, 64, device_template, (id + 3)%5); + + win->fd = open(name, O_RDWR); + if (win->fd < 0) { + LOGE("%s::Failed to open window device (%s) : %s", + __func__, strerror(errno), device_template); + goto error; + } + + return 0; + +error: + if (0 <= win->fd) + close(win->fd); + win->fd = -1; + + return -1; +} + +int window_close(struct hwc_win_info_t *win) +{ + int ret = 0; + + if (0 <= win->fd) + ret = close(win->fd); + win->fd = -1; + + return ret; +} + +int window_set_pos(struct hwc_win_info_t *win) +{ + struct secfb_user_window window; + + /* before changing the screen configuration...powerdown the window */ + if(window_hide(win) != 0) + return -1; + + win->var_info.xres = win->rect_info.w; + win->var_info.yres = win->rect_info.h; + + win->var_info.activate &= ~FB_ACTIVATE_MASK; + win->var_info.activate |= FB_ACTIVATE_FORCE; + + if (ioctl(win->fd, FBIOPUT_VSCREENINFO, &(win->var_info)) < 0) { + LOGE("%s::FBIOPUT_VSCREENINFO(%d, %d) fail", + __func__, win->rect_info.w, win->rect_info.h); + return -1; + } + + window.x = win->rect_info.x; + window.y = win->rect_info.y; + + if (ioctl(win->fd, SECFB_WIN_POSITION, &window) < 0) { + LOGE("%s::S3CFB_WIN_POSITION(%d, %d) fail", + __func__, window.x, window.y); + return -1; + } + + return 0; +} + +int window_get_info(struct hwc_win_info_t *win) +{ + if (ioctl(win->fd, FBIOGET_FSCREENINFO, &win->fix_info) < 0) { + LOGE("FBIOGET_FSCREENINFO failed : %s", strerror(errno)); + goto error; + } + + return 0; + +error: + win->fix_info.smem_start = 0; + + return -1; +} + +int window_pan_display(struct hwc_win_info_t *win) +{ + struct fb_var_screeninfo *lcd_info = &(win->lcd_info); + + lcd_info->yoffset = lcd_info->yres * win->buf_index; + + if (ioctl(win->fd, FBIOPAN_DISPLAY, lcd_info) < 0) { + LOGE("%s::FBIOPAN_DISPLAY(%d / %d / %d) fail(%s)", + __func__, lcd_info->yres, win->buf_index, lcd_info->yres_virtual, + strerror(errno)); + return -1; + } + return 0; +} + +int window_show(struct hwc_win_info_t *win) +{ + if(win->power_state == 0) { + if (ioctl(win->fd, FBIOBLANK, FB_BLANK_UNBLANK) < 0) { + LOGE("%s: FBIOBLANK failed : (%d:%s)", __func__, win->fd, + strerror(errno)); + return -1; + } + win->power_state = 1; + } + return 0; +} + +int window_hide(struct hwc_win_info_t *win) +{ + if (win->power_state == 1) { + if (ioctl(win->fd, FBIOBLANK, FB_BLANK_POWERDOWN) < 0) { + LOGE("%s::FBIOBLANK failed : (%d:%s)", + __func__, win->fd, strerror(errno)); + return -1; + } + win->power_state = 0; + } + return 0; +} + +int window_get_global_lcd_info(struct fb_var_screeninfo *lcd_info) +{ + struct hwc_win_info_t win; + int ret = 0; + + if (window_open(&win, 2) < 0) { + LOGE("%s:: Failed to open window 2 device ", __func__); + return -1; + } + + if (ioctl(win.fd, FBIOGET_VSCREENINFO, lcd_info) < 0) { + LOGE("FBIOGET_VSCREENINFO failed : %s", strerror(errno)); + ret = -1; + goto fun_err; + } + + if (lcd_info->xres == 0) { + lcd_info->xres = DEFAULT_LCD_WIDTH; + lcd_info->xres_virtual = DEFAULT_LCD_WIDTH; + } + + if (lcd_info->yres == 0) { + lcd_info->yres = DEFAULT_LCD_HEIGHT; + lcd_info->yres_virtual = DEFAULT_LCD_HEIGHT * NUM_OF_WIN_BUF; + } + + if (lcd_info->bits_per_pixel == 0) + lcd_info->bits_per_pixel = DEFAULT_LCD_BPP; + +fun_err: + if (window_close(&win) < 0) + LOGE("%s::window2 close fail", __func__); + + return ret; +} + +int fimc_v4l2_set_src(int fd, unsigned int hw_ver, s5p_fimc_img_info *src) +{ + struct v4l2_format fmt; + struct v4l2_cropcap cropcap; + struct v4l2_crop crop; + struct v4l2_requestbuffers req; + + /* + * To set size & format for source image (DMA-INPUT) + */ + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + fmt.fmt.pix.width = src->full_width; + fmt.fmt.pix.height = src->full_height; + fmt.fmt.pix.pixelformat = src->color_space; + fmt.fmt.pix.field = V4L2_FIELD_NONE; + + if (ioctl (fd, VIDIOC_S_FMT, &fmt) < 0) { + LOGE("VIDIOC_S_FMT failed : errno=%d (%s) : fd=%d", errno, + strerror(errno), fd); + return -1; + } + + /* + * crop input size + */ + crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + if (0x50 == hw_ver) { + crop.c.left = src->start_x; + crop.c.top = src->start_y; + } else { + crop.c.left = 0; + crop.c.top = 0; + } + crop.c.width = src->width; + crop.c.height = src->height; + if (ioctl(fd, VIDIOC_S_CROP, &crop) < 0) { + LOGE("Error in video VIDIOC_S_CROP (%d, %d, %d, %d)", + crop.c.left, crop.c.top, crop.c.width, crop.c.height); + return -1; + } + + /* + * input buffer type + */ + req.count = 1; + req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + req.memory = V4L2_MEMORY_USERPTR; + + if (ioctl (fd, VIDIOC_REQBUFS, &req) < 0) { + LOGE("Error in VIDIOC_REQBUFS"); + return -1; + } + + return 0; +} + +int fimc_v4l2_set_dst(int fd, + s5p_fimc_img_info *dst, + int rotation, + int flag_h_flip, + int flag_v_flip, + unsigned int addr) +{ + struct v4l2_format sFormat; + struct v4l2_control vc; + struct v4l2_framebuffer fbuf; + + /* + * set rotation configuration + */ + vc.id = V4L2_CID_HFLIP; + vc.value = flag_h_flip; + if (ioctl(fd, VIDIOC_S_CTRL, &vc) < 0) { + LOGE("Error in video VIDIOC_S_CTRL - flag_h_flip (%d)", flag_h_flip); + return -1; + } + + vc.id = V4L2_CID_VFLIP; + vc.value = flag_v_flip; + if (ioctl(fd, VIDIOC_S_CTRL, &vc) < 0) { + LOGE("Error in video VIDIOC_S_CTRL - flag_v_flip (%d)", flag_v_flip); + return -1; + } + + vc.id = V4L2_CID_ROTATION; + vc.value = rotation; + if (ioctl(fd, VIDIOC_S_CTRL, &vc) < 0) { + LOGE("Error in video VIDIOC_S_CTRL - rotation (%d)", rotation); + return -1; + } + + /* + * set size, format & address for destination image (DMA-OUTPUT) + */ + if (ioctl (fd, VIDIOC_G_FBUF, &fbuf) < 0) { + LOGE("Error in video VIDIOC_G_FBUF"); + return -1; + } + + fbuf.base = (void *)addr; + fbuf.fmt.width = dst->full_width; + fbuf.fmt.height = dst->full_height; + fbuf.fmt.pixelformat = dst->color_space; + if (ioctl (fd, VIDIOC_S_FBUF, &fbuf) < 0) { + LOGE("Error in video VIDIOC_S_FBUF 0x%x %d %d %d", + (void *)addr, dst->full_width, dst->full_height, + dst->color_space); + return -1; + } + + /* + * set destination window + */ + sFormat.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + sFormat.fmt.win.w.left = dst->start_x; + sFormat.fmt.win.w.top = dst->start_y; + sFormat.fmt.win.w.width = dst->width; + sFormat.fmt.win.w.height = dst->height; + if (ioctl(fd, VIDIOC_S_FMT, &sFormat) < 0) { + LOGE("Error in video VIDIOC_S_FMT %d %d %d %d", + dst->start_x, dst->start_y, dst->width, dst->height); + return -1; + } + + return 0; +} + +int fimc_v4l2_stream_on(int fd, enum v4l2_buf_type type) +{ + if (ioctl (fd, VIDIOC_STREAMON, &type) < 0) { + LOGE("Error in VIDIOC_STREAMON"); + return -1; + } + + return 0; +} + +int fimc_v4l2_queue(int fd, struct fimc_buf *fimc_buf) +{ + struct v4l2_buffer buf; + + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + buf.memory = V4L2_MEMORY_USERPTR; + buf.m.userptr = (unsigned long)fimc_buf; + buf.length = 0; + buf.index = 0; + + if (ioctl (fd, VIDIOC_QBUF, &buf) < 0) { + LOGE("Error in VIDIOC_QBUF"); + return -1; + } + + return 0; +} + +int fimc_v4l2_dequeue(int fd) +{ + struct v4l2_buffer buf; + + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + buf.memory = V4L2_MEMORY_USERPTR; + + if (ioctl (fd, VIDIOC_DQBUF, &buf) < 0) { + LOGE("Error in VIDIOC_DQBUF"); + return -1; + } + + return buf.index; +} + +int fimc_v4l2_stream_off(int fd) +{ + enum v4l2_buf_type type; + type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + if (ioctl (fd, VIDIOC_STREAMOFF, &type) < 0) { + LOGE("Error in VIDIOC_STREAMOFF"); + return -1; + } + + return 0; +} + +int fimc_v4l2_clr_buf(int fd) +{ + struct v4l2_requestbuffers req; + + req.count = 0; + req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + req.memory = V4L2_MEMORY_USERPTR; + + if (ioctl (fd, VIDIOC_REQBUFS, &req) < 0) { + LOGE("Error in VIDIOC_REQBUFS"); + } + + return 0; +} + +int fimc_handle_oneshot(int fd, struct fimc_buf *fimc_buf) +{ + int ret =0; + + if (fimc_v4l2_stream_on(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT) < 0) { + LOGE("Fail : v4l2_stream_on()"); + return -1; + } + + if (fimc_v4l2_queue(fd, fimc_buf) < 0) { + LOGE("Fail : v4l2_queue()"); + ret = -1; + goto stream_off; + } + + if (fimc_v4l2_dequeue(fd) < 0) { + LOGE("Fail : v4l2_dequeue()"); + ret = -1; + goto stream_off; + } + +stream_off: + if (fimc_v4l2_stream_off(fd) < 0) { + LOGE("Fail : v4l2_stream_off()"); + return -1; + } + + if (fimc_v4l2_clr_buf(fd) < 0) { + LOGE("Fail : v4l2_clr_buf()"); + return -1; + } + + return ret; +} + +static int get_src_phys_addr(struct hwc_context_t *ctx, + sec_img *src_img, + unsigned int *phyAddr) +{ + s5p_fimc_t *fimc = &ctx->fimc; + + if(src_img->mem_type == HWC_PHYS_MEM_TYPE) { + switch(src_img->format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + fimc->params.src.buf_addr_phy_rgb_y = phyAddr[0]; + fimc->params.src.buf_addr_phy_cb = phyAddr[1]; + break; + default: + LOGE("%s format error (format=0x%x)", __func__, + src_img->format); + return -1; + } + } else { + LOGE("%s mem_type error (mem_type=%d)", __func__, src_img->mem_type); + return -1; + } + + return 0; +} + +static int get_dst_phys_addr(struct hwc_context_t *ctx, + sec_img *dst_img) +{ + unsigned int dst_phys_addr = 0; + + if (HWC_PHYS_MEM_TYPE == dst_img->mem_type && 0 != dst_img->base) + dst_phys_addr = dst_img->base; + else { + LOGE("%s::get_dst_phys_addr fail ", __func__); + dst_phys_addr = 0; + } + return dst_phys_addr; +} + +static inline int rotateValueHAL2PP(unsigned char transform, + int *flag_h_flip, + int *flag_v_flip) +{ + int rotate_result = 0; + int rotate_flag = transform & 0x7; + + switch (rotate_flag) { + case HAL_TRANSFORM_ROT_90: + rotate_result = 90; + break; + case HAL_TRANSFORM_ROT_180: + rotate_result = 180; + break; + case HAL_TRANSFORM_ROT_270: + rotate_result = 270; + break; + } + + switch (rotate_flag) { + case HAL_TRANSFORM_FLIP_H: + *flag_h_flip = 1; + *flag_v_flip = 0; + break; + case HAL_TRANSFORM_FLIP_V: + *flag_h_flip = 0; + *flag_v_flip = 1; + break; + default: + *flag_h_flip = 0; + *flag_v_flip = 0; + break; + } + + return rotate_result; +} + +static inline int multipleOfN(int number, int N) +{ + int result = number; + switch (N) { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + case 256: + result = (number - (number & (N-1))); + break; + default: + result = number - (number % N); + break; + } + return result; +} + +static inline int widthOfPP(unsigned int ver, + int pp_color_format, + int number) +{ + if (0x50 == ver) { + switch(pp_color_format) { + /* 422 1/2/3 plane */ + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_YUV422P: + + /* 420 2/3 plane */ + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV12T: + case V4L2_PIX_FMT_YUV420: + return multipleOfN(number, 2); + + default : + return number; + } + } else { + switch(pp_color_format) { + case V4L2_PIX_FMT_RGB565: + return multipleOfN(number, 8); + + case V4L2_PIX_FMT_RGB32: + return multipleOfN(number, 4); + + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + return multipleOfN(number, 4); + + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV16: + return multipleOfN(number, 8); + + case V4L2_PIX_FMT_YUV422P: + return multipleOfN(number, 16); + + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV12T: + return multipleOfN(number, 8); + + case V4L2_PIX_FMT_YUV420: + return multipleOfN(number, 16); + + default : + return number; + } + } + return number; +} + +static inline int heightOfPP(int pp_color_format, + int number) +{ + switch(pp_color_format) { + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV12T: + case V4L2_PIX_FMT_YUV420: + return multipleOfN(number, 2); + + default : + return number; + } + return number; +} + +static int runcFimcCore(struct hwc_context_t *ctx, + sec_img *src_img, + sec_rect *src_rect, + uint32_t src_color_space, + unsigned int dst_phys_addr, + sec_img *dst_img, + sec_rect *dst_rect, + uint32_t dst_color_space, + int transform) +{ + s5p_fimc_t * fimc = &ctx->fimc; + s5p_fimc_params_t * params = &(fimc->params); + + unsigned int frame_size = 0; + struct fimc_buf fimc_src_buf; + + int src_bpp, src_planes; + int flag_h_flip = 0; + int flag_v_flip = 0; + int rotate_value = rotateValueHAL2PP(transform, &flag_h_flip, &flag_v_flip); + + /* set post processor configuration */ + params->src.full_width = src_img->w; + params->src.full_height = src_img->h; + params->src.start_x = src_rect->x; + params->src.start_y = src_rect->y; + params->src.width = widthOfPP(fimc->hw_ver, src_color_space, src_rect->w); + params->src.height = heightOfPP(src_color_space, src_rect->h); + params->src.color_space = src_color_space; + + + /* check minimum */ + if (src_rect->w < 16 || src_rect->h < 8) { + LOGE("%s src size is not supported by fimc : f_w=%d f_h=%d x=%d y=%d \ + w=%d h=%d (ow=%d oh=%d) format=0x%x", __func__, + params->src.full_width, params->src.full_height, + params->src.start_x, params->src.start_y, params->src.width, + params->src.height, src_rect->w, src_rect->h, + params->src.color_space); + return -1; + } + +switch (rotate_value) { + case 0: + params->dst.full_width = dst_img->w; + params->dst.full_height = dst_img->h; + + params->dst.start_x = dst_rect->x; + params->dst.start_y = dst_rect->y; + + params->dst.width = + widthOfPP(fimc->hw_ver, dst_color_space, dst_rect->w); + params->dst.height = heightOfPP(dst_color_space, dst_rect->h); + break; + case 90: + params->dst.full_width = dst_img->h; + params->dst.full_height = dst_img->w; + + params->dst.start_x = dst_rect->y; + params->dst.start_y = dst_img->w - (dst_rect->x + dst_rect->w); + + params->dst.width = + widthOfPP(fimc->hw_ver, dst_color_space, dst_rect->h); + params->dst.height = + widthOfPP(fimc->hw_ver, dst_color_space, dst_rect->w); + + if (0x50 > fimc->hw_ver) + params->dst.start_y += (dst_rect->w - params->dst.height); + break; + case 180: + params->dst.full_width = dst_img->w; + params->dst.full_height = dst_img->h; + + params->dst.start_x = dst_img->w - (dst_rect->x + dst_rect->w); + params->dst.start_y = dst_img->h - (dst_rect->y + dst_rect->h); + + params->dst.width = + widthOfPP(fimc->hw_ver, dst_color_space, dst_rect->w); + params->dst.height = heightOfPP(dst_color_space, dst_rect->h); + break; + case 270: + params->dst.full_width = dst_img->h; + params->dst.full_height = dst_img->w; + + params->dst.start_x = dst_img->h - (dst_rect->y + dst_rect->h); + params->dst.start_y = dst_rect->x; + + params->dst.width = + widthOfPP(fimc->hw_ver, dst_color_space, dst_rect->h); + params->dst.height = + widthOfPP(fimc->hw_ver, dst_color_space, dst_rect->w); + + if (0x50 > fimc->hw_ver) + params->dst.start_y += (dst_rect->w - params->dst.height); + break; + } + + + params->dst.color_space = dst_color_space; + + /* check minimum */ + if (dst_rect->w < 8 || dst_rect->h < 4) { + LOGE("%s dst size is not supported by fimc : \ + f_w=%d f_h=%d x=%d y=%d w=%d h=%d (ow=%d oh=%d) format=0x%x", + __func__, params->dst.full_width, params->dst.full_height, + params->dst.start_x, params->dst.start_y, params->dst.width, + params->dst.height, dst_rect->w, dst_rect->h, + params->dst.color_space); + return -1; + } + + /* check scaling limit + * the scaling limie must not be more than MAX_RESIZING_RATIO_LIMIT + */ + if (((src_rect->w > dst_rect->w) && + ((src_rect->w / dst_rect->w) > MAX_RESIZING_RATIO_LIMIT)) || + ((dst_rect->w > src_rect->w) && + ((dst_rect->w / src_rect->w) > MAX_RESIZING_RATIO_LIMIT))) { + LOGE("%s over scaling limit : src.w=%d dst.w=%d (limit=%d)", + __func__, src_rect->w, dst_rect->w, MAX_RESIZING_RATIO_LIMIT); + return -1; + } + + + /* set configuration related to destination (DMA-OUT) + * - set input format & size + * - crop input size + * - set input buffer + * - set buffer type (V4L2_MEMORY_USERPTR) + */ + if (fimc_v4l2_set_dst(fimc->dev_fd, + ¶ms->dst, + rotate_value, + flag_h_flip, + flag_v_flip, + dst_phys_addr) < 0) { + return -1; + } + + /* set configuration related to source (DMA-INPUT) + * - set input format & size + * - crop input size + * - set input buffer + * - set buffer type (V4L2_MEMORY_USERPTR) + */ + if (fimc_v4l2_set_src(fimc->dev_fd, fimc->hw_ver, ¶ms->src) < 0) + return -1; + + /* set input dma address (Y/RGB, Cb, Cr) */ + switch (src_img->format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + /* for video display zero copy case */ + fimc_src_buf.base[0] = params->src.buf_addr_phy_rgb_y; + fimc_src_buf.base[1] = params->src.buf_addr_phy_cb; + break; + + default: + /* set source image */ + fimc_src_buf.base[0] = params->src.buf_addr_phy_rgb_y; + break; + } + + if (fimc_handle_oneshot(fimc->dev_fd, &fimc_src_buf) < 0) { + fimc_v4l2_clr_buf(fimc->dev_fd); + return -1; + } + + return 0; +} + +int createFimc(s5p_fimc_t *fimc) +{ + struct v4l2_capability cap; + struct v4l2_format fmt; + struct v4l2_control vc; + + #define PP_DEVICE_DEV_NAME "/dev/video1" + + /* open device file */ + if(fimc->dev_fd < 0) { + fimc->dev_fd = open(PP_DEVICE_DEV_NAME, O_RDWR); + + if (fimc->dev_fd < 0) { + LOGE("%s::Post processor open error (%d)", __func__, errno); + goto err; + } + } + + /* check capability */ + if (ioctl(fimc->dev_fd, VIDIOC_QUERYCAP, &cap) < 0) { + LOGE("VIDIOC_QUERYCAP failed"); + goto err; + } + + if (!(cap.capabilities & V4L2_CAP_STREAMING)) { + LOGE("%d has no streaming support", fimc->dev_fd); + goto err; + } + + if (!(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { + LOGE("%d is no video output", fimc->dev_fd); + goto err; + } + + /* + * malloc fimc_outinfo structure + */ + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + if (ioctl(fimc->dev_fd, VIDIOC_G_FMT, &fmt) < 0) { + LOGE("%s::Error in video VIDIOC_G_FMT", __func__); + goto err; + } + + vc.id = V4L2_CID_FIMC_VERSION; + vc.value = 0; + + if (ioctl(fimc->dev_fd, VIDIOC_G_CTRL, &vc) < 0) { + LOGE("%s::Error in video VIDIOC_G_CTRL", __func__); + goto err; + } + fimc->hw_ver = vc.value; + + return 0; + +err: + if (0 <= fimc->dev_fd) + close(fimc->dev_fd); + fimc->dev_fd = -1; + + return -1; +} + +int destroyFimc(s5p_fimc_t *fimc) +{ + if (fimc->out_buf.virt_addr != NULL) { + fimc->out_buf.virt_addr = NULL; + fimc->out_buf.length = 0; + } + + /* close */ + if (0 <= fimc->dev_fd) + close(fimc->dev_fd); + fimc->dev_fd = -1; + + return 0; +} + +int runFimc(struct hwc_context_t *ctx, + struct sec_img *src_img, + struct sec_rect *src_rect, + struct sec_img *dst_img, + struct sec_rect *dst_rect, + unsigned int *phyAddr, + uint32_t transform) +{ + s5p_fimc_t *fimc = &ctx->fimc; + unsigned int dst_phys_addr = 0; + int32_t src_color_space; + int32_t dst_color_space; + + /* 1 : source address and size */ + + if(0 > get_src_phys_addr(ctx, src_img, phyAddr)) + return -1; + + /* 2 : destination address and size */ + if(0 == (dst_phys_addr = get_dst_phys_addr(ctx, dst_img))) + return -2; + + /* check whether fimc supports the src format */ + if (0 > (src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(src_img->format))) + return -3; + + if (0 > (dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(dst_img->format))) + return -4; + + if(runcFimcCore(ctx, src_img, src_rect, (uint32_t)src_color_space, + dst_phys_addr, dst_img, dst_rect, (uint32_t)dst_color_space, transform) < 0) + return -5; + + return 0; +} diff --git a/libhwcomposer/SecHWCUtils.h b/libhwcomposer/SecHWCUtils.h new file mode 100644 index 0000000..21d6598 --- /dev/null +++ b/libhwcomposer/SecHWCUtils.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2010 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. + */ + +/* + * + * @author Rama, Meka(v.meka@samsung.com) + Sangwoo, Park(sw5771.park@samsung.com) + Jamie, Oh (jung-min.oh@samsung.com) + * @date 2011-07-28 + * + */ + +#ifndef ANDROID_SEC_HWC_UTILS_H_ +#define ANDROID_SEC_HWC_UTILS_H_ +#include +#include +#include +#include +#include +#include +#include "linux/fb.h" +#include + +#include +#include +#include + +#include "s5p_fimc.h" +#include "sec_lcd.h" +#include "sec_format.h" +#include "sec_utils.h" +#include "hal_public.h" + +#define GRALLOC_USAGE_PHYS_CONTIG GRALLOC_USAGE_PRIVATE_1 + +#define NUM_OF_WIN (1) +#define NUM_OF_WIN_BUF (3) +#define NUM_OF_MEM_OBJ (1) +#define MAX_NUM_PLANES (3) + +#define MAX_RESIZING_RATIO_LIMIT (63) + +struct sec_rect { + uint32_t x; + uint32_t y; + uint32_t w; + uint32_t h; +}; + +struct sec_img { + uint32_t w; + uint32_t h; + uint32_t format; + uint32_t base; + uint32_t offset; + int mem_id; + int mem_type; +}; + +inline int SEC_MIN(int x, int y) { + return ((x < y) ? x : y); +} + +inline int SEC_MAX(int x, int y) { + return ((x > y) ? x : y); +} + +struct hwc_win_info_t { + int fd; + int size; + sec_rect rect_info; + uint32_t addr[NUM_OF_WIN_BUF]; + int buf_index; + int power_state; + int blending; + int layer_index; + uint32_t layer_prev_buf; + int set_win_flag; + int status; + int vsync; + + struct fb_fix_screeninfo fix_info; + struct fb_var_screeninfo var_info; + struct fb_var_screeninfo lcd_info; +}; + +enum { + HWC_WIN_FREE = 0, + HWC_WIN_RESERVED, +}; + +enum { + HWC_UNKNOWN_MEM_TYPE = 0, + HWC_PHYS_MEM_TYPE, + HWC_VIRT_MEM_TYPE, +}; + +struct hwc_context_t { + hwc_composer_device_t device; + + /* our private state goes below here */ + struct hwc_win_info_t win[NUM_OF_WIN]; + struct fb_var_screeninfo lcd_info; + s5p_fimc_t fimc; + unsigned int num_of_fb_layer; + unsigned int num_of_hwc_layer; + unsigned int num_of_fb_layer_prev; +}; + +int window_open(struct hwc_win_info_t *win, int id); +int window_close(struct hwc_win_info_t *win); +int window_set_pos(struct hwc_win_info_t *win); +int window_get_info(struct hwc_win_info_t *win); +int window_pan_display(struct hwc_win_info_t *win); +int window_show(struct hwc_win_info_t *win); +int window_hide(struct hwc_win_info_t *win); +int window_get_global_lcd_info(struct fb_var_screeninfo *lcd_info); + +int createFimc(s5p_fimc_t *fimc); +int destroyFimc(s5p_fimc_t *fimc); +int runFimc(struct hwc_context_t *ctx, + struct sec_img *src_img, struct sec_rect *src_rect, + struct sec_img *dst_img, struct sec_rect *dst_rect, + unsigned int *phyAddr, + uint32_t transform); +#endif /* ANDROID_SEC_HWC_UTILS_H_*/ + diff --git a/liblights/Android.mk b/liblights/Android.mk new file mode 100644 index 0000000..bf55cbe --- /dev/null +++ b/liblights/Android.mk @@ -0,0 +1,31 @@ +# 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. + +LOCAL_PATH:= $(call my-dir) +# HAL module implemenation, not prelinked and stored in +# hw/..so +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := lights.c + +LOCAL_MODULE_TAGS:= optional +LOCAL_PRELINK_MODULE := false +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + +LOCAL_SHARED_LIBRARIES := liblog + +LOCAL_MODULE := lights.s5pc110 + +include $(BUILD_SHARED_LIBRARY) + diff --git a/liblights/NOTICE b/liblights/NOTICE new file mode 100644 index 0000000..68c1616 --- /dev/null +++ b/liblights/NOTICE @@ -0,0 +1,192 @@ +(Modified by Michael Richter in 2010.) + + Copyright (c) 2008, The Android Open Source Project + Copyright (C) 2010 Michael Richter (alias neldar) + + 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/liblights/lights.c b/liblights/lights.c new file mode 100644 index 0000000..965c97f --- /dev/null +++ b/liblights/lights.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2011 Dominik Behr + * + * 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 "lights" + +#include + +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include + +static pthread_once_t g_init = PTHREAD_ONCE_INIT; +static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER; + +char const*const BUTTON_FILE = "/sys/class/leds/button-backlight/brightness"; + +char const*const LCD_BACKLIGHT_FILE = "/sys/class/backlight/s5p_bl/brightness"; + +char const*const NOTIFICATION_FILE = "/sys/class/misc/backlightnotification/notification_led"; + +/** + * Aux method, write int to file + */ +static int write_int (const char* path, int value) { + int fd; + static int already_warned = 0; + + fd = open(path, O_WRONLY); + if (fd < 0) { + if (already_warned == 0) { + LOGE("write_int failed to open %s\n", path); + already_warned = 1; + } + return -errno; + } + + char buffer[20]; + int bytes = snprintf(buffer, sizeof(buffer), "%d\n",value); + int written = write (fd, buffer, bytes); + close (fd); + + return written == -1 ? -errno : 0; + +} + +void init_globals (void) { + pthread_mutex_init (&g_lock, NULL); +} + +static int is_lit (struct light_state_t const* state) { + return state->color & 0x00ffffff; +} + +static int set_light_buttons (struct light_device_t* dev, + struct light_state_t const* state) { + int err = 0; + int on = is_lit (state); + pthread_mutex_lock (&g_lock); + err = write_int (BUTTON_FILE, on?255:0); + pthread_mutex_unlock (&g_lock); + + return 0; +} + +static int rgb_to_brightness(struct light_state_t const* state) +{ + int color = state->color & 0x00ffffff; + return ((77*((color>>16)&0x00ff)) + + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8; +} + +static int set_light_backlight(struct light_device_t* dev, + struct light_state_t const* state) { + int err = 0; + int brightness = rgb_to_brightness(state); + LOGV("%s brightness=%d color=0x%08x", + __func__,brightness, state->color); + pthread_mutex_lock(&g_lock); + err = write_int(LCD_BACKLIGHT_FILE, brightness); + // if LCD backlight is on then button backlight should be on too + // Samsung has some annoying code that turns on buttons light only when touchscreen is pressed + // and it turns off automatically afterwards, leaving user hunting for buttons in the dark + { + int on = is_lit (state); + err = write_int (BUTTON_FILE, on?255:0); + } + pthread_mutex_unlock(&g_lock); + return err; +} + +static int +set_light_notifications(struct light_device_t* dev, + struct light_state_t const* state) +{ + int err = 0; + int on = is_lit(state); + LOGV("%s color=%08x flashMode=%d flashOnMS=%d flashOffMS=%d\n", __func__, + state->color, state->flashMode, state->flashOnMS, state->flashOffMS); + pthread_mutex_lock(&g_lock); + err = write_int(NOTIFICATION_FILE, on?1:0); + pthread_mutex_unlock(&g_lock); + return err; +} + +static int close_lights (struct light_device_t *dev) { + if (dev) + free (dev); + + return 0; +} + +static int open_lights (const struct hw_module_t* module, char const* name, + struct hw_device_t** device) { + int (*set_light)(struct light_device_t* dev, + struct light_state_t const* state); + + if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) { + set_light = set_light_backlight; + } + else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) { + set_light = set_light_buttons; + } + else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) { + set_light = set_light_notifications; + } + else { + return -EINVAL; + } + + pthread_once (&g_init, init_globals); + struct light_device_t *dev = malloc (sizeof (struct light_device_t)); + memset (dev,0,sizeof(*dev)); + + dev->common.tag = HARDWARE_DEVICE_TAG; + dev->common.version = 0; + dev->common.module = (struct hw_module_t*)module; + dev->common.close = (int (*)(struct hw_device_t*))close_lights; + dev->set_light = set_light; + + *device = (struct hw_device_t*) dev; + return 0; + +} + +static struct hw_module_methods_t lights_module_methods = { + .open = open_lights, +}; + + +const struct hw_module_t HAL_MODULE_INFO_SYM = { + .tag = HARDWARE_MODULE_TAG, + .version_major = 1, + .version_minor = 0, + .id = LIGHTS_HARDWARE_MODULE_ID, + .name = "GT-P1000 lights module", + .author = "Dominik Behr", + .methods = &lights_module_methods, +}; diff --git a/libs3cjpeg/Android.mk b/libs3cjpeg/Android.mk new file mode 100644 index 0000000..7b1618f --- /dev/null +++ b/libs3cjpeg/Android.mk @@ -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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + + +LOCAL_C_INCLUDES := $(LOCAL_PATH) +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include + +LOCAL_SRC_FILES:= \ + JpegEncoder.cpp + +LOCAL_SHARED_LIBRARIES:= liblog +LOCAL_SHARED_LIBRARIES+= libdl + +LOCAL_MODULE:= libs3cjpeg + +LOCAL_MODULE_TAGS := optional + +LOCAL_PRELINK_MODULE := false + +include $(BUILD_SHARED_LIBRARY) + diff --git a/libs3cjpeg/Exif.h b/libs3cjpeg/Exif.h new file mode 100644 index 0000000..96e11dd --- /dev/null +++ b/libs3cjpeg/Exif.h @@ -0,0 +1,233 @@ +/* + * Copyright Samsung Electronics Co.,LTD. + * Copyright (C) 2010 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_EXIF_H +#define ANDROID_HARDWARE_EXIF_H + +#include + +#define EXIF_LOG2(x) (log((double)(x)) / log(2.0)) +#define APEX_FNUM_TO_APERTURE(x) ((int)(EXIF_LOG2((double)(x)) * 2 + 0.5)) +#define APEX_EXPOSURE_TO_SHUTTER(x) ((x) >= 1 ? \ + (int)(-(EXIF_LOG2((double)(x)) + 0.5)) : \ + (int)(-(EXIF_LOG2((double)(x)) - 0.5))) +#define APEX_ISO_TO_FILMSENSITIVITY(x) ((int)(EXIF_LOG2((x) / 3.125) + 0.5)) + +#define NUM_SIZE 2 +#define IFD_SIZE 12 +#define OFFSET_SIZE 4 + +#define NUM_0TH_IFD_TIFF 10 +#define NUM_0TH_IFD_EXIF 22 +#define NUM_0TH_IFD_GPS 10 +#define NUM_1TH_IFD_TIFF 9 + +/* Type */ +#define EXIF_TYPE_BYTE 1 +#define EXIF_TYPE_ASCII 2 +#define EXIF_TYPE_SHORT 3 +#define EXIF_TYPE_LONG 4 +#define EXIF_TYPE_RATIONAL 5 +#define EXIF_TYPE_UNDEFINED 7 +#define EXIF_TYPE_SLONG 9 +#define EXIF_TYPE_SRATIONAL 10 + +#define EXIF_FILE_SIZE 28800 + +/* 0th IFD TIFF Tags */ +#define EXIF_TAG_IMAGE_WIDTH 0x0100 +#define EXIF_TAG_IMAGE_HEIGHT 0x0101 +#define EXIF_TAG_MAKE 0x010f +#define EXIF_TAG_MODEL 0x0110 +#define EXIF_TAG_ORIENTATION 0x0112 +#define EXIF_TAG_SOFTWARE 0x0131 +#define EXIF_TAG_DATE_TIME 0x0132 +#define EXIF_TAG_YCBCR_POSITIONING 0x0213 +#define EXIF_TAG_EXIF_IFD_POINTER 0x8769 +#define EXIF_TAG_GPS_IFD_POINTER 0x8825 + +/* 0th IFD Exif Private Tags */ +#define EXIF_TAG_EXPOSURE_TIME 0x829A +#define EXIF_TAG_FNUMBER 0x829D +#define EXIF_TAG_EXPOSURE_PROGRAM 0x8822 +#define EXIF_TAG_ISO_SPEED_RATING 0x8827 +#define EXIF_TAG_EXIF_VERSION 0x9000 +#define EXIF_TAG_DATE_TIME_ORG 0x9003 +#define EXIF_TAG_DATE_TIME_DIGITIZE 0x9004 +#define EXIF_TAG_SHUTTER_SPEED 0x9201 +#define EXIF_TAG_APERTURE 0x9202 +#define EXIF_TAG_BRIGHTNESS 0x9203 +#define EXIF_TAG_EXPOSURE_BIAS 0x9204 +#define EXIF_TAG_MAX_APERTURE 0x9205 +#define EXIF_TAG_METERING_MODE 0x9207 +#define EXIF_TAG_FLASH 0x9209 +#define EXIF_TAG_FOCAL_LENGTH 0x920A +#define EXIF_TAG_USER_COMMENT 0x9286 +#define EXIF_TAG_COLOR_SPACE 0xA001 +#define EXIF_TAG_PIXEL_X_DIMENSION 0xA002 +#define EXIF_TAG_PIXEL_Y_DIMENSION 0xA003 +#define EXIF_TAG_EXPOSURE_MODE 0xA402 +#define EXIF_TAG_WHITE_BALANCE 0xA403 +#define EXIF_TAG_SCENCE_CAPTURE_TYPE 0xA406 + +/* 0th IFD GPS Info Tags */ +#define EXIF_TAG_GPS_VERSION_ID 0x0000 +#define EXIF_TAG_GPS_LATITUDE_REF 0x0001 +#define EXIF_TAG_GPS_LATITUDE 0x0002 +#define EXIF_TAG_GPS_LONGITUDE_REF 0x0003 +#define EXIF_TAG_GPS_LONGITUDE 0x0004 +#define EXIF_TAG_GPS_ALTITUDE_REF 0x0005 +#define EXIF_TAG_GPS_ALTITUDE 0x0006 +#define EXIF_TAG_GPS_TIMESTAMP 0x0007 +#define EXIF_TAG_GPS_PROCESSING_METHOD 0x001B +#define EXIF_TAG_GPS_DATESTAMP 0x001D + +/* 1th IFD TIFF Tags */ +#define EXIF_TAG_COMPRESSION_SCHEME 0x0103 +#define EXIF_TAG_X_RESOLUTION 0x011A +#define EXIF_TAG_Y_RESOLUTION 0x011B +#define EXIF_TAG_RESOLUTION_UNIT 0x0128 +#define EXIF_TAG_JPEG_INTERCHANGE_FORMAT 0x0201 +#define EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN 0x0202 + + +typedef enum { + EXIF_ORIENTATION_UP = 1, + EXIF_ORIENTATION_90 = 6, + EXIF_ORIENTATION_180 = 3, + EXIF_ORIENTATION_270 = 8, +} ExifOrientationType; + +typedef enum { + EXIF_SCENE_STANDARD, + EXIF_SCENE_LANDSCAPE, + EXIF_SCENE_PORTRAIT, + EXIF_SCENE_NIGHT, +} CamExifSceneCaptureType; + +typedef enum { + EXIF_METERING_UNKNOWN, + EXIF_METERING_AVERAGE, + EXIF_METERING_CENTER, + EXIF_METERING_SPOT, + EXIF_METERING_MULTISPOT, + EXIF_METERING_PATTERN, + EXIF_METERING_PARTIAL, + EXIF_METERING_OTHER = 255, +} CamExifMeteringModeType; + +typedef enum { + EXIF_EXPOSURE_AUTO, + EXIF_EXPOSURE_MANUAL, + EXIF_EXPOSURE_AUTO_BRACKET, +} CamExifExposureModeType; + +typedef enum { + EXIF_WB_AUTO, + EXIF_WB_MANUAL, +} CamExifWhiteBalanceType; + +/* Values */ +#define EXIF_DEF_MAKER "SAMSUNG" +#define EXIF_DEF_MODEL "GT-I9020" +#define EXIF_DEF_SOFTWARE "CRESPOJH2" +#define EXIF_DEF_EXIF_VERSION "0220" +#define EXIF_DEF_USERCOMMENTS "User comments" + +#define EXIF_DEF_YCBCR_POSITIONING 1 /* centered */ +#define EXIF_DEF_FNUMBER_NUM 26 /* 2.6 */ +#define EXIF_DEF_FNUMBER_DEN 10 +#define EXIF_DEF_EXPOSURE_PROGRAM 3 /* aperture priority */ +#define EXIF_DEF_FOCAL_LEN_NUM 278 /* 2.78mm */ +#define EXIF_DEF_FOCAL_LEN_DEN 100 +#define EXIF_DEF_FLASH 0 /* O: off, 1: on*/ +#define EXIF_DEF_COLOR_SPACE 1 +#define EXIF_DEF_EXPOSURE_MODE EXIF_EXPOSURE_AUTO +#define EXIF_DEF_APEX_DEN 10 + +#define EXIF_DEF_COMPRESSION 6 +#define EXIF_DEF_RESOLUTION_NUM 72 +#define EXIF_DEF_RESOLUTION_DEN 1 +#define EXIF_DEF_RESOLUTION_UNIT 2 /* inches */ + +typedef struct { + uint32_t num; + uint32_t den; +} rational_t; + +typedef struct { + int32_t num; + int32_t den; +} srational_t; + +typedef struct { + bool enableGps; + bool enableThumb; + + unsigned char maker[32]; + unsigned char model[32]; + unsigned char software[32]; + unsigned char exif_version[4]; + unsigned char date_time[20]; + unsigned char user_comment[150]; + + uint32_t width; + uint32_t height; + uint32_t widthThumb; + uint32_t heightThumb; + + uint16_t orientation; + uint16_t ycbcr_positioning; + uint16_t exposure_program; + uint16_t iso_speed_rating; + uint16_t metering_mode; + uint16_t flash; + uint16_t color_space; + uint16_t exposure_mode; + uint16_t white_balance; + uint16_t scene_capture_type; + + rational_t exposure_time; + rational_t fnumber; + rational_t aperture; + rational_t max_aperture; + rational_t focal_length; + + srational_t shutter_speed; + srational_t brightness; + srational_t exposure_bias; + + unsigned char gps_latitude_ref[2]; + unsigned char gps_longitude_ref[2]; + + uint8_t gps_version_id[4]; + uint8_t gps_altitude_ref; + + rational_t gps_latitude[3]; + rational_t gps_longitude[3]; + rational_t gps_altitude; + rational_t gps_timestamp[3]; + unsigned char gps_datestamp[11]; + unsigned char gps_processing_method[100]; + + rational_t x_resolution; + rational_t y_resolution; + uint16_t resolution_unit; + uint16_t compression_scheme; +} exif_attribute_t; + + +#endif /* ANDROID_HARDWARE_EXIF_H */ diff --git a/libs3cjpeg/JpegEncoder.cpp b/libs3cjpeg/JpegEncoder.cpp new file mode 100644 index 0000000..1361bca --- /dev/null +++ b/libs3cjpeg/JpegEncoder.cpp @@ -0,0 +1,796 @@ +/* + * Copyright Samsung Electronics Co.,LTD. + * Copyright (C) 2010 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. + * + * JPEG DRIVER MODULE (JpegEncoder.cpp) + * Author : ge.lee -- initial version + * Date : 03 June 2010 + * Purpose : This file implements the JPEG encoder APIs as needed by Camera HAL + */ +#define LOG_TAG "JpegEncoder" +#define MAIN_DUMP 0 +#define THUMB_DUMP 0 + +#include +#include +#include + +#include "JpegEncoder.h" + +static const char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; + +namespace android { +JpegEncoder::JpegEncoder() : available(false) +{ + mArgs.mmapped_addr = (char *)MAP_FAILED; + mArgs.enc_param = NULL; + mArgs.thumb_enc_param = NULL; + + mDevFd = open(JPG_DRIVER_NAME, O_RDWR); + if (mDevFd < 0) { + LOGE("Failed to open the device"); + return; + } + + mArgs.mmapped_addr = (char *)mmap(0, + JPG_TOTAL_BUF_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + mDevFd, + 0); + + if (mArgs.mmapped_addr == MAP_FAILED) { + LOGE("Failed to mmap"); + return; + } + + mArgs.enc_param = new jpg_enc_proc_param; + if (mArgs.enc_param == NULL) { + LOGE("Failed to allocate the memory for enc_param"); + return; + } + memset(mArgs.enc_param, 0, sizeof(jpg_enc_proc_param)); + + mArgs.thumb_enc_param = new jpg_enc_proc_param; + if (mArgs.thumb_enc_param == NULL) { + LOGE("Failed to allocate the memory for thumb_enc_param"); + delete mArgs.enc_param; + return; + } + memset(mArgs.thumb_enc_param, 0, sizeof(jpg_enc_proc_param)); + + mArgs.enc_param->sample_mode = JPG_420; + mArgs.enc_param->enc_type = JPG_MAIN; + mArgs.thumb_enc_param->sample_mode = JPG_420; + mArgs.thumb_enc_param->enc_type = JPG_THUMBNAIL; + + available = true; +} + +JpegEncoder::~JpegEncoder() +{ + if (mArgs.mmapped_addr != (char*)MAP_FAILED) + munmap(mArgs.mmapped_addr, JPG_TOTAL_BUF_SIZE); + + delete mArgs.enc_param; + + delete mArgs.thumb_enc_param; + + if (mDevFd > 0) + close(mDevFd); +} + +jpg_return_status JpegEncoder::setConfig(jpeg_conf type, int32_t value) +{ + if (!available) + return JPG_FAIL; + + jpg_return_status ret = JPG_SUCCESS; + + switch (type) { + case JPEG_SET_ENCODE_WIDTH: + if (value < 0 || value > MAX_JPG_WIDTH) + ret = JPG_FAIL; + else + mArgs.enc_param->width = value; + break; + + case JPEG_SET_ENCODE_HEIGHT: + if (value < 0 || value > MAX_JPG_HEIGHT) + ret = JPG_FAIL; + else + mArgs.enc_param->height = value; + break; + + case JPEG_SET_ENCODE_QUALITY: + if (value < JPG_QUALITY_LEVEL_1 || value > JPG_QUALITY_LEVEL_4) + ret = JPG_FAIL; + else + mArgs.enc_param->quality = (image_quality_type_t)value; + break; + + case JPEG_SET_ENCODE_IN_FORMAT: + if (value != JPG_MODESEL_YCBCR && value != JPG_MODESEL_RGB) { + ret = JPG_FAIL; + } else { + mArgs.enc_param->in_format = (in_mode_t)value; + mArgs.thumb_enc_param->in_format = (in_mode_t)value; + } + break; + + case JPEG_SET_SAMPING_MODE: + if (value != JPG_420 && value != JPG_422) { + ret = JPG_FAIL; + } else { + mArgs.enc_param->sample_mode = (sample_mode_t)value; + mArgs.thumb_enc_param->sample_mode = (sample_mode_t)value; + } + break; + + case JPEG_SET_THUMBNAIL_WIDTH: + if (value < 0 || value > MAX_JPG_THUMBNAIL_WIDTH) + ret = JPG_FAIL; + else + mArgs.thumb_enc_param->width = value; + break; + + case JPEG_SET_THUMBNAIL_HEIGHT: + if (value < 0 || value > MAX_JPG_THUMBNAIL_HEIGHT) + ret = JPG_FAIL; + else + mArgs.thumb_enc_param->height = value; + break; + + default: + LOGE("Invalid Config type"); + ret = ERR_UNKNOWN; + } + + if (ret == JPG_FAIL) + LOGE("Invalid value(%d) for %d type", value, type); + + return ret; +} + +void* JpegEncoder::getInBuf(uint64_t size) +{ + if (!available) + return NULL; + + if (size > JPG_FRAME_BUF_SIZE) { + LOGE("The buffer size requested is too large"); + return NULL; + } + mArgs.in_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_FRMBUF, mArgs.mmapped_addr); + return (void *)(mArgs.in_buf); +} + +void* JpegEncoder::getOutBuf(uint64_t *size) +{ + if (!available) + return NULL; + + if (mArgs.enc_param->file_size <= 0) { + LOGE("The buffer requested doesn't have data"); + return NULL; + } + mArgs.out_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_STRBUF, mArgs.mmapped_addr); + *size = mArgs.enc_param->file_size; + return (void *)(mArgs.out_buf); +} + +void* JpegEncoder::getThumbInBuf(uint64_t size) +{ + if (!available) + return NULL; + + if (size > JPG_FRAME_THUMB_BUF_SIZE) { + LOGE("The buffer size requested is too large"); + return NULL; + } + mArgs.in_thumb_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_THUMB_FRMBUF, mArgs.mmapped_addr); + return (void *)(mArgs.in_thumb_buf); +} + +void* JpegEncoder::getThumbOutBuf(uint64_t *size) +{ + if (!available) + return NULL; + + if (mArgs.thumb_enc_param->file_size <= 0) { + LOGE("The buffer requested doesn't have data"); + return NULL; + } + mArgs.out_thumb_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_THUMB_STRBUF, mArgs.mmapped_addr); + *size = mArgs.thumb_enc_param->file_size; + return (void *)(mArgs.out_thumb_buf); +} + +jpg_return_status JpegEncoder::encode(unsigned int *size, exif_attribute_t *exifInfo) +{ + if (!available) + return JPG_FAIL; + + LOGD("encode E"); + + jpg_return_status ret = JPG_FAIL; + unsigned char *exifOut = NULL; + jpg_enc_proc_param *param = mArgs.enc_param; + + ret = checkMcu(param->sample_mode, param->width, param->height, false); + if (ret != JPG_SUCCESS) + return ret; + + param->enc_type = JPG_MAIN; + ret = (jpg_return_status)ioctl(mDevFd, IOCTL_JPG_ENCODE, &mArgs); + if (ret != JPG_SUCCESS) { + LOGE("Failed to encode main image"); + return ret; + } + + mArgs.out_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_STRBUF, mArgs.mmapped_addr); + + if (exifInfo) { + unsigned int thumbLen, exifLen; + + uint_t bufSize = 0; + if (exifInfo->enableThumb) { + ret = encodeThumbImg(&thumbLen); + if (ret != JPG_SUCCESS) { + LOGE("Failed to encode for thumbnail image"); + bufSize = EXIF_FILE_SIZE; + exifInfo->enableThumb = false; + } else { + bufSize = EXIF_FILE_SIZE + thumbLen; + } + } else { + bufSize = EXIF_FILE_SIZE; + } + + if (mArgs.enc_param->file_size + bufSize > JPG_TOTAL_BUF_SIZE) + return ret; + + exifOut = new unsigned char[bufSize]; + if (exifOut == NULL) { + LOGE("Failed to allocate for exifOut"); + return ret; + } + memset(exifOut, 0, bufSize); + + ret = makeExif (exifOut, exifInfo, &exifLen); + if (ret != JPG_SUCCESS) { + LOGE("Failed to make EXIF"); + delete[] exifOut; + return ret; + } + + memmove(&mArgs.out_buf[exifLen + 2], &mArgs.out_buf[2], param->file_size - 2); + memcpy(&mArgs.out_buf[2], exifOut, exifLen); + param->file_size += exifLen; + } + + delete[] exifOut; + + *size = param->file_size; + +#if MAIN_DUMP + FILE *fout = NULL; + char file_name[50] = "/data/main.jpg"; + fout = fopen(file_name, "wb"); + if (!fout) + perror(&file_name[0]); + size_t nwrite = fwrite(mArgs.out_buf, sizeof(char), param->file_size, fout); + fclose(fout); +#endif + + LOGD("encode X"); + + return ret; +} + +jpg_return_status JpegEncoder::encodeThumbImg(unsigned int *size, bool useMain) +{ + if (!available) + return JPG_FAIL; + + LOGD("encodeThumbImg E"); + + jpg_return_status ret = JPG_FAIL; + jpg_enc_proc_param *param = mArgs.thumb_enc_param; + + if (useMain) { + mArgs.in_thumb_buf = (char *)getThumbInBuf(param->width*param->height*2); + if (mArgs.in_thumb_buf == NULL) { + LOGE("Failed to get the buffer for thumbnail"); + return JPG_FAIL; + } + + ret = (jpg_return_status)scaleDownYuv422(mArgs.in_buf, + mArgs.enc_param->width, + mArgs.enc_param->height, + mArgs.in_thumb_buf, + param->width, + param->height); + if (ret != JPG_SUCCESS) + return JPG_FAIL; + } + + ret = checkMcu(param->sample_mode, param->width, param->height, true); + if (ret != JPG_SUCCESS) + return JPG_FAIL; + + mArgs.enc_param->enc_type = JPG_THUMBNAIL; + ret = (jpg_return_status)ioctl(mDevFd, IOCTL_JPG_ENCODE, &mArgs); + if (ret != JPG_SUCCESS) { + LOGE("Failed to encode for thumbnail"); + return JPG_FAIL; + } + + mArgs.out_thumb_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_THUMB_STRBUF, mArgs.mmapped_addr); + +#if THUMB_DUMP + FILE *fout = NULL; + char file_name[50] = "/data/thumb.jpg"; + fout = fopen(file_name, "wb"); + if (!fout) + perror(&file_name[0]); + size_t nwrite = fwrite(mArgs.out_thumb_buf, sizeof(char), param->file_size, fout); + fclose(fout); +#endif + + LOGD("encodeThumbImg X"); + + return JPG_SUCCESS; +} + +jpg_return_status JpegEncoder::makeExif (unsigned char *exifOut, + exif_attribute_t *exifInfo, + unsigned int *size, + bool useMainbufForThumb) +{ + if (!available) + return JPG_FAIL; + + LOGD("makeExif E"); + + unsigned char *pCur, *pApp1Start, *pIfdStart, *pGpsIfdPtr, *pNextIfdOffset; + unsigned int tmp, LongerTagOffest = 0; + pApp1Start = pCur = exifOut; + + //2 Exif Identifier Code & TIFF Header + pCur += 4; // Skip 4 Byte for APP1 marker and length + unsigned char ExifIdentifierCode[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + memcpy(pCur, ExifIdentifierCode, 6); + pCur += 6; + + /* Byte Order - little endian, Offset of IFD - 0x00000008.H */ + unsigned char TiffHeader[8] = { 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 }; + memcpy(pCur, TiffHeader, 8); + pIfdStart = pCur; + pCur += 8; + + //2 0th IFD TIFF Tags + if (exifInfo->enableGps) + tmp = NUM_0TH_IFD_TIFF; + else + tmp = NUM_0TH_IFD_TIFF - 1; + + memcpy(pCur, &tmp, NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += 8 + NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG, + 1, exifInfo->width); + writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG, + 1, exifInfo->height); + writeExifIfd(&pCur, EXIF_TAG_MAKE, EXIF_TYPE_ASCII, + strlen((char *)exifInfo->maker) + 1, exifInfo->maker, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_MODEL, EXIF_TYPE_ASCII, + strlen((char *)exifInfo->model) + 1, exifInfo->model, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT, + 1, exifInfo->orientation); + writeExifIfd(&pCur, EXIF_TAG_SOFTWARE, EXIF_TYPE_ASCII, + strlen((char *)exifInfo->software) + 1, exifInfo->software, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_DATE_TIME, EXIF_TYPE_ASCII, + 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_YCBCR_POSITIONING, EXIF_TYPE_SHORT, + 1, exifInfo->ycbcr_positioning); + writeExifIfd(&pCur, EXIF_TAG_EXIF_IFD_POINTER, EXIF_TYPE_LONG, + 1, LongerTagOffest); + if (exifInfo->enableGps) { + pGpsIfdPtr = pCur; + pCur += IFD_SIZE; // Skip a ifd size for gps IFD pointer + } + + pNextIfdOffset = pCur; // Skip a offset size for next IFD offset + pCur += OFFSET_SIZE; + + //2 0th IFD Exif Private Tags + pCur = pIfdStart + LongerTagOffest; + + tmp = NUM_0TH_IFD_EXIF; + memcpy(pCur, &tmp , NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += NUM_SIZE + NUM_0TH_IFD_EXIF*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_TIME, EXIF_TYPE_RATIONAL, + 1, &exifInfo->exposure_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_FNUMBER, EXIF_TYPE_RATIONAL, + 1, &exifInfo->fnumber, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_PROGRAM, EXIF_TYPE_SHORT, + 1, exifInfo->exposure_program); + writeExifIfd(&pCur, EXIF_TAG_ISO_SPEED_RATING, EXIF_TYPE_SHORT, + 1, exifInfo->iso_speed_rating); + writeExifIfd(&pCur, EXIF_TAG_EXIF_VERSION, EXIF_TYPE_UNDEFINED, + 4, exifInfo->exif_version); + writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_ORG, EXIF_TYPE_ASCII, + 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_TYPE_ASCII, + 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_SHUTTER_SPEED, EXIF_TYPE_SRATIONAL, + 1, (rational_t *)&exifInfo->shutter_speed, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_APERTURE, EXIF_TYPE_RATIONAL, + 1, &exifInfo->aperture, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_BRIGHTNESS, EXIF_TYPE_SRATIONAL, + 1, (rational_t *)&exifInfo->brightness, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_BIAS, EXIF_TYPE_SRATIONAL, + 1, (rational_t *)&exifInfo->exposure_bias, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_MAX_APERTURE, EXIF_TYPE_RATIONAL, + 1, &exifInfo->max_aperture, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_METERING_MODE, EXIF_TYPE_SHORT, + 1, exifInfo->metering_mode); + writeExifIfd(&pCur, EXIF_TAG_FLASH, EXIF_TYPE_SHORT, + 1, exifInfo->flash); + writeExifIfd(&pCur, EXIF_TAG_FOCAL_LENGTH, EXIF_TYPE_RATIONAL, + 1, &exifInfo->focal_length, &LongerTagOffest, pIfdStart); + char code[8] = { 0x00, 0x00, 0x00, 0x49, 0x49, 0x43, 0x53, 0x41 }; + int commentsLen = strlen((char *)exifInfo->user_comment) + 1; + memmove(exifInfo->user_comment + sizeof(code), exifInfo->user_comment, commentsLen); + memcpy(exifInfo->user_comment, code, sizeof(code)); + writeExifIfd(&pCur, EXIF_TAG_USER_COMMENT, EXIF_TYPE_UNDEFINED, + commentsLen + sizeof(code), exifInfo->user_comment, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_COLOR_SPACE, EXIF_TYPE_SHORT, + 1, exifInfo->color_space); + writeExifIfd(&pCur, EXIF_TAG_PIXEL_X_DIMENSION, EXIF_TYPE_LONG, + 1, exifInfo->width); + writeExifIfd(&pCur, EXIF_TAG_PIXEL_Y_DIMENSION, EXIF_TYPE_LONG, + 1, exifInfo->height); + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_MODE, EXIF_TYPE_LONG, + 1, exifInfo->exposure_mode); + writeExifIfd(&pCur, EXIF_TAG_WHITE_BALANCE, EXIF_TYPE_LONG, + 1, exifInfo->white_balance); + writeExifIfd(&pCur, EXIF_TAG_SCENCE_CAPTURE_TYPE, EXIF_TYPE_LONG, + 1, exifInfo->scene_capture_type); + tmp = 0; + memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset + pCur += OFFSET_SIZE; + + //2 0th IFD GPS Info Tags + if (exifInfo->enableGps) { + writeExifIfd(&pGpsIfdPtr, EXIF_TAG_GPS_IFD_POINTER, EXIF_TYPE_LONG, + 1, LongerTagOffest); // GPS IFD pointer skipped on 0th IFD + + pCur = pIfdStart + LongerTagOffest; + + if (exifInfo->gps_processing_method[0] == 0) { + // don't create GPS_PROCESSING_METHOD tag if there isn't any + tmp = NUM_0TH_IFD_GPS - 1; + } else { + tmp = NUM_0TH_IFD_GPS; + } + memcpy(pCur, &tmp, NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_GPS_VERSION_ID, EXIF_TYPE_BYTE, + 4, exifInfo->gps_version_id); + writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE_REF, EXIF_TYPE_ASCII, + 2, exifInfo->gps_latitude_ref); + writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE, EXIF_TYPE_RATIONAL, + 3, exifInfo->gps_latitude, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_TYPE_ASCII, + 2, exifInfo->gps_longitude_ref); + writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE, EXIF_TYPE_RATIONAL, + 3, exifInfo->gps_longitude, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_TYPE_BYTE, + 1, exifInfo->gps_altitude_ref); + writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE, EXIF_TYPE_RATIONAL, + 1, &exifInfo->gps_altitude, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_GPS_TIMESTAMP, EXIF_TYPE_RATIONAL, + 3, exifInfo->gps_timestamp, &LongerTagOffest, pIfdStart); + tmp = strlen((char*)exifInfo->gps_processing_method); + if (tmp > 0) { + if (tmp > 100) { + tmp = 100; + } + unsigned char tmp_buf[100+sizeof(ExifAsciiPrefix)]; + memcpy(tmp_buf, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)); + memcpy(&tmp_buf[sizeof(ExifAsciiPrefix)], exifInfo->gps_processing_method, tmp); + writeExifIfd(&pCur, EXIF_TAG_GPS_PROCESSING_METHOD, EXIF_TYPE_UNDEFINED, + tmp+sizeof(ExifAsciiPrefix), tmp_buf, &LongerTagOffest, pIfdStart); + } + writeExifIfd(&pCur, EXIF_TAG_GPS_DATESTAMP, EXIF_TYPE_ASCII, + 11, exifInfo->gps_datestamp, &LongerTagOffest, pIfdStart); + tmp = 0; + memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset + pCur += OFFSET_SIZE; + } + + //2 1th IFD TIFF Tags + char *thumbBuf; + int thumbSize; + + if (useMainbufForThumb) { + thumbBuf = mArgs.out_buf; + thumbSize = mArgs.enc_param->file_size; + } else { + thumbBuf = mArgs.out_thumb_buf; + thumbSize = mArgs.thumb_enc_param->file_size; + } + + if (exifInfo->enableThumb && (thumbBuf != NULL) && (thumbSize > 0)) { + tmp = LongerTagOffest; + memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD + + pCur = pIfdStart + LongerTagOffest; + + tmp = NUM_1TH_IFD_TIFF; + memcpy(pCur, &tmp, NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += NUM_SIZE + NUM_1TH_IFD_TIFF*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG, + 1, exifInfo->widthThumb); + writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG, + 1, exifInfo->heightThumb); + writeExifIfd(&pCur, EXIF_TAG_COMPRESSION_SCHEME, EXIF_TYPE_SHORT, + 1, exifInfo->compression_scheme); + writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT, + 1, exifInfo->orientation); + writeExifIfd(&pCur, EXIF_TAG_X_RESOLUTION, EXIF_TYPE_RATIONAL, + 1, &exifInfo->x_resolution, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_Y_RESOLUTION, EXIF_TYPE_RATIONAL, + 1, &exifInfo->y_resolution, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_RESOLUTION_UNIT, EXIF_TYPE_SHORT, + 1, exifInfo->resolution_unit); + writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_TYPE_LONG, + 1, LongerTagOffest); + writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN, EXIF_TYPE_LONG, + 1, thumbSize); + + tmp = 0; + memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset + pCur += OFFSET_SIZE; + + memcpy(pIfdStart + LongerTagOffest, + thumbBuf, thumbSize); + LongerTagOffest += thumbSize; + } else { + tmp = 0; + memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD + } + + unsigned char App1Marker[2] = { 0xff, 0xe1 }; + memcpy(pApp1Start, App1Marker, 2); + pApp1Start += 2; + + *size = 10 + LongerTagOffest; + tmp = *size - 2; // APP1 Maker isn't counted + unsigned char size_mm[2] = {(tmp >> 8) & 0xFF, tmp & 0xFF}; + memcpy(pApp1Start, size_mm, 2); + + LOGD("makeExif X"); + + return JPG_SUCCESS; +} + +jpg_return_status JpegEncoder::checkMcu(sample_mode_t sampleMode, + uint32_t width, uint32_t height, bool isThumb) +{ + if (!available) + return JPG_FAIL; + + uint32_t expectedWidth = width; + uint32_t expectedHeight = height; + + switch (sampleMode){ + case JPG_422: + if (width % 16 != 0) + expectedWidth = width + 16 - (width % 16); + if (height % 8 != 0) + expectedHeight = height + 8 - (height % 8); + break; + + case JPG_420: + if (width % 16 != 0) + expectedWidth = width + 16 - (width % 16); + if (height % 16 != 0) + expectedHeight = height + 16 - (height % 16); + break; + + default: + LOGE("Invaild sample mode"); + return JPG_FAIL; + } + + if (expectedWidth == width && expectedHeight == height) + return JPG_SUCCESS; + + LOGW("The image is not matched for MCU"); + + uint32_t size = width*height * 2; + char *srcBuf, *dstBuf; + + if ((srcBuf = new char[size]) == NULL) { + LOGE("Failed to allocate for srcBuf"); + return JPG_FAIL; + } + + if (!isThumb) + dstBuf = mArgs.in_buf; + else + dstBuf = mArgs.in_thumb_buf; + + memcpy(srcBuf, dstBuf, size); + bool ret = pad(srcBuf, width, height, dstBuf, expectedWidth, expectedHeight); + + delete[] srcBuf; + + return JPG_SUCCESS; +} + +bool JpegEncoder::pad(char *srcBuf, uint32_t srcWidth, uint32_t srcHight, + char *dstBuf, uint32_t dstWidth, uint32_t dstHight) +{ + if (!available) + return false; + + if (srcBuf == NULL || dstBuf == NULL) { + LOGE("srcBuf or dstBuf is NULL"); + return false; + } + + int padW = dstWidth - srcWidth; + int padH = dstHight - srcHight; + + if ((int)(dstWidth - srcWidth) < 0 || + (int)(dstHight - srcHight) < 0) { + LOGE("dstSize is smaller than srcSize"); + return false; + } + memset(dstBuf, 0, dstWidth*dstHight * 2); + + for (uint32_t i = 0; i < srcHight; i++) + memcpy(dstBuf + i * dstWidth * 2, srcBuf + i * srcWidth * 2, srcWidth * 2); + + return true; +} + +bool JpegEncoder::scaleDownYuv422(char *srcBuf, uint32_t srcWidth, uint32_t srcHight, + char *dstBuf, uint32_t dstWidth, uint32_t dstHight) +{ + if (!available) + return false; + + int32_t step_x, step_y; + int32_t iXsrc, iXdst; + int32_t x, y, src_y_start_pos, dst_pos, src_pos; + + if (dstWidth % 2 != 0 || dstHight % 2 != 0){ + LOGE("scale_down_yuv422: invalid width, height for scaling"); + return false; + } + + step_x = srcWidth / dstWidth; + step_y = srcHight / dstHight; + + dst_pos = 0; + for (uint32_t y = 0; y < dstHight; y++) { + src_y_start_pos = (y * step_y * (srcWidth * 2)); + + for (uint32_t x = 0; x < dstWidth; x += 2) { + src_pos = src_y_start_pos + (x * (step_x * 2)); + + dstBuf[dst_pos++] = srcBuf[src_pos ]; + dstBuf[dst_pos++] = srcBuf[src_pos + 1]; + dstBuf[dst_pos++] = srcBuf[src_pos + 2]; + dstBuf[dst_pos++] = srcBuf[src_pos + 3]; + } + } + + return true; +} + +inline void JpegEncoder::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + uint32_t value) +{ + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, &value, 4); + *pCur += 4; +} + +inline void JpegEncoder::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned char *pValue) +{ + char buf[4] = { 0,}; + + memcpy(buf, pValue, count); + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, buf, 4); + *pCur += 4; +} + + +inline void JpegEncoder::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned char *pValue, + unsigned int *offset, + unsigned char *start) +{ + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, offset, 4); + *pCur += 4; + memcpy(start + *offset, pValue, count); + *offset += count; +} + +inline void JpegEncoder::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + rational_t *pValue, + unsigned int *offset, + unsigned char *start) +{ + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, offset, 4); + *pCur += 4; + memcpy(start + *offset, pValue, 8 * count); + *offset += 8 * count; +} + +}; diff --git a/libs3cjpeg/JpegEncoder.h b/libs3cjpeg/JpegEncoder.h new file mode 100644 index 0000000..b95b1b1 --- /dev/null +++ b/libs3cjpeg/JpegEncoder.h @@ -0,0 +1,240 @@ +/* + * Copyright Samsung Electronics Co.,LTD. + * Copyright (C) 2010 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. + * + * JPEG DRIVER MODULE (JpegEncoder.h) + * Author : ge.lee -- initial version + * Date : 03 June 2010 + * Purpose : This file implements the JPEG encoder APIs as needed by Camera HAL + */ +#ifndef __JPG_API_H__ +#define __JPG_API_H__ + +#include +#include + +#include "Exif.h" + +namespace android { +#define MAX_JPG_WIDTH 800 +#define MAX_JPG_HEIGHT 480 +#define MAX_JPG_RESOLUTION (MAX_JPG_WIDTH * MAX_JPG_HEIGHT) + +#define MAX_JPG_THUMBNAIL_WIDTH 320 +#define MAX_JPG_THUMBNAIL_HEIGHT 240 +#define MAX_JPG_THUMBNAIL_RESOLUTION (MAX_JPG_THUMBNAIL_WIDTH * \ + MAX_JPG_THUMBNAIL_HEIGHT) + +#define MAX_RGB_WIDTH 800 +#define MAX_RGB_HEIGHT 480 +#define MAX_RGB_RESOLUTION (MAX_RGB_WIDTH * MAX_RGB_HEIGHT) + +/*******************************************************************************/ +/* define JPG & image memory */ +/* memory area is 4k(PAGE_SIZE) aligned because of VirtualCopyEx() */ +#define JPG_STREAM_BUF_SIZE \ + (MAX_JPG_RESOLUTION / PAGE_SIZE + 1) * PAGE_SIZE +#define JPG_STREAM_THUMB_BUF_SIZE \ + (MAX_JPG_THUMBNAIL_RESOLUTION / PAGE_SIZE + 1) * PAGE_SIZE +#define JPG_FRAME_BUF_SIZE \ + ((MAX_JPG_RESOLUTION * 3) / PAGE_SIZE + 1) * PAGE_SIZE +#define JPG_FRAME_THUMB_BUF_SIZE \ + ((MAX_JPG_THUMBNAIL_RESOLUTION * 3) / PAGE_SIZE + 1) * PAGE_SIZE +#define JPG_RGB_BUF_SIZE \ + ((MAX_RGB_RESOLUTION * 4) / PAGE_SIZE + 1) * PAGE_SIZE + +#define JPG_TOTAL_BUF_SIZE (JPG_STREAM_BUF_SIZE + \ + JPG_STREAM_THUMB_BUF_SIZE + \ + JPG_FRAME_BUF_SIZE + \ + JPG_FRAME_THUMB_BUF_SIZE + \ + JPG_RGB_BUF_SIZE) + +#define JPG_MAIN_START 0x00 +#define JPG_THUMB_START JPG_STREAM_BUF_SIZE +#define IMG_MAIN_START (JPG_STREAM_BUF_SIZE + JPG_STREAM_THUMB_BUF_SIZE) +#define IMG_THUMB_START (IMG_MAIN_START + JPG_FRAME_BUF_SIZE) +/*******************************************************************************/ + +#define JPG_DRIVER_NAME "/dev/s3c-jpg" + +#define JPEG_IOCTL_MAGIC 'J' +#define IOCTL_JPG_DECODE _IO(JPEG_IOCTL_MAGIC, 1) +#define IOCTL_JPG_ENCODE _IO(JPEG_IOCTL_MAGIC, 2) +#define IOCTL_JPG_GET_STRBUF _IO(JPEG_IOCTL_MAGIC, 3) +#define IOCTL_JPG_GET_FRMBUF _IO(JPEG_IOCTL_MAGIC, 4) +#define IOCTL_JPG_GET_THUMB_STRBUF _IO(JPEG_IOCTL_MAGIC, 5) +#define IOCTL_JPG_GET_THUMB_FRMBUF _IO(JPEG_IOCTL_MAGIC, 6) +#define IOCTL_JPG_GET_PHY_FRMBUF _IO(JPEG_IOCTL_MAGIC, 7) +#define IOCTL_JPG_GET_PHY_THUMB_FRMBUF _IO(JPEG_IOCTL_MAGIC, 8) + +typedef enum { + JPEG_SET_ENCODE_WIDTH, + JPEG_SET_ENCODE_HEIGHT, + JPEG_SET_ENCODE_QUALITY, + JPEG_SET_ENCODE_IN_FORMAT, + JPEG_SET_SAMPING_MODE, + JPEG_SET_THUMBNAIL_WIDTH, + JPEG_SET_THUMBNAIL_HEIGHT +} jpeg_conf; + +typedef enum { + JPG_FAIL, + JPG_SUCCESS, + OK_HD_PARSING, + ERR_HD_PARSING, + OK_ENC_OR_DEC, + ERR_ENC_OR_DEC, + ERR_UNKNOWN +} jpg_return_status; + +typedef enum { + JPG_RGB16, + JPG_YCBYCR, + JPG_TYPE_UNKNOWN +} image_type_t; + +typedef enum { + JPG_444, + JPG_422, + JPG_420, + JPG_400, + RESERVED1, + RESERVED2, + JPG_411, + JPG_SAMPLE_UNKNOWN +} sample_mode_t; + +typedef enum { + YCBCR_422, + YCBCR_420, + YCBCR_SAMPLE_UNKNOWN +} out_mode_t; + +typedef enum { + JPG_MODESEL_YCBCR = 1, + JPG_MODESEL_RGB, + JPG_MODESEL_UNKNOWN +} in_mode_t; + +typedef enum { + JPG_MAIN, + JPG_THUMBNAIL +} encode_type_t; + +typedef enum { + JPG_QUALITY_LEVEL_1, /* high */ + JPG_QUALITY_LEVEL_2, + JPG_QUALITY_LEVEL_3, + JPG_QUALITY_LEVEL_4 /* low */ +} image_quality_type_t; + +typedef struct { + sample_mode_t sample_mode; + encode_type_t dec_type; + out_mode_t out_format; + uint32_t width; + uint32_t height; + uint32_t data_size; + uint32_t file_size; +} jpg_dec_proc_param; + +typedef struct { + sample_mode_t sample_mode; + encode_type_t enc_type; + in_mode_t in_format; + image_quality_type_t quality; + uint32_t width; + uint32_t height; + uint32_t data_size; + uint32_t file_size; + uint32_t set_framebuf; +} jpg_enc_proc_param; + +typedef struct { + char *in_buf; + char *phy_in_buf; + int in_buf_size; + char *out_buf; + char *phy_out_buf; + int out_buf_size; + char *in_thumb_buf; + char *phy_in_thumb_buf; + int in_thumb_buf_size; + char *out_thumb_buf; + char *phy_out_thumb_buf; + int out_thumb_buf_size; + char *mmapped_addr; + jpg_dec_proc_param *dec_param; + jpg_enc_proc_param *enc_param; + jpg_enc_proc_param *thumb_enc_param; +} jpg_args; + +class JpegEncoder { +public: + JpegEncoder(); + virtual ~JpegEncoder(); + + int openHardware(); + jpg_return_status setConfig(jpeg_conf type, int32_t value); + void *getInBuf(uint64_t size); + void *getOutBuf(uint64_t *size); + void *getThumbInBuf(uint64_t size); + void *getThumbOutBuf(uint64_t *size); + jpg_return_status encode(unsigned int *size, exif_attribute_t *exifInfo); + jpg_return_status encodeThumbImg(unsigned int *size, bool useMain = true); + jpg_return_status makeExif(unsigned char *exifOut, + exif_attribute_t *exifIn, + unsigned int *size, + bool useMainbufForThumb = false); + +private: + jpg_return_status checkMcu(sample_mode_t sampleMode, uint32_t width, uint32_t height, bool isThumb); + bool pad(char *srcBuf, uint32_t srcWidth, uint32_t srcHight, + char *dstBuf, uint32_t dstWidth, uint32_t dstHight); + bool scaleDownYuv422(char *srcBuf, uint32_t srcWidth, uint32_t srcHight, + char *dstBuf, uint32_t dstWidth, uint32_t dstHight); + + inline void writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + uint32_t value); + inline void writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned char *pValue); + inline void writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + rational_t *pValue, + unsigned int *offset, + unsigned char *start); + inline void writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned char *pValue, + unsigned int *offset, + unsigned char *start); + int mDevFd; + jpg_args mArgs; + + bool available; + +}; +}; +#endif /* __JPG_API_H__ */ diff --git a/libstagefrighthw/Android.mk b/libstagefrighthw/Android.mk new file mode 100644 index 0000000..af3de3b --- /dev/null +++ b/libstagefrighthw/Android.mk @@ -0,0 +1,24 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + SEC_OMX_Plugin.cpp + +LOCAL_CFLAGS += $(PV_CFLAGS_MINUS_VISIBILITY) + +LOCAL_C_INCLUDES:= \ + $(TOP)/frameworks/base/include/media/stagefright/openmax \ + $(LOCAL_PATH)/../include \ + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libutils \ + libcutils \ + libui \ + libdl \ + +LOCAL_MODULE := libstagefrighthw + +LOCAL_MODULE_TAGS := optional +include $(BUILD_SHARED_LIBRARY) + diff --git a/libstagefrighthw/SEC_OMX_Plugin.cpp b/libstagefrighthw/SEC_OMX_Plugin.cpp new file mode 100644 index 0000000..c78999c --- /dev/null +++ b/libstagefrighthw/SEC_OMX_Plugin.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2010 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 "SEC_OMX_Plugin.h" + +#include + +#include +#include + +namespace android { + +OMXPluginBase *createOMXPlugin() { + return new SECOMXPlugin; +} + +SECOMXPlugin::SECOMXPlugin() + : mLibHandle(dlopen("libSEC_OMX_Core.s5pc110.so", RTLD_NOW)), + mInit(NULL), + mDeinit(NULL), + mComponentNameEnum(NULL), + mGetHandle(NULL), + mFreeHandle(NULL), + mGetRolesOfComponentHandle(NULL) { + if (mLibHandle != NULL) { + mInit = (InitFunc)dlsym(mLibHandle, "SEC_OMX_Init"); + mDeinit = (DeinitFunc)dlsym(mLibHandle, "SEC_OMX_DeInit"); + + mComponentNameEnum = + (ComponentNameEnumFunc)dlsym(mLibHandle, "SEC_OMX_ComponentNameEnum"); + + mGetHandle = (GetHandleFunc)dlsym(mLibHandle, "SEC_OMX_GetHandle"); + mFreeHandle = (FreeHandleFunc)dlsym(mLibHandle, "SEC_OMX_FreeHandle"); + + mGetRolesOfComponentHandle = + (GetRolesOfComponentFunc)dlsym( + mLibHandle, "SEC_OMX_GetRolesOfComponent"); + + (*mInit)(); + + } +} + +SECOMXPlugin::~SECOMXPlugin() { + if (mLibHandle != NULL) { + (*mDeinit)(); + + dlclose(mLibHandle); + mLibHandle = NULL; + } +} + +OMX_ERRORTYPE SECOMXPlugin::makeComponentInstance( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) { + if (mLibHandle == NULL) { + return OMX_ErrorUndefined; + } + + return (*mGetHandle)( + reinterpret_cast(component), + const_cast(name), + appData, const_cast(callbacks)); +} + +OMX_ERRORTYPE SECOMXPlugin::destroyComponentInstance( + OMX_COMPONENTTYPE *component) { + if (mLibHandle == NULL) { + return OMX_ErrorUndefined; + } + + return (*mFreeHandle)(reinterpret_cast(component)); +} + +OMX_ERRORTYPE SECOMXPlugin::enumerateComponents( + OMX_STRING name, + size_t size, + OMX_U32 index) { + if (mLibHandle == NULL) { + return OMX_ErrorUndefined; + } + + return (*mComponentNameEnum)(name, size, index); +} + +OMX_ERRORTYPE SECOMXPlugin::getRolesOfComponent( + const char *name, + Vector *roles) { + roles->clear(); + + if (mLibHandle == NULL) { + return OMX_ErrorUndefined; + } + + OMX_U32 numRoles; + OMX_ERRORTYPE err = (*mGetRolesOfComponentHandle)( + const_cast(name), &numRoles, NULL); + + if (err != OMX_ErrorNone) { + return err; + } + + if (numRoles > 0) { + OMX_U8 **array = new OMX_U8 *[numRoles]; + for (OMX_U32 i = 0; i < numRoles; ++i) { + array[i] = new OMX_U8[OMX_MAX_STRINGNAME_SIZE]; + } + + OMX_U32 numRoles2; + err = (*mGetRolesOfComponentHandle)( + const_cast(name), &numRoles2, array); + + CHECK_EQ(err, OMX_ErrorNone); + CHECK_EQ(numRoles, numRoles2); + + for (OMX_U32 i = 0; i < numRoles; ++i) { + String8 s((const char *)array[i]); + roles->push(s); + + delete[] array[i]; + array[i] = NULL; + } + + delete[] array; + array = NULL; + } + + return OMX_ErrorNone; +} + +} // namespace android + diff --git a/libstagefrighthw/SEC_OMX_Plugin.h b/libstagefrighthw/SEC_OMX_Plugin.h new file mode 100644 index 0000000..6df2d31 --- /dev/null +++ b/libstagefrighthw/SEC_OMX_Plugin.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010 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 SEC_OMX_PLUGIN + +#define SEC_OMX_PLUGIN + +#include + +namespace android { + +struct SECOMXPlugin : public OMXPluginBase { + SECOMXPlugin(); + virtual ~SECOMXPlugin(); + + virtual OMX_ERRORTYPE makeComponentInstance( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component); + + virtual OMX_ERRORTYPE destroyComponentInstance( + OMX_COMPONENTTYPE *component); + + virtual OMX_ERRORTYPE enumerateComponents( + OMX_STRING name, + size_t size, + OMX_U32 index); + + virtual OMX_ERRORTYPE getRolesOfComponent( + const char *name, + Vector *roles); + +private: + void *mLibHandle; + + typedef OMX_ERRORTYPE (*InitFunc)(); + typedef OMX_ERRORTYPE (*DeinitFunc)(); + typedef OMX_ERRORTYPE (*ComponentNameEnumFunc)( + OMX_STRING, OMX_U32, OMX_U32); + + typedef OMX_ERRORTYPE (*GetHandleFunc)( + OMX_HANDLETYPE *, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE *); + + typedef OMX_ERRORTYPE (*FreeHandleFunc)(OMX_HANDLETYPE *); + + typedef OMX_ERRORTYPE (*GetRolesOfComponentFunc)( + OMX_STRING, OMX_U32 *, OMX_U8 **); + + InitFunc mInit; + DeinitFunc mDeinit; + ComponentNameEnumFunc mComponentNameEnum; + GetHandleFunc mGetHandle; + FreeHandleFunc mFreeHandle; + GetRolesOfComponentFunc mGetRolesOfComponentHandle; + + SECOMXPlugin(const SECOMXPlugin &); + SECOMXPlugin &operator=(const SECOMXPlugin &); +}; + +} // namespace android + +#endif // SEC_OMX_PLUGIN diff --git a/lpm.rc b/lpm.rc new file mode 100755 index 0000000..0585939 --- /dev/null +++ b/lpm.rc @@ -0,0 +1,63 @@ +on early-init + start ueventd + +on init + +# GyuTae FIX : we should not use system partition!!!!! +# export PATH /sbin:/bin + + export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin + export LD_LIBRARY_PATH /vendor/lib:/system/lib + export ANDROID_ROOT /system + export ANDROID_DATA /data + export EXTERNAL_STORAGE /sdcard + + symlink /system/etc /etc + + mkdir /sdcard + mkdir /system + mkdir /data + mkdir /cache + mkdir /tmp + mkdir /mnt 0775 root root + #mount /tmp /tmp tmpfs + +on early-fs + + +on fs + mount tmpfs tmpfs /tmp + mount yaffs2 mtd@system /system + +on boot + + ifup lo + hostname localhost + domainname localdomain + + class_start default + +service ueventd /sbin/ueventd + critical + +service console /system/bin/sh + console + +# adbd is controlled by the persist.service.adb.enable system property +service adbd /sbin/adbd + disabled + +service playlpm /system/bin/playlpm + user root + oneshot + +service lpmkey /system/bin/charging_mode + user root + oneshot + +on property:persist.service.adb.enable=1 + start adbd + +on property:persist.service.adb.enable=0 + stop adbd + diff --git a/mkshbootimg.py b/mkshbootimg.py new file mode 100755 index 0000000..dcc8294 --- /dev/null +++ b/mkshbootimg.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +import sys, os + +def copydata(outfile, infile): + while 1: + data = infile.read(512) + if (data): + outfile.write(data) + else: + break + +def alignoffset(outfile): + offset = outfile.tell() + outfile.seek((offset + 511) & ~511) + return outfile.tell() + +def appendimage(outfile, infile): + offset = alignoffset(outfile) + copydata(outfile, infile) + length = alignoffset(outfile) - offset + assert (offset % 512 == 0) + assert (length % 512 == 0) + return (offset/512, length/512) + +if len(sys.argv) < 4: + print "Usage:", sys.argv[0], "output kernel boot [recovery]" + sys.exit(1) + +outfile = open(sys.argv[1], 'wb') +kernel = open(sys.argv[2], 'r') +boot = open(sys.argv[3], 'r') +recovery = None +if (len(sys.argv) == 5): + recovery = open(sys.argv[4], 'r') +offset_table = "\n\nBOOT_IMAGE_OFFSETS\n" +copydata(outfile, kernel) +table_loc = alignoffset(outfile) +outfile.write('\x00' * 512) +offset_table += "boot_offset=%d;boot_len=%d;" % appendimage(outfile, boot) +if recovery: + offset_table += "recovery_offset=%d;recovery_len=%d;" % appendimage(outfile, recovery) +offset_table += "\n\n" +outfile.seek(table_loc) +outfile.write(offset_table) +outfile.flush() +os.fsync(outfile.fileno()) +outfile.close() diff --git a/overlay/frameworks/base/core/res/res/values-large/config.xml b/overlay/frameworks/base/core/res/res/values-large/config.xml new file mode 100644 index 0000000..27d1d32 --- /dev/null +++ b/overlay/frameworks/base/core/res/res/values-large/config.xml @@ -0,0 +1,24 @@ + + + + + + 1 + diff --git a/overlay/frameworks/base/core/res/res/values-sw600dp/config.xml b/overlay/frameworks/base/core/res/res/values-sw600dp/config.xml new file mode 100644 index 0000000..e83ea7f --- /dev/null +++ b/overlay/frameworks/base/core/res/res/values-sw600dp/config.xml @@ -0,0 +1,25 @@ + + + + + + 1 + 2 + diff --git a/overlay/frameworks/base/core/res/res/values/arrays.xml b/overlay/frameworks/base/core/res/res/values/arrays.xml new file mode 100644 index 0000000..5b65ae4 --- /dev/null +++ b/overlay/frameworks/base/core/res/res/values/arrays.xml @@ -0,0 +1,35 @@ + + + + + + + @string/reboot_reboot + @string/reboot_recovery + + + + + + recovery + + + diff --git a/overlay/frameworks/base/core/res/res/values/config.xml b/overlay/frameworks/base/core/res/res/values/config.xml new file mode 100644 index 0000000..16900dc --- /dev/null +++ b/overlay/frameworks/base/core/res/res/values/config.xml @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + "wifi,1,1,1,-1,true" + "mobile,0,0,0,-1,true" + "mobile_mms,2,0,2,60000,true" + "mobile_supl,3,0,2,60000,true" + "mobile_dun,4,0,4,60000,true" + "mobile_hipri,5,0,3,60000,true" + + + + + "usb0" + + + + + "wl0.1" + + + + true + + + true + + + true + + + true + + + + 10 + 25 + 50 + 100 + 150 + 200 + 700 + 1300 + 2000 + 3000 + 4000 + 5000 + 6000 + 7000 + 8000 + 9000 + + + + + 32 + 32 + 32 + 32 + 64 + 64 + 95 + 95 + 122 + 149 + 176 + 197 + 228 + 255 + 255 + 255 + 255 + + + + + 255 + 255 + 255 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + 10 + + + true + + + + + true + + + com.google.android.location.NetworkLocationProvider + + + com.google.android.location.GeocodeProvider + + + ppp0 + + + false + + + true + + diff --git a/overlay/frameworks/base/core/res/res/xml/eri.xml b/overlay/frameworks/base/core/res/res/xml/eri.xml new file mode 100644 index 0000000..9218f2f --- /dev/null +++ b/overlay/frameworks/base/core/res/res/xml/eri.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/overlay/frameworks/base/core/res/res/xml/power_profile.xml b/overlay/frameworks/base/core/res/res/xml/power_profile.xml new file mode 100644 index 0000000..630d7b4 --- /dev/null +++ b/overlay/frameworks/base/core/res/res/xml/power_profile.xml @@ -0,0 +1,52 @@ + + + + + + 0 + 30 + 0.4 + 0.8 + + 35690 + 50 + 0.2 + 0.1 + 0.1 + 74 + 243 + 200 + 70 + 30 + + 3 + 2 + + + 1000000 + + + 1.5 + + + 20 + + + 4000 + diff --git a/overlay/frameworks/base/core/res/res/xml/storage_list.xml b/overlay/frameworks/base/core/res/res/xml/storage_list.xml new file mode 100644 index 0000000..0769cfa --- /dev/null +++ b/overlay/frameworks/base/core/res/res/xml/storage_list.xml @@ -0,0 +1,43 @@ + + + + + + + + + diff --git a/overlay/frameworks/base/data/etc/platform.xml b/overlay/frameworks/base/data/etc/platform.xml new file mode 100644 index 0000000..8a749ba --- /dev/null +++ b/overlay/frameworks/base/data/etc/platform.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + diff --git a/overlay/frameworks/base/packages/SystemUI/res/values/config.xml b/overlay/frameworks/base/packages/SystemUI/res/values/config.xml new file mode 100644 index 0000000..4af4a5a --- /dev/null +++ b/overlay/frameworks/base/packages/SystemUI/res/values/config.xml @@ -0,0 +1,27 @@ + + + + + + + + true + diff --git a/overlay/packages/apps/Mms/res/xml/mms_config.xml b/overlay/packages/apps/Mms/res/xml/mms_config.xml new file mode 100644 index 0000000..3777b12 --- /dev/null +++ b/overlay/packages/apps/Mms/res/xml/mms_config.xml @@ -0,0 +1,40 @@ + + + + + + + + 1024000 + + + 1200 + + + 1600 + + + http://wap.samsungmobile.com/uaprof/GT-P1000.xml + + + + Mozilla/5.0 + diff --git a/overlay/packages/apps/Settings/res/values/bools.xml b/overlay/packages/apps/Settings/res/values/bools.xml new file mode 100644 index 0000000..61e1d03 --- /dev/null +++ b/overlay/packages/apps/Settings/res/values/bools.xml @@ -0,0 +1,20 @@ + + + + + + false + diff --git a/overlay/packages/apps/Trebuchet/res/xml/default_workspace.xml b/overlay/packages/apps/Trebuchet/res/xml/default_workspace.xml new file mode 100644 index 0000000..3a12fc3 --- /dev/null +++ b/overlay/packages/apps/Trebuchet/res/xml/default_workspace.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + diff --git a/prebuilt/etc/asound.conf b/prebuilt/etc/asound.conf new file mode 100644 index 0000000..7568874 --- /dev/null +++ b/prebuilt/etc/asound.conf @@ -0,0 +1,1238 @@ +# Android ALSA configuration file for the WM8994 audio. + + +################################################################################################################################## +# +# {name "Playback Path" value 2} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK +# # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER +# # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL +# {name "Capture MIC Path" value 1} # 0:Main Mic 1:Ear MIC 2:BT MIC +# {name "Voice Call Path" value 1} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT +# {name "Voice Call Recording" value 1} # 0:CALL_RECORDING_OFF 1:CALL_RECORDING_MAIN 2:CALL_RECORDING_SUB +# {name "Voip Call Path" value 1} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT +# +################################################################################################################################## + +## +## Mixer Devices +## + +ctl.AndroidPlayback { + type hw + card 0 +} + +ctl.AndroidRecord { + type hw + card 0 +} + + +## +## Playback Devices +## + +pcm.AndroidPlayback { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + ] + } +} + +pcm.AndroidPlayback_Earpiece { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 1} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Speaker { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 2} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Headset { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 3} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Headphone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 4} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Bluetooth { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 5} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Earpiece_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 1} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Speaker_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 2} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Headset_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 3} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Headphone_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 4} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Bluetooth_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 5} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Speaker_Headset_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 6} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Speaker_Headphone_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 6} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} +pcm.AndroidPlayback_Speaker_LineOut_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 2} + {name "Playback Path" value 11} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Speaker_LineOut_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 2} + {name "Playback Path" value 11} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_LineOut_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 11} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + + +pcm.AndroidPlayback_Hdmi_TVOut_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 13} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Speaker_Hdmi_TVOut_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 14} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Speaker_Hdmi_TVOut_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 15} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Earpiece_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 6} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Speaker_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 10} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Headset_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 8} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Bluetooth_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 5} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Speaker_Headset_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 10} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Speaker_Headphone_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Playback Path" value 10} + # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT 6:SPK_HP 7:RING_SPK + # 8:RING_HP 9:RING_HP_NO_MIC 10:RING_SPK_HP 11:EXTRA_DOCK_SPEAKER + # 12:TV_OUT 13:HDMI_TV_OUT 14:HDMI_SPK 15:HDMI_DUAL + ] + } +} + +pcm.AndroidPlayback_Earpiece_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 1} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Speaker_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 2} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Headset_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 3} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Headphone_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 4} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Bluetooth_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 5} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Speaker_Headset_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 3} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + + +# +# FMRadio +# +pcm.AndroidPlayback_Speaker_fmradio { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "FM Radio Path" value 1} # 0:OFF 1:SPK 2:HP 3:SPK_MIX 4:HP_MIX + ] + } +} + +pcm.AndroidPlayback_Headset_fmradio { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "FM Radio Path" value 2} # 0:OFF 1:SPK 2:HP 3:SPK_MIX 4:HP_MIX + ] + } +} + +pcm.AndroidPlayback_Speaker_Headset_fmradio { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "FM Radio Path" value 5} # 0:OFF 1:SPK 2:HP 3:SPK_MIX 4:HP_MIX 5:DUAL MIX + ] + } +} +# +# FM Radio + AP Play +# +pcm.AndroidPlayback_Speaker_dualinput { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "FM Radio Path" value 3} # 0:OFF 1:SPK 2:HP 3:SPK_MIX 4:HP_MIX + ] + } +} + +pcm.AndroidPlayback_Headset_dualinput { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "FM Radio Path" value 4} # 0:OFF 1:SPK 2:HP 3:SPK_MIX 4:HP_MIX + ] + } +} + +pcm.AndroidPlayback_Speaker_Headset_dualinput { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "FM Radio Path" value 5} # 0:OFF 1:SPK 2:HP 3:SPK_MIX 4:HP_MIX 5:SPK_HP_MIX + ] + } +} + +# +# Video Call - Output stream +# +pcm.AndroidPlayback_Earpiece_videocall { + type hooks + slave.pcm { + type hw + card 1 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 1} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Speaker_videocall { + type hooks + slave.pcm { + type hw + card 1 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 2} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Headset_videocall { + type hooks + slave.pcm { + type hw + card 1 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 3} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Headphone_videocall { + type hooks + slave.pcm { + type hw + card 1 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 4} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Bluetooth_videocall { + type hooks + slave.pcm { + type hw + card 1 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Path" value 5} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + + +## +## Capture device +## + +pcm.AndroidRecord { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 0} # 0:Main Mic 1:Ear Mic 2:BT Mic 3:OFF + ] + } +} + +pcm.AndroidRecord_Microphone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 0} # 0:Main Mic 1:Ear Mic 2:BT Mic 3:OFF + ] + } +} + +pcm.AndroidRecord_Earpiece_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 0} # 0:Main Mic 1:Ear Mic 2:BT Mic 3:OFF + ] + } +} + +pcm.AndroidRecord_Speaker_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 0} # 0:Main Mic 1:Sub MIC + ] + } +} + +pcm.AndroidRecord_Headset_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 1} # 0:Main Mic 1:Ear Mic 2:BT Mic 3:OFF + ] + } +} + +pcm.AndroidRecord_Bluetooth_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 2} # 0:Main Mic 1:Ear Mic 2:BT Mic 3:OFF + ] + } +} + +pcm.AndroidRecord_Speaker_Headset_normal { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 0} # 0:Main Mic 1:Ear Mic 2:BT Mic 3:OFF + ] + } +} + +pcm.AndroidRecord_Speaker_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 0} # 0:Main Mic 1:Ear Mic 2:BT Mic 3:OFF + ] + } +} + +pcm.AndroidRecord_Headset_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 1} # 0:Main Mic 1:Ear Mic 2:BT Mic 3:OFF + ] + } +} + +pcm.AndroidRecord_Headphone_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 0} # 0:Main Mic 1:Ear Mic 2:BT Mic 3:OFF + ] + } +} + +pcm.AndroidRecord_Speaker_Headset_ringtone { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "Capture MIC Path" value 0} # 0:Main Mic 1:Ear Mic 2:BT Mic 3:OFF + ] + } +} + +pcm.AndroidRecord_Earpiece_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Recording" value 1} # 0:CALL_RECORDING_OFF 1:CALL_RECORDING_MAIN 2:CALL_RECORDING_SUB + ] + } +} + +pcm.AndroidRecord_Speaker_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Recording" value 1} # 0:CALL_RECORDING_OFF 1:CALL_RECORDING_MAIN 2:CALL_RECORDING_SUB + ] + } +} + +pcm.AndroidRecord_Headset_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Recording" value 2} # 0:CALL_RECORDING_OFF 1:CALL_RECORDING_MAIN 2:CALL_RECORDING_SUB + ] + } +} + +pcm.AndroidRecord_Headphone_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Recording" value 1} # 0:CALL_RECORDING_OFF 1:CALL_RECORDING_MAIN 2:CALL_RECORDING_SUB + ] + } +} + +pcm.AndroidRecord_Bluetooth_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Recording" value 0} # 0:CALL_RECORDING_OFF 1:CALL_RECORDING_MAIN 2:CALL_RECORDING_SUB + ] + } +} + +pcm.AndroidRecord_Speaker_Headset_incall { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "Voice Call Recording" value 0} # 0:CALL_RECORDING_OFF 1:CALL_RECORDING_MAIN 2:CALL_RECORDING_SUB + ] + } +} + +# +# Video Call - Input stream +# +pcm.AndroidRecord_Earpiece_videocall { + type hooks + slave.pcm { + type hw + card 1 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + # Already called codec path by Video call outputstream + ] + } +} + +pcm.AndroidRecord_Speaker_videocall { + type hooks + slave.pcm { + type hw + card 1 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + # Already called codec path by Video call outputstream + ] + } +} + +pcm.AndroidRecord_Headset_videocall { + type hooks + slave.pcm { + type hw + card 1 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + # Already called codec path by Video call outputstream + ] + } +} + +pcm.AndroidRecord_Headphone_videocall { + type hooks + slave.pcm { + type hw + card 1 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + # Already called codec path by Video call outputstream + ] + } +} + +pcm.AndroidRecord_Bluetooth_videocall { + type hooks + slave.pcm { + type hw + card 1 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + # Already called codec path by Video call outputstream + #{name "Voice Call Path" value 5} # 0:OFF 1:RCV 2:SPK 3:HP3P 4:HP4P 5:BT + ] + } +} + + +# +# ATV - Input stream (LTN_ATV) +# +pcm.AndroidRecord_Atv_normal { + type hooks + slave.pcm { + type hw + card 2 + device 0 # Must be of type "digital audio capture" + } + hooks.0 { + type ctl_elems + hook_args [ + ] + } +} + + +## FEATURE_SEC_KOREA_MM_AUDIO +## +## Playback VOIP Call Devices +## + +pcm.AndroidPlayback_Earpiece_voip { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "VoIP Call Path" value 1} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Speaker_voip { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "VoIP Call Path" value 2} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Headset_voip { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "VoIP Call Path" value 3} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Headphone_voip { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + # Enable audio output from the DSP + {name "VoIP Call Path" value 4} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + +pcm.AndroidPlayback_Bluetooth_voip { + type hooks + slave.pcm { + type hw + card 0 + device 0 # Must be of type "digital audio playback" + } + hooks.0 { + type ctl_elems + hook_args [ + {name "VoIP Call Path" value 5} # 0:OFF 1:RCV 2:SPK 3:HP 4:HP_NO_MIC 5:BT + ] + } +} + diff --git a/prebuilt/etc/bluetooth/main.conf b/prebuilt/etc/bluetooth/main.conf new file mode 100644 index 0000000..3989580 --- /dev/null +++ b/prebuilt/etc/bluetooth/main.conf @@ -0,0 +1,66 @@ +[General] + +# List of plugins that should not be loaded on bluetoothd startup +#DisablePlugins = network,input + +# Default adaper name +# %h - substituted for hostname +# %d - substituted for adapter id +# %b - substituted for ro.product.brand +# %m - substituted for ro.product.model +# %n - substituted for ro.product.name +Name = %m + +# Default device class. Only the major and minor device class bits are +# considered. +# Local device class +# 0x400000 - Service class: Telephony +# 0x000200 - Major class: Phone +# 0x00000C - Minor class: Smart phone +Class = 0x40020C + +# How long to stay in discoverable mode before going back to non-discoverable +# The value is in seconds. Default is 180, i.e. 3 minutes. +# 0 = disable timer, i.e. stay discoverable forever +DiscoverableTimeout = 120 + +# How long to stay in pairable mode before going back to non-discoverable +# The value is in seconds. Default is 0. +# 0 = disable timer, i.e. stay pairable forever +PairableTimeout = 0 + +# Use some other page timeout than the controller default one +# which is 16384 (10 seconds). +PageTimeout = 8192 + +# Discover scheduler interval used in Adapter.DiscoverDevices +# The value is in seconds. Defaults is 0 to use controller scheduler. +DiscoverSchedulerInterval = 0 + +# What value should be assumed for the adapter Powered property when +# SetProperty(Powered, ...) hasn't been called yet. Defaults to true +InitiallyPowered = true + +# Remember the previously stored Powered state when initializing adapters +RememberPowered = true + +# Use vendor, product and version information for DID profile support. +# The values are separated by ":" and VID, PID and version. +DeviceID = android:generic:1.5 + +# Do reverse service discovery for previously unknown devices that connect to +# us. This option is really only needed for qualification since the BITE tester +# doesn't like us doing reverse SDP for some test cases (though there could in +# theory be other useful purposes for this too). Defaults to true. +ReverseServiceDiscovery = true + +# Enable name resolving after inquiry. Set it to 'false' if you don't need +# remote devices name and want shorter discovery cycle. Defaults to 'true'. +NameResolving = true + +# The link policy for connections. By default it's set to 15(0x000f) which is +# a bitwise OR of role switch(0x0001), hold mode(0x0002), sniff mode(0x0004) +# and park state(0x0008) are all enabled. However, some devices have +# connection stability issue or fail to setup SCO when the link is in park +# state, which requires park state bit cleared. +DefaultLinkPolicy = 7 diff --git a/prebuilt/etc/media_profiles.xml b/prebuilt/etc/media_profiles.xml new file mode 100644 index 0000000..7fd5a2b --- /dev/null +++ b/prebuilt/etc/media_profiles.xml @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prebuilt/etc/vold.fstab b/prebuilt/etc/vold.fstab new file mode 100644 index 0000000..d677118 --- /dev/null +++ b/prebuilt/etc/vold.fstab @@ -0,0 +1,14 @@ +## Vold 2.0 Generic fstab +## - San Mehat (san@android.com) +## + +####################### +## Regular device mount +## +## Format: dev_mount