diff options
36 files changed, 2284 insertions, 399 deletions
@@ -22,6 +22,7 @@ LOCAL_PATH := $(call my-dir) +ifeq ($(BOARD_CREATE_TUNA_HDCP_KEYS_SYMLINK), true) include $(CLEAR_VARS) LOCAL_MODULE := tuna_hdcp_keys @@ -44,3 +45,5 @@ $(LOCAL_BUILT_MODULE): $(hide) touch $@ include $(call all-makefiles-under,$(LOCAL_PATH)) + +endif diff --git a/BoardConfig.mk b/BoardConfig.mk index b1a43ac..7fa3d44 100644 --- a/BoardConfig.mk +++ b/BoardConfig.mk @@ -35,14 +35,18 @@ BOARD_KERNEL_BASE := 0x80000000 TARGET_NO_RADIOIMAGE := true TARGET_BOARD_PLATFORM := omap4 TARGET_BOOTLOADER_BOARD_NAME := tuna -TARGET_BOARD_INFO_FILE := device/samsung/tuna/board-info.txt +TARGET_BOARD_INFO_FILE ?= device/samsung/tuna/board-info.txt BOARD_EGL_CFG := device/samsung/tuna/egl.cfg +BOARD_CREATE_TUNA_HDCP_KEYS_SYMLINK := true #BOARD_USES_HGL := true #BOARD_USES_OVERLAY := true USE_OPENGL_RENDERER := true +# set if the target supports FBIO_WAITFORVSYNC +TARGET_HAS_WAITFORVSYNC := true + TARGET_RECOVERY_PIXEL_FORMAT := "BGRA_8888" TARGET_RECOVERY_UI_LIB := librecovery_ui_tuna diff --git a/CleanSpec.mk b/CleanSpec.mk index cff019a..51b1305 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -50,3 +50,4 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/phone_intermediates) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/updatecmds/migrate_nfc.txt) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/hw/keystore.tuna.so) diff --git a/audio/Android.mk b/audio/Android.mk index 28aae85..e422761 100644 --- a/audio/Android.mk +++ b/audio/Android.mk @@ -21,8 +21,8 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_SRC_FILES := audio_hw.c ril_interface.c LOCAL_C_INCLUDES += \ external/tinyalsa/include \ - system/media/audio_utils/include \ - system/media/audio_effects/include + $(call include-path-for, audio-utils) \ + $(call include-path-for, audio-effects) LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libdl LOCAL_MODULE_TAGS := optional diff --git a/audio/audio_hw.c b/audio/audio_hw.c index 850a1b1..403e5f3 100755..100644 --- a/audio/audio_hw.c +++ b/audio/audio_hw.c @@ -39,6 +39,7 @@ #include "ril_interface.h" + /* Mixer control names */ #define MIXER_DL2_LEFT_EQUALIZER "DL2 Left Equalizer" #define MIXER_DL2_RIGHT_EQUALIZER "DL2 Right Equalizer" @@ -399,6 +400,38 @@ struct route_setting mm_ul2_amic_right[] = { }, }; +/* dual mic configuration with main mic on main channel and sub mic on aux channel. + * Used for handset mode (near talk) */ +struct route_setting mm_ul2_amic_dual_main_sub[] = { + { + .ctl_name = MIXER_MUX_UL10, + .strval = MIXER_AMIC0, + }, + { + .ctl_name = MIXER_MUX_UL11, + .strval = MIXER_AMIC1, + }, + { + .ctl_name = NULL, + }, +}; + +/* dual mic configuration with sub mic on main channel and main mic on aux channel. + * Used for speakerphone mode (far talk) */ +struct route_setting mm_ul2_amic_dual_sub_main[] = { + { + .ctl_name = MIXER_MUX_UL10, + .strval = MIXER_AMIC1, + }, + { + .ctl_name = MIXER_MUX_UL11, + .strval = MIXER_AMIC0, + }, + { + .ctl_name = NULL, + }, +}; + /* VX UL front-end paths */ struct route_setting vx_ul_amic_left[] = { { @@ -483,7 +516,7 @@ struct tuna_audio_device { pthread_mutex_t lock; /* see note below on mutex acquisition order */ struct mixer *mixer; struct mixer_ctls mixer_ctls; - int mode; + audio_mode_t mode; int devices; struct pcm *pcm_modem_dl; struct pcm *pcm_modem_ul; @@ -527,6 +560,19 @@ struct tuna_stream_out { #define MAX_PREPROCESSORS 3 /* maximum one AGC + one NS + one AEC per input stream */ +struct effect_info_s { + effect_handle_t effect_itfe; + size_t num_channel_configs; + channel_config_t* channel_configs; +}; + +#define NUM_IN_AUX_CNL_CONFIGS 2 +channel_config_t in_aux_cnl_configs[NUM_IN_AUX_CNL_CONFIGS] = { + { AUDIO_CHANNEL_IN_FRONT , AUDIO_CHANNEL_IN_BACK}, + { AUDIO_CHANNEL_IN_STEREO , AUDIO_CHANNEL_IN_RIGHT} +}; + + struct tuna_stream_in { struct audio_stream_in stream; @@ -536,23 +582,33 @@ struct tuna_stream_in { int device; struct resampler_itfe *resampler; struct resampler_buffer_provider buf_provider; - int16_t *buffer; - size_t frames_in; unsigned int requested_rate; int standby; int source; struct echo_reference_itfe *echo_reference; bool need_echo_reference; - effect_handle_t preprocessors[MAX_PREPROCESSORS]; - int num_preprocessors; - int16_t *proc_buf; + + int16_t *read_buf; + size_t read_buf_size; + size_t read_buf_frames; + + int16_t *proc_buf_in; + int16_t *proc_buf_out; size_t proc_buf_size; - size_t proc_frames_in; + size_t proc_buf_frames; + int16_t *ref_buf; size_t ref_buf_size; - size_t ref_frames_in; + size_t ref_buf_frames; + int read_status; + int num_preprocessors; + struct effect_info_s preprocessors[MAX_PREPROCESSORS]; + + bool aux_channels_changed; + uint32_t main_channels; + uint32_t aux_channels; struct tuna_audio_device *dev; }; @@ -567,6 +623,7 @@ static void select_input_device(struct tuna_audio_device *adev); static int adev_set_voice_volume(struct audio_hw_device *dev, float volume); static int do_input_standby(struct tuna_stream_in *in); static int do_output_standby(struct tuna_stream_out *out); +static void in_update_aux_channels(struct tuna_stream_in *in, effect_handle_t effect); /* Returns true on devices that are toro, false otherwise */ static int is_device_toro(void) @@ -616,7 +673,7 @@ static int set_route_by_array(struct mixer *mixer, struct route_setting *route, static int start_call(struct tuna_audio_device *adev) { - LOGE("Opening modem PCMs"); + ALOGE("Opening modem PCMs"); pcm_config_vx.rate = adev->wb_amr ? VX_WB_SAMPLING_RATE : VX_NB_SAMPLING_RATE; @@ -624,7 +681,7 @@ static int start_call(struct tuna_audio_device *adev) if (adev->pcm_modem_dl == NULL) { adev->pcm_modem_dl = pcm_open(0, PORT_MODEM, PCM_OUT, &pcm_config_vx); if (!pcm_is_ready(adev->pcm_modem_dl)) { - LOGE("cannot open PCM modem DL stream: %s", pcm_get_error(adev->pcm_modem_dl)); + ALOGE("cannot open PCM modem DL stream: %s", pcm_get_error(adev->pcm_modem_dl)); goto err_open_dl; } } @@ -632,7 +689,7 @@ static int start_call(struct tuna_audio_device *adev) if (adev->pcm_modem_ul == NULL) { adev->pcm_modem_ul = pcm_open(0, PORT_MODEM, PCM_IN, &pcm_config_vx); if (!pcm_is_ready(adev->pcm_modem_ul)) { - LOGE("cannot open PCM modem UL stream: %s", pcm_get_error(adev->pcm_modem_ul)); + ALOGE("cannot open PCM modem UL stream: %s", pcm_get_error(adev->pcm_modem_ul)); goto err_open_ul; } } @@ -654,7 +711,7 @@ err_open_dl: static void end_call(struct tuna_audio_device *adev) { - LOGE("Closing modem PCMs"); + ALOGE("Closing modem PCMs"); pcm_stop(adev->pcm_modem_dl); pcm_stop(adev->pcm_modem_ul); @@ -740,7 +797,7 @@ static void set_input_volumes(struct tuna_audio_device *adev, int main_mic_on, if (adev->mode == AUDIO_MODE_IN_CALL) { int sub_mic_volume = is_device_toro() ? VOICE_CALL_SUB_MIC_VOLUME_TORO : - VOICE_CALL_SUB_MIC_VOLUME_MAGURO; + VOICE_CALL_SUB_MIC_VOLUME_MAGURO; /* special case: don't look at input source for IN_CALL state */ volume = DB_TO_ABE_GAIN(main_mic_on ? VOICE_CALL_MAIN_MIC_VOLUME : (headset_mic_on ? VOICE_CALL_HEADSET_MIC_VOLUME : @@ -876,7 +933,7 @@ static void force_all_standby(struct tuna_audio_device *adev) static void select_mode(struct tuna_audio_device *adev) { if (adev->mode == AUDIO_MODE_IN_CALL) { - LOGE("Entering IN_CALL state, in_call=%d", adev->in_call); + ALOGE("Entering IN_CALL state, in_call=%d", adev->in_call); if (!adev->in_call) { force_all_standby(adev); /* force earpiece route for in call state if speaker is the @@ -896,12 +953,11 @@ static void select_mode(struct tuna_audio_device *adev) adev->devices &= ~AUDIO_DEVICE_OUT_SPEAKER; select_output_device(adev); start_call(adev); - ril_set_call_clock_sync(&adev->ril, SOUND_CLOCK_START); adev_set_voice_volume(&adev->hw_device, adev->voice_volume); adev->in_call = 1; } } else { - LOGE("Leaving IN_CALL state, in_call=%d, mode=%d", + ALOGE("Leaving IN_CALL state, in_call=%d, mode=%d", adev->in_call, adev->mode); if (adev->in_call) { adev->in_call = 0; @@ -1083,12 +1139,32 @@ static void select_input_device(struct tuna_audio_device *adev) set_route_by_array(adev->mixer, mm_ul2_bt, 1); else { /* Select front end */ - if (main_mic_on || headset_on) - set_route_by_array(adev->mixer, mm_ul2_amic_left, 1); - else if (sub_mic_on) - set_route_by_array(adev->mixer, mm_ul2_amic_right, 1); - else - set_route_by_array(adev->mixer, mm_ul2_amic_left, 0); + + + if ((adev->active_input != 0) && (adev->active_input->aux_channels)) { + ALOGV("select input device(): multi-mic configuration main mic %s sub mic %s", + main_mic_on ? "ON" : "OFF", sub_mic_on ? "ON" : "OFF"); + if (main_mic_on) { + set_route_by_array(adev->mixer, mm_ul2_amic_dual_main_sub, 1); + sub_mic_on = 1; + } + else if (sub_mic_on) { + set_route_by_array(adev->mixer, mm_ul2_amic_dual_sub_main, 1); + main_mic_on = 1; + } + else { + set_route_by_array(adev->mixer, mm_ul2_amic_dual_main_sub, 0); + } + } else { + ALOGV("select input device(): single mic configuration"); + if (main_mic_on || headset_on) + set_route_by_array(adev->mixer, mm_ul2_amic_left, 1); + else if (sub_mic_on) + set_route_by_array(adev->mixer, mm_ul2_amic_right, 1); + else + set_route_by_array(adev->mixer, mm_ul2_amic_left, 0); + } + /* Select back end */ mixer_ctl_set_enum_by_string(adev->mixer_ctls.right_capture, @@ -1147,7 +1223,7 @@ static int start_output_stream(struct tuna_stream_out *out) /* Close any PCMs that could not be opened properly and return an error */ for (i = 0; i < PCM_TOTAL; i++) { if (out->pcm[i] && !pcm_is_ready(out->pcm[i])) { - LOGE("cannot open pcm_out driver: %s", pcm_get_error(out->pcm[i])); + ALOGE("cannot open pcm_out driver: %s", pcm_get_error(out->pcm[i])); pcm_close(out->pcm[i]); out->pcm[i] = NULL; success = false; @@ -1166,7 +1242,7 @@ static int start_output_stream(struct tuna_stream_out *out) return -ENOMEM; } -static int check_input_parameters(uint32_t sample_rate, int format, int channel_count) +static int check_input_parameters(uint32_t sample_rate, audio_format_t format, int channel_count) { if (format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL; @@ -1191,7 +1267,7 @@ static int check_input_parameters(uint32_t sample_rate, int format, int channel_ return 0; } -static size_t get_input_buffer_size(uint32_t sample_rate, int format, int channel_count) +static size_t get_input_buffer_size(uint32_t sample_rate, audio_format_t format, int channel_count) { size_t size; size_t device_rate; @@ -1281,7 +1357,7 @@ static int get_playback_delay(struct tuna_stream_out *out, buffer->time_stamp.tv_sec = 0; buffer->time_stamp.tv_nsec = 0; buffer->delay_ns = 0; - LOGV("get_playback_delay(): pcm_get_htimestamp error," + ALOGV("get_playback_delay(): pcm_get_htimestamp error," "setting playbackTimestamp to 0"); return status; } @@ -1325,12 +1401,12 @@ static uint32_t out_get_channels(const struct audio_stream *stream) return AUDIO_CHANNEL_OUT_STEREO; } -static int out_get_format(const struct audio_stream *stream) +static audio_format_t out_get_format(const struct audio_stream *stream) { return AUDIO_FORMAT_PCM_16_BIT; } -static int out_set_format(struct audio_stream *stream, int format) +static int out_set_format(struct audio_stream *stream, audio_format_t format) { return 0; } @@ -1432,7 +1508,8 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) (adev->devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) || (adev->devices & (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) || - (val == AUDIO_DEVICE_OUT_SPEAKER)) + ((val & AUDIO_DEVICE_OUT_SPEAKER) ^ + (adev->devices & AUDIO_DEVICE_OUT_SPEAKER))) do_output_standby(out); } adev->devices &= ~AUDIO_DEVICE_OUT_ALL; @@ -1485,7 +1562,6 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, struct tuna_stream_in *in; bool low_power; int kernel_frames; - void *buf; /* If we're in out_write, we will find at least one pcm active */ int primary_pcm = -1; int i; @@ -1645,6 +1721,27 @@ static int start_input_stream(struct tuna_stream_in *in) select_input_device(adev); } + if (in->aux_channels_changed) + { + in->aux_channels_changed = false; + in->config.channels = popcount(in->main_channels | in->aux_channels); + + if (in->resampler) { + /* release and recreate the resampler with the new number of channel of the input */ + release_resampler(in->resampler); + in->resampler = NULL; + ret = create_resampler(in->config.rate, + in->requested_rate, + in->config.channels, + RESAMPLER_QUALITY_DEFAULT, + &in->buf_provider, + &in->resampler); + } + ALOGV("start_input_stream(): New channel configuration, " + "main_channels = [%04x], aux_channels = [%04x], config.channels = %d", + in->main_channels, in->aux_channels, in->config.channels); + } + if (in->need_echo_reference && in->echo_reference == NULL) in->echo_reference = get_echo_reference(adev, AUDIO_FORMAT_PCM_16_BIT, @@ -1654,16 +1751,20 @@ static int start_input_stream(struct tuna_stream_in *in) /* this assumes routing is done previously */ in->pcm = pcm_open(0, PORT_MM2_UL, PCM_IN, &in->config); if (!pcm_is_ready(in->pcm)) { - LOGE("cannot open pcm_in driver: %s", pcm_get_error(in->pcm)); + ALOGE("cannot open pcm_in driver: %s", pcm_get_error(in->pcm)); pcm_close(in->pcm); adev->active_input = NULL; return -ENOMEM; } + /* force read and proc buf reallocation case of frame size or channel count change */ + in->read_buf_frames = 0; + in->read_buf_size = 0; + in->proc_buf_frames = 0; + in->proc_buf_size = 0; /* if no supported sample rate is available, use the resampler */ if (in->resampler) { in->resampler->reset(in->resampler); - in->frames_in = 0; } return 0; } @@ -1686,26 +1787,22 @@ static size_t in_get_buffer_size(const struct audio_stream *stream) return get_input_buffer_size(in->requested_rate, AUDIO_FORMAT_PCM_16_BIT, - in->config.channels); + popcount(in->main_channels)); } static uint32_t in_get_channels(const struct audio_stream *stream) { struct tuna_stream_in *in = (struct tuna_stream_in *)stream; - if (in->config.channels == 1) { - return AUDIO_CHANNEL_IN_MONO; - } else { - return AUDIO_CHANNEL_IN_STEREO; - } + return in->main_channels; } -static int in_get_format(const struct audio_stream *stream) +static audio_format_t in_get_format(const struct audio_stream *stream) { return AUDIO_FORMAT_PCM_16_BIT; } -static int in_set_format(struct audio_stream *stream, int format) +static int in_set_format(struct audio_stream *stream, audio_format_t format) { return 0; } @@ -1786,6 +1883,9 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) if ((in->device != val) && (val != 0)) { in->device = val; do_standby = true; + /* make sure new device selection is incompatible with multi-mic pre processing + * configuration */ + in_update_aux_channels(in, NULL); } } @@ -1826,15 +1926,19 @@ static void get_capture_delay(struct tuna_stream_in *in, buffer->time_stamp.tv_sec = 0; buffer->time_stamp.tv_nsec = 0; buffer->delay_ns = 0; - LOGW("read get_capture_delay(): pcm_htimestamp error"); + ALOGW("read get_capture_delay(): pcm_htimestamp error"); return; } /* read frames available in audio HAL input buffer * add number of frames being read as we want the capture time of first sample * in current buffer */ - buf_delay = (long)(((int64_t)(in->frames_in + in->proc_frames_in) * 1000000000) - / in->config.rate); + /* frames in in->buffer are at driver sampling rate while frames in in->proc_buf are + * at requested sampling rate */ + buf_delay = (long)(((int64_t)(in->read_buf_frames) * 1000000000) / in->config.rate + + ((int64_t)(in->proc_buf_frames) * 1000000000) / + in->requested_rate); + /* add delay introduced by resampler */ rsmp_delay = 0; if (in->resampler) { @@ -1847,12 +1951,12 @@ static void get_capture_delay(struct tuna_stream_in *in, buffer->time_stamp = tstamp; buffer->delay_ns = delay_ns; - LOGV("get_capture_delay time_stamp = [%ld].[%ld], delay_ns: [%d]," + ALOGV("get_capture_delay time_stamp = [%ld].[%ld], delay_ns: [%d]," " kernel_delay:[%ld], buf_delay:[%ld], rsmp_delay:[%ld], kernel_frames:[%d], " - "in->frames_in:[%d], in->proc_frames_in:[%d], frames:[%d]", + "in->read_buf_frames:[%d], in->proc_buf_frames:[%d], frames:[%d]", buffer->time_stamp.tv_sec , buffer->time_stamp.tv_nsec, buffer->delay_ns, kernel_delay, buf_delay, rsmp_delay, kernel_frames, - in->frames_in, in->proc_frames_in, frames); + in->read_buf_frames, in->proc_buf_frames, frames); } @@ -1861,31 +1965,32 @@ static int32_t update_echo_reference(struct tuna_stream_in *in, size_t frames) struct echo_reference_buffer b; b.delay_ns = 0; - LOGV("update_echo_reference, frames = [%d], in->ref_frames_in = [%d], " + ALOGV("update_echo_reference, frames = [%d], in->ref_buf_frames = [%d], " "b.frame_count = [%d]", - frames, in->ref_frames_in, frames - in->ref_frames_in); - if (in->ref_frames_in < frames) { + frames, in->ref_buf_frames, frames - in->ref_buf_frames); + if (in->ref_buf_frames < frames) { if (in->ref_buf_size < frames) { in->ref_buf_size = frames; - in->ref_buf = (int16_t *)realloc(in->ref_buf, - in->ref_buf_size * - in->config.channels * sizeof(int16_t)); + in->ref_buf = (int16_t *)realloc(in->ref_buf, pcm_frames_to_bytes(in->pcm, frames)); + ALOG_ASSERT((in->ref_buf != NULL), + "update_echo_reference() failed to reallocate ref_buf"); + ALOGV("update_echo_reference(): ref_buf %p extended to %d bytes", + in->ref_buf, pcm_frames_to_bytes(in->pcm, frames)); } - - b.frame_count = frames - in->ref_frames_in; - b.raw = (void *)(in->ref_buf + in->ref_frames_in * in->config.channels); + b.frame_count = frames - in->ref_buf_frames; + b.raw = (void *)(in->ref_buf + in->ref_buf_frames * in->config.channels); get_capture_delay(in, frames, &b); if (in->echo_reference->read(in->echo_reference, &b) == 0) { - in->ref_frames_in += b.frame_count; - LOGV("update_echo_reference: in->ref_frames_in:[%d], " + in->ref_buf_frames += b.frame_count; + ALOGV("update_echo_reference(): in->ref_buf_frames:[%d], " "in->ref_buf_size:[%d], frames:[%d], b.frame_count:[%d]", - in->ref_frames_in, in->ref_buf_size, frames, b.frame_count); + in->ref_buf_frames, in->ref_buf_size, frames, b.frame_count); } } else - LOGW("update_echo_reference: NOT enough frames to read ref buffer"); + ALOGW("update_echo_reference(): NOT enough frames to read ref buffer"); return b.delay_ns; } @@ -1925,32 +2030,32 @@ static int set_preprocessor_echo_delay(effect_handle_t handle, static void push_echo_reference(struct tuna_stream_in *in, size_t frames) { /* read frames from echo reference buffer and update echo delay - * in->ref_frames_in is updated with frames available in in->ref_buf */ + * in->ref_buf_frames is updated with frames available in in->ref_buf */ int32_t delay_us = update_echo_reference(in, frames)/1000; int i; audio_buffer_t buf; - if (in->ref_frames_in < frames) - frames = in->ref_frames_in; + if (in->ref_buf_frames < frames) + frames = in->ref_buf_frames; buf.frameCount = frames; buf.raw = in->ref_buf; for (i = 0; i < in->num_preprocessors; i++) { - if ((*in->preprocessors[i])->process_reverse == NULL) + if ((*in->preprocessors[i].effect_itfe)->process_reverse == NULL) continue; - (*in->preprocessors[i])->process_reverse(in->preprocessors[i], + (*in->preprocessors[i].effect_itfe)->process_reverse(in->preprocessors[i].effect_itfe, &buf, NULL); - set_preprocessor_echo_delay(in->preprocessors[i], delay_us); + set_preprocessor_echo_delay(in->preprocessors[i].effect_itfe, delay_us); } - in->ref_frames_in -= buf.frameCount; - if (in->ref_frames_in) { + in->ref_buf_frames -= buf.frameCount; + if (in->ref_buf_frames) { memcpy(in->ref_buf, in->ref_buf + buf.frameCount * in->config.channels, - in->ref_frames_in * in->config.channels * sizeof(int16_t)); + in->ref_buf_frames * in->config.channels * sizeof(int16_t)); } } @@ -1972,23 +2077,31 @@ static int get_next_buffer(struct resampler_buffer_provider *buffer_provider, return -ENODEV; } - if (in->frames_in == 0) { - in->read_status = pcm_read(in->pcm, - (void*)in->buffer, - in->config.period_size * - audio_stream_frame_size(&in->stream.common)); + if (in->read_buf_frames == 0) { + size_t size_in_bytes = pcm_frames_to_bytes(in->pcm, in->config.period_size); + if (in->read_buf_size < in->config.period_size) { + in->read_buf_size = in->config.period_size; + in->read_buf = (int16_t *) realloc(in->read_buf, size_in_bytes); + ALOG_ASSERT((in->read_buf != NULL), + "get_next_buffer() failed to reallocate read_buf"); + ALOGV("get_next_buffer(): read_buf %p extended to %d bytes", + in->read_buf, size_in_bytes); + } + + in->read_status = pcm_read(in->pcm, (void*)in->read_buf, size_in_bytes); + if (in->read_status != 0) { - LOGE("get_next_buffer() pcm_read error %d", in->read_status); + ALOGE("get_next_buffer() pcm_read error %d", in->read_status); buffer->raw = NULL; buffer->frame_count = 0; return in->read_status; } - in->frames_in = in->config.period_size; + in->read_buf_frames = in->config.period_size; } - buffer->frame_count = (buffer->frame_count > in->frames_in) ? - in->frames_in : buffer->frame_count; - buffer->i16 = in->buffer + (in->config.period_size - in->frames_in) * + buffer->frame_count = (buffer->frame_count > in->read_buf_frames) ? + in->read_buf_frames : buffer->frame_count; + buffer->i16 = in->read_buf + (in->config.period_size - in->read_buf_frames) * in->config.channels; return in->read_status; @@ -2006,7 +2119,7 @@ static void release_buffer(struct resampler_buffer_provider *buffer_provider, in = (struct tuna_stream_in *)((char *)buffer_provider - offsetof(struct tuna_stream_in, buf_provider)); - in->frames_in -= buffer->frame_count; + in->read_buf_frames -= buffer->frame_count; } /* read_frames() reads frames from kernel driver, down samples to capture rate @@ -2019,9 +2132,10 @@ static ssize_t read_frames(struct tuna_stream_in *in, void *buffer, ssize_t fram size_t frames_rd = frames - frames_wr; if (in->resampler != NULL) { in->resampler->resample_from_provider(in->resampler, - (int16_t *)((char *)buffer + - frames_wr * audio_stream_frame_size(&in->stream.common)), - &frames_rd); + (int16_t *)((char *)buffer + + pcm_frames_to_bytes(in->pcm ,frames_wr)), + &frames_rd); + } else { struct resampler_buffer buf = { { raw : NULL, }, @@ -2030,9 +2144,9 @@ static ssize_t read_frames(struct tuna_stream_in *in, void *buffer, ssize_t fram get_next_buffer(&in->buf_provider, &buf); if (buf.raw != NULL) { memcpy((char *)buffer + - frames_wr * audio_stream_frame_size(&in->stream.common), + pcm_frames_to_bytes(in->pcm, frames_wr), buf.raw, - buf.frame_count * audio_stream_frame_size(&in->stream.common)); + pcm_frames_to_bytes(in->pcm, buf.frame_count)); frames_rd = buf.frame_count; } release_buffer(&in->buf_provider, &buf); @@ -2056,66 +2170,127 @@ static ssize_t process_frames(struct tuna_stream_in *in, void* buffer, ssize_t f audio_buffer_t in_buf; audio_buffer_t out_buf; int i; + bool has_aux_channels = (~in->main_channels & in->aux_channels); + void *proc_buf_out; + + if (has_aux_channels) + proc_buf_out = in->proc_buf_out; + else + proc_buf_out = buffer; + /* since all the processing below is done in frames and using the config.channels + * as the number of channels, no changes is required in case aux_channels are present */ while (frames_wr < frames) { /* first reload enough frames at the end of process input buffer */ - if (in->proc_frames_in < (size_t)frames) { + if (in->proc_buf_frames < (size_t)frames) { ssize_t frames_rd; if (in->proc_buf_size < (size_t)frames) { + size_t size_in_bytes = pcm_frames_to_bytes(in->pcm, frames); + in->proc_buf_size = (size_t)frames; - in->proc_buf = (int16_t *)realloc(in->proc_buf, - in->proc_buf_size * - in->config.channels * sizeof(int16_t)); - LOGV("process_frames(): in->proc_buf %p size extended to %d frames", - in->proc_buf, in->proc_buf_size); + in->proc_buf_in = (int16_t *)realloc(in->proc_buf_in, size_in_bytes); + ALOG_ASSERT((in->proc_buf_in != NULL), + "process_frames() failed to reallocate proc_buf_in"); + if (has_aux_channels) { + in->proc_buf_out = (int16_t *)realloc(in->proc_buf_out, size_in_bytes); + ALOG_ASSERT((in->proc_buf_out != NULL), + "process_frames() failed to reallocate proc_buf_out"); + proc_buf_out = in->proc_buf_out; + } + ALOGV("process_frames(): proc_buf_in %p extended to %d bytes", + in->proc_buf_in, size_in_bytes); } frames_rd = read_frames(in, - in->proc_buf + - in->proc_frames_in * in->config.channels, - frames - in->proc_frames_in); + in->proc_buf_in + + in->proc_buf_frames * in->config.channels, + frames - in->proc_buf_frames); if (frames_rd < 0) { frames_wr = frames_rd; break; } - in->proc_frames_in += frames_rd; + in->proc_buf_frames += frames_rd; } if (in->echo_reference != NULL) - push_echo_reference(in, in->proc_frames_in); + push_echo_reference(in, in->proc_buf_frames); /* in_buf.frameCount and out_buf.frameCount indicate respectively * the maximum number of frames to be consumed and produced by process() */ - in_buf.frameCount = in->proc_frames_in; - in_buf.s16 = in->proc_buf; + in_buf.frameCount = in->proc_buf_frames; + in_buf.s16 = in->proc_buf_in; out_buf.frameCount = frames - frames_wr; - out_buf.s16 = (int16_t *)buffer + frames_wr * in->config.channels; - - for (i = 0; i < in->num_preprocessors; i++) - (*in->preprocessors[i])->process(in->preprocessors[i], + out_buf.s16 = (int16_t *)proc_buf_out + frames_wr * in->config.channels; + + /* FIXME: this works because of current pre processing library implementation that + * does the actual process only when the last enabled effect process is called. + * The generic solution is to have an output buffer for each effect and pass it as + * input to the next. + */ + for (i = 0; i < in->num_preprocessors; i++) { + (*in->preprocessors[i].effect_itfe)->process(in->preprocessors[i].effect_itfe, &in_buf, &out_buf); + } /* process() has updated the number of frames consumed and produced in * in_buf.frameCount and out_buf.frameCount respectively - * move remaining frames to the beginning of in->proc_buf */ - in->proc_frames_in -= in_buf.frameCount; - if (in->proc_frames_in) { - memcpy(in->proc_buf, - in->proc_buf + in_buf.frameCount * in->config.channels, - in->proc_frames_in * in->config.channels * sizeof(int16_t)); + * move remaining frames to the beginning of in->proc_buf_in */ + in->proc_buf_frames -= in_buf.frameCount; + + if (in->proc_buf_frames) { + memcpy(in->proc_buf_in, + in->proc_buf_in + in_buf.frameCount * in->config.channels, + in->proc_buf_frames * in->config.channels * sizeof(int16_t)); } /* if not enough frames were passed to process(), read more and retry. */ - if (out_buf.frameCount == 0) + if (out_buf.frameCount == 0) { + ALOGW("No frames produced by preproc"); continue; + } - frames_wr += out_buf.frameCount; + if ((frames_wr + (ssize_t)out_buf.frameCount) <= frames) { + frames_wr += out_buf.frameCount; + } else { + /* The effect does not comply to the API. In theory, we should never end up here! */ + ALOGE("preprocessing produced too many frames: %d + %d > %d !", + (unsigned int)frames_wr, out_buf.frameCount, (unsigned int)frames); + frames_wr = frames; + } } + + /* Remove aux_channels that have been added on top of main_channels + * Assumption is made that the channels are interleaved and that the main + * channels are first. */ + if (has_aux_channels) + { + size_t src_channels = in->config.channels; + size_t dst_channels = popcount(in->main_channels); + int16_t* src_buffer = (int16_t *)proc_buf_out; + int16_t* dst_buffer = (int16_t *)buffer; + + if (dst_channels == 1) { + for (i = frames_wr; i > 0; i--) + { + *dst_buffer++ = *src_buffer; + src_buffer += src_channels; + } + } else { + for (i = frames_wr; i > 0; i--) + { + memcpy(dst_buffer, src_buffer, dst_channels*sizeof(int16_t)); + dst_buffer += dst_channels; + src_buffer += src_channels; + } + } + } + return frames_wr; } static ssize_t in_read(struct audio_stream_in *stream, void* buffer, + size_t bytes) { int ret = 0; @@ -2166,6 +2341,284 @@ static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) return 0; } +#define GET_COMMAND_STATUS(status, fct_status, cmd_status) \ + do { \ + if (fct_status != 0) \ + status = fct_status; \ + else if (cmd_status != 0) \ + status = cmd_status; \ + } while(0) + +static int in_configure_reverse(struct tuna_stream_in *in) +{ + int32_t cmd_status; + uint32_t size = sizeof(int); + effect_config_t config; + int32_t status = 0; + int32_t fct_status = 0; + int i; + + if (in->num_preprocessors > 0) { + config.inputCfg.channels = in->main_channels; + config.outputCfg.channels = in->main_channels; + config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + config.inputCfg.samplingRate = in->requested_rate; + config.outputCfg.samplingRate = in->requested_rate; + config.inputCfg.mask = + ( EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT ); + config.outputCfg.mask = + ( EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT ); + + for (i = 0; i < in->num_preprocessors; i++) + { + if ((*in->preprocessors[i].effect_itfe)->process_reverse == NULL) + continue; + fct_status = (*(in->preprocessors[i].effect_itfe))->command( + in->preprocessors[i].effect_itfe, + EFFECT_CMD_SET_CONFIG_REVERSE, + sizeof(effect_config_t), + &config, + &size, + &cmd_status); + GET_COMMAND_STATUS(status, fct_status, cmd_status); + } + } + return status; +} + +#define MAX_NUM_CHANNEL_CONFIGS 10 + +static void in_read_audio_effect_channel_configs(struct tuna_stream_in *in, + struct effect_info_s *effect_info) +{ + /* size and format of the cmd are defined in hardware/audio_effect.h */ + effect_handle_t effect = effect_info->effect_itfe; + uint32_t cmd_size = 2 * sizeof(uint32_t); + uint32_t cmd[] = { EFFECT_FEATURE_AUX_CHANNELS, MAX_NUM_CHANNEL_CONFIGS }; + /* reply = status + number of configs (n) + n x channel_config_t */ + uint32_t reply_size = + 2 * sizeof(uint32_t) + (MAX_NUM_CHANNEL_CONFIGS * sizeof(channel_config_t)); + int32_t reply[reply_size]; + int32_t cmd_status; + + ALOG_ASSERT((effect_info->num_channel_configs == 0), + "in_read_audio_effect_channel_configs() num_channel_configs not cleared"); + ALOG_ASSERT((effect_info->channel_configs == NULL), + "in_read_audio_effect_channel_configs() channel_configs not cleared"); + + /* if this command is not supported, then the effect is supposed to return -EINVAL. + * This error will be interpreted as if the effect supports the main_channels but does not + * support any aux_channels */ + cmd_status = (*effect)->command(effect, + EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, + cmd_size, + (void*)&cmd, + &reply_size, + (void*)&reply); + + if (cmd_status != 0) { + ALOGV("in_read_audio_effect_channel_configs(): " + "fx->command returned %d", cmd_status); + return; + } + + if (reply[0] != 0) { + ALOGW("in_read_audio_effect_channel_configs(): " + "command EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS error %d num configs %d", + reply[0], (reply[0] == -ENOMEM) ? reply[1] : MAX_NUM_CHANNEL_CONFIGS); + return; + } + + /* the feature is not supported */ + ALOGV("in_read_audio_effect_channel_configs()(): " + "Feature supported and adding %d channel configs to the list", reply[1]); + effect_info->num_channel_configs = reply[1]; + effect_info->channel_configs = + (channel_config_t *) malloc(sizeof(channel_config_t) * reply[1]); /* n x configs */ + memcpy(effect_info->channel_configs, (reply + 2), sizeof(channel_config_t) * reply[1]); +} + + +static uint32_t in_get_aux_channels(struct tuna_stream_in *in) +{ + int i; + channel_config_t new_chcfg = {0, 0}; + + if (in->num_preprocessors == 0) + return 0; + + /* do not enable dual mic configurations when capturing from other microphones than + * main or sub */ + if (!(in->device & (AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_BACK_MIC))) + return 0; + + /* retain most complex aux channels configuration compatible with requested main channels and + * supported by audio driver and all pre processors */ + for (i = 0; i < NUM_IN_AUX_CNL_CONFIGS; i++) { + channel_config_t *cur_chcfg = &in_aux_cnl_configs[i]; + if (cur_chcfg->main_channels == in->main_channels) { + size_t match_cnt; + size_t idx_preproc; + for (idx_preproc = 0, match_cnt = 0; + /* no need to continue if at least one preprocessor doesn't match */ + idx_preproc < (size_t)in->num_preprocessors && match_cnt == idx_preproc; + idx_preproc++) { + struct effect_info_s *effect_info = &in->preprocessors[idx_preproc]; + size_t idx_chcfg; + + for (idx_chcfg = 0; idx_chcfg < effect_info->num_channel_configs; idx_chcfg++) { + if (memcmp(effect_info->channel_configs + idx_chcfg, + cur_chcfg, + sizeof(channel_config_t)) == 0) { + match_cnt++; + break; + } + } + } + /* if all preprocessors match, we have a candidate */ + if (match_cnt == (size_t)in->num_preprocessors) { + /* retain most complex aux channels configuration */ + if (popcount(cur_chcfg->aux_channels) > popcount(new_chcfg.aux_channels)) { + new_chcfg = *cur_chcfg; + } + } + } + } + + ALOGV("in_get_aux_channels(): return %04x", new_chcfg.aux_channels); + + return new_chcfg.aux_channels; +} + +static int in_configure_effect_channels(effect_handle_t effect, + channel_config_t *channel_config) +{ + int status = 0; + int fct_status; + int32_t cmd_status; + uint32_t reply_size; + effect_config_t config; + uint32_t cmd[(sizeof(uint32_t) + sizeof(channel_config_t) - 1) / sizeof(uint32_t) + 1]; + + ALOGV("in_configure_effect_channels(): configure effect with channels: [%04x][%04x]", + channel_config->main_channels, + channel_config->aux_channels); + + config.inputCfg.mask = EFFECT_CONFIG_CHANNELS; + config.outputCfg.mask = EFFECT_CONFIG_CHANNELS; + reply_size = sizeof(effect_config_t); + fct_status = (*effect)->command(effect, + EFFECT_CMD_GET_CONFIG, + 0, + NULL, + &reply_size, + &config); + if (fct_status != 0) { + ALOGE("in_configure_effect_channels(): EFFECT_CMD_GET_CONFIG failed"); + return fct_status; + } + + config.inputCfg.channels = channel_config->main_channels | channel_config->aux_channels; + config.outputCfg.channels = config.inputCfg.channels; + reply_size = sizeof(uint32_t); + fct_status = (*effect)->command(effect, + EFFECT_CMD_SET_CONFIG, + sizeof(effect_config_t), + &config, + &reply_size, + &cmd_status); + GET_COMMAND_STATUS(status, fct_status, cmd_status); + + cmd[0] = EFFECT_FEATURE_AUX_CHANNELS; + memcpy(cmd + 1, channel_config, sizeof(channel_config_t)); + reply_size = sizeof(uint32_t); + fct_status = (*effect)->command(effect, + EFFECT_CMD_SET_FEATURE_CONFIG, + sizeof(cmd), //sizeof(uint32_t) + sizeof(channel_config_t), + cmd, + &reply_size, + &cmd_status); + GET_COMMAND_STATUS(status, fct_status, cmd_status); + + /* some implementations need to be re-enabled after a config change */ + reply_size = sizeof(uint32_t); + fct_status = (*effect)->command(effect, + EFFECT_CMD_ENABLE, + 0, + NULL, + &reply_size, + &cmd_status); + GET_COMMAND_STATUS(status, fct_status, cmd_status); + + return status; +} + +static int in_reconfigure_channels(struct tuna_stream_in *in, + effect_handle_t effect, + channel_config_t *channel_config, + bool config_changed) { + + int status = 0; + + ALOGV("in_reconfigure_channels(): config_changed %d effect %p", + config_changed, effect); + + /* if config changed, reconfigure all previously added effects */ + if (config_changed) { + int i; + for (i = 0; i < in->num_preprocessors; i++) + { + int cur_status = in_configure_effect_channels(in->preprocessors[i].effect_itfe, + channel_config); + if (cur_status != 0) { + ALOGV("in_reconfigure_channels(): error %d configuring effect " + "%d with channels: [%04x][%04x]", + cur_status, + i, + channel_config->main_channels, + channel_config->aux_channels); + status = cur_status; + } + } + } else if (effect != NULL && channel_config->aux_channels) { + /* if aux channels config did not change but aux channels are present, + * we still need to configure the effect being added */ + status = in_configure_effect_channels(effect, channel_config); + } + return status; +} + +static void in_update_aux_channels(struct tuna_stream_in *in, + effect_handle_t effect) +{ + uint32_t aux_channels; + channel_config_t channel_config; + int status; + + aux_channels = in_get_aux_channels(in); + + channel_config.main_channels = in->main_channels; + channel_config.aux_channels = aux_channels; + status = in_reconfigure_channels(in, + effect, + &channel_config, + (aux_channels != in->aux_channels)); + + if (status != 0) { + ALOGV("in_update_aux_channels(): in_reconfigure_channels error %d", status); + /* resetting aux channels configuration */ + aux_channels = 0; + channel_config.aux_channels = 0; + in_reconfigure_channels(in, effect, &channel_config, true); + } + if (in->aux_channels != aux_channels) { + in->aux_channels_changed = true; + in->aux_channels = aux_channels; + do_input_standby(in); + } +} + static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { @@ -2184,15 +2637,26 @@ static int in_add_audio_effect(const struct audio_stream *stream, if (status != 0) goto exit; - in->preprocessors[in->num_preprocessors++] = effect; + in->preprocessors[in->num_preprocessors].effect_itfe = effect; + /* add the supported channel of the effect in the channel_configs */ + in_read_audio_effect_channel_configs(in, &in->preprocessors[in->num_preprocessors]); + + in->num_preprocessors++; + + /* check compatibility between main channel supported and possible auxiliary channels */ + in_update_aux_channels(in, effect); + + ALOGV("in_add_audio_effect(), effect type: %08x", desc.type.timeLow); if (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) { in->need_echo_reference = true; do_input_standby(in); + in_configure_reverse(in); } exit: + ALOGW_IF(status != 0, "in_add_audio_effect() error %d", status); pthread_mutex_unlock(&in->lock); pthread_mutex_unlock(&in->dev->lock); return status; @@ -2204,7 +2668,6 @@ static int in_remove_audio_effect(const struct audio_stream *stream, struct tuna_stream_in *in = (struct tuna_stream_in *)stream; int i; int status = -EINVAL; - bool found = false; effect_descriptor_t desc; pthread_mutex_lock(&in->dev->lock); @@ -2215,14 +2678,17 @@ static int in_remove_audio_effect(const struct audio_stream *stream, } for (i = 0; i < in->num_preprocessors; i++) { - if (found) { - in->preprocessors[i - 1] = in->preprocessors[i]; + if (status == 0) { /* status == 0 means an effect was removed from a previous slot */ + in->preprocessors[i - 1].effect_itfe = in->preprocessors[i].effect_itfe; + in->preprocessors[i - 1].channel_configs = in->preprocessors[i].channel_configs; + in->preprocessors[i - 1].num_channel_configs = in->preprocessors[i].num_channel_configs; + ALOGV("in_remove_audio_effect moving fx from %d to %d", i, i - 1); continue; } - if (in->preprocessors[i] == effect) { - in->preprocessors[i] = NULL; + if (in->preprocessors[i].effect_itfe == effect) { + ALOGV("in_remove_audio_effect found fx at index %d", i); + free(in->preprocessors[i].channel_configs); status = 0; - found = true; } } @@ -2230,10 +2696,21 @@ static int in_remove_audio_effect(const struct audio_stream *stream, goto exit; in->num_preprocessors--; + /* if we remove one effect, at least the last preproc should be reset */ + in->preprocessors[in->num_preprocessors].num_channel_configs = 0; + in->preprocessors[in->num_preprocessors].effect_itfe = NULL; + in->preprocessors[in->num_preprocessors].channel_configs = NULL; + + + /* check compatibility between main channel supported and possible auxiliary channels */ + in_update_aux_channels(in, NULL); status = (*effect)->get_descriptor(effect, &desc); if (status != 0) goto exit; + + ALOGV("in_remove_audio_effect(), effect type: %08x", desc.type.timeLow); + if (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) { in->need_echo_reference = false; do_input_standby(in); @@ -2241,6 +2718,7 @@ static int in_remove_audio_effect(const struct audio_stream *stream, exit: + ALOGW_IF(status != 0, "in_remove_audio_effect() error %d", status); pthread_mutex_unlock(&in->lock); pthread_mutex_unlock(&in->dev->lock); return status; @@ -2248,14 +2726,18 @@ exit: static int adev_open_output_stream(struct audio_hw_device *dev, - uint32_t devices, int *format, - uint32_t *channels, uint32_t *sample_rate, + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config, struct audio_stream_out **stream_out) { struct tuna_audio_device *ladev = (struct tuna_audio_device *)dev; struct tuna_stream_out *out; int ret; + *stream_out = NULL; + out = (struct tuna_stream_out *)calloc(1, sizeof(struct tuna_stream_out)); if (!out) return -ENOMEM; @@ -2298,16 +2780,15 @@ static int adev_open_output_stream(struct audio_hw_device *dev, * This is because out_set_parameters() with a route is not * guaranteed to be called after an output stream is opened. */ - *format = out_get_format(&out->stream.common); - *channels = out_get_channels(&out->stream.common); - *sample_rate = out_get_sample_rate(&out->stream.common); + config->format = out_get_format(&out->stream.common); + config->channel_mask = out_get_channels(&out->stream.common); + config->sample_rate = out_get_sample_rate(&out->stream.common); *stream_out = &out->stream; return 0; err_open: free(out); - *stream_out = NULL; return ret; } @@ -2405,7 +2886,7 @@ static int adev_set_master_volume(struct audio_hw_device *dev, float volume) return -ENOSYS; } -static int adev_set_mode(struct audio_hw_device *dev, int mode) +static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) { struct tuna_audio_device *adev = (struct tuna_audio_device *)dev; @@ -2438,29 +2919,30 @@ static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) } static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, - uint32_t sample_rate, int format, - int channel_count) + const struct audio_config *config) { size_t size; - - if (check_input_parameters(sample_rate, format, channel_count) != 0) + int channel_count = popcount(config->channel_mask); + if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0) return 0; - return get_input_buffer_size(sample_rate, format, channel_count); + return get_input_buffer_size(config->sample_rate, config->format, channel_count); } -static int adev_open_input_stream(struct audio_hw_device *dev, uint32_t devices, - int *format, uint32_t *channel_mask, - uint32_t *sample_rate, - audio_in_acoustics_t acoustics, +static int adev_open_input_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config, struct audio_stream_in **stream_in) { struct tuna_audio_device *ladev = (struct tuna_audio_device *)dev; struct tuna_stream_in *in; int ret; - int channel_count = popcount(*channel_mask); + int channel_count = popcount(config->channel_mask); + + *stream_in = NULL; - if (check_input_parameters(*sample_rate, *format, channel_count) != 0) + if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0) return -EINVAL; in = (struct tuna_stream_in *)calloc(1, sizeof(struct tuna_stream_in)); @@ -2483,17 +2965,15 @@ static int adev_open_input_stream(struct audio_hw_device *dev, uint32_t devices, in->stream.read = in_read; in->stream.get_input_frames_lost = in_get_input_frames_lost; - in->requested_rate = *sample_rate; + in->requested_rate = config->sample_rate; memcpy(&in->config, &pcm_config_mm_ul, sizeof(pcm_config_mm_ul)); in->config.channels = channel_count; - in->buffer = malloc(in->config.period_size * - audio_stream_frame_size(&in->stream.common)); - if (!in->buffer) { - ret = -ENOMEM; - goto err; - } + in->main_channels = config->channel_mask; + + /* initialisation of preprocessor structure array is implicit with the calloc. + * same for in->aux_channels and in->aux_channels_changed */ if (in->requested_rate != in->config.rate) { in->buf_provider.get_next_buffer = get_next_buffer; @@ -2523,7 +3003,6 @@ err: release_resampler(in->resampler); free(in); - *stream_in = NULL; return ret; } @@ -2531,15 +3010,22 @@ static void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream) { struct tuna_stream_in *in = (struct tuna_stream_in *)stream; + int i; in_standby(&stream->common); + for (i = 0; i < in->num_preprocessors; i++) { + free(in->preprocessors[i].channel_configs); + } + + free(in->read_buf); if (in->resampler) { - free(in->buffer); release_resampler(in->resampler); } - if (in->proc_buf) - free(in->proc_buf); + if (in->proc_buf_in) + free(in->proc_buf_in); + if (in->proc_buf_out) + free(in->proc_buf_out); if (in->ref_buf) free(in->ref_buf); @@ -2601,7 +3087,7 @@ static int adev_open(const hw_module_t* module, const char* name, return -ENOMEM; adev->hw_device.common.tag = HARDWARE_DEVICE_TAG; - adev->hw_device.common.version = 0; + adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_1_0; adev->hw_device.common.module = (struct hw_module_t *) module; adev->hw_device.common.close = adev_close; @@ -2624,7 +3110,7 @@ static int adev_open(const hw_module_t* module, const char* name, adev->mixer = mixer_open(0); if (!adev->mixer) { free(adev); - LOGE("Unable to open the mixer, aborting."); + ALOGE("Unable to open the mixer, aborting."); return -EINVAL; } @@ -2679,7 +3165,7 @@ static int adev_open(const hw_module_t* module, const char* name, !adev->mixer_ctls.earpiece_volume) { mixer_close(adev->mixer); free(adev); - LOGE("Unable to locate all mixer controls, aborting."); + ALOGE("Unable to locate all mixer controls, aborting."); return -EINVAL; } @@ -2716,8 +3202,8 @@ static struct hw_module_methods_t hal_module_methods = { struct audio_module HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, - .version_major = 1, - .version_minor = 0, + .module_api_version = AUDIO_MODULE_API_VERSION_0_1, + .hal_api_version = HARDWARE_HAL_API_VERSION, .id = AUDIO_HARDWARE_MODULE_ID, .name = "Tuna audio HW HAL", .author = "The Android Open Source Project", diff --git a/audio/audio_policy.conf b/audio/audio_policy.conf new file mode 100644 index 0000000..ca95b0b --- /dev/null +++ b/audio/audio_policy.conf @@ -0,0 +1,52 @@ +# Global configuration section: lists input and output devices always present on the device +# as well as the output device selected by default. +# Devices are designated by a string that corresponds to the enum in audio.h + +global_configuration { + attached_output_devices AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_SPEAKER + default_output_device AUDIO_DEVICE_OUT_SPEAKER + attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_BACK_MIC +} + +# audio hardware module section: contains descriptors for all audio hw modules present on the +# device. Each hw module node is named after the corresponding hw module library base name. +# For instance, "primary" corresponds to audio.primary.<device>.so. +# The "primary" module is mandatory and must include at least one output with +# AUDIO_OUTPUT_FLAG_PRIMARY flag. +# Each module descriptor contains one or more output profile descriptors and zero or more +# input profile descriptors. Each profile lists all the parameters supported by a given output +# or input stream category. +# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding +# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n". + +audio_hw_modules { + primary { + outputs { + primary { + sampling_rates 44100 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO|AUDIO_DEVICE_OUT_AUX_DIGITAL|AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET + flags AUDIO_OUTPUT_FLAG_PRIMARY + } + } + inputs { + primary { + sampling_rates 8000|11025|16000|22050|32000|44100|48000 + channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET|AUDIO_DEVICE_IN_WIRED_HEADSET|AUDIO_DEVICE_IN_BACK_MIC + } + } + } + a2dp { + outputs { + a2dp { + sampling_rates 44100 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_ALL_A2DP + } + } + } +} diff --git a/audio/ril_interface.c b/audio/ril_interface.c index 4e1e2a1..3d7ce06 100755..100644 --- a/audio/ril_interface.c +++ b/audio/ril_interface.c @@ -36,7 +36,6 @@ int (*_ril_is_connected)(void *); int (*_ril_disconnect)(void *); int (*_ril_set_call_volume)(void *, enum ril_sound_type, int); int (*_ril_set_call_audio_path)(void *, enum ril_audio_path); -int (*_ril_set_call_clock_sync)(void *, enum ril_clock_state); int (*_ril_register_unsolicited_handler)(void *, int, void *); int (*_ril_get_wb_amr)(void *, void *); @@ -72,7 +71,7 @@ static int ril_connect_if_required(struct ril_handle *ril) return 0; if (_ril_connect(ril->client) != RIL_CLIENT_ERR_SUCCESS) { - LOGE("ril_connect() failed"); + ALOGE("ril_connect() failed"); return -1; } @@ -94,7 +93,7 @@ int ril_open(struct ril_handle *ril) ril->handle = dlopen(RIL_CLIENT_LIBPATH, RTLD_NOW); if (!ril->handle) { - LOGE("Cannot open '%s'", RIL_CLIENT_LIBPATH); + ALOGE("Cannot open '%s'", RIL_CLIENT_LIBPATH); return -1; } @@ -105,7 +104,6 @@ int ril_open(struct ril_handle *ril) _ril_disconnect = dlsym(ril->handle, "Disconnect_RILD"); _ril_set_call_volume = dlsym(ril->handle, "SetCallVolume"); _ril_set_call_audio_path = dlsym(ril->handle, "SetCallAudioPath"); - _ril_set_call_clock_sync = dlsym(ril->handle, "SetCallClockSync"); _ril_register_unsolicited_handler = dlsym(ril->handle, "RegisterUnsolicitedHandler"); /* since this function is not supported in all RILs, don't require it */ @@ -113,16 +111,15 @@ int ril_open(struct ril_handle *ril) if (!_ril_open_client || !_ril_close_client || !_ril_connect || !_ril_is_connected || !_ril_disconnect || !_ril_set_call_volume || - !_ril_set_call_audio_path || !_ril_set_call_clock_sync || - !_ril_register_unsolicited_handler) { - LOGE("Cannot get symbols from '%s'", RIL_CLIENT_LIBPATH); + !_ril_set_call_audio_path || !_ril_register_unsolicited_handler) { + ALOGE("Cannot get symbols from '%s'", RIL_CLIENT_LIBPATH); dlclose(ril->handle); return -1; } ril->client = _ril_open_client(); if (!ril->client) { - LOGE("ril_open_client() failed"); + ALOGE("ril_open_client() failed"); dlclose(ril->handle); return -1; } @@ -148,7 +145,7 @@ int ril_close(struct ril_handle *ril) if ((_ril_disconnect(ril->client) != RIL_CLIENT_ERR_SUCCESS) || (_ril_close_client(ril->client) != RIL_CLIENT_ERR_SUCCESS)) { - LOGE("ril_disconnect() or ril_close_client() failed"); + ALOGE("ril_disconnect() or ril_close_client() failed"); return -1; } @@ -173,11 +170,3 @@ int ril_set_call_audio_path(struct ril_handle *ril, enum ril_audio_path path) return _ril_set_call_audio_path(ril->client, path); } - -int ril_set_call_clock_sync(struct ril_handle *ril, enum ril_clock_state state) -{ - if (ril_connect_if_required(ril)) - return 0; - - return _ril_set_call_clock_sync(ril->client, state); -} diff --git a/audio/ril_interface.h b/audio/ril_interface.h index 676772c..2ea83f8 100755..100644 --- a/audio/ril_interface.h +++ b/audio/ril_interface.h @@ -66,7 +66,6 @@ int ril_close(struct ril_handle *ril); int ril_set_call_volume(struct ril_handle *ril, enum ril_sound_type sound_type, float volume); int ril_set_call_audio_path(struct ril_handle *ril, enum ril_audio_path path); -int ril_set_call_clock_sync(struct ril_handle *ril, enum ril_clock_state state); void ril_register_set_wb_amr_callback(void *function, void *data); #endif diff --git a/board-info.txt b/board-info.txt index e906c5e..9d45087 100644 --- a/board-info.txt +++ b/board-info.txt @@ -1,3 +1,3 @@ require board=tuna -require version-bootloader=PRIMELA03 +require version-bootloader=PRIMELC03 @@ -47,19 +47,30 @@ PRODUCT_PACKAGES += \ nfc.tuna PRODUCT_PACKAGES += \ + power.tuna + +# Audio +PRODUCT_PACKAGES += \ audio.primary.tuna \ - audio.a2dp.default \ - libaudioutils + audio.a2dp.default + +PRODUCT_COPY_FILES += \ + device/samsung/tuna/audio/audio_policy.conf:system/etc/audio_policy.conf + PRODUCT_PACKAGES += \ tuna_hdcp_keys -PRODUCT_COPY_FILES := \ +#PRODUCT_PACKAGES += \ +# keystore.tuna + +PRODUCT_COPY_FILES += \ $(LOCAL_KERNEL):kernel \ device/samsung/tuna/init.tuna.rc:root/init.tuna.rc \ device/samsung/tuna/init.tuna.usb.rc:root/init.tuna.usb.rc \ device/samsung/tuna/ueventd.tuna.rc:root/ueventd.tuna.rc \ device/samsung/tuna/media_profiles.xml:system/etc/media_profiles.xml \ + device/samsung/tuna/media_codecs.xml:system/etc/media_codecs.xml \ device/samsung/tuna/gps.conf:system/etc/gps.conf # Bluetooth configuration files @@ -75,8 +86,7 @@ PRODUCT_COPY_FILES += \ device/samsung/tuna/bcmdhd.cal:system/etc/wifi/bcmdhd.cal PRODUCT_PROPERTY_OVERRIDES := \ - wifi.interface=wlan0 \ - wifi.supplicant_scan_interval=15 + wifi.interface=wlan0 # Set default USB interface PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \ @@ -101,7 +111,9 @@ PRODUCT_COPY_FILES += \ device/samsung/tuna/tuna-gpio-keypad.kl:system/usr/keylayout/tuna-gpio-keypad.kl \ device/samsung/tuna/tuna-gpio-keypad.kcm:system/usr/keychars/tuna-gpio-keypad.kcm \ device/samsung/tuna/sec_jack.kl:system/usr/keylayout/sec_jack.kl \ - device/samsung/tuna/sec_jack.kcm:system/usr/keychars/sec_jack.kcm + device/samsung/tuna/sec_jack.kcm:system/usr/keychars/sec_jack.kcm \ + device/samsung/tuna/sii9234_rcp.kl:system/usr/keylayout/sii9234_rcp.kl \ + device/samsung/tuna/sii9234_rcp.kcm:system/usr/keychars/sii9234_rcp.kcm # Input device calibration files PRODUCT_COPY_FILES += \ @@ -109,21 +121,21 @@ PRODUCT_COPY_FILES += \ # These are the hardware-specific features PRODUCT_COPY_FILES += \ - frameworks/base/data/etc/handheld_core_hardware.xml:system/etc/permissions/handheld_core_hardware.xml \ - frameworks/base/data/etc/android.hardware.camera.flash-autofocus.xml:system/etc/permissions/android.hardware.camera.flash-autofocus.xml \ - frameworks/base/data/etc/android.hardware.camera.front.xml:system/etc/permissions/android.hardware.camera.front.xml \ - frameworks/base/data/etc/android.hardware.location.gps.xml:system/etc/permissions/android.hardware.location.gps.xml \ - frameworks/base/data/etc/android.hardware.wifi.xml:system/etc/permissions/android.hardware.wifi.xml \ - frameworks/base/data/etc/android.hardware.wifi.direct.xml:system/etc/permissions/android.hardware.wifi.direct.xml \ - frameworks/base/data/etc/android.hardware.sensor.proximity.xml:system/etc/permissions/android.hardware.sensor.proximity.xml \ - frameworks/base/data/etc/android.hardware.sensor.light.xml:system/etc/permissions/android.hardware.sensor.light.xml \ - frameworks/base/data/etc/android.hardware.sensor.gyroscope.xml:system/etc/permissions/android.hardware.sensor.gyroscope.xml \ - frameworks/base/data/etc/android.hardware.sensor.barometer.xml:system/etc/permissions/android.hardware.sensor.barometer.xml \ - frameworks/base/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml:system/etc/permissions/android.hardware.touchscreen.multitouch.jazzhand.xml \ - frameworks/base/data/etc/android.hardware.nfc.xml:system/etc/permissions/android.hardware.nfc.xml \ - frameworks/base/data/etc/android.software.sip.voip.xml:system/etc/permissions/android.software.sip.voip.xml \ - frameworks/base/data/etc/android.hardware.usb.accessory.xml:system/etc/permissions/android.hardware.usb.accessory.xml \ - frameworks/base/data/etc/android.hardware.usb.host.xml:system/etc/permissions/android.hardware.usb.host.xml \ + frameworks/native/data/etc/handheld_core_hardware.xml:system/etc/permissions/handheld_core_hardware.xml \ + frameworks/native/data/etc/android.hardware.camera.flash-autofocus.xml:system/etc/permissions/android.hardware.camera.flash-autofocus.xml \ + frameworks/native/data/etc/android.hardware.camera.front.xml:system/etc/permissions/android.hardware.camera.front.xml \ + frameworks/native/data/etc/android.hardware.location.gps.xml:system/etc/permissions/android.hardware.location.gps.xml \ + frameworks/native/data/etc/android.hardware.wifi.xml:system/etc/permissions/android.hardware.wifi.xml \ + frameworks/native/data/etc/android.hardware.wifi.direct.xml:system/etc/permissions/android.hardware.wifi.direct.xml \ + frameworks/native/data/etc/android.hardware.sensor.proximity.xml:system/etc/permissions/android.hardware.sensor.proximity.xml \ + frameworks/native/data/etc/android.hardware.sensor.light.xml:system/etc/permissions/android.hardware.sensor.light.xml \ + frameworks/native/data/etc/android.hardware.sensor.gyroscope.xml:system/etc/permissions/android.hardware.sensor.gyroscope.xml \ + frameworks/native/data/etc/android.hardware.sensor.barometer.xml:system/etc/permissions/android.hardware.sensor.barometer.xml \ + frameworks/native/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml:system/etc/permissions/android.hardware.touchscreen.multitouch.jazzhand.xml \ + frameworks/native/data/etc/android.hardware.nfc.xml:system/etc/permissions/android.hardware.nfc.xml \ + frameworks/native/data/etc/android.software.sip.voip.xml:system/etc/permissions/android.software.sip.voip.xml \ + frameworks/native/data/etc/android.hardware.usb.accessory.xml:system/etc/permissions/android.hardware.usb.accessory.xml \ + frameworks/native/data/etc/android.hardware.usb.host.xml:system/etc/permissions/android.hardware.usb.host.xml \ packages/wallpapers/LivePicker/android.software.live_wallpaper.xml:system/etc/permissions/android.software.live_wallpaper.xml # HACK: copy panda init for now to boot on both boards @@ -145,13 +157,13 @@ PRODUCT_COPY_FILES += \ # file that declares the MIFARE NFC constant PRODUCT_COPY_FILES += \ - device/sample/nxp/com.nxp.mifare.xml:system/etc/permissions/com.nxp.mifare.xml + frameworks/native/data/etc/com.nxp.mifare.xml:system/etc/permissions/com.nxp.mifare.xml # NFC EXTRAS add-on API PRODUCT_PACKAGES += \ com.android.nfc_extras PRODUCT_COPY_FILES += \ - frameworks/base/nfc-extras/com.android.nfc_extras.xml:system/etc/permissions/com.android.nfc_extras.xml + frameworks/native/data/etc/com.android.nfc_extras.xml:system/etc/permissions/com.android.nfc_extras.xml # NFCEE access control ifeq ($(TARGET_BUILD_VARIANT),user) @@ -187,7 +199,7 @@ PRODUCT_COPY_FILES += \ system/extras/bugmailer/bugmailer.sh:system/bin/bugmailer.sh \ system/extras/bugmailer/send_bug:system/bin/send_bug -$(call inherit-product, frameworks/base/build/phone-xhdpi-1024-dalvik-heap.mk) +$(call inherit-product, frameworks/native/build/phone-xhdpi-1024-dalvik-heap.mk) $(call inherit-product-if-exists, vendor/nxp/pn544/nxp-pn544-fw-vendor.mk) $(call inherit-product, hardware/ti/omap4xxx/omap4.mk) diff --git a/dumpstate/Android.mk b/dumpstate/Android.mk index e4168db..ce5195b 100644 --- a/dumpstate/Android.mk +++ b/dumpstate/Android.mk @@ -15,7 +15,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_C_INCLUDES := frameworks/base/cmds/dumpstate +LOCAL_C_INCLUDES := frameworks/native/cmds/dumpstate LOCAL_SRC_FILES := dumpstate.c @@ -1,3 +1 @@ -0 0 android -0 1 POWERVR_SGX540_120 - +0 0 POWERVR_SGX540_120 diff --git a/full_tuna.mk b/full_tuna.mk index f2d8d61..0e4aa5b 100644 --- a/full_tuna.mk +++ b/full_tuna.mk @@ -21,10 +21,6 @@ # lines, full and toro, hence its name. # -# Camera -PRODUCT_PACKAGES := \ - Camera - # Inherit from those products. Most specific first. $(call inherit-product, $(SRC_TARGET_DIR)/product/full_base.mk) # This is where we'd set a backup provider if we had one @@ -1,4 +1,3 @@ -NTP_SERVER=north-america.pool.ntp.org
XTRA_SERVER_1=http://xtra1.gpsonextra.net/xtra.bin
XTRA_SERVER_2=http://xtra2.gpsonextra.net/xtra.bin
XTRA_SERVER_3=http://xtra3.gpsonextra.net/xtra.bin
diff --git a/init.tuna.rc b/init.tuna.rc index 70f1cbe..36d6bb9 100755 --- a/init.tuna.rc +++ b/init.tuna.rc @@ -1,14 +1,16 @@ import init.tuna.usb.rc on early-init - export EXTERNAL_STORAGE /mnt/sdcard - mkdir /mnt/sdcard 0000 system system + export EXTERNAL_STORAGE /storage/sdcard0 + mkdir /storage 0050 system sdcard_r + mkdir /storage/sdcard0 0000 system system # for backwards compatibility - symlink /mnt/sdcard /sdcard + symlink /storage/sdcard0 /sdcard + symlink /storage/sdcard0 /mnt/sdcard on post-fs-data - # we will remap this as /mnt/sdcard with the sdcard fuse tool - mkdir /data/media 0775 media_rw media_rw + # we will remap this as /storage/sdcard0 with the sdcard fuse tool + mkdir /data/media 0770 media_rw media_rw chown media_rw media_rw /data/media mkdir /data/misc/wifi 0770 wifi wifi mkdir /data/misc/wifi/sockets 0770 wifi wifi @@ -23,6 +25,9 @@ on post-fs-data mkdir /data/misc/camera 0770 media media mkdir /data/misc/camera/R5_MVEN003_LD2_ND0_IR0_SH0_FL1_SVEN003_DCCID1044 0770 media media + mkdir /data/radio 0775 radio radio + mkdir /data/radio/log 0775 radio radio + setprop vold.post_fs_data_done 1 # LTE @@ -38,14 +43,6 @@ on boot chmod 0666 /dev/pvrsrvkm setprop ro.crypto.keyfile.userdata /dev/block/platform/omap/omap_hsmmc.0/by-name/metadata -# Lower maximum frequency when screen is off - write /sys/devices/system/cpu/cpu0/cpufreq/screen_off_max_freq 700000 - -# cpufreq interactive governor: timer 20ms, min sample 20ms, hispeed 700MHz - write /sys/devices/system/cpu/cpufreq/interactive/timer_rate 20000 - write /sys/devices/system/cpu/cpufreq/interactive/min_sample_time 20000 - write /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq 700000 - # autosuspend root hubs immediatly after attached devices write /sys/bus/usb/devices/usb1/power/autosuspend_delay_ms 0 write /sys/bus/usb/devices/usb2/power/autosuspend_delay_ms 0 @@ -77,8 +74,6 @@ on fs # We chown/chmod /factory because mount is run as root + defaults chown radio radio /factory chmod 0775 /factory - mkdir /data/radio 0775 radio radio - mkdir /data/radio/log 0775 radio radio # add symlink for HDCP key symlink /factory/hdcp.keys /system/vendor/firmware/hdcp.keys @@ -116,10 +111,10 @@ on fs chown radio radio /sys/bus/usb/devices/usb1/power/control on property:persist.sys.tuna.off_mode=* - write /d/pm_debug/enable_off_mode $persist.sys.tuna.off_mode + write /d/pm_debug/enable_off_mode ${persist.sys.tuna.off_mode} on property:ril.modem.lte.powercontrol=* - write /sys/bus/usb/devices/1-1/power/control $ril.modem.lte.powercontrol + write /sys/bus/usb/devices/1-1/power/control ${ril.modem.lte.powercontrol} service fRom /system/bin/fRom \ -x /data/misc/camera/R5_MVEN003_LD2_ND0_IR0_SH0_FL1_SVEN003_DCCID1044 \ @@ -138,7 +133,7 @@ service hciattach /system/bin/brcm_patchram_plus --enable_hci --no2bytes --enabl disabled oneshot -service pvrsrvinit /vendor/bin/pvrsrvinit +service pvrsrvctl /vendor/bin/pvrsrvctl --start --no-module class core user root group root @@ -167,14 +162,26 @@ service smc_pa_wvdrm /system/bin/smc_pa_ctrl \ group drmrpc oneshot -# create virtual SD card at /mnt/sdcard, based on the /data/media directory +# create virtual SD card at /storage/sdcard0, based on the /data/media directory # daemon will drop to user/group system/media_rw after initializing # underlying files in /data/media will be created with user and group media_rw (1023) service sdcard /system/bin/sdcard /data/media 1023 1023 class late_start +service p2p_supplicant /system/bin/wpa_supplicant \ + -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf -N \ + -ip2p0 -Dnl80211 -c/data/misc/wifi/p2p_supplicant.conf -e/data/misc/wifi/entropy.bin -puse_p2p_group_interface=1 + # we will start as root and wpa_supplicant will switch to user wifi + # after setting up the capabilities required for WEXT + # user wifi + # group wifi inet keystore + class main + socket wpa_wlan0 dgram 660 wifi wifi + disabled + oneshot + service wpa_supplicant /system/bin/wpa_supplicant \ - -Dnl80211 -iwlan0 -puse_p2p_group_interface=1 -e/data/misc/wifi/entropy.bin + -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf -e/data/misc/wifi/entropy.bin # we will start as root and wpa_supplicant will switch to user wifi # after setting up the capabilities required for WEXT # user wifi @@ -184,7 +191,7 @@ service wpa_supplicant /system/bin/wpa_supplicant \ disabled oneshot -service dhcpcd_wlan0 /system/bin/dhcpcd -ABKL +service dhcpcd_wlan0 /system/bin/dhcpcd -aABKL class main disabled oneshot diff --git a/init.tuna.usb.rc b/init.tuna.usb.rc index 20bf090..e86a7bd 100755 --- a/init.tuna.usb.rc +++ b/init.tuna.usb.rc @@ -1,79 +1,79 @@ on init - write /sys/class/android_usb/android0/iSerial $ro.serialno + write /sys/class/android_usb/android0/iSerial ${ro.serialno} write /sys/class/android_usb/android0/f_rndis/manufacturer Samsung write /sys/class/android_usb/android0/f_rndis/vendorID 04e8 write /sys/class/android_usb/android0/f_rndis/wceis 1 on boot - write /sys/class/android_usb/android0/iManufacturer $ro.product.manufacturer - write /sys/class/android_usb/android0/iProduct $ro.product.model + write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer} + write /sys/class/android_usb/android0/iProduct ${ro.product.model} on property:sys.usb.config=mtp write /sys/class/android_usb/android0/enable 0 write /sys/class/android_usb/android0/idVendor 04e8 write /sys/class/android_usb/android0/idProduct 685c - write /sys/class/android_usb/android0/functions $sys.usb.config + write /sys/class/android_usb/android0/functions ${sys.usb.config} write /sys/class/android_usb/android0/enable 1 - setprop sys.usb.state $sys.usb.config + setprop sys.usb.state ${sys.usb.config} on property:sys.usb.config=mtp,adb write /sys/class/android_usb/android0/enable 0 write /sys/class/android_usb/android0/idVendor 04e8 write /sys/class/android_usb/android0/idProduct 6860 - write /sys/class/android_usb/android0/functions $sys.usb.config + write /sys/class/android_usb/android0/functions ${sys.usb.config} write /sys/class/android_usb/android0/enable 1 start adbd - setprop sys.usb.state $sys.usb.config + setprop sys.usb.state ${sys.usb.config} on property:sys.usb.config=rndis write /sys/class/android_usb/android0/enable 0 write /sys/class/android_usb/android0/idVendor 04e8 write /sys/class/android_usb/android0/idProduct 6863 - write /sys/class/android_usb/android0/functions $sys.usb.config + write /sys/class/android_usb/android0/functions ${sys.usb.config} write /sys/class/android_usb/android0/bDeviceClass 224 write /sys/class/android_usb/android0/enable 1 - setprop sys.usb.state $sys.usb.config + setprop sys.usb.state ${sys.usb.config} on property:sys.usb.config=rndis,adb write /sys/class/android_usb/android0/enable 0 write /sys/class/android_usb/android0/idVendor 04e8 write /sys/class/android_usb/android0/idProduct 6864 - write /sys/class/android_usb/android0/functions $sys.usb.config + write /sys/class/android_usb/android0/functions ${sys.usb.config} write /sys/class/android_usb/android0/bDeviceClass 224 write /sys/class/android_usb/android0/enable 1 start adbd - setprop sys.usb.state $sys.usb.config + setprop sys.usb.state ${sys.usb.config} on property:sys.usb.config=ptp write /sys/class/android_usb/android0/enable 0 write /sys/class/android_usb/android0/idVendor 04e8 write /sys/class/android_usb/android0/idProduct 6865 - write /sys/class/android_usb/android0/functions $sys.usb.config + write /sys/class/android_usb/android0/functions ${sys.usb.config} write /sys/class/android_usb/android0/enable 1 - setprop sys.usb.state $sys.usb.config + setprop sys.usb.state ${sys.usb.config} on property:sys.usb.config=ptp,adb write /sys/class/android_usb/android0/enable 0 write /sys/class/android_usb/android0/idVendor 04e8 write /sys/class/android_usb/android0/idProduct 6866 - write /sys/class/android_usb/android0/functions $sys.usb.config + write /sys/class/android_usb/android0/functions ${sys.usb.config} write /sys/class/android_usb/android0/enable 1 start adbd - setprop sys.usb.state $sys.usb.config + setprop sys.usb.state ${sys.usb.config} on property:sys.usb.config=rndis,dm write /sys/class/android_usb/android0/enable 0 write /sys/class/android_usb/android0/idVendor 04e8 write /sys/class/android_usb/android0/idProduct 6864 - write /sys/class/android_usb/android0/functions $sys.usb.config + write /sys/class/android_usb/android0/functions ${sys.usb.config} write /sys/class/android_usb/android0/enable 1 - setprop sys.usb.state $sys.usb.config + setprop sys.usb.state ${sys.usb.config} on property:sys.usb.config=rndis,acm,dm write /sys/class/android_usb/android0/enable 0 write /sys/class/android_usb/android0/idVendor 04e8 write /sys/class/android_usb/android0/idProduct 6864 - write /sys/class/android_usb/android0/functions $sys.usb.config + write /sys/class/android_usb/android0/functions ${sys.usb.config} write /sys/class/android_usb/android0/f_acm/instances 1 write /sys/class/android_usb/android0/enable 1 - setprop sys.usb.state $sys.usb.config + setprop sys.usb.state ${sys.usb.config} Binary files differdiff --git a/keymaster/Android.mk b/keymaster/Android.mk new file mode 100644 index 0000000..885812f --- /dev/null +++ b/keymaster/Android.mk @@ -0,0 +1,43 @@ +# Copyright (C) 2011 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ifeq ($(TARGET_BOARD_PLATFORM),omap4) +ifeq ($(BOARD_USES_SECURE_SERVICES),true) + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := keystore.tuna + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + +LOCAL_SRC_FILES := \ + keymaster_tuna.cpp + +LOCAL_C_INCLUDES := \ + libcore/include \ + external/openssl/include \ + hardware/ti/omap4xxx/security/tf_sdk/include + +LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror + +LOCAL_SHARED_LIBRARIES := libcutils liblog libcrypto libtf_crypto_sst + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) + +endif # ifeq ($(BOARD_USES_SECURE_SERVICES),true) +endif # ifeq ($(TARGET_BOARD_PLATFORM),omap4) diff --git a/keymaster/keymaster_tuna.cpp b/keymaster/keymaster_tuna.cpp new file mode 100644 index 0000000..fbc654f --- /dev/null +++ b/keymaster/keymaster_tuna.cpp @@ -0,0 +1,966 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <errno.h> +#include <string.h> +#include <stdint.h> + +// For debugging +#define LOG_NDEBUG 0 + +// TEE is the Trusted Execution Environment +#define LOG_TAG "TEEKeyMaster" +#include <cutils/log.h> + +#include <hardware/hardware.h> +#include <hardware/keymaster.h> + +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/rand.h> +#include <openssl/x509.h> + +#include <cryptoki.h> +#include <pkcs11.h> + +#include <UniquePtr.h> + + +/** The size of a key ID in bytes */ +#define ID_LENGTH 32 + +/** The current stored key version. */ +const static uint32_t KEY_VERSION = 1; + + +struct EVP_PKEY_Delete { + void operator()(EVP_PKEY* p) const { + EVP_PKEY_free(p); + } +}; +typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY; + +struct RSA_Delete { + void operator()(RSA* p) const { + RSA_free(p); + } +}; +typedef UniquePtr<RSA, RSA_Delete> Unique_RSA; + +struct PKCS8_PRIV_KEY_INFO_Delete { + void operator()(PKCS8_PRIV_KEY_INFO* p) const { + PKCS8_PRIV_KEY_INFO_free(p); + } +}; +typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO; + +typedef UniquePtr<keymaster_device_t> Unique_keymaster_device_t; + +typedef UniquePtr<CK_BYTE[]> Unique_CK_BYTE; + +typedef UniquePtr<CK_ATTRIBUTE[]> Unique_CK_ATTRIBUTE; + +class ByteArray { +public: + ByteArray(CK_BYTE* array, size_t len) : + mArray(array), mLength(len) { + } + + ByteArray(size_t len) : + mLength(len) { + mArray = new CK_BYTE[len]; + } + + ~ByteArray() { + if (mArray != NULL) { + delete[] mArray; + } + } + + CK_BYTE* get() const { + return mArray; + } + + size_t length() const { + return mLength; + } + + CK_BYTE* release() { + CK_BYTE* array = mArray; + mArray = NULL; + return array; + } + +private: + CK_BYTE* mArray; + size_t mLength; +}; +typedef UniquePtr<ByteArray> Unique_ByteArray; + +class CryptoSession { +public: + CryptoSession(CK_SESSION_HANDLE masterHandle) : + mHandle(masterHandle), mSubsession(CK_INVALID_HANDLE) { + CK_SESSION_HANDLE subsessionHandle = mHandle; + CK_RV openSessionRV = C_OpenSession(CKV_TOKEN_USER, + CKF_SERIAL_SESSION | CKF_RW_SESSION | CKVF_OPEN_SUB_SESSION, + NULL, + NULL, + &subsessionHandle); + + if (openSessionRV != CKR_OK || subsessionHandle == CK_INVALID_HANDLE) { + (void) C_Finalize(NULL_PTR); + ALOGE("Error opening secondary session with TEE: 0x%x", openSessionRV); + } else { + ALOGV("Opening subsession 0x%x", subsessionHandle); + mSubsession = subsessionHandle; + } + } + + ~CryptoSession() { + if (mSubsession != CK_INVALID_HANDLE) { + CK_RV rv = C_CloseSession(mSubsession); + ALOGV("Closing subsession 0x%x: 0x%x", mSubsession, rv); + mSubsession = CK_INVALID_HANDLE; + } + } + + CK_SESSION_HANDLE get() const { + return mSubsession; + } + + CK_SESSION_HANDLE getPrimary() const { + return mHandle; + } + +private: + CK_SESSION_HANDLE mHandle; + CK_SESSION_HANDLE mSubsession; +}; + +class ObjectHandle { +public: + ObjectHandle(const CryptoSession* session, CK_OBJECT_HANDLE handle = CK_INVALID_HANDLE) : + mSession(session), mHandle(handle) { + } + + ~ObjectHandle() { + if (mHandle != CK_INVALID_HANDLE) { + CK_RV rv = C_CloseObjectHandle(mSession->getPrimary(), mHandle); + if (rv != CKR_OK) { + ALOGW("Couldn't close object handle 0x%x: 0x%x", mHandle, rv); + } else { + ALOGV("Closing object handle 0x%x", mHandle); + mHandle = CK_INVALID_HANDLE; + } + } + } + + CK_OBJECT_HANDLE get() const { + return mHandle; + } + + void reset(CK_OBJECT_HANDLE handle) { + mHandle = handle; + } + +private: + const CryptoSession* mSession; + CK_OBJECT_HANDLE mHandle; +}; + + +/** + * Many OpenSSL APIs take ownership of an argument on success but don't free the argument + * on failure. This means we need to tell our scoped pointers when we've transferred ownership, + * without triggering a warning by not using the result of release(). + */ +#define OWNERSHIP_TRANSFERRED(obj) \ + typeof (obj.release()) _dummy __attribute__((unused)) = obj.release() + + +/* + * Checks this thread's OpenSSL error queue and logs if + * necessary. + */ +static void logOpenSSLError(const char* location) { + int error = ERR_get_error(); + + if (error != 0) { + char message[256]; + ERR_error_string_n(error, message, sizeof(message)); + ALOGE("OpenSSL error in %s %d: %s", location, error, message); + } + + ERR_clear_error(); + ERR_remove_state(0); +} + + +/** + * Convert from OpenSSL's BIGNUM format to TEE's Big Integer format. + */ +static ByteArray* bignum_to_array(const BIGNUM* bn) { + const int bignumSize = BN_num_bytes(bn); + + Unique_CK_BYTE bytes(new CK_BYTE[bignumSize]); + + unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get()); + if (BN_bn2bin(bn, tmp) != bignumSize) { + ALOGE("public exponent size wasn't what was expected"); + return NULL; + } + + return new ByteArray(bytes.release(), bignumSize); +} + +static void set_attribute(CK_ATTRIBUTE* attrib, CK_ATTRIBUTE_TYPE type, void* pValue, + CK_ULONG ulValueLen) { + attrib->type = type; + attrib->pValue = pValue; + attrib->ulValueLen = ulValueLen; +} + +static ByteArray* generate_random_id() { + Unique_ByteArray id(new ByteArray(ID_LENGTH)); + if (RAND_pseudo_bytes(reinterpret_cast<unsigned char*>(id->get()), id->length()) < 0) { + return NULL; + } + + return id.release(); +} + +static int keyblob_save(ByteArray* objId, uint8_t** key_blob, size_t* key_blob_length) { + Unique_ByteArray handleBlob(new ByteArray(sizeof(uint32_t) + objId->length())); + if (handleBlob.get() == NULL) { + ALOGE("Could not allocate key blob"); + return -1; + } + uint8_t* tmp = handleBlob->get(); + for (size_t i = 0; i < sizeof(uint32_t); i++) { + *tmp++ = KEY_VERSION >> ((sizeof(uint32_t) - i - 1) * 8); + } + memcpy(tmp, objId->get(), objId->length()); + + *key_blob_length = handleBlob->length(); + *key_blob = handleBlob->get(); + ByteArray* unused __attribute__((unused)) = handleBlob.release(); + + return 0; +} + +static int find_single_object(const uint8_t* obj_id, const size_t obj_id_length, + CK_OBJECT_CLASS obj_class, const CryptoSession* session, ObjectHandle* object) { + + // Note that the CKA_ID attribute is never written, so we can cast away const here. + void* obj_id_ptr = reinterpret_cast<void*>(const_cast<uint8_t*>(obj_id)); + CK_ATTRIBUTE attributes[] = { + { CKA_ID, obj_id_ptr, obj_id_length }, + { CKA_CLASS, &obj_class, sizeof(obj_class) }, + }; + + CK_RV rv = C_FindObjectsInit(session->get(), attributes, + sizeof(attributes) / sizeof(CK_ATTRIBUTE)); + if (rv != CKR_OK) { + ALOGE("Error in C_FindObjectsInit: 0x%x", rv); + return -1; + } + + CK_OBJECT_HANDLE tmpHandle; + CK_ULONG tmpCount; + + rv = C_FindObjects(session->get(), &tmpHandle, 1, &tmpCount); + ALOGV("Found %d object 0x%x : class 0x%x", tmpCount, tmpHandle, obj_class); + if (rv != CKR_OK || tmpCount != 1) { + C_FindObjectsFinal(session->get()); + ALOGE("Couldn't find key!"); + return -1; + } + C_FindObjectsFinal(session->get()); + + object->reset(tmpHandle); + return 0; +} + +static int keyblob_restore(const CryptoSession* session, const uint8_t* keyBlob, + const size_t keyBlobLength, ObjectHandle* public_key, ObjectHandle* private_key) { + if (keyBlob == NULL) { + ALOGE("key blob was null"); + return -1; + } + + if (keyBlobLength < (sizeof(KEY_VERSION) + ID_LENGTH)) { + ALOGE("key blob is not correct size"); + return -1; + } + + uint32_t keyVersion = 0; + + const uint8_t* p = keyBlob; + for (size_t i = 0; i < sizeof(keyVersion); i++) { + keyVersion = (keyVersion << 8) | *p++; + } + + if (keyVersion != 1) { + ALOGE("Invalid key version %d", keyVersion); + return -1; + } + + return find_single_object(p, ID_LENGTH, CKO_PUBLIC_KEY, session, public_key) + || find_single_object(p, ID_LENGTH, CKO_PRIVATE_KEY, session, private_key); +} + +static int tee_generate_keypair(const keymaster_device_t* dev, + const keymaster_keypair_t type, const void* key_params, + uint8_t** key_blob, size_t* key_blob_length) { + CK_BBOOL bTRUE = CK_TRUE; + + if (type != TYPE_RSA) { + ALOGW("Unknown key type %d", type); + return -1; + } + + if (key_params == NULL) { + ALOGW("generate_keypair params were NULL"); + return -1; + } + + keymaster_rsa_keygen_params_t* rsa_params = (keymaster_rsa_keygen_params_t*) key_params; + + CK_MECHANISM mechanism = { + CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0, + }; + CK_ULONG modulusBits = (CK_ULONG) rsa_params->modulus_size; + + /** + * Convert our unsigned 64-bit integer to the TEE Big Integer class. It's + * an unsigned array of bytes with MSB first. + */ + CK_BYTE publicExponent[sizeof(uint64_t)]; + const uint64_t exp = rsa_params->public_exponent; + size_t offset = sizeof(publicExponent) - 1; + for (size_t i = 0; i < sizeof(publicExponent); i++) { + publicExponent[offset--] = (exp >> (i * CHAR_BIT)) & 0xFF; + } + + Unique_ByteArray objId(generate_random_id()); + if (objId.get() == NULL) { + ALOGE("Couldn't generate random key ID"); + return -1; + } + + CK_ATTRIBUTE publicKeyTemplate[] = { + {CKA_ID, objId->get(), objId->length()}, + {CKA_TOKEN, &bTRUE, sizeof(bTRUE)}, + {CKA_ENCRYPT, &bTRUE, sizeof(bTRUE)}, + {CKA_VERIFY, &bTRUE, sizeof(bTRUE)}, + {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)}, + {CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent)}, + }; + + CK_ATTRIBUTE privateKeyTemplate[] = { + {CKA_ID, objId->get(), objId->length()}, + {CKA_TOKEN, &bTRUE, sizeof(bTRUE)}, + {CKA_DECRYPT, &bTRUE, sizeof(bTRUE)}, + {CKA_SIGN, &bTRUE, sizeof(bTRUE)}, + }; + + CryptoSession session(reinterpret_cast<CK_SESSION_HANDLE>(dev->context)); + + CK_OBJECT_HANDLE hPublicKey, hPrivateKey; + CK_RV rv = C_GenerateKeyPair(session.get(), + &mechanism, + publicKeyTemplate, + sizeof(publicKeyTemplate)/sizeof(CK_ATTRIBUTE), + privateKeyTemplate, + sizeof(privateKeyTemplate)/sizeof(CK_ATTRIBUTE), + &hPublicKey, + &hPrivateKey); + + if (rv != CKR_OK) { + ALOGE("Generate keypair failed: 0x%x", rv); + return -1; + } + + ObjectHandle publicKey(&session, hPublicKey); + ObjectHandle privateKey(&session, hPrivateKey); + ALOGV("public handle = 0x%x, private handle = 0x%x", publicKey.get(), privateKey.get()); + + return keyblob_save(objId.get(), key_blob, key_blob_length); +} + +static int tee_import_keypair(const keymaster_device_t* dev, + const uint8_t* key, const size_t key_length, + uint8_t** key_blob, size_t* key_blob_length) { + CK_RV rv; + CK_BBOOL bTRUE = CK_TRUE; + + if (key == NULL) { + ALOGW("provided key is null"); + return -1; + } + + Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length)); + if (pkcs8.get() == NULL) { + logOpenSSLError("tee_import_keypair"); + return -1; + } + + /* assign to EVP */ + Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get())); + if (pkey.get() == NULL) { + logOpenSSLError("tee_import_keypair"); + return -1; + } + + if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { + ALOGE("Unsupported key type: %d", EVP_PKEY_type(pkey->type)); + return -1; + } + + Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey.get())); + if (rsa.get() == NULL) { + logOpenSSLError("tee_import_keypair"); + return -1; + } + + Unique_ByteArray modulus(bignum_to_array(rsa->n)); + if (modulus.get() == NULL) { + ALOGW("Could not convert modulus to array"); + return -1; + } + + Unique_ByteArray publicExponent(bignum_to_array(rsa->e)); + if (publicExponent.get() == NULL) { + ALOGW("Could not convert publicExponent to array"); + return -1; + } + + CK_KEY_TYPE rsaType = CKK_RSA; + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; + + Unique_ByteArray objId(generate_random_id()); + if (objId.get() == NULL) { + ALOGE("Couldn't generate random key ID"); + return -1; + } + + CK_ATTRIBUTE publicKeyTemplate[] = { + {CKA_ID, objId->get(), objId->length()}, + {CKA_TOKEN, &bTRUE, sizeof(bTRUE)}, + {CKA_CLASS, &pubClass, sizeof(pubClass)}, + {CKA_KEY_TYPE, &rsaType, sizeof(rsaType)}, + {CKA_ENCRYPT, &bTRUE, sizeof(bTRUE)}, + {CKA_VERIFY, &bTRUE, sizeof(bTRUE)}, + {CKA_MODULUS, modulus->get(), modulus->length()}, + {CKA_PUBLIC_EXPONENT, publicExponent->get(), publicExponent->length()}, + }; + + CryptoSession session(reinterpret_cast<CK_SESSION_HANDLE>(dev->context)); + + CK_OBJECT_HANDLE hPublicKey; + rv = C_CreateObject(session.get(), + publicKeyTemplate, + sizeof(publicKeyTemplate)/sizeof(CK_ATTRIBUTE), + &hPublicKey); + if (rv != CKR_OK) { + ALOGE("Creation of public key failed: 0x%x", rv); + return -1; + } + ObjectHandle publicKey(&session, hPublicKey); + + Unique_ByteArray privateExponent(bignum_to_array(rsa->d)); + if (privateExponent.get() == NULL) { + ALOGW("Could not convert private exponent"); + return -1; + } + + + /* + * Normally we need: + * CKA_ID + * CKA_TOKEN + * CKA_CLASS + * CKA_KEY_TYPE + * + * CKA_DECRYPT + * CKA_SIGN + * + * CKA_MODULUS + * CKA_PUBLIC_EXPONENT + * CKA_PRIVATE_EXPONENT + */ +#define PRIV_ATTRIB_NORMAL_NUM (4 + 2 + 3) + + /* + * For additional private key values: + * CKA_PRIME_1 + * CKA_PRIME_2 + * + * CKA_EXPONENT_1 + * CKA_EXPONENT_2 + * + * CKA_COEFFICIENT + */ +#define PRIV_ATTRIB_EXTENDED_NUM (PRIV_ATTRIB_NORMAL_NUM + 5) + + /* + * If we have the prime, prime exponents, and coefficient, we can + * copy them in. + */ + bool has_extra_data = (rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) && + (rsa->dmq1 != NULL) && (rsa->iqmp != NULL); + + Unique_CK_ATTRIBUTE privateKeyTemplate(new CK_ATTRIBUTE[ + has_extra_data ? PRIV_ATTRIB_EXTENDED_NUM : PRIV_ATTRIB_NORMAL_NUM]); + + CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; + + size_t templateOffset = 0; + + set_attribute(&privateKeyTemplate[templateOffset++], CKA_ID, objId->get(), objId->length()); + set_attribute(&privateKeyTemplate[templateOffset++], CKA_TOKEN, &bTRUE, sizeof(bTRUE)); + set_attribute(&privateKeyTemplate[templateOffset++], CKA_CLASS, &privClass, sizeof(privClass)); + set_attribute(&privateKeyTemplate[templateOffset++], CKA_KEY_TYPE, &rsaType, sizeof(rsaType)); + + set_attribute(&privateKeyTemplate[templateOffset++], CKA_DECRYPT, &bTRUE, sizeof(bTRUE)); + set_attribute(&privateKeyTemplate[templateOffset++], CKA_SIGN, &bTRUE, sizeof(bTRUE)); + + set_attribute(&privateKeyTemplate[templateOffset++], CKA_MODULUS, modulus->get(), + modulus->length()); + set_attribute(&privateKeyTemplate[templateOffset++], CKA_PUBLIC_EXPONENT, + publicExponent->get(), publicExponent->length()); + set_attribute(&privateKeyTemplate[templateOffset++], CKA_PRIVATE_EXPONENT, + privateExponent->get(), privateExponent->length()); + + Unique_ByteArray prime1, prime2, exp1, exp2, coeff; + if (has_extra_data) { + prime1.reset(bignum_to_array(rsa->p)); + if (prime1->get() == NULL) { + ALOGW("Could not convert prime1"); + return -1; + } + set_attribute(&privateKeyTemplate[templateOffset++], CKA_PRIME_1, prime1->get(), + prime1->length()); + + prime2.reset(bignum_to_array(rsa->q)); + if (prime2->get() == NULL) { + ALOGW("Could not convert prime2"); + return -1; + } + set_attribute(&privateKeyTemplate[templateOffset++], CKA_PRIME_2, prime2->get(), + prime2->length()); + + exp1.reset(bignum_to_array(rsa->dmp1)); + if (exp1->get() == NULL) { + ALOGW("Could not convert exponent 1"); + return -1; + } + set_attribute(&privateKeyTemplate[templateOffset++], CKA_EXPONENT_1, exp1->get(), + exp1->length()); + + exp2.reset(bignum_to_array(rsa->dmq1)); + if (exp2->get() == NULL) { + ALOGW("Could not convert exponent 2"); + return -1; + } + set_attribute(&privateKeyTemplate[templateOffset++], CKA_EXPONENT_2, exp2->get(), + exp2->length()); + + coeff.reset(bignum_to_array(rsa->iqmp)); + if (coeff->get() == NULL) { + ALOGW("Could not convert coefficient"); + return -1; + } + set_attribute(&privateKeyTemplate[templateOffset++], CKA_COEFFICIENT, coeff->get(), + coeff->length()); + } + + CK_OBJECT_HANDLE hPrivateKey; + rv = C_CreateObject(session.get(), + privateKeyTemplate.get(), + templateOffset, + &hPrivateKey); + if (rv != CKR_OK) { + ALOGE("Creation of private key failed: 0x%x", rv); + return -1; + } + ObjectHandle privateKey(&session, hPrivateKey); + + ALOGV("public handle = 0x%x, private handle = 0x%x", publicKey.get(), privateKey.get()); + + return keyblob_save(objId.get(), key_blob, key_blob_length); +} + +static int tee_get_keypair_public(const struct keymaster_device* dev, + const uint8_t* key_blob, const size_t key_blob_length, + uint8_t** x509_data, size_t* x509_data_length) { + + CryptoSession session(reinterpret_cast<CK_SESSION_HANDLE>(dev->context)); + + ObjectHandle publicKey(&session); + ObjectHandle privateKey(&session); + + if (keyblob_restore(&session, key_blob, key_blob_length, &publicKey, &privateKey)) { + return -1; + } + + if (x509_data == NULL || x509_data_length == NULL) { + ALOGW("Provided destination variables were null"); + return -1; + } + + CK_ATTRIBUTE attributes[] = { + {CKA_MODULUS, NULL, 0}, + {CKA_PUBLIC_EXPONENT, NULL, 0}, + }; + + // Call first to get the sizes of the values. + CK_RV rv = C_GetAttributeValue(session.get(), publicKey.get(), attributes, + sizeof(attributes)/sizeof(CK_ATTRIBUTE)); + if (rv != CKR_OK) { + ALOGW("Could not query attribute value sizes: 0x%02x", rv); + return -1; + } + + ByteArray modulus(new CK_BYTE[attributes[0].ulValueLen], attributes[0].ulValueLen); + ByteArray exponent(new CK_BYTE[attributes[1].ulValueLen], attributes[1].ulValueLen); + + attributes[0].pValue = modulus.get(); + attributes[1].pValue = exponent.get(); + + rv = C_GetAttributeValue(session.get(), publicKey.get(), attributes, + sizeof(attributes) / sizeof(CK_ATTRIBUTE)); + if (rv != CKR_OK) { + ALOGW("Could not query attribute values: 0x%02x", rv); + return -1; + } + + ALOGV("modulus is %d, exponent is %d", modulus.length(), exponent.length()); + + Unique_RSA rsa(RSA_new()); + if (rsa.get() == NULL) { + ALOGE("Could not allocate RSA structure"); + return -1; + } + + rsa->n = BN_bin2bn(reinterpret_cast<const unsigned char*>(modulus.get()), modulus.length(), + NULL); + if (rsa->n == NULL) { + logOpenSSLError("tee_get_keypair_public"); + return -1; + } + + rsa->e = BN_bin2bn(reinterpret_cast<const unsigned char*>(exponent.get()), exponent.length(), + NULL); + if (rsa->e == NULL) { + logOpenSSLError("tee_get_keypair_public"); + return -1; + } + + Unique_EVP_PKEY pkey(EVP_PKEY_new()); + if (pkey.get() == NULL) { + ALOGE("Could not allocate EVP_PKEY structure"); + return -1; + } + if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) { + logOpenSSLError("tee_get_keypair_public"); + return -1; + } + OWNERSHIP_TRANSFERRED(rsa); + + int len = i2d_PUBKEY(pkey.get(), NULL); + if (len <= 0) { + logOpenSSLError("tee_get_keypair_public"); + return -1; + } + + UniquePtr<uint8_t> key(static_cast<uint8_t*>(malloc(len))); + if (key.get() == NULL) { + ALOGE("Could not allocate memory for public key data"); + return -1; + } + + unsigned char* tmp = reinterpret_cast<unsigned char*>(key.get()); + if (i2d_PUBKEY(pkey.get(), &tmp) != len) { + logOpenSSLError("tee_get_keypair_public"); + return -1; + } + + ALOGV("Length of x509 data is %d", len); + *x509_data_length = len; + *x509_data = key.release(); + + return 0; +} + +static int tee_delete_keypair(const struct keymaster_device* dev, + const uint8_t* key_blob, const size_t key_blob_length) { + + CryptoSession session(reinterpret_cast<CK_SESSION_HANDLE>(dev->context)); + + ObjectHandle publicKey(&session); + ObjectHandle privateKey(&session); + + if (keyblob_restore(&session, key_blob, key_blob_length, &publicKey, &privateKey)) { + return -1; + } + + // Delete the private key. + CK_RV rv = C_DestroyObject(session.get(), privateKey.get()); + if (rv != CKR_OK) { + ALOGW("Could destroy private key object: 0x%02x", rv); + return -1; + } + + // Delete the public key. + rv = C_DestroyObject(session.get(), publicKey.get()); + if (rv != CKR_OK) { + ALOGW("Could destroy public key object: 0x%02x", rv); + return -1; + } + + return 0; +} + +static int tee_sign_data(const keymaster_device_t* dev, + const void* params, + const uint8_t* key_blob, const size_t key_blob_length, + const uint8_t* data, const size_t dataLength, + uint8_t** signedData, size_t* signedDataLength) { + ALOGV("tee_sign_data(%p, %p, %llu, %p, %llu, %p, %p)", dev, key_blob, + (unsigned long long) key_blob_length, data, (unsigned long long) dataLength, signedData, + signedDataLength); + + if (params == NULL) { + ALOGW("Signing params were null"); + return -1; + } + + CryptoSession session(reinterpret_cast<CK_SESSION_HANDLE>(dev->context)); + + ObjectHandle publicKey(&session); + ObjectHandle privateKey(&session); + + if (keyblob_restore(&session, key_blob, key_blob_length, &publicKey, &privateKey)) { + return -1; + } + ALOGV("public handle = 0x%x, private handle = 0x%x", publicKey.get(), privateKey.get()); + + keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params; + if (sign_params->digest_type != DIGEST_NONE) { + ALOGW("Cannot handle digest type %d", sign_params->digest_type); + return -1; + } else if (sign_params->padding_type != PADDING_NONE) { + ALOGW("Cannot handle padding type %d", sign_params->padding_type); + return -1; + } + + CK_MECHANISM rawRsaMechanism = { + CKM_RSA_X_509, NULL, 0 + }; + + CK_RV rv = C_SignInit(session.get(), &rawRsaMechanism, privateKey.get()); + if (rv != CKR_OK) { + ALOGV("C_SignInit failed: 0x%x", rv); + return -1; + } + + CK_BYTE signature[1024]; + CK_ULONG signatureLength = 1024; + + rv = C_Sign(session.get(), data, dataLength, signature, &signatureLength); + if (rv != CKR_OK) { + ALOGV("C_SignFinal failed: 0x%x", rv); + return -1; + } + + UniquePtr<uint8_t[]> finalSignature(new uint8_t[signatureLength]); + if (finalSignature.get() == NULL) { + ALOGE("Couldn't allocate memory to copy signature"); + return -1; + } + + memcpy(finalSignature.get(), signature, signatureLength); + + *signedData = finalSignature.release(); + *signedDataLength = static_cast<size_t>(signatureLength); + + ALOGV("tee_sign_data(%p, %p, %llu, %p, %llu, %p, %p) => %p size %llu", dev, key_blob, + (unsigned long long) key_blob_length, data, (unsigned long long) dataLength, signedData, + signedDataLength, *signedData, (unsigned long long) *signedDataLength); + + return 0; +} + +static int tee_verify_data(const keymaster_device_t* dev, + const void* params, + const uint8_t* keyBlob, const size_t keyBlobLength, + const uint8_t* signedData, const size_t signedDataLength, + const uint8_t* signature, const size_t signatureLength) { + ALOGV("tee_verify_data(%p, %p, %llu, %p, %llu, %p, %llu)", dev, keyBlob, + (unsigned long long) keyBlobLength, signedData, (unsigned long long) signedDataLength, + signature, (unsigned long long) signatureLength); + + if (params == NULL) { + ALOGW("Verification params were null"); + return -1; + } + + CryptoSession session(reinterpret_cast<CK_SESSION_HANDLE>(dev->context)); + + ObjectHandle publicKey(&session); + ObjectHandle privateKey(&session); + + if (keyblob_restore(&session, keyBlob, keyBlobLength, &publicKey, &privateKey)) { + return -1; + } + ALOGV("public handle = 0x%x, private handle = 0x%x", publicKey.get(), privateKey.get()); + + keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params; + if (sign_params->digest_type != DIGEST_NONE) { + ALOGW("Cannot handle digest type %d", sign_params->digest_type); + return -1; + } else if (sign_params->padding_type != PADDING_NONE) { + ALOGW("Cannot handle padding type %d", sign_params->padding_type); + return -1; + } + + CK_MECHANISM rawRsaMechanism = { + CKM_RSA_X_509, NULL, 0 + }; + + CK_RV rv = C_VerifyInit(session.get(), &rawRsaMechanism, publicKey.get()); + if (rv != CKR_OK) { + ALOGV("C_VerifyInit failed: 0x%x", rv); + return -1; + } + + // This is a bad prototype for this function. C_Verify should have only const args. + rv = C_Verify(session.get(), signedData, signedDataLength, + const_cast<unsigned char*>(signature), signatureLength); + if (rv != CKR_OK) { + ALOGV("C_Verify failed: 0x%x", rv); + return -1; + } + + return 0; +} + +/* Close an opened OpenSSL instance */ +static int tee_close(hw_device_t *dev) { + keymaster_device_t *keymaster_dev = (keymaster_device_t *) dev; + if (keymaster_dev != NULL) { + CK_SESSION_HANDLE handle = reinterpret_cast<CK_SESSION_HANDLE>(keymaster_dev->context); + if (handle != CK_INVALID_HANDLE) { + C_CloseSession(handle); + } + } + + CK_RV finalizeRV = C_Finalize(NULL_PTR); + if (finalizeRV != CKR_OK) { + ALOGE("Error closing the TEE"); + } + free(dev); + + return 0; +} + +/* + * Generic device handling + */ +static int tee_open(const hw_module_t* module, const char* name, + hw_device_t** device) { + if (strcmp(name, KEYSTORE_KEYMASTER) != 0) + return -EINVAL; + + Unique_keymaster_device_t dev(new keymaster_device_t); + if (dev.get() == NULL) + return -ENOMEM; + + dev->common.tag = HARDWARE_DEVICE_TAG; + dev->common.version = 1; + dev->common.module = (struct hw_module_t*) module; + dev->common.close = tee_close; + + dev->generate_keypair = tee_generate_keypair; + dev->import_keypair = tee_import_keypair; + dev->get_keypair_public = tee_get_keypair_public; + dev->delete_keypair = tee_delete_keypair; + dev->sign_data = tee_sign_data; + dev->verify_data = tee_verify_data; + + CK_RV initializeRV = C_Initialize(NULL); + if (initializeRV != CKR_OK) { + ALOGE("Error initializing TEE: 0x%x", initializeRV); + return -ENODEV; + } + + CK_INFO info; + CK_RV infoRV = C_GetInfo(&info); + if (infoRV != CKR_OK) { + (void) C_Finalize(NULL_PTR); + ALOGE("Error getting information about TEE during initialization: 0x%x", infoRV); + return -ENODEV; + } + + ALOGI("C_GetInfo cryptokiVer=%d.%d manufID=%s flags=%d libDesc=%s libVer=%d.%d\n", + info.cryptokiVersion.major, info.cryptokiVersion.minor, + info.manufacturerID, info.flags, info.libraryDescription, + info.libraryVersion.major, info.libraryVersion.minor); + + CK_SESSION_HANDLE sessionHandle = CK_INVALID_HANDLE; + + CK_RV openSessionRV = C_OpenSession(CKV_TOKEN_USER, + CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, + NULL, + &sessionHandle); + + if (openSessionRV != CKR_OK || sessionHandle == CK_INVALID_HANDLE) { + (void) C_Finalize(NULL_PTR); + ALOGE("Error opening primary session with TEE: 0x%x", openSessionRV); + return -1; + } + + ERR_load_crypto_strings(); + ERR_load_BIO_strings(); + + dev->context = reinterpret_cast<void*>(sessionHandle); + *device = reinterpret_cast<hw_device_t*>(dev.release()); + + return 0; +} + +static struct hw_module_methods_t keystore_module_methods = { + open: tee_open, +}; + +struct keystore_module HAL_MODULE_INFO_SYM +__attribute__ ((visibility ("default"))) = { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: KEYSTORE_HARDWARE_MODULE_ID, + name: "Keymaster TEE HAL", + author: "The Android Open Source Project", + methods: &keystore_module_methods, + dso: 0, + reserved: {}, + }, +}; diff --git a/liblight/lights.c b/liblight/lights.c index 8c675b2..1dfcd8b 100644 --- a/liblight/lights.c +++ b/liblight/lights.c @@ -54,7 +54,7 @@ static int write_int(char const *path, int value) already_warned = 0; - LOGV("write_int: path %s, value %d", path, value); + ALOGV("write_int: path %s, value %d", path, value); fd = open(path, O_RDWR); if (fd >= 0) { @@ -65,7 +65,7 @@ static int write_int(char const *path, int value) return amt == -1 ? -errno : 0; } else { if (already_warned == 0) { - LOGE("write_int failed to open %s\n", path); + ALOGE("write_int failed to open %s\n", path); already_warned = 1; } return -errno; @@ -95,7 +95,7 @@ static int set_light_backlight(struct light_device_t *dev, static int close_lights(struct light_device_t *dev) { - LOGV("close_light is called"); + ALOGV("close_light is called"); if (dev) free(dev); @@ -115,15 +115,15 @@ static int write_leds(struct an30259a_pr_control *led) if (fd >= 0) { err = ioctl(fd, AN30259A_PR_SET_IMAX, &imax); if (err) - LOGE("failed to set imax"); + ALOGE("failed to set imax"); err = ioctl(fd, AN30259A_PR_SET_LED, led); if (err < 0) - LOGE("failed to set leds!"); + ALOGE("failed to set leds!"); close(fd); } else { - LOGE("failed to open %s!", LED_FILE); + ALOGE("failed to open %s!", LED_FILE); err = -errno; } @@ -211,7 +211,7 @@ static struct hw_module_methods_t lights_module_methods = { .open = open_lights, }; -const struct hw_module_t HAL_MODULE_INFO_SYM = { +struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, diff --git a/libsensors/SamsungSensorBase.cpp b/libsensors/SamsungSensorBase.cpp index 0ec4915..fe3f14e 100644 --- a/libsensors/SamsungSensorBase.cpp +++ b/libsensors/SamsungSensorBase.cpp @@ -70,13 +70,13 @@ SamsungSensorBase::SamsungSensorBase(const char *dev_name, return; mInputSysfsEnable = makeSysfsName(input_name, "enable"); if (!mInputSysfsEnable) { - LOGE("%s: unable to allocate mem for %s:enable", __func__, + ALOGE("%s: unable to allocate mem for %s:enable", __func__, data_name); return; } mInputSysfsPollDelay = makeSysfsName(input_name, "poll_delay"); if (!mInputSysfsPollDelay) { - LOGE("%s: unable to allocate mem for %s:poll_delay", __func__, + ALOGE("%s: unable to allocate mem for %s:poll_delay", __func__, data_name); return; } diff --git a/libsensors/sensors.cpp b/libsensors/sensors.cpp index 156f08d..2a33731 100644 --- a/libsensors/sensors.cpp +++ b/libsensors/sensors.cpp @@ -16,7 +16,7 @@ #define LOG_NDEBUG 0 #define LOG_TAG "Sensors" -//#define FUNC_LOG LOGV("%s", __PRETTY_FUNCTION__) +//#define FUNC_LOG ALOGV("%s", __PRETTY_FUNCTION__) #define FUNC_LOG #include <hardware/sensors.h> @@ -215,7 +215,7 @@ sensors_poll_context_t::sensors_poll_context_t() int wakeFds[2]; int result = pipe(wakeFds); - LOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno)); + ALOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno)); fcntl(wakeFds[0], F_SETFL, O_NONBLOCK); fcntl(wakeFds[1], F_SETFL, O_NONBLOCK); mWritePipeFd = wakeFds[1]; @@ -249,7 +249,7 @@ int sensors_poll_context_t::activate(int handle, int enabled) if (!err) { const char wakeMessage(WAKE_MESSAGE); int result = write(mWritePipeFd, &wakeMessage, 1); - LOGE_IF(result<0, "error sending wake message (%s)", strerror(errno)); + ALOGE_IF(result<0, "error sending wake message (%s)", strerror(errno)); } return err; } @@ -306,14 +306,14 @@ int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count) n = poll(mPollFds, numFds, nbEvents ? 0 : polltime); } while (n < 0 && errno == EINTR); if (n<0) { - LOGE("poll() failed (%s)", strerror(errno)); + ALOGE("poll() failed (%s)", strerror(errno)); return -errno; } if (mPollFds[wake].revents & POLLIN) { char msg; int result = read(mPollFds[wake].fd, &msg, 1); - LOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno)); - LOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg)); + ALOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno)); + ALOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg)); mPollFds[wake].revents = 0; } if(mPollFds[mpl_power].revents & POLLIN) { diff --git a/media_codecs.xml b/media_codecs.xml new file mode 100644 index 0000000..af21aa4 --- /dev/null +++ b/media_codecs.xml @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- +<!DOCTYPE MediaCodecs [ +<!ELEMENT MediaCodecs (Decoders,Encoders)> +<!ELEMENT Decoders (MediaCodec*)> +<!ELEMENT Encoders (MediaCodec*)> +<!ELEMENT MediaCodec (Type*,Quirk*)> +<!ATTLIST MediaCodec name CDATA #REQUIRED> +<!ATTLIST MediaCodec type CDATA> +<!ELEMENT Type EMPTY> +<!ATTLIST Type name CDATA #REQUIRED> +<!ELEMENT Quirk EMPTY> +<!ATTLIST Quirk name CDATA #REQUIRED> +]> + +There's a simple and a complex syntax to declare the availability of a +media codec: + +A codec that properly follows the OpenMax spec and therefore doesn't have any +quirks and that only supports a single content type can be declared like so: + + <MediaCodec name="OMX.foo.bar" type="something/interesting" /> + +If a codec has quirks OR supports multiple content types, the following syntax +can be used: + + <MediaCodec name="OMX.foo.bar" > + <Type name="something/interesting" /> + <Type name="something/else" /> + ... + <Quirk name="requires-allocate-on-input-ports" /> + <Quirk name="requires-allocate-on-output-ports" /> + <Quirk name="output-buffers-are-unreadable" /> + </MediaCodec> + +Only the three quirks included above are recognized at this point: + +"requires-allocate-on-input-ports" + must be advertised if the component does not properly support specification + of input buffers using the OMX_UseBuffer(...) API but instead requires + OMX_AllocateBuffer to be used. + +"requires-allocate-on-output-ports" + must be advertised if the component does not properly support specification + of output buffers using the OMX_UseBuffer(...) API but instead requires + OMX_AllocateBuffer to be used. + +"output-buffers-are-unreadable" + must be advertised if the emitted output buffers of a decoder component + are not readable, i.e. use a custom format even though abusing one of + the official OMX colorspace constants. + Clients of such decoders will not be able to access the decoded data, + naturally making the component much less useful. The only use for + a component with this quirk is to render the output to the screen. + Audio decoders MUST NOT advertise this quirk. + Video decoders that advertise this quirk must be accompanied by a + corresponding color space converter for thumbnail extraction, + matching surfaceflinger support that can render the custom format to + a texture and possibly other code, so just DON'T USE THIS QUIRK. + +--> + +<MediaCodecs> + <Decoders> + <MediaCodec name="OMX.TI.DUCATI1.VIDEO.DECODER" > + <Type name="video/mp4v-es" /> + <Type name="video/3gpp" /> + <Type name="video/avc" /> + <Quirk name="requires-allocate-on-input-ports" /> + <Quirk name="requires-allocate-on-output-ports" /> + </MediaCodec> + + <MediaCodec name="OMX.google.mp3.decoder" type="audio/mpeg" /> + <MediaCodec name="OMX.google.amrnb.decoder" type="audio/3gpp" /> + <MediaCodec name="OMX.google.amrwb.decoder" type="audio/amr-wb" /> + <MediaCodec name="OMX.google.aac.decoder" type="audio/mp4a-latm" /> + <MediaCodec name="OMX.google.g711.alaw.decoder" type="audio/g711-alaw" /> + <MediaCodec name="OMX.google.g711.mlaw.decoder" type="audio/g711-mlaw" /> + <MediaCodec name="OMX.google.vorbis.decoder" type="audio/vorbis" /> + + <MediaCodec name="OMX.google.mpeg4.decoder" type="video/mp4v-es" /> + <MediaCodec name="OMX.google.h263.decoder" type="video/3gpp" /> + <MediaCodec name="OMX.google.h264.decoder" type="video/avc" /> + <MediaCodec name="OMX.google.vpx.decoder" type="video/x-vnd.on2.vp8" /> + </Decoders> + + <Encoders> + <MediaCodec name="OMX.TI.DUCATI1.VIDEO.MPEG4E" > + <Type name="video/mp4v-es" /> + <Type name="video/3gpp" /> + <Quirk name="requires-allocate-on-input-ports" /> + <Quirk name="requires-allocate-on-output-ports" /> + </MediaCodec> + + <MediaCodec name="OMX.TI.DUCATI1.VIDEO.H264E" type="video/avc" > + <Quirk name="requires-allocate-on-input-ports" /> + <Quirk name="requires-allocate-on-output-ports" /> + </MediaCodec> + + <MediaCodec name="OMX.google.amrnb.encoder" type="audio/3gpp" /> + <MediaCodec name="OMX.google.amrwb.encoder" type="audio/amr-wb" /> + <MediaCodec name="OMX.google.aac.encoder" type="audio/mp4a-latm" /> + </Encoders> +</MediaCodecs> diff --git a/media_profiles.xml b/media_profiles.xml index 02058a5..5769e2b 100755 --- a/media_profiles.xml +++ b/media_profiles.xml @@ -149,11 +149,11 @@ channels="1" /> </EncoderProfile> - <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30"> + <EncoderProfile quality="timelapseqvga" fileFormat="mp4" duration="30"> <Video codec="h264" bitRate="192000" - width="176" - height="144" + width="320" + height="240" frameRate="30" /> <!-- audio setting is ignored --> <Audio codec="amrnb" @@ -271,11 +271,11 @@ channels="1" /> </EncoderProfile> - <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30"> + <EncoderProfile quality="timelapseqvga" fileFormat="mp4" duration="30"> <Video codec="h264" bitRate="192000" - width="176" - height="144" + width="320" + height="240" frameRate="30" /> <!-- audio setting is ignored --> <Audio codec="amrnb" @@ -367,7 +367,7 @@ minChannels="1" maxChannels="1" /> <AudioEncoderCap name="amrnb" enabled="true" - minBitRate="5525" maxBitRate="12200" + minBitRate="4750" maxBitRate="12200" minSampleRate="8000" maxSampleRate="8000" minChannels="1" maxChannels="1" /> diff --git a/nfc/nfc_hw.c b/nfc/nfc_hw.c index 99adc29..cd26be5 100644 --- a/nfc/nfc_hw.c +++ b/nfc/nfc_hw.c @@ -31,8 +31,6 @@ static uint8_t pn544_eedata_settings[][4] = { ,{0x00,0x9B,0xD6,0x1E} // GSP setting for this threshold ,{0x00,0x9B,0xDD,0x1C} // GSP setting for this threshold ,{0x00,0x9B,0x84,0x13} // ANACM2 setting - ,{0x00,0x99,0x81,0x7F} // ANAVMID setting PCD - ,{0x00,0x99,0x31,0x70} // ANAVMID setting PICC #ifdef maguro // Maguro load modulation settings ,{0x00,0x99,0x29,0xF4} // Type A load modulation amplitude fine tuning @@ -86,8 +84,8 @@ static uint8_t pn544_eedata_settings[][4] = { ,{0x00,0x9C,0x12,0x00} // ,{0x00,0x9C,0x13,0x00} // - //WTX for LLCP communication - ,{0x00,0x98,0xA2,0x0E} // Max value: 14 (default value: 09) + // NFC-DEP Target Waiting Time (WT) + ,{0x00,0x98,0xA2,0x08} // Set to 0x08 as required by [digital] (default value: 09) //SE GPIO ,{0x00, 0x98, 0x93, 0x40} diff --git a/overlay/frameworks/base/core/res/res/values/config.xml b/overlay/frameworks/base/core/res/res/values/config.xml index 1af8aad..5b1f566 100644 --- a/overlay/frameworks/base/core/res/res/values/config.xml +++ b/overlay/frameworks/base/core/res/res/values/config.xml @@ -41,10 +41,10 @@ <bool name="config_unplugTurnsOnScreen">true</bool> <!-- Component name of the service providing network location support. --> - <string name="config_networkLocationProvider">com.google.android.location.NetworkLocationProvider</string> + <string name="config_networkLocationProvider" translatable="false">com.google.android.location.NetworkLocationProvider</string> <!-- Component name of the service providing geocoder API support. --> - <string name="config_geocodeProvider">com.google.android.location.GeocodeProvider</string> + <string name="config_geocodeProvider" translatable="false">com.google.android.location.GeocodeProvider</string> <!-- Flag indicating whether we should enable the automatic brightness in Settings. config_hardware_automatic_brightness_available is not set, so we will use software implementation --> @@ -239,17 +239,17 @@ <bool name="config_ui_enableFadingMarquee">false</bool> <!-- Component name of the service providing network location support. --> - <string name="config_networkLocationProvider">com.google.android.location.NetworkLocationProvider</string> + <string name="config_networkLocationProvider" translatable="false">com.google.android.location.NetworkLocationProvider</string> <!-- Component name of the service providing geocoder API support. --> - <string name="config_geocodeProvider">com.google.android.location.GeocodeProvider</string> + <string name="config_geocodeProvider" translatable="false">com.google.android.location.GeocodeProvider</string> <!-- Is the notification LED intrusive? Used to decide if there should be a disable option --> <bool name="config_intrusiveNotificationLed">true</bool> <!-- Component name of the default wallpaper. This will be ImageWallpaper if not specified --> - <string name="default_wallpaper_component">com.android.phasebeam/.PhaseBeamWallpaper</string> + <string name="default_wallpaper_component" translatable="false">com.android.phasebeam/.PhaseBeamWallpaper</string> <!-- Vibrator pattern for feedback about touching a virtual key --> <integer-array name="config_virtualKeyVibePattern"> diff --git a/overlay/frameworks/base/core/res/res/xml/storage_list.xml b/overlay/frameworks/base/core/res/res/xml/storage_list.xml index 043530d..0a03928 100644 --- a/overlay/frameworks/base/core/res/res/xml/storage_list.xml +++ b/overlay/frameworks/base/core/res/res/xml/storage_list.xml @@ -33,7 +33,7 @@ --> <StorageList xmlns:android="http://schemas.android.com/apk/res/android"> - <storage android:mountPoint="/mnt/sdcard" + <storage android:mountPoint="/storage/sdcard0" android:storageDescription="@string/storage_internal" android:primary="true" android:emulated="true" diff --git a/overlay/packages/apps/Settings/res/values-pl/arrays.xml b/overlay/packages/apps/Settings/res/values-pl/arrays.xml index 265da14..3028803 100644 --- a/overlay/packages/apps/Settings/res/values-pl/arrays.xml +++ b/overlay/packages/apps/Settings/res/values-pl/arrays.xml @@ -21,11 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string-array name="screen_timeout_entries"> - <item msgid="5314770629356662739">"15 sekund"</item> - <item msgid="8672738773876256432">"30 sekund"</item> - <item msgid="465923292941002466">"1 minuta"</item> - <item msgid="7955177189296850016">"2 minuty"</item> - <item msgid="1244255986255344525">"5 minut"</item> - <item msgid="294890536998091748">"10 minut"</item> + <item msgid="5314770629356662739">"15 sek."</item> + <item msgid="8672738773876256432">"30 sek."</item> + <item msgid="465923292941002466">"1 min."</item> + <item msgid="7955177189296850016">"2 min."</item> + <item msgid="1244255986255344525">"5 min."</item> + <item msgid="294890536998091748">"10 min."</item> </string-array> </resources> diff --git a/overlay/packages/apps/Settings/res/values/bools.xml b/overlay/packages/apps/Settings/res/values/bools.xml index b5e8b7b..711eb51 100644 --- a/overlay/packages/apps/Settings/res/values/bools.xml +++ b/overlay/packages/apps/Settings/res/values/bools.xml @@ -17,4 +17,6 @@ <resources> <!-- Show dock settings when docked --> <bool name="has_dock_settings">true</bool> + <!-- Enable user management --> + <bool name="enable_user_management">true</bool> </resources> diff --git a/power/Android.mk b/power/Android.mk new file mode 100644 index 0000000..da60418 --- /dev/null +++ b/power/Android.mk @@ -0,0 +1,27 @@ +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +LOCAL_PATH := $(call my-dir) + +# HAL module implemenation stored in +# hw/<POWERS_HARDWARE_MODULE_ID>.<ro.hardware>.so +include $(CLEAR_VARS) + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_SHARED_LIBRARIES := liblog libcutils +LOCAL_SRC_FILES := power_tuna.c +LOCAL_MODULE := power.tuna +LOCAL_MODULE_TAGS := optional +include $(BUILD_SHARED_LIBRARY) diff --git a/power/power_tuna.c b/power/power_tuna.c new file mode 100644 index 0000000..eb38410 --- /dev/null +++ b/power/power_tuna.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#define LOG_TAG "Tuna PowerHAL" +#include <utils/Log.h> + +#include <hardware/hardware.h> +#include <hardware/power.h> + +/* + * Tuna uses the legacy interface for requesting early suspend and late resume. + */ + +#define LEGACY_SYS_POWER_STATE "/sys/power/state" + +static int sPowerStatefd; +static const char *pwr_states[] = { "mem", "on" }; + +static void sysfs_write(char *path, char *s) +{ + char buf[80]; + int len; + int fd = open(path, O_WRONLY); + + if (fd < 0) { + strerror_r(errno, buf, sizeof(buf)); + ALOGE("Error opening %s: %s\n", path, buf); + return; + } + + len = write(fd, s, strlen(s)); + if (len < 0) { + strerror_r(errno, buf, sizeof(buf)); + ALOGE("Error writing to %s: %s\n", path, buf); + } + + close(fd); +} + +static void tuna_power_init(struct power_module *module) +{ + char buf[80]; + + sPowerStatefd = open(LEGACY_SYS_POWER_STATE, O_RDWR); + + if (sPowerStatefd < 0) { + strerror_r(errno, buf, sizeof(buf)); + ALOGE("Error opening %s: %s\n", LEGACY_SYS_POWER_STATE, buf); + } + + /* + * cpufreq interactive governor: timer 20ms, min sample 100ms, + * hispeed 700MHz at load 40% + */ + + sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate", + "20000"); + sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/min_sample_time", + "100000"); + sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq", + "700000"); + sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load", + "40"); + sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay", + "100000"); +} + +static void tuna_power_set_interactive(struct power_module *module, int on) +{ + char buf[80]; + int len; + + /* + * Lower maximum frequency when screen is off. CPU 0 and 1 share a + * cpufreq policy. + */ + + sysfs_write("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", + on ? "1200000" : "700000"); + + len = write(sPowerStatefd, pwr_states[!!on], strlen(pwr_states[!!on])); + if (len < 0) { + strerror_r(errno, buf, sizeof(buf)); + ALOGE("Error writing to %s: %s\n", LEGACY_SYS_POWER_STATE, buf); + } +} + + +static struct hw_module_methods_t power_module_methods = { + .open = NULL, +}; + +struct power_module HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .version_major = 1, + .version_minor = 0, + .id = POWER_HARDWARE_MODULE_ID, + .name = "Tuna Power HAL", + .author = "The Android Open Source Project", + .methods = &power_module_methods, + }, + + .init = tuna_power_init, + .setInteractive = tuna_power_set_interactive, +}; diff --git a/recovery/Android.mk b/recovery/Android.mk index 2fc8313..770feee 100644 --- a/recovery/Android.mk +++ b/recovery/Android.mk @@ -5,7 +5,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := eng LOCAL_C_INCLUDES += bootable/recovery -LOCAL_SRC_FILES := recovery_ui.c +LOCAL_SRC_FILES := recovery_ui.cpp # should match TARGET_RECOVERY_UI_LIB set in BoardConfig.mk LOCAL_MODULE := librecovery_ui_tuna diff --git a/recovery/recovery_ui.c b/recovery/recovery_ui.c deleted file mode 100644 index 50f8383..0000000 --- a/recovery/recovery_ui.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <linux/input.h> -#include <sys/stat.h> -#include <errno.h> -#include <string.h> - -#include "recovery_ui.h" -#include "common.h" - -char* MENU_HEADERS[] = { "Volume up/down to move highlight;", - "power button to select.", - "", - NULL }; - -char* MENU_ITEMS[] = { "reboot system now", - "apply update from /cache", - "wipe data/factory reset", - "wipe cache partition", - NULL }; - -void device_ui_init(UIParameters* ui_parameters) { -} - -int device_recovery_start() { - // recovery can get started before the kernel has created the EMMC - // devices, which will make the wipe_data operation fail (trying - // to open a device that doesn't exist). Hold up the start of - // recovery for up to 5 seconds waiting for the userdata partition - // block device to exist. - - const char* fn = "/dev/block/platform/omap/omap_hsmmc.0/by-name/userdata"; - - int tries = 0; - int ret; - struct stat buf; - do { - ++tries; - ret = stat(fn, &buf); - if (ret) { - printf("try %d: %s\n", tries, strerror(errno)); - sleep(1); - } - } while (ret && tries < 5); - if (!ret) { - printf("stat() of %s succeeded on try %d\n", fn, tries); - } else { - printf("failed to stat %s\n", fn); - } - - // We let recovery attempt to carry on even if the stat never - // succeeded. - - return 0; -} - -int device_toggle_display(volatile char* key_pressed, int key_code) { - // hold power and press volume-up - return key_pressed[KEY_POWER] && key_code == KEY_VOLUMEUP; -} - -int device_reboot_now(volatile char* key_pressed, int key_code) { - // Reboot if the power key is pressed five times in a row, with - // no other keys in between. - static int presses = 0; - if (key_code == KEY_POWER) { // power button - ++presses; - return presses == 5; - } else { - presses = 0; - return 0; - } -} - -int device_handle_key(int key_code, int visible) { - if (visible) { - switch (key_code) { - case KEY_DOWN: - case KEY_VOLUMEDOWN: - return HIGHLIGHT_DOWN; - - case KEY_UP: - case KEY_VOLUMEUP: - return HIGHLIGHT_UP; - - case KEY_ENTER: - case KEY_POWER: // crespo power - return SELECT_ITEM; - } - } - - return NO_ACTION; -} - -int device_perform_action(int which) { - return which == 1 ? ITEM_APPLY_CACHE : which; -} - -int device_wipe_data() { - return 0; -} diff --git a/recovery/recovery_ui.cpp b/recovery/recovery_ui.cpp new file mode 100644 index 0000000..0c8b8f9 --- /dev/null +++ b/recovery/recovery_ui.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <linux/input.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> + +#include "common.h" +#include "device.h" +#include "screen_ui.h" + +const char* HEADERS[] = { "Volume up/down to move highlight;", + "power button to select.", + "", + NULL }; + +const char* ITEMS[] = { "reboot system now", + "apply update from ADB", + "apply update from USB drive", + "wipe data/factory reset", + "wipe cache partition", + NULL }; + +class TunaUI : public ScreenRecoveryUI { + public: + TunaUI() : + consecutive_power_keys(0) { + } + + virtual KeyAction CheckKey(int key) { + if (IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) { + return TOGGLE; + } + if (key == KEY_POWER) { + ++consecutive_power_keys; + if (consecutive_power_keys >= 7) { + return REBOOT; + } + } else { + consecutive_power_keys = 0; + } + return ENQUEUE; + } + + private: + int consecutive_power_keys; +}; + + +class TunaDevice : public Device { + public: + TunaDevice() : + ui(new TunaUI) { + } + + RecoveryUI* GetUI() { return ui; } + + int HandleMenuKey(int key_code, int visible) { + if (visible) { + switch (key_code) { + case KEY_DOWN: + case KEY_VOLUMEDOWN: + return kHighlightDown; + + case KEY_UP: + case KEY_VOLUMEUP: + return kHighlightUp; + + case KEY_POWER: + return kInvokeItem; + } + } + + return kNoAction; + } + + BuiltinAction InvokeMenuItem(int menu_position) { + switch (menu_position) { + case 0: return REBOOT; + case 1: return APPLY_ADB_SIDELOAD; + case 2: return APPLY_EXT; + case 3: return WIPE_DATA; + case 4: return WIPE_CACHE; + default: return NO_ACTION; + } + } + + const char* const* GetMenuHeaders() { return HEADERS; } + const char* const* GetMenuItems() { return ITEMS; } + + private: + RecoveryUI* ui; +}; + +Device* make_device() { + return new TunaDevice; +} diff --git a/sii9234_rcp.kcm b/sii9234_rcp.kcm new file mode 100644 index 0000000..6fc2422 --- /dev/null +++ b/sii9234_rcp.kcm @@ -0,0 +1,15 @@ +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +type SPECIAL_FUNCTION diff --git a/sii9234_rcp.kl b/sii9234_rcp.kl new file mode 100644 index 0000000..12589f8 --- /dev/null +++ b/sii9234_rcp.kl @@ -0,0 +1,49 @@ +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +key 353 DPAD_CENTER +key 103 DPAD_UP +key 108 DPAD_DOWN +key 105 DPAD_LEFT +key 106 DPAD_RIGHT + +key 139 MENU + +key 174 BACK + +key 512 NUMPAD_0 +key 513 NUMPAD_1 +key 514 NUMPAD_2 +key 515 NUMPAD_3 +key 516 NUMPAD_4 +key 517 NUMPAD_5 +key 518 NUMPAD_6 +key 519 NUMPAD_7 +key 520 NUMPAD_8 +key 521 NUMPAD_9 +key 52 NUMPAD_DOT +key 28 NUMPAD_ENTER +key 355 CLEAR + +key 207 MEDIA_PLAY +key 128 MEDIA_STOP +key 164 MEDIA_PLAY_PAUSE + +key 168 MEDIA_REWIND +key 208 MEDIA_FAST_FORWARD + +key 163 MEDIA_NEXT +key 165 MEDIA_PREVIOUS + +key 119 MEDIA_PAUSE |