From 8137654e8f6f82196b4697f6c5df95436ca3d706 Mon Sep 17 00:00:00 2001 From: Markinus Date: Mon, 30 Aug 2010 12:48:18 +0200 Subject: [PATCH] Revert "htcleo: add audio drivers, qdsp6 modifications and enhanced venc driver" This reverts commit b739bce6290e5e21b4a90a3efaef4b3178c873fc. Conflicts: arch/arm/configs/htcleo_defconfig arch/arm/mach-msm/Makefile arch/arm/mach-msm/board-htcleo.c --- arch/arm/configs/htcleo_defconfig | 8 +- arch/arm/mach-msm/Makefile | 3 +- arch/arm/mach-msm/board-htcleo-acoustic.c | 247 -- arch/arm/mach-msm/board-htcleo-audio.c | 330 --- arch/arm/mach-msm/board-htcleo-hds.c | 351 --- arch/arm/mach-msm/board-htcleo.c | 2 - .../mach-msm/include/mach/msm_qdsp6_audio.h | 4 +- arch/arm/mach-msm/qdsp6/Makefile | 10 +- arch/arm/mach-msm/qdsp6/aac_in.c | 217 -- arch/arm/mach-msm/qdsp6/audio_ctl.c | 39 +- arch/arm/mach-msm/qdsp6/dal.c | 228 +- arch/arm/mach-msm/qdsp6/dal.h | 18 +- arch/arm/mach-msm/qdsp6/dal_acdb.h | 6 +- arch/arm/mach-msm/qdsp6/dal_adie.h | 6 +- arch/arm/mach-msm/qdsp6/dal_audio.h | 295 +- arch/arm/mach-msm/qdsp6/mp3.c | 10 - arch/arm/mach-msm/qdsp6/msm_q6vdec.c | 113 +- arch/arm/mach-msm/qdsp6/msm_q6venc.c | 1695 +++++++---- arch/arm/mach-msm/qdsp6/pcm_in.c | 23 +- arch/arm/mach-msm/qdsp6/pcm_out.c | 39 +- arch/arm/mach-msm/qdsp6/q6audio.c | 303 +- arch/arm/mach-msm/qdsp6/q6audio_htcleo.c | 2634 ----------------- arch/arm/mach-msm/qdsp6/qcelp_in.c | 212 -- include/linux/msm_q6venc.h | 368 ++- 24 files changed, 2027 insertions(+), 5134 deletions(-) delete mode 100644 arch/arm/mach-msm/board-htcleo-acoustic.c delete mode 100644 arch/arm/mach-msm/board-htcleo-audio.c delete mode 100644 arch/arm/mach-msm/board-htcleo-hds.c delete mode 100644 arch/arm/mach-msm/qdsp6/aac_in.c delete mode 100644 arch/arm/mach-msm/qdsp6/q6audio_htcleo.c delete mode 100644 arch/arm/mach-msm/qdsp6/qcelp_in.c diff --git a/arch/arm/configs/htcleo_defconfig b/arch/arm/configs/htcleo_defconfig index aba9cc88..b805ec89 100644 --- a/arch/arm/configs/htcleo_defconfig +++ b/arch/arm/configs/htcleo_defconfig @@ -220,8 +220,8 @@ CONFIG_MACH_HTCLEO=y CONFIG_HTC_35MM_JACK=y # CONFIG_HTC_PWRSPLY is not set # CONFIG_HTC_PWRSINK is not set -CONFIG_MSM_DALRPC=y # CONFIG_MSM_DALRPC_TEST is not set +# CONFIG_MSM_DALRPC is not set CONFIG_CACHE_FLUSH_RANGE_LIMIT=0x40000 CONFIG_MSM7X00A_USE_GP_TIMER=y # CONFIG_MSM7X00A_USE_DG_TIMER is not set @@ -251,10 +251,7 @@ CONFIG_MSM_RPCSERVERS=y # CONFIG_MSM_CPU_FREQ_SCREEN is not set # CONFIG_MSM_HW3D is not set CONFIG_MSM_QDSP6=y -CONFIG_QSD_AUDIO=y -CONFIG_QSD_HTC_FM=y # CONFIG_MSM_CLOCK_CTRL_DEBUG is not set -CONFIG_ARCH_MSM_FLASHLIGHT=y CONFIG_WIFI_CONTROL_FUNC=y CONFIG_WIFI_MEM_PREALLOC=y CONFIG_WIFI_NVS_PROC_CREATE=y @@ -265,8 +262,7 @@ CONFIG_HTCLEO_ENABLE_MULTI_TOUCH=y # CONFIG_ENABLE_BRAVO_UART_DRV is not set # CONFIG_ENABLE_USE_DESIRE_AMSS is not set CONFIG_PHYS_OFFSET=0x11800000 -# CONFIG_HTC_ACOUSTIC is not set -# CONFIG_HTC_ACOUSTIC_QSD is not set + # # Processor Type # diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 172dcccb..4ea17310 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -112,7 +112,8 @@ obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-microp.o clock.o obj-$(CONFIG_MACH_HTCLEO) += board-htcleo.o board-htcleo-spi.o board-htcleo-panel.o board-htcleo-keypad.o obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-ts.o board-htcleo-mmc.o ieee754-df.o board-htcleo-power.o -obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-battery.o board-htcleo-log.o board-htcleo-acoustic.o board-htcleo-audio.o + +obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-battery.o board-htcleo-log.o obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-bt.o board-htcleo-microp.o board-htcleo-wifi.o obj-$(CONFIG_MACH_HTCLEO) += clock-wince.o diff --git a/arch/arm/mach-msm/board-htcleo-acoustic.c b/arch/arm/mach-msm/board-htcleo-acoustic.c deleted file mode 100644 index 2760e847..00000000 --- a/arch/arm/mach-msm/board-htcleo-acoustic.c +++ /dev/null @@ -1,247 +0,0 @@ -/* arch/arm/mach-msm/board-htcleo-acoustic.c - * - * Copyright (C) 2010 Cotulla - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "smd_private.h" -#include "dex_comm.h" - -#define ACOUSTIC_IOCTL_MAGIC 'p' -#define ACOUSTIC_UPDATE_ADIE \ - _IOW(ACOUSTIC_IOCTL_MAGIC, 24, unsigned int) - - -#define HTC_ACOUSTIC_TABLE_SIZE (0x20000) - -#define D(fmt, args...) printk(KERN_INFO "htc-acoustic: "fmt, ##args) -#define E(fmt, args...) printk(KERN_ERR "htc-acoustic: "fmt, ##args) - -static uint32_t htc_acoustic_vir_addr; -static struct mutex api_lock; -static struct qsd_acoustic_ops *the_ops; - -void acoustic_register_ops(struct qsd_acoustic_ops *ops) -{ - the_ops = ops; -} - -int turn_mic_bias_on(int on) -{ - D("%s called %d\n", __func__, on); - if (the_ops->enable_mic_bias) - the_ops->enable_mic_bias(on); - return 0; -} -EXPORT_SYMBOL(turn_mic_bias_on); - -int force_headset_speaker_on(int enable) -{ - printk("force_headset_speaker_on((%d)\n", enable); - - if (enable) - dex_audio(0x53); - else - dex_audio(0x54); - - return 0; -} -EXPORT_SYMBOL(force_headset_speaker_on); - -int enable_aux_loopback(uint32_t enable) -{ - printk("enable_aux_loopback(%d)\n", enable); - - if (enable) - dex_audio(0x51); - else - dex_audio(0x52); - - return 0; -} -EXPORT_SYMBOL(enable_aux_loopback); - -int set_aux_gain(int level) -{ - /* struct aux_gain_req { - struct rpc_request_hdr hdr; - int level; - } aux_req; - - D("%s called %d\n", __func__, level); - - if (is_rpc_connect() == -1) - return -1; - - aux_req.level = cpu_to_be32(level); - return msm_rpc_call(endpoint, - ONCRPC_SET_AUX_PGA_GAIN_PROC, - &aux_req, sizeof(aux_req), 5 * HZ);*/ - return 0; -} -EXPORT_SYMBOL(set_aux_gain); - - -static int acoustic_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned long pgoff; - int rc = -EINVAL; - size_t size; - - D("mmap\n"); - - mutex_lock(&api_lock); - - size = vma->vm_end - vma->vm_start; - - if (vma->vm_pgoff != 0) { - E("mmap failed: page offset %lx\n", vma->vm_pgoff); - goto done; - } - - if (!htc_acoustic_vir_addr) { - E("mmap failed: smem region not allocated\n"); - rc = -EIO; - goto done; - } - - pgoff = MSM_SHARED_RAM_PHYS + - (htc_acoustic_vir_addr - (uint32_t)MSM_SHARED_RAM_BASE); - pgoff = ((pgoff + 4095) & ~4095); - htc_acoustic_vir_addr = ((htc_acoustic_vir_addr + 4095) & ~4095); - - if (pgoff <= 0) { - E("pgoff wrong. %ld\n", pgoff); - goto done; - } - - if (size <= HTC_ACOUSTIC_TABLE_SIZE) { - pgoff = pgoff >> PAGE_SHIFT; - } else { - E("size > HTC_ACOUSTIC_TABLE_SIZE %d\n", size); - goto done; - } - - vma->vm_flags |= VM_IO | VM_RESERVED; - rc = io_remap_pfn_range(vma, vma->vm_start, pgoff, - size, vma->vm_page_prot); - - if (rc < 0) - E("mmap failed: remap error %d\n", rc); - -done: mutex_unlock(&api_lock); - return rc; -} - -static int acoustic_open(struct inode *inode, struct file *file) -{ - int rc = -EIO; - - D("open\n"); - - mutex_lock(&api_lock); - - if (!htc_acoustic_vir_addr) - { - htc_acoustic_vir_addr = (uint32_t)MSM_SHARED_RAM_BASE + 0xF8000; - } - - rc = 0; - mutex_unlock(&api_lock); - return rc; -} - -static int acoustic_release(struct inode *inode, struct file *file) -{ - D("release\n"); - return 0; -} - -static long acoustic_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int rc = 0; - - D("ioctl\n"); - - mutex_lock(&api_lock); - - switch (cmd) { - case ACOUSTIC_UPDATE_ADIE: - { - unsigned data = 0xE5; - - D("ioctl: ACOUSTIC_UPDATE_ADIE called %d.\n", current->pid); - -// CotullaTODO: finish this code. if we need android tables really... - - D("ioctl: done.\n"); - break; - } - default: - E("ioctl: invalid command\n"); - rc = -EINVAL; - } - - mutex_unlock(&api_lock); - return rc; -} - -struct rpc_set_uplink_mute_args { - int mute; -}; - -static struct file_operations acoustic_fops = { - .owner = THIS_MODULE, - .open = acoustic_open, - .release = acoustic_release, - .mmap = acoustic_mmap, - .unlocked_ioctl = acoustic_ioctl, -}; - -static struct miscdevice acoustic_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "htc-acoustic", - .fops = &acoustic_fops, -}; - -static int __init acoustic_init(void) -{ - mutex_init(&api_lock); - return misc_register(&acoustic_misc); -} - -static void __exit acoustic_exit(void) -{ - misc_deregister(&acoustic_misc); -} - -module_init(acoustic_init); -module_exit(acoustic_exit); - diff --git a/arch/arm/mach-msm/board-htcleo-audio.c b/arch/arm/mach-msm/board-htcleo-audio.c deleted file mode 100644 index c92ce2de..00000000 --- a/arch/arm/mach-msm/board-htcleo-audio.c +++ /dev/null @@ -1,330 +0,0 @@ -/* arch/arm/mach-msm/board-htcleo-audio.c - * - * Copyright (C) 2010 Cotulla - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "board-htcleo.h" -#include "devices.h" -#include "dex_comm.h" -#include "proc_comm.h" -#include "pmic.h" - - -#if 1 -#define D(fmt, args...) printk(KERN_INFO "Audio: "fmt, ##args) -#else -#define D(fmt, args...) do {} while (0) -#endif - -static struct mutex mic_lock; -static struct mutex bt_sco_lock; - -#if 1 - -// LEO -static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = -{ - [Q6_HW_HANDSET] = - { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_HEADSET] = - { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_SPEAKER] = - { - .min_gain = -1000, - .max_gain = 500, - }, - [Q6_HW_TTY] = - { - .min_gain = 0, - .max_gain = 0, - }, - [Q6_HW_BT_SCO] = - { - .min_gain = -1100, - .max_gain = 400, - }, - [Q6_HW_BT_A2DP] = - { - .min_gain = -1100, - .max_gain = 400, - }, -}; - -#else - -// old desire one -static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = -{ - [Q6_HW_HANDSET] = { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_HEADSET] = { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_SPEAKER] = { - .min_gain = -1500, - .max_gain = 0, - }, - [Q6_HW_TTY] = { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_BT_SCO] = { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_BT_A2DP] = { - .min_gain = -2000, - .max_gain = 0, - }, -}; - -#endif - -void htcleo_headset_enable(int en) -{ - D("%s %d\n", __func__, en); - /* enable audio amp */ - if (en) mdelay(60); - gpio_set_value(HTCLEO_AUD_JACKHP_EN, !!en); -} - -void htcleo_speaker_enable(int en) -{ - struct spkr_config_mode scm; - memset(&scm, 0, sizeof(scm)); - - D("%s %d\n", __func__, en); - if (en) - { - scm.is_right_chan_en = 0; - scm.is_left_chan_en = 1; - scm.is_stereo_en = 0; - scm.is_hpf_en = 0; //1; // CotullaTODO: check it - pmic_spkr_en_mute(LEFT_SPKR, 0); - pmic_spkr_en_mute(RIGHT_SPKR, 0); - pmic_set_spkr_configuration(&scm); - pmic_spkr_set_mux_hpf_corner_freq(SPKR_FREQ_0_76KHZ); - pmic_spkr_en(LEFT_SPKR, 1); - pmic_spkr_en(RIGHT_SPKR, 0); - - pmic_spkr_en_hpf(ON_CMD); // +LEO - - /* unmute */ - pmic_spkr_en_mute(LEFT_SPKR, 1); - mdelay(40); - } - else - { - pmic_spkr_en_mute(LEFT_SPKR, 0); - - pmic_spkr_en_hpf(OFF_CMD); // +LEO - pmic_spkr_en(LEFT_SPKR, 0); - pmic_spkr_en(RIGHT_SPKR, 0); - - pmic_set_spkr_configuration(&scm); - } -} - -void htcleo_receiver_enable(int en) -{ -// if (is_cdma_version(system_rev) && -// ((system_rev == 0xC1) || (system_rev == 0xC2))) { - struct spkr_config_mode scm; - memset(&scm, 0, sizeof(scm)); - - D("%s %d\n", __func__, en); - if (en) - { - scm.is_right_chan_en = 1; - scm.is_left_chan_en = 0; - scm.is_stereo_en = 0; - scm.is_hpf_en = 1; - pmic_spkr_en_mute(RIGHT_SPKR, 0); - pmic_set_spkr_configuration(&scm); - pmic_spkr_en(RIGHT_SPKR, 1); - - /* unmute */ - pmic_spkr_en_mute(RIGHT_SPKR, 1); - } - else - { - pmic_spkr_en_mute(RIGHT_SPKR, 0); - - pmic_spkr_en(RIGHT_SPKR, 0); - - pmic_set_spkr_configuration(&scm); - - } - // } -} - -static uint32_t bt_sco_enable[] = -{ - PCOM_GPIO_CFG(HTCLEO_BT_PCM_OUT, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), - PCOM_GPIO_CFG(HTCLEO_BT_PCM_IN, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), - PCOM_GPIO_CFG(HTCLEO_BT_PCM_SYNC, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), - PCOM_GPIO_CFG(HTCLEO_BT_PCM_CLK, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA) -}; - -static uint32_t bt_sco_disable[] = -{ - PCOM_GPIO_CFG(HTCLEO_BT_PCM_OUT, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), - PCOM_GPIO_CFG(HTCLEO_BT_PCM_IN, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), - PCOM_GPIO_CFG(HTCLEO_BT_PCM_SYNC, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), - PCOM_GPIO_CFG(HTCLEO_BT_PCM_CLK, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA) -}; - -void htcleo_bt_sco_enable(int en) -{ - static int bt_sco_refcount; - D("%s %d\n", __func__, en); - - mutex_lock(&bt_sco_lock); - if (en) - { - if (++bt_sco_refcount == 1) - { - config_gpio_table(bt_sco_enable, ARRAY_SIZE(bt_sco_enable)); - } - } - else - { - if (--bt_sco_refcount == 0) - { - config_gpio_table(bt_sco_disable, ARRAY_SIZE(bt_sco_disable)); - gpio_set_value(HTCLEO_BT_PCM_OUT, 0); - } - } - mutex_unlock(&bt_sco_lock); -} - -void htcleo_mic_enable(int en) -{ - static int old_state = 0, new_state = 0; - - D("%s %d\n", __func__, en); - - mutex_lock(&mic_lock); - if (!!en) - new_state++; - else - new_state--; - - if (new_state == 1 && old_state == 0) - { - gpio_set_value(HTCLEO_AUD_2V5_EN, 1); - mdelay(60); - } - else if (new_state == 0 && old_state == 1) - { - gpio_set_value(HTCLEO_AUD_2V5_EN, 0); - } - else - { - D("%s: do nothing %d %d\n", __func__, old_state, new_state); - } - - old_state = new_state; - mutex_unlock(&mic_lock); -} - - -void htcleo_analog_init(void) -{ - D("%s\n", __func__); - /* stereo pmic init */ - pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB); - pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB); - pmic_spkr_en_right_chan(OFF_CMD); - pmic_spkr_en_left_chan(OFF_CMD); - pmic_spkr_add_right_left_chan(OFF_CMD); - pmic_spkr_en_stereo(OFF_CMD); - pmic_spkr_select_usb_with_hpf_20hz(OFF_CMD); - pmic_spkr_bypass_mux(OFF_CMD); - pmic_spkr_en_hpf(OFF_CMD); - pmic_spkr_en_sink_curr_from_ref_volt_cir(OFF_CMD); - pmic_spkr_set_mux_hpf_corner_freq(SPKR_FREQ_0_76KHZ); - pmic_mic_set_volt(MIC_VOLT_1_80V); - - gpio_request(HTCLEO_AUD_JACKHP_EN, "aud_jackhp_en"); - gpio_request(HTCLEO_BT_PCM_OUT, "bt_pcm_out"); - - gpio_direction_output(HTCLEO_AUD_JACKHP_EN, 0); - - mutex_lock(&bt_sco_lock); - config_gpio_table(bt_sco_disable, ARRAY_SIZE(bt_sco_disable)); - gpio_direction_output(HTCLEO_BT_PCM_OUT, 0); - mutex_unlock(&bt_sco_lock); -} - -int htcleo_get_rx_vol(uint8_t hw, int level) -{ - int vol; - - if (level > 100) - level = 100; - else if (level < 0) - level = 0; - - // TODO: is it correct? - struct q6_hw_info *info; - info = &q6_audio_hw[hw]; - vol = info->min_gain + ((info->max_gain - info->min_gain) * level) / 100; - - D("%s %d\n", __func__, vol); - return vol; -} - -static struct qsd_acoustic_ops acoustic = -{ - .enable_mic_bias = htcleo_mic_enable, -}; - -static struct q6audio_analog_ops ops = -{ - .init = htcleo_analog_init, - .speaker_enable = htcleo_speaker_enable, - .headset_enable = htcleo_headset_enable, - .receiver_enable = htcleo_receiver_enable, - .bt_sco_enable = htcleo_bt_sco_enable, - .int_mic_enable = htcleo_mic_enable, - .ext_mic_enable = htcleo_mic_enable, - .get_rx_vol = htcleo_get_rx_vol, -}; - -void __init htcleo_audio_init(void) -{ - mutex_init(&mic_lock); - mutex_init(&bt_sco_lock); - q6audio_register_analog_ops(&ops); - acoustic_register_ops(&acoustic); -// q6audio_set_acdb_file("default_PMIC.acdb"); -} - -// END OF FILE diff --git a/arch/arm/mach-msm/board-htcleo-hds.c b/arch/arm/mach-msm/board-htcleo-hds.c deleted file mode 100644 index 3cbd27a6..00000000 --- a/arch/arm/mach-msm/board-htcleo-hds.c +++ /dev/null @@ -1,351 +0,0 @@ -/* board-htcleo-hds.c -* -* Copyright (C) 2010 Cotulla -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "board-htcleo.h" -#include "gpio_chip.h" - - -int microp_get_remote_adc(uint32_t *val); -int microp_set_adc_req(uint8_t value, int enable); - - -static int headset_has_mic(void); -static int enable_headset_plug_event(void); -static int enable_key_event(void); -static int disable_key_event(void); - -static struct h35mm_platform_data htcleo_h35mm_data = -{ - .plug_event_enable = enable_headset_plug_event, - .headset_has_mic = headset_has_mic, - .key_event_enable = enable_key_event, - .key_event_disable = disable_key_event, -}; - -static struct platform_device htcleo_h35mm = -{ - .name = "htc_headset", - .id = -1, - .dev = - { - .platform_data = &htcleo_h35mm_data, - }, -}; - -///////////////////////////////////////////////////////////////////////////////////////////// - -struct hds_data -{ - int inited; - int gpio_mic; - int gpio_det; - int irq_mic; - int irq_det; - int headset_is_in; - int is_hpin_pin_stable; - int last_pressed_key; - struct work_struct work_det; - struct work_struct work_mic; - struct delayed_work hpin_debounce_work; -}; - -static struct hds_data hds; -///////////////////////////////////////////////////////////////////////////////////////////// - -static int headset_detect_mic(void) -{ - return !gpio_get_value(hds.gpio_mic); -} - -static int headset_is_in(void) -{ - return !gpio_get_value(hds.gpio_det); -} - -static int get_remote_keycode(int *keycode) -{ - uint32_t val; - uint32_t btn = 0; - - microp_set_adc_req(1, 1); - if (microp_get_remote_adc(&val)) - { - // failed. who know why? ignore - *keycode = 0; - return 1; - } - - if((val >= 0) && (val <= 33)) - { - btn = 1; - } - else if((val >= 38) && (val <= 82)) - { - btn = 2; - } - else if((val >= 95) && (val <= 200)) - { - btn = 3; - } - else if(val > 200) - { - // check previous key - if (hds.last_pressed_key) - { - *keycode = hds.last_pressed_key | 0x80; - hds.last_pressed_key = 0; - return 0; - } - *keycode = 0; - return 1; - } - - hds.last_pressed_key = btn; - *keycode = btn; - return 0; -} - -static int headset_has_mic(void) -{ - int mic1 = -1; - int mic2 = -1; - int count = 0; - - mic2 = headset_detect_mic(); - - /* debounce the detection wait until 2 consecutive read are equal */ - while ((mic1 != mic2) && (count < 10)) - { - mic1 = mic2; - msleep(600); - mic2 = headset_detect_mic(); - count++; - } - - printk("%s: microphone (%d) %s\n", __func__, count, mic1 ? "present" : "not present"); - - return mic1; -} - -static int enable_headset_plug_event(void) -{ - uint16_t stat; - - enable_irq(hds.irq_det); - - // see if headset state has changed - stat = headset_is_in(); - printk("headsetisin: old %d new %d\n", hds.headset_is_in, stat); - if (hds.headset_is_in != stat) - { - hds.headset_is_in = stat; - printk("Headset state changed\n"); - htc_35mm_jack_plug_event(stat, &hds.is_hpin_pin_stable); - } - return 1; -} - -static int enable_key_event(void) -{ - printk("enable_key_event\n"); - enable_irq(hds.irq_mic); - return 0; -} - -static int disable_key_event(void) -{ - printk("disable_key_event\n"); - disable_irq(hds.irq_mic); - return 0; -} - -static void hpin_debounce_do_work(struct work_struct *work) -{ - int insert = 0; - - insert = headset_is_in(); - printk("debonce new %d old %d\n", insert, hds.headset_is_in); - if (insert != hds.headset_is_in) - { - // clear keypress state - hds.last_pressed_key = 0; - - hds.headset_is_in = insert; - printk("headset %s\n", insert ? "inserted" : "removed"); - htc_35mm_jack_plug_event(hds.headset_is_in, &hds.is_hpin_pin_stable); - } -} - - -static void det_intr_work_func(struct work_struct *work) -{ - int value1; - - printk("det_intr_work_func\n"); - hds.is_hpin_pin_stable = 0; - // TODO: - // wake_lock_timeout(µp_i2c_wakelock, 3 * HZ); - if (!hds.headset_is_in) - schedule_delayed_work(&hds.hpin_debounce_work, msecs_to_jiffies(500)); - else - schedule_delayed_work(&hds.hpin_debounce_work, msecs_to_jiffies(300)); -} - -static void mic_intr_work_func(struct work_struct *work) -{ - int keycode = 0; - int value1; - - printk("mic_intr_work_func\n"); - if ((get_remote_keycode(&keycode) == 0) && (hds.is_hpin_pin_stable)) - { - printk("keycode %d\n", keycode); - htc_35mm_key_event(keycode, &hds.is_hpin_pin_stable); - } -} - - -static irqreturn_t detect_irq_handler(int irq, void *dev_id) -{ - int value1, value2; - int retry_limit = 10; - - do - { - value1 = gpio_get_value(hds.gpio_det); - set_irq_type(hds.irq_det, value1 ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); - value2 = gpio_get_value(hds.gpio_det); - - } while (value1 != value2 && retry_limit-- > 0); - - schedule_work(&hds.work_det); - return IRQ_HANDLED; -} - -static irqreturn_t mic_irq_handler(int irq, void *dev_id) -{ - int value1, value2; - int retry_limit = 10; - - do - { - value1 = gpio_get_value(hds.gpio_mic); - set_irq_type(hds.irq_mic, value1 ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); - value2 = gpio_get_value(hds.gpio_mic); - - } while (value1 != value2 && retry_limit-- > 0); - - schedule_work(&hds.work_mic); - return IRQ_HANDLED; -} - -///////////////////////////////////////////////////////////////////////////////////////////// - -static int htcleo_hds_probe(struct platform_device *pdev) -{ - int rc = 0; - - printk("htcleo_hds_probe()\n"); - - // allow run it only once - if (hds.inited != 0) - { - return -1; - } - hds.last_pressed_key = 0; - hds.inited = 1; - hds.gpio_mic = HTCLEO_GPIO_HDS_MIC; - hds.gpio_det = HTCLEO_GPIO_HDS_DET; - - hds.irq_mic = gpio_to_irq(hds.gpio_mic); - hds.irq_det = gpio_to_irq(hds.gpio_det); - - gpio_request(hds.gpio_det, "hds_detect"); - gpio_request(hds.gpio_mic, "hds_mic"); - - gpio_direction_input(hds.gpio_det); - gpio_direction_input(hds.gpio_mic); - - hds.headset_is_in = 0; - hds.is_hpin_pin_stable = 1; - INIT_WORK(&hds.work_det, det_intr_work_func); - INIT_WORK(&hds.work_mic, mic_intr_work_func); - INIT_DELAYED_WORK(&hds.hpin_debounce_work, hpin_debounce_do_work); - - - rc = request_irq(hds.irq_det, detect_irq_handler, IRQF_DISABLED | IRQF_TRIGGER_LOW, "hds_detect_intr", 0); - rc = request_irq(hds.irq_mic, mic_irq_handler, IRQF_DISABLED | IRQF_TRIGGER_LOW, "hds_mic_intr", 0); - disable_irq(hds.irq_mic); - - platform_device_register(&htcleo_h35mm); - - return rc; -} - -static int htcleo_hds_remove(struct platform_device *dev) -{ - platform_device_unregister(&htcleo_h35mm); - - free_irq(hds.irq_det, 0); - free_irq(hds.irq_mic, 0); - - gpio_free(hds.gpio_det); - gpio_free(hds.gpio_mic); - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////// - - -static struct platform_driver htcleo_hds_driver = -{ - .probe = htcleo_hds_probe, - .remove = htcleo_hds_remove, - .driver = - { - .name = "htcleo_hds", - .owner = THIS_MODULE, - }, -}; - -static int __init htcleo_hds_init(void) -{ - return platform_driver_register(&htcleo_hds_driver); -} - -static void __exit htcleo_hds_exit(void) -{ - platform_driver_unregister(&htcleo_hds_driver); -} - -module_init(htcleo_hds_init); -module_exit(htcleo_hds_exit); - -MODULE_AUTHOR("Cotulla"); -MODULE_DESCRIPTION("HTC LEO headset driver"); -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/board-htcleo.c b/arch/arm/mach-msm/board-htcleo.c index 7c25b212..8db5c7ec 100644 --- a/arch/arm/mach-msm/board-htcleo.c +++ b/arch/arm/mach-msm/board-htcleo.c @@ -58,7 +58,6 @@ void __init htcleo_microp_init(void); #endif extern int __init htcleo_init_mmc(unsigned debug_uart); -extern void __init htcleo_audio_init(void); /////////////////////////////////////////////////////////////////////// // SPI @@ -741,7 +740,6 @@ static void __init htcleo_init(void) platform_device_register(&htcleo_timed_gpios); htcleo_bt_init(); - htcleo_audio_init(); #ifdef CONFIG_USB_ANDROID msm_hsusb_set_vbus_state(htcleo_get_vbus_state()); diff --git a/arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h b/arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h index dfc62f06..ca5e735e 100644 --- a/arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h +++ b/arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h @@ -33,8 +33,7 @@ struct audio_client { int dsp_buf; /* next buffer the DSP will touch */ int running; int session; - int open_done; - int open_status; + wait_queue_head_t wait; struct dal_client *client; @@ -92,7 +91,6 @@ int q6audio_set_tx_mute(int mute); int q6audio_reinit_acdb(char* filename); int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst); int q6audio_set_rx_volume(int level); -int q6audio_set_rx_mute(int mute); int q6audio_set_stream_volume(struct audio_client *ac, int vol); struct q6audio_analog_ops { diff --git a/arch/arm/mach-msm/qdsp6/Makefile b/arch/arm/mach-msm/qdsp6/Makefile index 624db17e..87ccfed7 100644 --- a/arch/arm/mach-msm/qdsp6/Makefile +++ b/arch/arm/mach-msm/qdsp6/Makefile @@ -1,15 +1,11 @@ obj-y += dal.o -ifndef CONFIG_ARCH_HTCLEO -obj-y += q6audio_htcleo.o -else obj-y += q6audio.o -endif obj-y += pcm_out.o obj-y += pcm_in.o obj-y += mp3.o -obj-y += routing.o +#obj-y += routing.o obj-y += audio_ctl.o obj-y += msm_q6vdec.o obj-y += msm_q6venc.o -obj-y += aac_in.o -obj-y += qcelp_in.o +#obj-y += aac_in.o +#obj-y += qcelp_in.o diff --git a/arch/arm/mach-msm/qdsp6/aac_in.c b/arch/arm/mach-msm/qdsp6/aac_in.c deleted file mode 100644 index 5c7042bc..00000000 --- a/arch/arm/mach-msm/qdsp6/aac_in.c +++ /dev/null @@ -1,217 +0,0 @@ -/* arch/arm/mach-msm/qdsp6/aac_in.c - * - * Copyright (C) 2009 Google, Inc. - * Copyright (C) 2009 HTC Corporation - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BUFSZ (4096) -#define DMASZ (BUFSZ * 2) - -#if 0 -#define TRACE(x...) pr_info("Q6: "x) -#else -#define TRACE(x...) do{}while(0) -#endif - -static DEFINE_MUTEX(aac_in_lock); -static int aac_in_opened = 0; -static struct aac_format *af; - -void audio_client_dump(struct audio_client *ac); - -static long aac_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0; - - switch (cmd) { - case AUDIO_SET_VOLUME: - break; - case AUDIO_GET_STATS: { - struct msm_audio_stats stats; - memset(&stats, 0, sizeof(stats)); - if (copy_to_user((void*) arg, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - case AUDIO_START: { - uint32_t acdb_id; - rc = 0; - - if (arg == 0) { - acdb_id = 0; - } else if (copy_from_user(&acdb_id, - (void*) arg, sizeof(acdb_id))) { - rc = -EFAULT; - break; - } - - mutex_lock(&aac_in_lock); - if (file->private_data) { - rc = -EBUSY; - } else { - file->private_data = q6audio_open_aac( - BUFSZ, 48000, AUDIO_FLAG_READ, af, acdb_id); - if (!file->private_data) - rc = -ENOMEM; - } - mutex_unlock(&aac_in_lock); - break; - } - case AUDIO_STOP: - break; - case AUDIO_FLUSH: - break; - case AUDIO_SET_CONFIG: { - struct msm_audio_config config; - if (copy_from_user(&config, (void*) arg, sizeof(config))) { - rc = -EFAULT; - break; - } - if (config.sample_rate != 48000) - pr_info("only 48KHz AAC encode supported\n"); - af->channel_config = config.channel_count; - break; - } - case AUDIO_GET_CONFIG: { - struct msm_audio_config config; - config.buffer_size = BUFSZ; - config.buffer_count = 2; - config.sample_rate = 48000; - config.channel_count = af->channel_config; - config.unused[0] = 0; - config.unused[1] = 0; - config.unused[2] = 0; - if (copy_to_user((void*) arg, &config, sizeof(config))) { - rc = -EFAULT; - } - break; - } - default: - rc = -EINVAL; - } - return rc; -} - -static int aac_in_open(struct inode *inode, struct file *file) -{ - int rc; - - pr_info("aac_in: open\n"); - mutex_lock(&aac_in_lock); - if (aac_in_opened) { - pr_err("aac_in: busy\n"); - rc = -EBUSY; - } else { - af = kzalloc(sizeof(*af), GFP_KERNEL); - memset(af, 0, sizeof(struct aac_format)); - af->sample_rate = 3; /* 48000 */ - af->channel_config = 1; - af->block_formats = AUDIO_AAC_FORMAT_ADTS; - af->audio_object_type = 2; /* CAD to ADSP format */ - af->bit_rate = 192000; - - aac_in_opened = 1; - rc = 0; - } - mutex_unlock(&aac_in_lock); - return rc; -} - -static ssize_t aac_in_read(struct file *file, char __user *buf, - size_t count, loff_t *pos) -{ - struct audio_client *ac; - struct audio_buffer *ab; - const char __user *start = buf; - int xfer, res = 0; - - mutex_lock(&aac_in_lock); - ac = file->private_data; - if (!ac) { - res = -ENODEV; - goto fail; - } - while (count > 0) { - ab = ac->buf + ac->cpu_buf; - - if (ab->used) - if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) { - audio_client_dump(ac); - pr_err("aac_read: timeout. dsp dead?\n"); - BUG(); - } - - xfer = count; - if (xfer > ab->size) - xfer = ab->size; - - if (copy_to_user(buf, ab->data, xfer)) { - res = -EFAULT; - goto fail; - } - - buf += xfer; - count -= xfer; - - ab->used = 1; - q6audio_read(ac, ab); - ac->cpu_buf ^= 1; - } -fail: - res = buf - start; - mutex_unlock(&aac_in_lock); - return res; -} - -static int aac_in_release(struct inode *inode, struct file *file) -{ - int rc = 0; - pr_info("aac_in: release\n"); - mutex_lock(&aac_in_lock); - if (file->private_data) - rc = q6audio_close(file->private_data); - kfree(af); - aac_in_opened = 0; - mutex_unlock(&aac_in_lock); - return rc; -} - -static struct file_operations aac_in_fops = { - .owner = THIS_MODULE, - .open = aac_in_open, - .read = aac_in_read, - .release = aac_in_release, - .unlocked_ioctl = aac_in_ioctl, -}; - -struct miscdevice aac_in_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_aac_in", - .fops = &aac_in_fops, -}; - -static int __init aac_in_init(void) { - return misc_register(&aac_in_misc); -} - -device_initcall(aac_in_init); diff --git a/arch/arm/mach-msm/qdsp6/audio_ctl.c b/arch/arm/mach-msm/qdsp6/audio_ctl.c index 8606f183..90188c3a 100644 --- a/arch/arm/mach-msm/qdsp6/audio_ctl.c +++ b/arch/arm/mach-msm/qdsp6/audio_ctl.c @@ -25,20 +25,10 @@ #define BUFSZ (0) -#if 1 -#define AUDIO_INFO(x...) pr_info("Audio: "x) -#else -#define AUDIO_INFO(x...) do{}while(0) -#endif - -// from board-htcleo-accoustic -extern int set_aux_gain(int level); - static DEFINE_MUTEX(voice_lock); static DEFINE_MUTEX(fm_lock); static int voice_started; static int fm_started; -int global_now_phone_call; static struct audio_client *voc_tx_clnt; static struct audio_client *voc_rx_clnt; @@ -48,7 +38,6 @@ static int q6_voice_start(uint32_t rx_acdb_id, uint32_t tx_acdb_id) { int rc = 0; - printk("VOICE START (%d %d)\n", rx_acdb_id, tx_acdb_id); mutex_lock(&voice_lock); if (voice_started) { @@ -56,7 +45,6 @@ static int q6_voice_start(uint32_t rx_acdb_id, uint32_t tx_acdb_id) rc = -EBUSY; goto done; } - global_now_phone_call = 1; voc_rx_clnt = q6voice_open(AUDIO_FLAG_WRITE, rx_acdb_id); if (!voc_rx_clnt) { @@ -81,9 +69,7 @@ done: static int q6_voice_stop(void) { mutex_lock(&voice_lock); - global_now_phone_call = 0; - if (voice_started) - { + if (voice_started) { q6voice_close(voc_tx_clnt); q6voice_close(voc_rx_clnt); voice_started = 0; @@ -141,12 +127,9 @@ static int q6_ioctl(struct inode *inode, struct file *file, uint32_t id[2]; char filename[64]; -// printk("$$$ AUDIO IOCTL=%08X\n", cmd); - switch (cmd) { case AUDIO_SWITCH_DEVICE: rc = copy_from_user(&id, (void *)arg, sizeof(id)); - AUDIO_INFO("SWITCH DEVICE %d, acdb %d\n", id[0], id[1]); if (!rc) rc = q6audio_do_routing(id[0], id[1]); break; @@ -173,19 +156,15 @@ static int q6_ioctl(struct inode *inode, struct file *file, rc = -EFAULT; break; } - AUDIO_INFO("voice: start\n"); rc = q6_voice_start(id[0], id[1]); break; case AUDIO_STOP_VOICE: - AUDIO_INFO("voice: stop\n"); rc = q6_voice_stop(); break; case AUDIO_START_FM: - AUDIO_INFO("FM: start\n"); rc = q6_fm_start(); break; case AUDIO_STOP_FM: - AUDIO_INFO("FM: stop\n"); rc = q6_fm_stop(); break; case AUDIO_REINIT_ACDB: @@ -199,25 +178,9 @@ static int q6_ioctl(struct inode *inode, struct file *file, rc = -EFAULT; break; } - AUDIO_INFO("audio_ctl: enable aux loopback %d\n", enable); rc = enable_aux_loopback(enable); break; } - case AUDIO_SET_AUXPGA_GAIN: { - int level; - if (copy_from_user(&level, (void*) arg, sizeof(level))) { - rc = -EFAULT; - break; - } - AUDIO_INFO("audio_ctl: set aux gain %d\n", level); - rc = set_aux_gain(level); - break; - } - case AUDIO_SET_RX_MUTE: - rc = copy_from_user(&n, (void *)arg, sizeof(n)); - if (!rc) - rc = q6audio_set_rx_mute(n); - break; default: rc = -EINVAL; } diff --git a/arch/arm/mach-msm/qdsp6/dal.c b/arch/arm/mach-msm/qdsp6/dal.c index d05ccfb0..cb2f3fe1 100644 --- a/arch/arm/mach-msm/qdsp6/dal.c +++ b/arch/arm/mach-msm/qdsp6/dal.c @@ -31,20 +31,20 @@ #define DAL_TRACE 0 struct dal_hdr { - uint32_t length:16; /* message length (header inclusive) */ - uint32_t version:8; /* DAL protocol version */ + uint32_t length:16; /* message length (header inclusive) */ + uint32_t version:8; /* DAL protocol version */ uint32_t priority:7; uint32_t async:1; uint32_t ddi:16; /* DDI method number */ - uint32_t prototype:8; /* DDI serialization format */ - uint32_t msgid:8; /* message id (DDI, ATTACH, DETACH, ...) */ + uint32_t prototype:8; /* DDI serialization format */ + uint32_t msgid:8; /* message id (DDI, ATTACH, DETACH, ...) */ void *from; void *to; } __attribute__((packed)); -#define TRACE_DATA_MAX 128 -#define TRACE_LOG_MAX 32 -#define TRACE_LOG_MASK (TRACE_LOG_MAX - 1) +#define TRACE_DATA_MAX 128 +#define TRACE_LOG_MAX 32 +#define TRACE_LOG_MASK (TRACE_LOG_MAX - 1) struct dal_trace { unsigned timestamp; @@ -129,17 +129,17 @@ void dal_trace(struct dal_client *c) if (c->tr_log) return; c->tr_log = kzalloc(sizeof(struct dal_trace) * TRACE_LOG_MAX, - GFP_KERNEL); + GFP_KERNEL); } void dal_trace_print(struct dal_hdr *hdr, unsigned *data, int len, unsigned when) { int i; printk("DAL %08x -> %08x L=%03x A=%d D=%04x P=%02x M=%02x T=%d", - (unsigned) hdr->from, (unsigned) hdr->to, - hdr->length, hdr->async, - hdr->ddi, hdr->prototype, hdr->msgid, - when); + (unsigned) hdr->from, (unsigned) hdr->to, + hdr->length, hdr->async, + hdr->ddi, hdr->prototype, hdr->msgid, + when); len /= 4; for (i = 0; i < len; i++) { if (!(i & 7)) @@ -226,7 +226,7 @@ again: } } pr_err("$$$ receiving unknown message len = %d $$$\n", - dch->count); + dch->count); dch->active = 0; dch->ptr = dch->data; } @@ -262,7 +262,8 @@ check_data: if (client->event) client->event(dch->ptr, len, client->cookie); else - pr_err("dal: client %p has no event handler\n", client); + pr_err("dal: client %p has no event handler\n", + client); goto again; } @@ -359,21 +360,20 @@ int dal_call_raw(struct dal_client *client, smd_write(dch->sch, data, data_len); spin_unlock_irqrestore(&dch->lock, flags); - if (!wait_event_timeout(client->wait, (client->status != -EBUSY), 5*HZ)) - { + if (!wait_event_timeout(client->wait, (client->status != -EBUSY), 5*HZ)) { dal_trace_dump(client); pr_err("dal: call timed out. dsp is probably dead.\n"); dal_trace_print(hdr, data, data_len, 0); -// BUG(); + BUG(); } return client->status; } int dal_call(struct dal_client *client, - unsigned ddi, unsigned prototype, - void *data, int data_len, - void *reply, int reply_max) + unsigned ddi, unsigned prototype, + void *data, int data_len, + void *reply, int reply_max) { struct dal_hdr hdr; int r; @@ -394,11 +394,11 @@ int dal_call(struct dal_client *client, mutex_lock(&client->write_lock); r = dal_call_raw(client, &hdr, data, data_len, reply, reply_max); mutex_unlock(&client->write_lock); -#if 1 +#if 0 if ((r > 3) && (((uint32_t*) reply)[0] == 0)) { - // pr_info("dal call OK\n"); + pr_info("dal call OK\n"); } else { - pr_info("dal call %d %d ERROR\n", ddi, prototype); + pr_info("dal call ERROR\n"); } #endif return r; @@ -415,67 +415,8 @@ struct dal_reply_attach { char name[64]; }; - -struct dal_client *dal_attach_ex(uint32_t device_id, const char *aname, const char *name, dal_event_func_t func, void *cookie) -{ - struct dal_hdr hdr; - struct dal_msg_attach msg; - struct dal_reply_attach reply; - struct dal_channel *dch; - struct dal_client *client; - unsigned long flags; - int r; - - dch = dal_open_channel(name); - if (!dch) - return 0; - - client = kzalloc(sizeof(*client), GFP_KERNEL); - if (!client) - return 0; - - client->dch = dch; - client->event = func; - client->cookie = cookie; - mutex_init(&client->write_lock); - spin_lock_init(&client->tr_lock); - init_waitqueue_head(&client->wait); - - spin_lock_irqsave(&dch->lock, flags); - list_add(&client->list, &dch->clients); - spin_unlock_irqrestore(&dch->lock, flags); - - memset(&hdr, 0, sizeof(hdr)); - memset(&msg, 0, sizeof(msg)); - - hdr.length = sizeof(hdr) + sizeof(msg); - hdr.version = DAL_VERSION; - hdr.msgid = DAL_MSGID_ATTACH; - hdr.from = client; - msg.device_id = device_id; - if (aname) - strcpy(msg.attach, aname); - - r = dal_call_raw(client, &hdr, &msg, sizeof(msg), - &reply, sizeof(reply)); - - if ((r == sizeof(reply)) && (reply.status == 0)) { - reply.name[63] = 0; - pr_info("dal_attach: status = %d, name = '%s'\n", - reply.status, reply.name); - return client; - } - - pr_err("dal_attach: failure\n"); - - dal_detach(client); - return 0; -} - - - struct dal_client *dal_attach(uint32_t device_id, const char *name, - dal_event_func_t func, void *cookie) + dal_event_func_t func, void *cookie) { struct dal_hdr hdr; struct dal_msg_attach msg; @@ -548,7 +489,7 @@ int dal_detach(struct dal_client *client) data = (uint32_t) client; dal_call_raw(client, &hdr, &data, sizeof(data), - &data, sizeof(data)); + &data, sizeof(data)); } dch = client->dch; @@ -602,8 +543,7 @@ int dal_call_f1(struct dal_client *client, uint32_t ddi, uint32_t arg1, uint32_t int dal_call_f5(struct dal_client *client, uint32_t ddi, void *ibuf, uint32_t ilen) { -// uint32_t tmp[128]; - uint32_t tmp[DAL_DATA_MAX]; + uint32_t tmp[128]; int res; int param_idx = 0; @@ -623,55 +563,23 @@ int dal_call_f5(struct dal_client *client, uint32_t ddi, void *ibuf, uint32_t il return res; } -int dal_call_f6(struct dal_client *client, uint32_t ddi, uint32_t cmd, void *ibuf, uint32_t ilen) -{ - uint32_t tmp[DAL_DATA_MAX]; - int res; - int param_idx = 0; - - if (ilen + 4 > DAL_DATA_MAX) - return -EINVAL; - - tmp[param_idx] = cmd; - param_idx++; - tmp[param_idx] = ilen; - param_idx++; - - memcpy(&tmp[param_idx], ibuf, ilen); - param_idx += DIV_ROUND_UP(ilen, 4); - - res = dal_call(client, ddi, 6, tmp, param_idx * 4, tmp, sizeof(tmp)); - - if (res >= 4) - return (int) tmp[0]; - return res; -} - -int dal_call_f8(struct dal_client *client, uint32_t ddi, void *ibuf, uint32_t ilen, void *obuf, uint32_t olen) +int dal_call_f9(struct dal_client *client, uint32_t ddi, void *obuf, + uint32_t olen) { uint32_t tmp[128]; int res; - int param_idx = 0; - if (ilen + 8 > DAL_DATA_MAX) + if (olen > sizeof(tmp) - 8) return -EINVAL; + tmp[0] = olen; - tmp[param_idx] = ilen; - param_idx++; - - memcpy(&tmp[param_idx], ibuf, ilen); - param_idx += DIV_ROUND_UP(ilen, 4); - - tmp[param_idx++] = olen; - res = dal_call(client, ddi, 8, tmp, param_idx * 4, tmp, sizeof(tmp)); + res = dal_call(client, ddi, 9, tmp, sizeof(uint32_t), tmp, + sizeof(tmp)); if (res >= 4) - { res = (int)tmp[0]; - } - if (!res) - { + if (!res) { if (tmp[1] > olen) return -EIO; memcpy(obuf, &tmp[2], tmp[1]); @@ -679,37 +587,9 @@ int dal_call_f8(struct dal_client *client, uint32_t ddi, void *ibuf, uint32_t il return res; } -int dal_call_f9(struct dal_client *client, uint32_t ddi, void *obuf, uint32_t olen) -{ - uint32_t tmp[128]; - int res; - int param_idx = 0; - - if (olen + 8 > DAL_DATA_MAX) - return -EINVAL; - - tmp[param_idx++] = olen; - res = dal_call(client, ddi, 9, tmp, param_idx * 4, tmp, sizeof(tmp)); - - if (res >= 4) - { - res = (int)tmp[0]; - } - - if (!res) - { - if (tmp[1] > olen) - return -EIO; - memcpy(obuf, &tmp[2], tmp[1]); - } - return res; -} - - - - int dal_call_f13(struct dal_client *client, uint32_t ddi, void *ibuf1, - uint32_t ilen1, void *ibuf2, uint32_t ilen2, void *obuf, uint32_t olen) + uint32_t ilen1, void *ibuf2, uint32_t ilen2, void *obuf, + uint32_t olen) { uint32_t tmp[128]; int res; @@ -742,5 +622,41 @@ int dal_call_f13(struct dal_client *client, uint32_t ddi, void *ibuf1, return res; } +int dal_call_f14(struct dal_client *client, uint32_t ddi, void *ibuf, + uint32_t ilen, void *obuf1, uint32_t olen1, void *obuf2, + uint32_t olen2, uint32_t *oalen2) +{ + uint32_t tmp[128]; + int res; + int param_idx = 0; -// END OF FILE + if (olen1 + olen2 + 8 > DAL_DATA_MAX || + ilen + 12 > DAL_DATA_MAX) + return -EINVAL; + + tmp[param_idx] = ilen; + param_idx++; + + memcpy(&tmp[param_idx], ibuf, ilen); + param_idx += DIV_ROUND_UP(ilen, 4); + + tmp[param_idx++] = olen1; + tmp[param_idx++] = olen2; + res = dal_call(client, ddi, 14, tmp, param_idx * 4, tmp, sizeof(tmp)); + + if (res >= 4) + res = (int)tmp[0]; + + if (!res) { + if (tmp[1] > olen1) + return -EIO; + param_idx = DIV_ROUND_UP(tmp[1], 4) + 2; + if (tmp[param_idx] > olen2) + return -EIO; + + memcpy(obuf1, &tmp[2], tmp[1]); + memcpy(obuf2, &tmp[param_idx+1], tmp[param_idx]); + *oalen2 = tmp[param_idx]; + } + return res; +} diff --git a/arch/arm/mach-msm/qdsp6/dal.h b/arch/arm/mach-msm/qdsp6/dal.h index 196053d6..92ccec0e 100644 --- a/arch/arm/mach-msm/qdsp6/dal.h +++ b/arch/arm/mach-msm/qdsp6/dal.h @@ -19,12 +19,16 @@ struct dal_client; +struct dal_info { + uint32_t size; + uint32_t version; + char name[32]; +}; + typedef void (*dal_event_func_t)(void *data, int len, void *cookie); struct dal_client *dal_attach(uint32_t device_id, const char *name, dal_event_func_t func, void *cookie); -struct dal_client *dal_attach_ex(uint32_t device_id, const char *aname, - const char *name, dal_event_func_t func, void *cookie); int dal_detach(struct dal_client *client); @@ -46,16 +50,14 @@ int dal_call_f1(struct dal_client *client, uint32_t ddi, uint32_t arg1, uint32_t arg2); int dal_call_f5(struct dal_client *client, uint32_t ddi, void *ibuf, uint32_t ilen); -int dal_call_f6(struct dal_client *client, uint32_t ddi, - uint32_t cmd, void *ibuf, uint32_t ilen); -int dal_call_f8(struct dal_client *client, uint32_t ddi, - void *ibuf, uint32_t ilen, void *obuf, uint32_t olen); -int dal_call_f9(struct dal_client *client, uint32_t ddi, +int dal_call_f9(struct dal_client *client, uint32_t ddi, void *obuf, uint32_t olen); - int dal_call_f13(struct dal_client *client, uint32_t ddi, void *ibuf1, uint32_t ilen1, void *ibuf2, uint32_t ilen2, void *obuf, uint32_t olen); +int dal_call_f14(struct dal_client *client, uint32_t ddi, void *ibuf, + uint32_t ilen, void *obuf1, uint32_t olen1, void *obuf2, + uint32_t olen2, uint32_t *oalen2); /* common DAL operations */ enum { diff --git a/arch/arm/mach-msm/qdsp6/dal_acdb.h b/arch/arm/mach-msm/qdsp6/dal_acdb.h index 58db5ac2..0e95b3b8 100644 --- a/arch/arm/mach-msm/qdsp6/dal_acdb.h +++ b/arch/arm/mach-msm/qdsp6/dal_acdb.h @@ -27,11 +27,7 @@ */ #define ACDB_DAL_DEVICE 0x02000069 -#if defined(CONFIG_MACH_HTCLEO) - #define ACDB_DAL_PORT "SMD_DAL00" -#else - #define ACDB_DAL_PORT "SMD_DAL_AM_AUD" -#endif +#define ACDB_DAL_PORT "SMD_DAL_AM_AUD" #define ACDB_OP_IOCTL DAL_OP_FIRST_DEVICE_API diff --git a/arch/arm/mach-msm/qdsp6/dal_adie.h b/arch/arm/mach-msm/qdsp6/dal_adie.h index 08b938a0..b7f58456 100644 --- a/arch/arm/mach-msm/qdsp6/dal_adie.h +++ b/arch/arm/mach-msm/qdsp6/dal_adie.h @@ -32,11 +32,7 @@ #include "dal.h" #define ADIE_DAL_DEVICE 0x02000029 -#if defined(CONFIG_MACH_HTCLEO) - #define ADIE_DAL_PORT "SMD_DAL00" -#else - #define ADIE_DAL_PORT "SMD_DAL_AM_AUD" -#endif +#define ADIE_DAL_PORT "SMD_DAL_AM_AUD" enum { ADIE_OP_GET_NUM_PATHS = DAL_OP_FIRST_DEVICE_API, diff --git a/arch/arm/mach-msm/qdsp6/dal_audio.h b/arch/arm/mach-msm/qdsp6/dal_audio.h index 674f0e80..b1ad07db 100644 --- a/arch/arm/mach-msm/qdsp6/dal_audio.h +++ b/arch/arm/mach-msm/qdsp6/dal_audio.h @@ -2,15 +2,15 @@ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor - * the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -30,29 +30,15 @@ #define __DAL_AUDIO_H__ #include "dal_audio_format.h" -#include "dal.h" -#include #define AUDIO_DAL_DEVICE 0x02000028 #define AUDIO_DAL_PORT "DSP_DAL_AQ_AUD" -enum -{ -#if defined(CONFIG_MACH_HTCLEO) - AUDIO_OP_OPEN = DAL_OP_FIRST_DEVICE_API, - AUDIO_OP_WRITE, - AUDIO_OP_READ, - AUDIO_OP_IOCTL, - AUDIO_OP_INIT, - AUDIO_OP_CLOSE, - AUDIO_OP_FLUSH -#else +enum { AUDIO_OP_CONTROL = DAL_OP_FIRST_DEVICE_API, AUDIO_OP_DATA, AUDIO_OP_INIT, - -#endif -}; +}; /* ---- common audio structures ---- */ @@ -60,37 +46,37 @@ enum /* buffer is a synchronization point or key frame, meaning no data */ /* before it in the stream is required in order to render the stream */ /* from this point onward. */ -#define ADSP_AUDIO_BUFFER_FLAG_SYNC_POINT 0x01 +#define ADSP_AUDIO_BUFFER_FLAG_SYNC_POINT 0x01 /* This flag, if set, indicates that the buffer object is using valid */ /* physical address used to store the media data */ -#define ADSP_AUDIO_BUFFER_FLAG_PHYS_ADDR 0x04 +#define ADSP_AUDIO_BUFFER_FLAG_PHYS_ADDR 0x04 /* This flag, if set, indicates that a media start timestamp has been */ /* set for a buffer. */ -#define ADSP_AUDIO_BUFFER_FLAG_START_SET 0x08 +#define ADSP_AUDIO_BUFFER_FLAG_START_SET 0x08 /* This flag, if set, indicates that a media stop timestamp has been set */ /* for a buffer. */ -#define ADSP_AUDIO_BUFFER_FLAG_STOP_SET 0x10 +#define ADSP_AUDIO_BUFFER_FLAG_STOP_SET 0x10 /* This flag, if set, indicates that a preroll timestamp has been set */ /* for a buffer. */ -#define ADSP_AUDIO_BUFFER_FLAG_PREROLL_SET 0x20 +#define ADSP_AUDIO_BUFFER_FLAG_PREROLL_SET 0x20 /* This flag, if set, indicates that the data in the buffer is a fragment of */ /* a larger block of data, and will be continued by the data in the next */ /* buffer to be delivered. */ -#define ADSP_AUDIO_BUFFER_FLAG_CONTINUATION 0x40 +#define ADSP_AUDIO_BUFFER_FLAG_CONTINUATION 0x40 struct adsp_audio_buffer { - u32 addr; /* Physical Address of buffer */ - u32 max_size; /* Maximum size of buffer */ + u32 addr; /* Physical Address of buffer */ + u32 max_size; /* Maximum size of buffer */ u32 actual_size; /* Actual size of valid data in the buffer */ - u32 offset; /* Offset to the first valid byte */ - u32 flags; /* ADSP_AUDIO_BUFFER_FLAGs that has been set */ - s64 start; /* Start timestamp, if any */ - s64 stop; /* Stop timestamp, if any */ + u32 offset; /* Offset to the first valid byte */ + u32 flags; /* ADSP_AUDIO_BUFFER_FLAGs that has been set */ + s64 start; /* Start timestamp, if any */ + s64 stop; /* Stop timestamp, if any */ s64 preroll; /* Preroll timestamp, if any */ } __attribute__ ((packed)); @@ -100,11 +86,10 @@ struct adsp_audio_buffer { /* Command/event response types */ #define ADSP_AUDIO_RESPONSE_COMMAND 0 -#define ADSP_AUDIO_RESPONSE_ASYNC 1 +#define ADSP_AUDIO_RESPONSE_ASYNC 1 -#if !defined(CONFIG_MACH_HTCLEO) struct adsp_command_hdr { - u32 size; /* sizeof(cmd) - sizeof(u32) */ + u32 size; /* sizeof(cmd) - sizeof(u32) */ u32 dst; u32 src; @@ -119,21 +104,13 @@ struct adsp_command_hdr { u32 padding; } __attribute__ ((packed)); -#else - -struct adsp_command_hdr -{ - u32 context; - u32 data; -} __attribute__ ((packed)); -#endif #define AUDIO_DOMAIN_APP 0 -#define AUDIO_DOMAIN_MODEM 1 +#define AUDIO_DOMAIN_MODEM 1 #define AUDIO_DOMAIN_DSP 2 -#define AUDIO_SERVICE_AUDIO 0 -#define AUDIO_SERVICE_VIDEO 1 /* really? */ +#define AUDIO_SERVICE_AUDIO 0 +#define AUDIO_SERVICE_VIDEO 1 /* really? */ /* adsp audio addresses are (byte order) domain, service, major, minor */ //#define AUDIO_ADDR(maj,min) ( (((maj) & 0xff) << 16) | (((min) & 0xff) << 24) | (1) ) @@ -147,17 +124,17 @@ struct adsp_command_hdr #define ADSP_AUDIO_ENC_ENHANCED_AAC_PLUS_MODE 2 struct adsp_audio_aac_enc_cfg { - u32 bit_rate; /* bits per second */ - u32 encoder_mode; /* ADSP_AUDIO_ENC_* */ + u32 bit_rate; /* bits per second */ + u32 encoder_mode; /* ADSP_AUDIO_ENC_* */ } __attribute__ ((packed)); -#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_LOUNDNESS 0 -#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_SNR 1 +#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_LOUNDNESS 0 +#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_SNR 1 -#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_MONO 1 -#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_STEREO 2 -#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_DUAL 8 -#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_JOINT_STEREO 9 +#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_MONO 1 +#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_STEREO 2 +#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_DUAL 8 +#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_JOINT_STEREO 9 struct adsp_audio_sbc_encoder_cfg { u32 num_subbands; @@ -168,36 +145,36 @@ struct adsp_audio_sbc_encoder_cfg { } __attribute__ ((packed)); /* AMR NB encoder modes */ -#define ADSP_AUDIO_AMR_MR475 0 -#define ADSP_AUDIO_AMR_MR515 1 -#define ADSP_AUDIO_AMR_MMR59 2 -#define ADSP_AUDIO_AMR_MMR67 3 -#define ADSP_AUDIO_AMR_MMR74 4 -#define ADSP_AUDIO_AMR_MMR795 5 -#define ADSP_AUDIO_AMR_MMR102 6 -#define ADSP_AUDIO_AMR_MMR122 7 +#define ADSP_AUDIO_AMR_MR475 0 +#define ADSP_AUDIO_AMR_MR515 1 +#define ADSP_AUDIO_AMR_MMR59 2 +#define ADSP_AUDIO_AMR_MMR67 3 +#define ADSP_AUDIO_AMR_MMR74 4 +#define ADSP_AUDIO_AMR_MMR795 5 +#define ADSP_AUDIO_AMR_MMR102 6 +#define ADSP_AUDIO_AMR_MMR122 7 /* The following are valid AMR NB DTX modes */ #define ADSP_AUDIO_AMR_DTX_MODE_OFF 0 -#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD1 1 -#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD2 2 -#define ADSP_AUDIO_AMR_DTX_MODE_ON_AUTO 3 +#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD1 1 +#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD2 2 +#define ADSP_AUDIO_AMR_DTX_MODE_ON_AUTO 3 /* AMR Encoder configuration */ struct adsp_audio_amr_enc_cfg { - u32 mode; /* ADSP_AUDIO_AMR_MR* */ - u32 dtx_mode; /* ADSP_AUDIO_AMR_DTX_MODE* */ - u32 enable; /* 1 = enable, 0 = disable */ + u32 mode; /* ADSP_AUDIO_AMR_MR* */ + u32 dtx_mode; /* ADSP_AUDIO_AMR_DTX_MODE* */ + u32 enable; /* 1 = enable, 0 = disable */ } __attribute__ ((packed)); struct adsp_audio_qcelp13k_enc_cfg { - u16 min_rate; - u16 max_rate; + u16 min_rate; + u16 max_rate; } __attribute__ ((packed)); struct adsp_audio_evrc_enc_cfg { - u16 min_rate; - u16 max_rate; + u16 min_rate; + u16 max_rate; } __attribute__ ((packed)); union adsp_audio_codec_config { @@ -220,9 +197,8 @@ union adsp_audio_codec_config { #define ADSP_AUDIO_OPEN_STREAM_MODE_SR_CM_NOTIFY 0x0002 /* This bit, if set, indicates that the sync clock is enabled */ -#define ADSP_AUDIO_OPEN_STREAM_MODE_ENABLE_SYNC_CLOCK 0x0004 +#define ADSP_AUDIO_OPEN_STREAM_MODE_ENABLE_SYNC_CLOCK 0x0004 -#if !defined(CONFIG_MACH_HTCLEO) struct adsp_open_command { struct adsp_command_hdr hdr; @@ -238,52 +214,22 @@ struct adsp_open_command { union adsp_audio_codec_config config; } __attribute__ ((packed)); -/* Opcode to open a device stream session to capture audio */ -#define ADSP_AUDIO_IOCTL_CMD_OPEN_READ 0x0108dd79 - -/* Opcode to open a device stream session to render audio */ -#define ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE 0x0108dd7a - -/* Opcode to open a device session, must open a device */ -#define ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE 0x0108dd7b - -/* Close an existing stream or device */ -#define ADSP_AUDIO_IOCTL_CMD_CLOSE 0x0108d8bc - -#else - -struct adsp_open_command -{ - struct adsp_command_hdr hdr; - - u32 opcode; - u32 numdev; - u32 dev[4]; - u32 stream_context; - - u32 format; - u32 pblock; - u32 blocklen; - - u32 buf_max_size; - u32 priority; - - union adsp_audio_codec_config config; - u32 mode; -} __attribute__ ((packed)); /* --- audio control and stream session ioctls ---- */ /* Opcode to open a device stream session to capture audio */ -#define ADSP_AUDIO_OPCODE_OPEN_READ 0x01 +#define ADSP_AUDIO_IOCTL_CMD_OPEN_READ 0x0108dd79 /* Opcode to open a device stream session to render audio */ -#define ADSP_AUDIO_OPCODE_OPEN_WRITE 0x02 +#define ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE 0x0108dd7a /* Opcode to open a device session, must open a device */ -#define ADSP_AUDIO_OPCODE_OPEN_DEV 0x04 +#define ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE 0x0108dd7b + +/* Close an existing stream or device */ +#define ADSP_AUDIO_IOCTL_CMD_CLOSE 0x0108d8bc + -#endif /* A device switch requires three IOCTL */ /* commands in the following sequence: PREPARE, STANDBY, COMMIT */ @@ -320,7 +266,7 @@ struct adsp_device_switch_command { #define ADSP_PATH_RX 0 #define ADSP_PATH_TX 1 -#define ADSP_PATH_BOTH 2 +#define ADSP_PATH_BOTH 2 /* These commands will affect a logical device and all its associated */ /* streams. */ @@ -405,13 +351,13 @@ struct adsp_buffer_command { /* Do sample slipping/stuffing on AAC outputs. The payload of */ /* this command is struct adsp_audio_slip_sample_command. */ -#define ADSP_AUDIO_IOCTL_CMD_STREAM_SLIPSAMPLE 0x0108d40e +#define ADSP_AUDIO_IOCTL_CMD_STREAM_SLIPSAMPLE 0x0108d40e /* Set stream volume. */ /* This command has data payload, struct adsp_audio_set_volume_command. */ #define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL 0x0108c0de -/* Set stream stereo volume. This command has data payl oad, */ +/* Set stream stereo volume. This command has data payload, */ /* struct adsp_audio_set_stereo_volume_command. */ #define ADSP_AUDIO_IOCTL_SET_STREAM_STEREO_VOL 0x0108dd7c @@ -469,39 +415,20 @@ struct adsp_buffer_command { /* Set session stereo volume. This command has data payload, */ /* struct adsp_audio_set_stereo_volume_command. */ -#define ADSP_AUDIO_IOCTL_SET_SESSION_STEREO_VOL 0x0108df3d +#define ADSP_AUDIO_IOCTL_SET_SESSION_STEREO_VOL 0x0108df3d /* Set L, R cross channel gain for a session. This command has */ /* data payload, struct adsp_audio_set_x_chan_gain_command. */ -#define ADSP_AUDIO_IOCTL_SET_SESSION_XCHAN_GAIN 0x0108df3f +#define ADSP_AUDIO_IOCTL_SET_SESSION_XCHAN_GAIN 0x0108df3f /* Set Session mute state. */ /* This command has data payload, struct adsp_audio_set_mute_command. */ -#define ADSP_AUDIO_IOCTL_SET_SESSION_MUTE 0x0108d8be +#define ADSP_AUDIO_IOCTL_SET_SESSION_MUTE 0x0108d8be /* Configure Equalizer for a stream. */ /* This command has payload struct adsp_audio_set_equalizer_command. */ #define ADSP_AUDIO_IOCTL_SET_SESSION_EQ_CONFIG 0x0108c0e0 -#define ADSP_AUDIO_MAX_EQ_BANDS 12 - -/* Definition for any one band of Equalizer. */ -struct adsp_audio_eq_band { - u16 band_idx; - u32 filter_type; - u32 center_freq_hz; - s32 filter_gain; - s32 q_factor; -} __attribute__ ((packed)); - -struct adsp_audio_set_equalizer_command { - struct adsp_command_hdr hdr; - u32 enable; - u32 num_bands; - struct adsp_audio_eq_band eq_bands[ADSP_AUDIO_MAX_EQ_BANDS]; -} __attribute__ ((packed)); - - /* Set Audio Video sync information. */ /* This command has data payload, struct adsp_audio_set_av_sync_command. */ #define ADSP_AUDIO_IOCTL_SET_SESSION_AVSYNC 0x0108d1e2 @@ -531,34 +458,33 @@ struct adsp_set_mute_command { /* event id after the IOCTL command has been executed. */ /* This event is generated after a media stream session is opened. */ -#define ADSP_AUDIO_EVT_STATUS_OPEN 0x0108c0d6 +#define ADSP_AUDIO_EVT_STATUS_OPEN 0x0108c0d6 /* This event is generated after a media stream session is closed. */ -#define ADSP_AUDIO_EVT_STATUS_CLOSE 0x0108c0d7 +#define ADSP_AUDIO_EVT_STATUS_CLOSE 0x0108c0d7 /* Asyncronous buffer consumption. This event is generated after a */ /* recived buffer is consumed during rendering or filled during */ /* capture opeartion. */ -#define ADSP_AUDIO_EVT_STATUS_BUF_DONE 0x0108c0d8 +#define ADSP_AUDIO_EVT_STATUS_BUF_DONE 0x0108c0d8 /* This event is generated when rendering operation is starving for */ /* data. In order to avoid audio loss at the end of a plauback, the */ /* client should wait for this event before issuing the close command. */ -#define ADSP_AUDIO_EVT_STATUS_BUF_UNDERRUN 0x0108c0d9 +#define ADSP_AUDIO_EVT_STATUS_BUF_UNDERRUN 0x0108c0d9 /* This event is generated during capture operation when there are no */ /* buffers available to copy the captured audio data */ -#define ADSP_AUDIO_EVT_STATUS_BUF_OVERFLOW 0x0108c0da +#define ADSP_AUDIO_EVT_STATUS_BUF_OVERFLOW 0x0108c0da /* This asynchronous event is generated as a result of an input */ /* sample rate change and/or channel mode change detected by the */ /* decoder. The event payload data is an array of 2 uint32 */ /* values containing the sample rate in Hz and channel mode. */ -#define ADSP_AUDIO_EVT_SR_CM_CHANGE 0x0108d329 +#define ADSP_AUDIO_EVT_SR_CM_CHANGE 0x0108d329 -struct adsp_event_hdr -{ - u32 evt_handle; /* DAL common header */ +struct adsp_event_hdr { + u32 evt_handle; /* DAL common header */ u32 evt_cookie; u32 evt_length; @@ -575,48 +501,17 @@ struct adsp_event_hdr u32 status; } __attribute__ ((packed)); -#if defined(CONFIG_MACH_HTCLEO) -union adsp_event_data -{ - u32 val32; - uint8_t data[32]; -} __attribute__ ((packed)); - - -struct adsp_audio_event -{ - struct adsp_command_hdr hdr; - u32 session; - u32 event_id; - u32 status; - u32 datalen; - union adsp_event_data data; -} __attribute__ ((packed)); - - -struct adsp_audio_dal_event -{ - u32 cb_evt; - u32 loc_evt; - u32 size; - struct adsp_audio_event ae; -} __attribute__ ((packed)); - -#else -struct adsp_buffer_event -{ +struct adsp_buffer_event { struct adsp_event_hdr hdr; struct adsp_audio_buffer buffer; } __attribute__ ((packed)); -#endif - /* ---- audio device IDs ---- */ /* Device direction Rx/Tx flag */ -#define ADSP_AUDIO_RX_DEVICE 0x00 -#define ADSP_AUDIO_TX_DEVICE 0x01 +#define ADSP_AUDIO_RX_DEVICE 0x00 +#define ADSP_AUDIO_TX_DEVICE 0x01 /* Default RX or TX device */ #define ADSP_AUDIO_DEVICE_ID_DEFAULT 0x1081679 @@ -631,18 +526,18 @@ struct adsp_buffer_event /* Special loopback pseudo device to be paired with an RX device */ /* with usage ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK */ -#define ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX 0x1089bf2 +#define ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX 0x1089bf2 /* Sink (RX) devices */ #define ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR 0x107ac88 #define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO 0x1081511 #define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO 0x107ac8a #define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO 0x1081513 -#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET 0x108c508 +#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET 0x108c508 #define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET 0x108c894 -#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO 0x1081514 +#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO 0x1081514 #define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET 0x108c895 -#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET 0x108c509 +#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET 0x108c509 #define ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR 0x1081519 #define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR 0x108151c #define ADSP_AUDIO_DEVICE_ID_I2S_SPKR 0x1089bf4 @@ -652,11 +547,11 @@ struct adsp_buffer_event /* This device must be paired with */ /* ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX using */ /* ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK mode */ -#define ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR 0x108151a +#define ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR 0x108151a /* Voice Destination identifier - specifically used for */ /* controlling Voice module from the Device Control Session */ -#define ADSP_AUDIO_DEVICE_ID_VOICE 0x0108df3c +#define ADSP_AUDIO_DEVICE_ID_VOICE 0x0108df3c /* Audio device usage types. */ /* This is a bit mask to determine which topology to use in the */ @@ -667,24 +562,4 @@ struct adsp_buffer_event #define ADSP_AUDIO_DEVICE_CONTEXT_RECORD 0x20 #define ADSP_AUDIO_DEVICE_CONTEXT_PCM_LOOPBACK 0x40 -/* for EQ */ -#define CAD_EQ_INVALID_DATA 0xFFFFFFFF - -/* Equalizer filter band types */ -#define ADSP_AUDIO_EQUALIZER_TYPE_NONE 0 -#define ADSP_AUDIO_EQUALIZER_BASS_BOOST 1 -#define ADSP_AUDIO_EQUALIZER_BASS_CUT 2 -#define ADSP_AUDIO_EQUALIZER_TREBLE_BOOST 3 -#define ADSP_AUDIO_EQUALIZER_TREBLE_CUT 4 -#define ADSP_AUDIO_EQUALIZER_BAND_BOOST 5 -#define ADSP_AUDIO_EQUALIZER_BAND_CUT 6 - -struct cad_audio_eq_cfg { - u32 enable; - u32 num_bands; - struct adsp_audio_eq_band eq_bands[ADSP_AUDIO_MAX_EQ_BANDS]; -} __attribute__ ((packed)); - -int q6audio_set_stream_eq(struct audio_client *ac, struct cad_audio_eq_cfg *eq_cfg); - #endif diff --git a/arch/arm/mach-msm/qdsp6/mp3.c b/arch/arm/mach-msm/qdsp6/mp3.c index 92e8f0f0..7a3adf13 100644 --- a/arch/arm/mach-msm/qdsp6/mp3.c +++ b/arch/arm/mach-msm/qdsp6/mp3.c @@ -25,7 +25,6 @@ #include #include -#include "dal_audio.h" #define BUFSZ (8192) #define DMASZ (BUFSZ * 2) @@ -40,7 +39,6 @@ struct mp3 { static long mp3_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct mp3 *mp3 = file->private_data; - struct cad_audio_eq_cfg eq_cfg; int rc = 0; if (cmd == AUDIO_GET_STATS) { @@ -62,14 +60,6 @@ static long mp3_ioctl(struct file *file, unsigned int cmd, unsigned long arg) rc = q6audio_set_stream_volume(mp3->ac, vol); break; } - case AUDIO_SET_EQ: { - if (copy_from_user(&eq_cfg, (void *)arg, sizeof(struct cad_audio_eq_cfg))) { - rc = -EFAULT; - break; - } - rc = q6audio_set_stream_eq(mp3->ac, &eq_cfg); - break; - } case AUDIO_START: { uint32_t acdb_id; if (arg == 0) { diff --git a/arch/arm/mach-msm/qdsp6/msm_q6vdec.c b/arch/arm/mach-msm/qdsp6/msm_q6vdec.c index d3fcfe77..73837529 100644 --- a/arch/arm/mach-msm/qdsp6/msm_q6vdec.c +++ b/arch/arm/mach-msm/qdsp6/msm_q6vdec.c @@ -66,35 +66,10 @@ #define TRACE(fmt,x...) \ do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0) #else -#define TRACE(fmt,x...) do { } while (0) +#define TRACE(fmt, x...) do { } while (0) #endif - -static DEFINE_MUTEX(idlecount_lock); -static int idlecount; -static struct wake_lock wakelock; -static struct wake_lock idlelock; - -static void prevent_sleep(void) -{ - mutex_lock(&idlecount_lock); - if (++idlecount == 1) { - wake_lock(&idlelock); - wake_lock(&wakelock); - } - mutex_unlock(&idlecount_lock); -} - -static void allow_sleep(void) -{ - mutex_lock(&idlecount_lock); - if (--idlecount == 0) { - wake_unlock(&idlelock); - wake_unlock(&wakelock); - } - mutex_unlock(&idlecount_lock); -} - +#define MAX_SUPPORTED_INSTANCES 2 enum { VDEC_DALRPC_INITIALIZE = DAL_OP_FIRST_DEVICE_API, @@ -162,6 +137,31 @@ static struct cdev vdec_cdev; static int ref_cnt; static DEFINE_MUTEX(vdec_ref_lock); +static DEFINE_MUTEX(idlecount_lock); +static int idlecount; +static struct wake_lock wakelock; +static struct wake_lock idlelock; + +static void prevent_sleep(void) +{ + mutex_lock(&idlecount_lock); + if (++idlecount == 1) { + wake_lock(&idlelock); + wake_lock(&wakelock); + } + mutex_unlock(&idlecount_lock); +} + +static void allow_sleep(void) +{ + mutex_lock(&idlecount_lock); + if (--idlecount == 0) { + wake_unlock(&idlelock); + wake_unlock(&wakelock); + } + mutex_unlock(&idlecount_lock); +} + static inline int vdec_check_version(u32 client, u32 server) { int ret = -EINVAL; @@ -447,6 +447,8 @@ static int vdec_queue(struct vdec_data *vd, void *argp) rpc.size = sizeof(struct vdec_input_buf_info); rpc.osize = sizeof(struct vdec_queue_status); + /* complete the writes to the buffer */ + wmb(); ret = dal_call(vd->vdec_handle, VDEC_DALRPC_QUEUE, 8, &rpc, sizeof(rpc), &rpc_res, sizeof(rpc_res)); if (ret < 4) { @@ -587,6 +589,22 @@ static int vdec_freebuffers(struct vdec_data *vd, void *argp) return ret; } + +static int vdec_getversion(struct vdec_data *vd, void *argp) +{ + struct vdec_version ver_info; + int ret = 0; + + ver_info.major = VDEC_GET_MAJOR_VERSION(VDEC_INTERFACE_VERSION); + ver_info.minor = VDEC_GET_MINOR_VERSION(VDEC_INTERFACE_VERSION); + + ret = copy_to_user(((struct vdec_version *)argp), + &ver_info, sizeof(ver_info)); + + return ret; + +} + static long vdec_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct vdec_data *vd = file->private_data; @@ -638,6 +656,9 @@ static long vdec_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (vd->close_decode) ret = -EINTR; + else + /* order the reads from the buffer */ + rmb(); break; case VDEC_IOCTL_CLOSE: @@ -663,7 +684,15 @@ static long vdec_ioctl(struct file *file, unsigned int cmd, unsigned long arg) pr_err("%s: remote function failed (%d)\n", __func__, ret); break; + case VDEC_IOCTL_GETVERSION: + TRACE("VDEC_IOCTL_GETVERSION (pid=%d tid=%d)\n", + current->group_leader->pid, current->pid); + ret = vdec_getversion(vd, argp); + if (ret) + pr_err("%s: remote function failed (%d)\n", + __func__, ret); + break; default: pr_err("%s: invalid ioctl!\n", __func__); ret = -EINVAL; @@ -684,7 +713,8 @@ static void vdec_dcdone_handler(struct vdec_data *vd, void *frame, unsigned long flags; int found = 0; - if (frame_size != sizeof(struct vdec_frame_info)) { +/*if (frame_size != sizeof(struct vdec_frame_info)) {*/ + if (frame_size < sizeof(struct vdec_frame_info)) { pr_warning("%s: msg size mismatch %d != %d\n", __func__, frame_size, sizeof(struct vdec_frame_info)); return; @@ -768,13 +798,14 @@ static int vdec_open(struct inode *inode, struct file *file) int i; struct vdec_msg_list *l; struct vdec_data *vd; + struct dal_info version_info; pr_info("q6vdec_open()\n"); mutex_lock(&vdec_ref_lock); - if (ref_cnt > 0) { - pr_err("%s: Instance alredy running\n", __func__); + if (ref_cnt >= MAX_SUPPORTED_INSTANCES) { + pr_err("%s: Max allowed instances exceeded \n", __func__); mutex_unlock(&vdec_ref_lock); - return -ENOMEM; + return -EBUSY; } ref_cnt++; mutex_unlock(&vdec_ref_lock); @@ -813,11 +844,26 @@ static int vdec_open(struct inode *inode, struct file *file) ret = -EIO; goto vdec_open_err_handle_list; } + ret = dal_call_f9(vd->vdec_handle, DAL_OP_INFO, + &version_info, sizeof(struct dal_info)); + + if (ret) { + pr_err("%s: failed to get version \n", __func__); + goto vdec_open_err_handle_version; + } + + TRACE("q6vdec_open() interface version 0x%x\n", version_info.version); + if (vdec_check_version(VDEC_INTERFACE_VERSION, + version_info.version)) { + pr_err("%s: driver version mismatch !\n", __func__); + goto vdec_open_err_handle_version; + } vd->running = 1; prevent_sleep(); return 0; - +vdec_open_err_handle_version: + dal_detach(vd->vdec_handle); vdec_open_err_handle_list: { struct vdec_msg_list *l, *n; @@ -827,6 +873,9 @@ vdec_open_err_handle_list: } } vdec_open_err_handle_vd: + mutex_lock(&vdec_ref_lock); + ref_cnt--; + mutex_unlock(&vdec_ref_lock); kfree(vd); return ret; } diff --git a/arch/arm/mach-msm/qdsp6/msm_q6venc.c b/arch/arm/mach-msm/qdsp6/msm_q6venc.c index 4f2db90a..dbbffd22 100644 --- a/arch/arm/mach-msm/qdsp6/msm_q6venc.c +++ b/arch/arm/mach-msm/qdsp6/msm_q6venc.c @@ -1,9 +1,4 @@ -/* - * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. - * Copyright (c) 2009, Google Inc. - * - * Original authors: Code Aurora Forum - * Major cleanup: Dima Zavin +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -17,6 +12,35 @@ * products derived from this software without specific prior written * permission. * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 and only version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -31,607 +55,1198 @@ * */ -//#define DEBUG 1 - -#include +#include #include +#include #include -#include #include -#include #include -#include #include #include #include +#include #include #include - -#include - #include "dal.h" -#define DALDEVICEID_VENC_DEVICE 0x0200002D -#define DALDEVICEID_VENC_PORTNAME "DSP_DAL_AQ_VID" +#define DALDEVICEID_VENC_DEVICE 0x0200002D +/*#define DALDEVICEID_VENC_PORTNAME "DAL_AQ_VID"*/ +#define DALDEVICEID_VENC_PORTNAME "DSP_DAL_AQ_VID" + +#define VENC_NAME "q6venc" +#define VENC_MSG_MAX 128 + +#define VENC_INTERFACE_VERSION 0x00020000 +#define MAJOR_MASK 0xFFFF0000 +#define MINOR_MASK 0x0000FFFF +#define VENC_GET_MAJOR_VERSION(version) ((version & MAJOR_MASK)>>16) +#define VENC_GET_MINOR_VERSION(version) (version & MINOR_MASK) + +uint32_t kpi_start[5]; +uint32_t kpi_end; +static uint32_t cnt = 0; enum { - VENC_DALRPC_INITIALIZE = DAL_OP_FIRST_DEVICE_API, - VENC_DALRPC_SET_CB_CHANNEL, - VENC_DALRPC_ENCODE, - VENC_DALRPC_INTRA_REFRESH, - VENC_DALRPC_RC_CONFIG, - VENC_DALRPC_ENCODE_CONFIG, + VENC_BUFFER_TYPE_INPUT, + VENC_BUFFER_TYPE_OUTPUT, + VENC_BUFFER_TYPE_QDSP6, + VENC_BUFFER_TYPE_HDR +}; +enum { + VENC_DALRPC_GET_SYNTAX_HEADER = DAL_OP_FIRST_DEVICE_API, + VENC_DALRPC_UPDATE_INTRA_REFRESH, + VENC_DALRPC_UPDATE_FRAME_RATE, + VENC_DALRPC_UPDATE_BITRATE, + VENC_DALRPC_UPDATE_QP_RANGE, + VENC_DALRPC_UPDATE_INTRA_PERIOD, + VENC_DALRPC_REQUEST_IFRAME, + VENC_DALRPC_START, VENC_DALRPC_STOP, + VENC_DALRPC_SUSPEND, + VENC_DALRPC_RESUME, + VENC_DALRPC_FLUSH, + VENC_DALRPC_QUEUE_INPUT, + VENC_DALRPC_QUEUE_OUTPUT +}; +struct venc_input_payload { + u32 data; +}; +struct venc_output_payload { + u32 size; + long long time_stamp; + u32 flags; + u32 data; + u32 client_data_from_input; +}; +union venc_payload { + struct venc_input_payload input_payload; + struct venc_output_payload output_payload; +}; +struct venc_msg_type { + u32 event; + u32 status; + union venc_payload payload; +}; +struct venc_input_buf { + struct venc_buf_type yuv_buf; + u32 data_size; + long long time_stamp; + u32 flags; + u32 dvs_offsetx; + u32 dvs_offsety; + u32 client_data; + u32 op_client_data; +}; +struct venc_output_buf { + struct venc_buf_type bit_stream_buf; + u32 client_data; }; -struct callback_event_data { - u32 data_notify_event; - u32 enc_cb_handle; - u32 empty_input_buffer_event; +struct venc_msg_list { + struct list_head list; + struct venc_msg msg_data; }; - -struct buf_info { - unsigned long paddr; - unsigned long vaddr; - struct file *file; - struct venc_buf venc_buf; -}; - -#define VENC_MAX_BUF_NUM 15 -#define RLC_MAX_BUF_NUM 2 -#define BITS_PER_PIXEL 12 -#define PIXELS_PER_MACROBLOCK 16 - -#define VENC_CB_EVENT_ID 0xd0e4c0de - -struct q6venc_dev { - struct dal_client *venc; - struct callback_event_data cb_ev_data; - bool stop_encode; - struct buf_info rlc_bufs[RLC_MAX_BUF_NUM]; - unsigned int rlc_buf_index; - unsigned int rlc_buf_len; - unsigned int enc_buf_size; - struct buf_info enc_bufs[VENC_MAX_BUF_NUM]; - unsigned int num_enc_bufs; - wait_queue_head_t encode_wq; - - /* protects all state in q6venc_dev except for cb stuff below */ - struct mutex lock; - - /* protects encode_done and done_frame inside the callback */ - spinlock_t done_lock; - struct frame_type done_frame; - bool encode_done; -}; - -static int get_buf_info(struct buf_info *buf_info, struct venc_buf *venc_buf) -{ - unsigned long len; - unsigned long vaddr; +struct venc_buf { + int fd; + u32 offset; + u32 size; + u32 btype; unsigned long paddr; struct file *file; - int ret; +}; +struct venc_pmem_list { + struct list_head list; + struct venc_buf buf; +}; +struct venc_dev { + bool is_active; + bool stop_called; + enum venc_state_type state; + struct list_head venc_msg_list_head; + struct list_head venc_msg_list_free; + spinlock_t venc_msg_list_lock; + struct list_head venc_pmem_list_head; + spinlock_t venc_pmem_list_lock; + struct dal_client *q6_handle; + wait_queue_head_t venc_msg_evt; + struct device *class_devp; +}; - ret = get_pmem_file(venc_buf->fd, &paddr, &vaddr, &len, &file); - if (ret) { - pr_err("%s: get_pmem_file failed for fd=%d offset=%ld\n", - __func__, venc_buf->fd, venc_buf->offset); - return ret; - } else if (venc_buf->offset >= len) { - /* XXX: we really should check venc_buf->size too, but userspace - * sometimes leaves this uninitialized (in encode ioctl) */ - pr_err("%s: invalid offset/size (%ld + %ld > %ld) for fd=%d\n", - __func__, venc_buf->offset, venc_buf->size, len, - venc_buf->fd); - put_pmem_file(file); - return -EINVAL; +#define DEBUG_VENC 0 +#if DEBUG_VENC +#define TRACE(fmt, x...) \ + do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0) +#else +#define TRACE(fmt, x...) do { } while (0) +#endif + +static struct cdev cdev; +static dev_t venc_dev_num; +static struct class *venc_class; +static struct venc_dev *venc_device_p; +static int venc_ref; + +static DEFINE_MUTEX(idlecount_lock); +static int idlecount; +static struct wake_lock wakelock; +static struct wake_lock idlelock; + +static void prevent_sleep(void) +{ + mutex_lock(&idlecount_lock); + if (++idlecount == 1) { + wake_lock(&idlelock); + wake_lock(&wakelock); } - - buf_info->file = file; - buf_info->paddr = paddr + venc_buf->offset; - buf_info->vaddr = vaddr; - memcpy(&buf_info->venc_buf, venc_buf, sizeof(struct venc_buf)); - return 0; + mutex_unlock(&idlecount_lock); } -static void put_buf_info(struct buf_info *buf_info) +static void allow_sleep(void) { - if (!buf_info || !buf_info->file) - return; - put_pmem_file(buf_info->file); - buf_info->file = NULL; + mutex_lock(&idlecount_lock); + if (--idlecount == 0) { + wake_unlock(&idlelock); + wake_unlock(&wakelock); + } + mutex_unlock(&idlecount_lock); } -static void q6venc_callback(void *context, void *data, uint32_t len) +static inline int venc_check_version(u32 client, u32 server) { - struct q6venc_dev *q6venc = context; - struct q6_frame_type *q6frame = data; - struct buf_info *rlc_buf; + int ret = -EINVAL; + + if ((VENC_GET_MAJOR_VERSION(client) == VENC_GET_MAJOR_VERSION(server)) + && (VENC_GET_MINOR_VERSION(client) <= + VENC_GET_MINOR_VERSION(server))) + ret = 0; + + return ret; +} + +static int venc_get_msg(struct venc_dev *dvenc, void *msg) +{ + struct venc_msg_list *l; unsigned long flags; - int i; + int ret = 0; + struct venc_msg qdsp_msg; - pr_debug("%s \n", __func__); - - spin_lock_irqsave(&q6venc->done_lock, flags); - q6venc->encode_done = true; - for (i = 0; i < RLC_MAX_BUF_NUM; ++i) { - rlc_buf = &q6venc->rlc_bufs[i]; - if (rlc_buf->paddr == q6frame->frame_addr) - goto frame_found; + if (!dvenc->is_active) + return -EPERM; + spin_lock_irqsave(&dvenc->venc_msg_list_lock, flags); + list_for_each_entry_reverse(l, &dvenc->venc_msg_list_head, list) { + memcpy(&qdsp_msg, &l->msg_data, sizeof(struct venc_msg)); + list_del(&l->list); + list_add(&l->list, &dvenc->venc_msg_list_free); + ret = 1; + break; } - - pr_err("%s: got incorrect phy address 0x%08x from q6 \n", __func__, - q6frame->frame_addr); - q6venc->done_frame.q6_frame_type.frame_len = 0; - wake_up_interruptible(&q6venc->encode_wq); - goto done; - -frame_found: - memcpy(&q6venc->done_frame.frame_addr, &rlc_buf->venc_buf, - sizeof(struct venc_buf)); - memcpy(&q6venc->done_frame.q6_frame_type, q6frame, - sizeof(struct q6_frame_type)); - - dmac_inv_range((const void *)q6venc->rlc_bufs[i].vaddr, - (const void *)(q6venc->rlc_bufs[i].vaddr + - q6venc->rlc_buf_len)); - - wake_up_interruptible(&q6venc->encode_wq); - -done: - spin_unlock_irqrestore(&q6venc->done_lock, flags); + spin_unlock_irqrestore(&dvenc->venc_msg_list_lock, flags); + if (copy_to_user(msg, &qdsp_msg, sizeof(struct venc_msg))) + pr_err("%s failed to copy_to_user\n", __func__); + return ret; } -static void callback(void *data, int len, void *cookie) +static void venc_put_msg(struct venc_dev *dvenc, struct venc_msg *msg) { - struct q6venc_dev *ve = (struct q6venc_dev *)cookie; + struct venc_msg_list *l; + unsigned long flags; + int found = 0; + + spin_lock_irqsave(&dvenc->venc_msg_list_lock, flags); + list_for_each_entry(l, &dvenc->venc_msg_list_free, list) { + memcpy(&l->msg_data, msg, sizeof(struct venc_msg)); + list_del(&l->list); + list_add(&l->list, &dvenc->venc_msg_list_head); + found = 1; + break; + } + spin_unlock_irqrestore(&dvenc->venc_msg_list_lock, flags); + if (found) + wake_up(&dvenc->venc_msg_evt); + else + pr_err("%s: failed to find a free node\n", __func__); + +} + +static struct venc_pmem_list *venc_add_pmem_to_list(struct venc_dev *dvenc, + struct venc_pmem *mptr, + u32 btype) +{ + int ret = 0; + unsigned long flags; + unsigned long len; + unsigned long vaddr; + struct venc_pmem_list *plist = NULL; + + plist = kzalloc(sizeof(struct venc_pmem_list), GFP_KERNEL); + if (!plist) { + pr_err("%s: kzalloc failed\n", __func__); + return NULL; + } + + ret = get_pmem_file(mptr->fd, &(plist->buf.paddr), + &vaddr, &len, &(plist->buf.file)); + if (ret) { + pr_err("%s: get_pmem_file failed for fd=%d offset=%d\n", + __func__, mptr->fd, mptr->offset); + goto err_venc_add_pmem; + } else if (mptr->offset >= len) { + pr_err("%s: invalid offset (%d > %ld) for fd=%d\n", + __func__, mptr->offset, len, mptr->fd); + ret = -EINVAL; + goto err_venc_get_pmem; + } + + plist->buf.fd = mptr->fd; + plist->buf.paddr += mptr->offset; + plist->buf.size = mptr->size; + plist->buf.btype = btype; + plist->buf.offset = mptr->offset; + + spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags); + list_add(&plist->list, &dvenc->venc_pmem_list_head); + spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags); + return plist; + +err_venc_get_pmem: + put_pmem_file(plist->buf.file); +err_venc_add_pmem: + kfree(plist); + return NULL; +} + +static struct venc_pmem_list *venc_get_pmem_from_list( + struct venc_dev *dvenc, u32 pmem_fd, + u32 offset, u32 btype) +{ + struct venc_pmem_list *plist; + unsigned long flags; + struct file *file; + int found = 0; + + file = fget(pmem_fd); + if (!file) { + pr_err("%s: invalid encoder buffer fd(%d)\n", __func__, + pmem_fd); + return NULL; + } + spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags); + list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list) { + if (plist->buf.btype == btype && plist->buf.file == file && + plist->buf.offset == offset) { + found = 1; + break; + } + } + spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags); + fput(file); + if (found) + return plist; + + else + return NULL; +} + +static int venc_set_buffer(struct venc_dev *dvenc, void *argp, + u32 btype) +{ + struct venc_pmem pmem; + struct venc_pmem_list *plist; + int ret = 0; + + ret = copy_from_user(&pmem, argp, sizeof(pmem)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + plist = venc_add_pmem_to_list(dvenc, &pmem, btype); + if (plist == NULL) { + pr_err("%s: buffer add_to_pmem_list failed\n", + __func__); + return -EPERM; + } + return ret; +} + +static int venc_assign_q6_buffers(struct venc_dev *dvenc, + struct venc_buffers *pbufs, + struct venc_nonio_buf_config *pcfg) +{ + int ret = 0; + struct venc_pmem_list *plist; + + plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[0]), + VENC_BUFFER_TYPE_QDSP6); + if (plist == NULL) { + pr_err("%s: recon_buf0 failed to add_to_pmem_list\n", + __func__); + return -EPERM; + } + pcfg->recon_buf1.region = pbufs->recon_buf[0].src; + pcfg->recon_buf1.phys = plist->buf.paddr; + pcfg->recon_buf1.size = plist->buf.size; + pcfg->recon_buf1.offset = 0; + + plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[1]), + VENC_BUFFER_TYPE_QDSP6); + if (plist == NULL) { + pr_err("%s: recons_buf1 failed to add_to_pmem_list\n", + __func__); + return -EPERM; + } + pcfg->recon_buf2.region = pbufs->recon_buf[1].src; + pcfg->recon_buf2.phys = plist->buf.paddr; + pcfg->recon_buf2.size = plist->buf.size; + pcfg->recon_buf2.offset = 0; + + plist = venc_add_pmem_to_list(dvenc, &(pbufs->wb_buf), + VENC_BUFFER_TYPE_QDSP6); + if (plist == NULL) { + pr_err("%s: wb_buf failed to add_to_pmem_list\n", + __func__); + return -EPERM; + } + pcfg->wb_buf.region = pbufs->wb_buf.src; + pcfg->wb_buf.phys = plist->buf.paddr; + pcfg->wb_buf.size = plist->buf.size; + pcfg->wb_buf.offset = 0; + + plist = venc_add_pmem_to_list(dvenc, &(pbufs->cmd_buf), + VENC_BUFFER_TYPE_QDSP6); + if (plist == NULL) { + pr_err("%s: cmd_buf failed to add_to_pmem_list\n", + __func__); + return -EPERM; + } + pcfg->cmd_buf.region = pbufs->cmd_buf.src; + pcfg->cmd_buf.phys = plist->buf.paddr; + pcfg->cmd_buf.size = plist->buf.size; + pcfg->cmd_buf.offset = 0; + + plist = venc_add_pmem_to_list(dvenc, &(pbufs->vlc_buf), + VENC_BUFFER_TYPE_QDSP6); + if (plist == NULL) { + pr_err("%s: vlc_buf failed to add_to_pmem_list" + " failed\n", __func__); + return -EPERM; + } + pcfg->vlc_buf.region = pbufs->vlc_buf.src; + pcfg->vlc_buf.phys = plist->buf.paddr; + pcfg->vlc_buf.size = plist->buf.size; + pcfg->vlc_buf.offset = 0; + + return ret; +} + +static int venc_start(struct venc_dev *dvenc, void *argp) +{ + int ret = 0; + struct venc_q6_config q6_config; + struct venc_init_config vconfig; + + dvenc->state = VENC_STATE_START; + ret = copy_from_user(&vconfig, argp, sizeof(struct venc_init_config)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + memcpy(&q6_config, &(vconfig.q6_config), sizeof(q6_config)); + ret = venc_assign_q6_buffers(dvenc, &(vconfig.q6_bufs), + &(q6_config.buf_params)); + if (ret != 0) { + pr_err("%s: assign_q6_buffers failed\n", __func__); + return -EPERM; + } + + q6_config.callback_event = dvenc->q6_handle; + TRACE("%s: parameters: handle:%p, config:%p, callback:%p \n", __func__, + dvenc->q6_handle, &q6_config, q6_config.callback_event); + TRACE("%s: parameters:recon1:0x%x, recon2:0x%x," + " wb_buf:0x%x, cmd:0x%x, vlc:0x%x\n", __func__, + q6_config.buf_params.recon_buf1.phys, + q6_config.buf_params.recon_buf2.phys, + q6_config.buf_params.wb_buf.phys, + q6_config.buf_params.cmd_buf.phys, + q6_config.buf_params.vlc_buf.phys); + TRACE("%s: size of param:%d \n", __func__, sizeof(q6_config)); + ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_START, &q6_config, + sizeof(q6_config)); + if (ret != 0) { + pr_err("%s: remote function failed (%d)\n", __func__, ret); + return ret; + } + return ret; +} + +static int venc_encode_frame(struct venc_dev *dvenc, void *argp) +{ + int ret = 0; + struct venc_pmem buf; + struct venc_input_buf q6_input; + struct venc_pmem_list *plist; + struct venc_buffer input; + + ret = copy_from_user(&input, argp, sizeof(struct venc_buffer)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + ret = copy_from_user(&buf, + ((struct venc_buffer *)argp)->ptr_buffer, + sizeof(struct venc_pmem)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + + plist = venc_get_pmem_from_list(dvenc, buf.fd, buf.offset, + VENC_BUFFER_TYPE_INPUT); + if (NULL == plist) { + plist = venc_add_pmem_to_list(dvenc, &buf, + VENC_BUFFER_TYPE_INPUT); + if (plist == NULL) { + pr_err("%s: buffer add_to_pmem_list failed\n", + __func__); + return -EPERM; + } + } + + q6_input.flags = 0; + if (input.flags & VENC_FLAG_EOS) + q6_input.flags |= 0x00000001; + q6_input.yuv_buf.region = 0; + q6_input.yuv_buf.phys = plist->buf.paddr; + q6_input.yuv_buf.size = plist->buf.size; + q6_input.yuv_buf.offset = 0; + q6_input.data_size = plist->buf.size; + q6_input.client_data = (u32)input.client_data; + q6_input.time_stamp = input.time_stamp; + q6_input.dvs_offsetx = 0; + q6_input.dvs_offsety = 0; + + +kpi_start[cnt] = ktime_to_ns(ktime_get()); +TRACE("kpi_start %d, %u \n", cnt, kpi_start[cnt]); +cnt++; + + TRACE("Pushing down input phys=0x%x fd= %d, client_data: 0x%x," + " time_stamp:%lld \n", q6_input.yuv_buf.phys, plist->buf.fd, + input.client_data, input.time_stamp); + ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_INPUT, + &q6_input, sizeof(q6_input)); + + if (ret != 0) + pr_err("%s: Q6 queue_input failed (%d)\n", __func__, + (int)ret); + return ret; +} + +static int venc_fill_output(struct venc_dev *dvenc, void *argp) +{ + int ret = 0; + struct venc_pmem buf; + struct venc_output_buf q6_output; + struct venc_pmem_list *plist; + struct venc_buffer output; + + ret = copy_from_user(&output, argp, sizeof(struct venc_buffer)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + ret = copy_from_user(&buf, + ((struct venc_buffer *)argp)->ptr_buffer, + sizeof(struct venc_pmem)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + plist = venc_get_pmem_from_list(dvenc, buf.fd, buf.offset, + VENC_BUFFER_TYPE_OUTPUT); + if (NULL == plist) { + plist = venc_add_pmem_to_list(dvenc, &buf, + VENC_BUFFER_TYPE_OUTPUT); + if (NULL == plist) { + pr_err("%s: output buffer failed to add_to_pmem_list" + "\n", __func__); + return -EPERM; + } + } + q6_output.bit_stream_buf.region = 0; + q6_output.bit_stream_buf.phys = (u32)plist->buf.paddr; + q6_output.bit_stream_buf.size = plist->buf.size; + q6_output.bit_stream_buf.offset = 0; + q6_output.client_data = (u32)output.client_data; + ret = + dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_OUTPUT, &q6_output, + sizeof(q6_output)); + if (ret != 0) + pr_err("%s: remote function failed (%d)\n", __func__, ret); + return ret; +} + +static int venc_stop(struct venc_dev *dvenc) +{ + int ret = 0; + struct venc_msg msg; + + dvenc->stop_called = 1; + ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1); + if (ret) { + pr_err("%s: remote runction failed (%d)\n", __func__, ret); + msg.msg_code = VENC_MSG_STOP; + msg.msg_data_size = 0; + msg.status_code = VENC_S_EFAIL; + venc_put_msg(dvenc, &msg); + } + return ret; +} + +static int venc_pause(struct venc_dev *dvenc) +{ + int ret = 0; + struct venc_msg msg; + + ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_SUSPEND, 1); + if (ret) { + pr_err("%s: remote function failed (%d)\n", __func__, ret); + msg.msg_code = VENC_MSG_PAUSE; + msg.status_code = VENC_S_EFAIL; + msg.msg_data_size = 0; + venc_put_msg(dvenc, &msg); + } + return ret; +} + +static int venc_resume(struct venc_dev *dvenc) +{ + int ret = 0; + struct venc_msg msg; + + ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_RESUME, 1); + if (ret) { + pr_err("%s: remote function failed (%d)\n", __func__, ret); + msg.msg_code = VENC_MSG_RESUME; + msg.msg_data_size = 0; + msg.status_code = VENC_S_EFAIL; + venc_put_msg(dvenc, &msg); + } + return ret; +} + +static int venc_flush(struct venc_dev *dvenc, void *argp) +{ + int ret = 0; + struct venc_msg msg; + union venc_msg_data smsg; + int status = VENC_S_SUCCESS; + struct venc_buffer_flush flush; + + if (copy_from_user(&flush, argp, sizeof(struct venc_buffer_flush))) + return -EFAULT; + if (flush.flush_mode == VENC_FLUSH_ALL) { + ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_FLUSH, 1); + if (ret) + status = VENC_S_EFAIL; + } else + status = VENC_S_ENOTSUPP; + + if (status != VENC_S_SUCCESS) { + if ((flush.flush_mode == VENC_FLUSH_INPUT) || + (flush.flush_mode == VENC_FLUSH_ALL)) { + smsg.flush_ret.flush_mode = VENC_FLUSH_INPUT; + msg.msg_data = smsg; + msg.status_code = status; + msg.msg_code = VENC_MSG_FLUSH; + msg.msg_data_size = sizeof(union venc_msg_data); + venc_put_msg(dvenc, &msg); + } + if (flush.flush_mode == VENC_FLUSH_OUTPUT || + (flush.flush_mode == VENC_FLUSH_ALL)) { + smsg.flush_ret.flush_mode = VENC_FLUSH_OUTPUT; + msg.msg_data = smsg; + msg.status_code = status; + msg.msg_code = VENC_MSG_FLUSH; + msg.msg_data_size = sizeof(union venc_msg_data); + venc_put_msg(dvenc, &msg); + } + return -EIO; + } + return ret; +} + +static int venc_get_sequence_hdr(struct venc_dev *dvenc, void *argp) +{ + pr_err("%s not supported\n", __func__); + return -EIO; +} + +static int venc_set_qp_range(struct venc_dev *dvenc, void *argp) +{ + int ret = 0; + struct venc_qp_range qp; + + ret = copy_from_user(&qp, argp, sizeof(struct venc_qp_range)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + + if (dvenc->state == VENC_STATE_START || + dvenc->state == VENC_STATE_PAUSE) { + ret = + dal_call_f5(dvenc->q6_handle, VENC_DALRPC_UPDATE_QP_RANGE, + &qp, sizeof(struct venc_qp_range)); + if (ret) { + pr_err("%s: remote function failed (%d) \n", __func__, + ret); + return ret; + } + } + return ret; +} + +static int venc_set_intra_period(struct venc_dev *dvenc, void *argp) +{ + int ret = 0; + u32 pnum = 0; + + ret = copy_from_user(&pnum, argp, sizeof(int)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + if (dvenc->state == VENC_STATE_START || + dvenc->state == VENC_STATE_PAUSE) { + ret = dal_call_f0(dvenc->q6_handle, + VENC_DALRPC_UPDATE_INTRA_PERIOD, pnum); + if (ret) + pr_err("%s: remote function failed (%d)\n", __func__, + ret); + } + return ret; +} + +static int venc_set_intra_refresh(struct venc_dev *dvenc, void *argp) +{ + int ret = 0; + u32 mb_num = 0; + + ret = copy_from_user(&mb_num, argp, sizeof(int)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + if (dvenc->state == VENC_STATE_START || + dvenc->state == VENC_STATE_PAUSE) { + ret = dal_call_f0(dvenc->q6_handle, + VENC_DALRPC_UPDATE_INTRA_REFRESH, mb_num); + if (ret) + pr_err("%s: remote function failed (%d)\n", __func__, + ret); + } + return ret; +} + +static int venc_set_frame_rate(struct venc_dev *dvenc, void *argp) +{ + int ret = 0; + struct venc_frame_rate pdata; + ret = copy_from_user(&pdata, argp, sizeof(struct venc_frame_rate)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + if (dvenc->state == VENC_STATE_START || + dvenc->state == VENC_STATE_PAUSE) { + ret = dal_call_f5(dvenc->q6_handle, + VENC_DALRPC_UPDATE_FRAME_RATE, + (void *)&(pdata), + sizeof(struct venc_frame_rate)); + if (ret) + pr_err("%s: remote function failed (%d)\n", __func__, + ret); + } + return ret; +} + +static int venc_set_target_bitrate(struct venc_dev *dvenc, void *argp) +{ + int ret = 0; + u32 pdata = 0; + + ret = copy_from_user(&pdata, argp, sizeof(int)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + if (dvenc->state == VENC_STATE_START || + dvenc->state == VENC_STATE_PAUSE) { + ret = dal_call_f0(dvenc->q6_handle, + VENC_DALRPC_UPDATE_BITRATE, pdata); + if (ret) + pr_err("%s: remote function failed (%d)\n", __func__, + ret); + } + return ret; +} + +static int venc_request_iframe(struct venc_dev *dvenc) +{ + int ret = 0; + + if (dvenc->state != VENC_STATE_START) + return -EINVAL; + + ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_REQUEST_IFRAME, 1); + if (ret) + pr_err("%s: remote function failed (%d)\n", __func__, ret); + return ret; +} + +static int venc_stop_read_msg(struct venc_dev *dvenc) +{ + struct venc_msg msg; + int ret = 0; + + msg.status_code = 0; + msg.msg_code = VENC_MSG_STOP_READING_MSG; + msg.msg_data_size = 0; + venc_put_msg(dvenc, &msg); + return ret; +} + +static int venc_q6_stop(struct venc_dev *dvenc) +{ + int ret = 0; + struct venc_pmem_list *plist; + + wake_up(&dvenc->venc_msg_evt); + list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list) + put_pmem_file(plist->buf.file); + dvenc->state = VENC_STATE_STOP; + return ret; +} + +static int venc_translate_error(enum venc_status_code q6_status) +{ + int ret = 0; + + switch (q6_status) { + case VENC_STATUS_SUCCESS: + ret = VENC_S_SUCCESS; + break; + case VENC_STATUS_ERROR: + ret = VENC_S_EFAIL; + break; + case VENC_STATUS_INVALID_STATE: + ret = VENC_S_EINVALSTATE; + break; + case VENC_STATUS_FLUSHING: + ret = VENC_S_EFLUSHED; + break; + case VENC_STATUS_INVALID_PARAM: + ret = VENC_S_EBADPARAM; + break; + case VENC_STATUS_CMD_QUEUE_FULL: + ret = VENC_S_ECMDQFULL; + break; + case VENC_STATUS_CRITICAL: + ret = VENC_S_EFATAL; + break; + case VENC_STATUS_INSUFFICIENT_RESOURCES: + ret = VENC_S_ENOHWRES; + break; + case VENC_STATUS_TIMEOUT: + ret = VENC_S_ETIMEOUT; + break; + } + if (q6_status != VENC_STATUS_SUCCESS) + pr_err("%s: Q6 failed (%d)", __func__, (int)q6_status); + return ret; +} + +static void venc_q6_callback(void *data, int len, void *cookie) +{ + int status = 0; + struct venc_dev *dvenc = (struct venc_dev *)cookie; + struct venc_msg_type *q6_msg = NULL; + struct venc_msg msg, msg1; + union venc_msg_data smsg1, smsg2; + unsigned long msg_code; + struct venc_input_payload *pload1; + struct venc_output_payload *pload2; uint32_t *tmp = (uint32_t *) data; - if (tmp[0] == VENC_CB_EVENT_ID) - q6venc_callback(ve, &tmp[3], tmp[2]); - else - pr_err("%s: Unknown callback received for %p\n", __func__, ve); + if (dvenc == NULL) { + pr_err("%s: empty driver parameter\n", __func__); + return; + } + if (tmp[2] == sizeof(struct venc_msg_type)) { + q6_msg = (struct venc_msg_type *)&tmp[3]; + } else { + pr_err("%s: callback with empty message (%d, %d)\n", + __func__, tmp[2], sizeof(struct venc_msg_type)); + return; + } + msg.msg_data_size = 0; + status = venc_translate_error(q6_msg->status); + switch ((enum venc_event_type_enum)q6_msg->event) { + case VENC_EVENT_START_STATUS: + dvenc->state = VENC_STATE_START; + msg_code = VENC_MSG_START; + break; + case VENC_EVENT_STOP_STATUS: + venc_q6_stop(dvenc); + msg_code = VENC_MSG_STOP; + break; + case VENC_EVENT_SUSPEND_STATUS: + dvenc->state = VENC_STATE_PAUSE; + msg_code = VENC_MSG_PAUSE; + break; + case VENC_EVENT_RESUME_STATUS: + dvenc->state = VENC_STATE_START; + msg_code = VENC_MSG_RESUME; + break; + case VENC_EVENT_FLUSH_STATUS: + smsg1.flush_ret.flush_mode = VENC_FLUSH_INPUT; + msg1.status_code = status; + msg1.msg_code = VENC_MSG_FLUSH; + msg1.msg_data = smsg1; + msg1.msg_data_size = sizeof(union venc_msg_data); + venc_put_msg(dvenc, &msg1); + smsg2.flush_ret.flush_mode = VENC_FLUSH_OUTPUT; + msg_code = VENC_MSG_FLUSH; + msg.msg_data = smsg2; + msg.msg_data_size = sizeof(union venc_msg_data); + break; + case VENC_EVENT_RELEASE_INPUT: + +kpi_end = ktime_to_ns(ktime_get()); +TRACE("KPI : encode a frame, %u ms\n", (kpi_end - kpi_start[0])/(1000*1000)); +if (cnt > 0) { + int i = 0; + for (i = 0; i < cnt; i++) + kpi_start[i] = kpi_start[i+1]; +} +cnt--; + pload1 = &((q6_msg->payload).input_payload); + TRACE("Release_input: data: 0x%x \n", pload1->data); + if (pload1 != NULL) { + msg.msg_data.buf.client_data = pload1->data; + msg_code = VENC_MSG_INPUT_BUFFER_DONE; + msg.msg_data_size = sizeof(union venc_msg_data); + } + break; + case VENC_EVENT_DELIVER_OUTPUT: + pload2 = &((q6_msg->payload).output_payload); + smsg1.buf.flags = 0; + if (pload2->flags & VENC_FLAG_SYNC_FRAME) + smsg1.buf.flags |= VENC_FLAG_SYNC_FRAME; + if (pload2->flags & VENC_FLAG_CODEC_CONFIG) + smsg1.buf.flags |= VENC_FLAG_CODEC_CONFIG; + if (pload2->flags & VENC_FLAG_END_OF_FRAME) + smsg1.buf.flags |= VENC_FLAG_END_OF_FRAME; + if (pload2->flags & VENC_FLAG_EOS) + smsg1.buf.flags |= VENC_FLAG_EOS; + smsg1.buf.len = pload2->size; + smsg1.buf.offset = 0; + smsg1.buf.time_stamp = pload2->time_stamp; + smsg1.buf.client_data = pload2->data; + msg_code = VENC_MSG_OUTPUT_BUFFER_DONE; + msg.msg_data = smsg1; + msg.msg_data_size = sizeof(union venc_msg_data); + break; + default: + pr_err("%s: invalid response from Q6 (%d)\n", __func__, + (int)q6_msg->event); + return; + } + msg.status_code = status; + msg.msg_code = msg_code; + venc_put_msg(dvenc, &msg); + return; +} + +static int venc_get_version(struct venc_dev *dvenc, void *argp) +{ + struct venc_version ver_info; + int ret = 0; + + ver_info.major = VENC_GET_MAJOR_VERSION(VENC_INTERFACE_VERSION); + ver_info.minor = VENC_GET_MINOR_VERSION(VENC_INTERFACE_VERSION); + + ret = copy_to_user(((struct venc_version *)argp), + &ver_info, sizeof(ver_info)); + if (ret) + pr_err("%s failed to copy_to_user\n", __func__); + + return ret; + +} + +static long q6venc_ioctl(struct file *file, u32 cmd, + unsigned long arg) +{ + long ret = 0; + void __user *argp = (void __user *)arg; + struct venc_dev *dvenc = file->private_data; + + if (!dvenc || !dvenc->is_active) + return -EPERM; + + switch (cmd) { + case VENC_IOCTL_SET_INPUT_BUFFER: + ret = venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_INPUT); + break; + case VENC_IOCTL_SET_OUTPUT_BUFFER: + ret = venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_OUTPUT); + break; + case VENC_IOCTL_GET_SEQUENCE_HDR: + ret = venc_get_sequence_hdr(dvenc, argp); + break; + case VENC_IOCTL_SET_QP_RANGE: + ret = venc_set_qp_range(dvenc, argp); + break; + case VENC_IOCTL_SET_INTRA_PERIOD: + ret = venc_set_intra_period(dvenc, argp); + break; + case VENC_IOCTL_SET_INTRA_REFRESH: + ret = venc_set_intra_refresh(dvenc, argp); + break; + case VENC_IOCTL_SET_FRAME_RATE: + ret = venc_set_frame_rate(dvenc, argp); + break; + case VENC_IOCTL_SET_TARGET_BITRATE: + ret = venc_set_target_bitrate(dvenc, argp); + break; + case VENC_IOCTL_CMD_REQUEST_IFRAME: + if (dvenc->state == VENC_STATE_START) + ret = venc_request_iframe(dvenc); + break; + case VENC_IOCTL_CMD_START: + ret = venc_start(dvenc, argp); + break; + case VENC_IOCTL_CMD_STOP: + ret = venc_stop(dvenc); + break; + case VENC_IOCTL_CMD_PAUSE: + ret = venc_pause(dvenc); + break; + case VENC_IOCTL_CMD_RESUME: + ret = venc_resume(dvenc); + break; + case VENC_IOCTL_CMD_ENCODE_FRAME: + ret = venc_encode_frame(dvenc, argp); + break; + case VENC_IOCTL_CMD_FILL_OUTPUT_BUFFER: + ret = venc_fill_output(dvenc, argp); + break; + case VENC_IOCTL_CMD_FLUSH: + ret = venc_flush(dvenc, argp); + break; + case VENC_IOCTL_CMD_READ_NEXT_MSG: + wait_event_interruptible(dvenc->venc_msg_evt, + venc_get_msg(dvenc, argp)); + break; + case VENC_IOCTL_CMD_STOP_READ_MSG: + ret = venc_stop_read_msg(dvenc); + break; + case VENC_IOCTL_GET_VERSION: + ret = venc_get_version(dvenc, argp); + break; + default: + pr_err("%s: invalid ioctl code (%d)\n", __func__, cmd); + ret = -ENOTTY; + break; + } + return ret; } static int q6venc_open(struct inode *inode, struct file *file) { - struct q6venc_dev *q6venc; - int err; + int i; + int ret = 0; + struct venc_dev *dvenc; + struct venc_msg_list *plist; + struct dal_info version_info; - q6venc = kzalloc(sizeof(struct q6venc_dev), GFP_KERNEL); - if (!q6venc) { - pr_err("%s: Unable to allocate memory for q6venc_dev\n", - __func__); + dvenc = kzalloc(sizeof(struct venc_dev), GFP_KERNEL); + if (!dvenc) { + pr_err("%s: unable to allocate memory for struct venc_dev\n", + __func__); return -ENOMEM; } - - file->private_data = q6venc; - - init_waitqueue_head(&q6venc->encode_wq); - mutex_init(&q6venc->lock); - spin_lock_init(&q6venc->done_lock); - - q6venc->venc = dal_attach(DALDEVICEID_VENC_DEVICE, - DALDEVICEID_VENC_PORTNAME, - callback, q6venc); - if (!q6venc->venc) { - pr_err("%s: dal_attach failed\n", __func__); - err = -EIO; - goto err_dal_attach; + file->private_data = dvenc; + INIT_LIST_HEAD(&dvenc->venc_msg_list_head); + INIT_LIST_HEAD(&dvenc->venc_msg_list_free); + INIT_LIST_HEAD(&dvenc->venc_pmem_list_head); + init_waitqueue_head(&dvenc->venc_msg_evt); + spin_lock_init(&dvenc->venc_msg_list_lock); + spin_lock_init(&dvenc->venc_pmem_list_lock); + venc_ref++; + for (i = 0; i < VENC_MSG_MAX; i++) { + plist = kzalloc(sizeof(struct venc_msg_list), GFP_KERNEL); + if (!plist) { + pr_err("%s: kzalloc failed\n", __func__); + ret = -ENOMEM; + goto err_venc_create_msg_list; + } + list_add(&plist->list, &dvenc->venc_msg_list_free); + } + dvenc->q6_handle = + dal_attach(DALDEVICEID_VENC_DEVICE, DALDEVICEID_VENC_PORTNAME, + venc_q6_callback, (void *)dvenc); + if (!(dvenc->q6_handle)) { + pr_err("%s: daldevice_attach failed (%d)\n", __func__, ret); + goto err_venc_dal_attach; + } + ret = dal_call_f9(dvenc->q6_handle, DAL_OP_INFO, &version_info, + sizeof(struct dal_info)); + if (ret) { + pr_err("%s: failed to get version\n", __func__); + goto err_venc_dal_open; } - q6venc->cb_ev_data.enc_cb_handle = VENC_CB_EVENT_ID; - err = dal_call_f5(q6venc->venc, VENC_DALRPC_SET_CB_CHANNEL, - &q6venc->cb_ev_data, sizeof(q6venc->cb_ev_data)); - if (err) { - pr_err("%s: set_cb_channgel failed\n", __func__); - goto err_dal_call_set_cb; + pr_info("VENC_INTERFACE_VERSION %X, version_info.version %X\n", + VENC_INTERFACE_VERSION, version_info.version); +#if 0 + if (venc_check_version(VENC_INTERFACE_VERSION, version_info.version)) { + pr_err("%s: driver version mismatch\n", __func__); + goto err_venc_dal_open; } - - pr_info("%s() handle=%p enc_cb=%08x\n", __func__, q6venc->venc, - q6venc->cb_ev_data.enc_cb_handle); - - return 0; - -err_dal_call_set_cb: - dal_detach(q6venc->venc); -err_dal_attach: - file->private_data = NULL; - mutex_destroy(&q6venc->lock); - kfree(q6venc); - return err; +#endif + ret = dal_call_f0(dvenc->q6_handle, DAL_OP_OPEN, 1); + if (ret) { + pr_err("%s: dal_call_open failed (%d)\n", __func__, ret); + goto err_venc_dal_open; + } + dvenc->state = VENC_STATE_STOP; + dvenc->is_active = 1; + prevent_sleep(); + return ret; +err_venc_dal_open: + dal_detach(dvenc->q6_handle); +err_venc_dal_attach: + list_for_each_entry(plist, &dvenc->venc_msg_list_free, list) { + list_del(&plist->list); + kfree(plist); + } +err_venc_create_msg_list: + kfree(dvenc); + venc_ref--; + return ret; } static int q6venc_release(struct inode *inode, struct file *file) { - struct q6venc_dev *q6venc; - int id, err; + int ret = 0; + struct venc_msg_list *l, *n; + struct venc_pmem_list *plist, *m; + struct venc_dev *dvenc; - q6venc = file->private_data; - file->private_data = NULL; - - pr_info("q6venc_close() handle=%p\n", q6venc->venc); - for (id = 0; id < q6venc->num_enc_bufs; id++) - put_buf_info(&q6venc->enc_bufs[id]); - put_buf_info(&q6venc->rlc_bufs[0]); - put_buf_info(&q6venc->rlc_bufs[1]); - - if(!q6venc->stop_encode) - { - err = dal_call_f0(q6venc->venc, VENC_DALRPC_STOP, 1); - if (err) - pr_err("%s: dal_rpc STOP call failed\n", __func__); - q6venc->stop_encode = true; + venc_ref--; + dvenc = file->private_data; + dvenc->is_active = 0; + wake_up_all(&dvenc->venc_msg_evt); + if (!dvenc->stop_called) + dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1); + dal_call_f0(dvenc->q6_handle, DAL_OP_CLOSE, 1); + dal_detach(dvenc->q6_handle); + list_for_each_entry_safe(l, n, &dvenc->venc_msg_list_free, list) { + list_del(&l->list); + kfree(l); + } + list_for_each_entry_safe(l, n, &dvenc->venc_msg_list_head, list) { + list_del(&l->list); + kfree(l); + } + if (!dvenc->stop_called) { + list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list) + put_pmem_file(plist->buf.file); + dvenc->stop_called = 1; } - dal_detach(q6venc->venc); - mutex_destroy(&q6venc->lock); - kfree(q6venc); - return 0; -} - -static int q6_config_encode(struct q6venc_dev *q6venc, uint32_t type, - struct init_config *init_config) -{ - struct q6_init_config *q6_init_config = &init_config->q6_init_config; - int ret; - int i; - - mutex_lock(&q6venc->lock); - - if (q6venc->num_enc_bufs != 0) { - pr_err("%s: multiple sessions not supported\n", __func__); - ret = -EBUSY; - goto err_busy; + list_for_each_entry_safe(plist, m, &dvenc->venc_pmem_list_head, list) { + list_del(&plist->list); + kfree(plist); } - - ret = get_buf_info(&q6venc->enc_bufs[0], &init_config->ref_frame_buf1); - if (ret) { - pr_err("%s: can't get ref_frame_buf1\n", __func__); - goto err_get_ref_frame_buf1; - } - - ret = get_buf_info(&q6venc->enc_bufs[1], &init_config->ref_frame_buf2); - if (ret) { - pr_err("%s: can't get ref_frame_buf2\n", __func__); - goto err_get_ref_frame_buf2; - } - - ret = get_buf_info(&q6venc->rlc_bufs[0], &init_config->rlc_buf1); - if (ret) { - pr_err("%s: can't get rlc_buf1\n", __func__); - goto err_get_rlc_buf1; - } - - ret = get_buf_info(&q6venc->rlc_bufs[1], &init_config->rlc_buf2); - if (ret) { - pr_err("%s: can't get rlc_buf2\n", __func__); - goto err_get_rlc_buf2; - } - q6venc->rlc_buf_len = 2 * q6_init_config->rlc_buf_length; - q6venc->num_enc_bufs = 2; - - q6venc->enc_buf_size = - (q6_init_config->enc_frame_width_inmb * PIXELS_PER_MACROBLOCK) * - (q6_init_config->enc_frame_height_inmb * PIXELS_PER_MACROBLOCK) * - BITS_PER_PIXEL / 8; - - q6_init_config->ref_frame_buf1_phy = q6venc->enc_bufs[0].paddr; - q6_init_config->ref_frame_buf2_phy = q6venc->enc_bufs[1].paddr; - q6_init_config->rlc_buf1_phy = q6venc->rlc_bufs[0].paddr; - q6_init_config->rlc_buf2_phy = q6venc->rlc_bufs[1].paddr; - - // The DSP may use the rlc_bufs during initialization, - for (i=0; irlc_bufs[i].vaddr, - (const void *)(q6venc->rlc_bufs[i].vaddr + - q6venc->rlc_buf_len)); - } - - ret = dal_call_f5(q6venc->venc, type, q6_init_config, - sizeof(struct q6_init_config)); - if (ret) { - pr_err("%s: rpc failed \n", __func__); - goto err_dal_rpc_init; - } - mutex_unlock(&q6venc->lock); - return 0; - -err_dal_rpc_init: - q6venc->num_enc_bufs = 0; - put_pmem_file(q6venc->rlc_bufs[1].file); -err_get_rlc_buf2: - put_pmem_file(q6venc->rlc_bufs[0].file); -err_get_rlc_buf1: - put_pmem_file(q6venc->enc_bufs[1].file); -err_get_ref_frame_buf2: - put_pmem_file(q6venc->enc_bufs[0].file); -err_get_ref_frame_buf1: -err_busy: - mutex_unlock(&q6venc->lock); + kfree(dvenc); + allow_sleep(); return ret; } -static int q6_encode(struct q6venc_dev *q6venc, struct encode_param *enc_param) -{ - struct q6_encode_param *q6_param = &enc_param->q6_encode_param; - struct file *file; - struct buf_info *buf; - int i; - int ret; - int rlc_buf_index; - - pr_debug("y_addr fd=%d offset=0x%08lx uv_offset=0x%08lx\n", - enc_param->y_addr.fd, enc_param->y_addr.offset, - enc_param->uv_offset); - - file = fget(enc_param->y_addr.fd); - if (!file) { - pr_err("%s: invalid encode buffer fd %d\n", __func__, - enc_param->y_addr.fd); - return -EBADF; - } - - mutex_lock(&q6venc->lock); - - for (i = 0; i < q6venc->num_enc_bufs; i++) { - buf = &q6venc->enc_bufs[i]; - if (buf->file == file - && buf->venc_buf.offset == enc_param->y_addr.offset) - break; - } - - if (i == q6venc->num_enc_bufs) { - if (q6venc->num_enc_bufs == VENC_MAX_BUF_NUM) { - pr_err("%s: too many input buffers\n", __func__); - ret = -ENOMEM; - goto done; - } - - buf = &q6venc->enc_bufs[q6venc->num_enc_bufs]; - ret = get_buf_info(buf, &enc_param->y_addr); - if (ret) { - pr_err("%s: can't get encode buffer\n", __func__); - ret = -EINVAL; - goto done; - } - - if (!IS_ALIGNED(buf->paddr, PAGE_SIZE)) { - pr_err("%s: input buffer not 4k aligned\n", __func__); - put_buf_info(buf); - ret = -EINVAL; - goto done; - } - q6venc->num_enc_bufs++; - } - - /* We must invalidate the buffer that the DSP will write to - * to ensure that a dirty cache line doesn't get flushed on - * top of the data that the DSP is writing. - * Unfortunately, we have to predict which rlc_buf index the - * DSP is going to write to. We assume it will write to buf - * 0 the first time we call q6_encode, and alternate afterwards - * */ - rlc_buf_index = q6venc->rlc_buf_index; - dmac_inv_range((const void *)q6venc->rlc_bufs[rlc_buf_index].vaddr, - (const void *)(q6venc->rlc_bufs[rlc_buf_index].vaddr + - q6venc->rlc_buf_len)); - q6venc->rlc_buf_index = (q6venc->rlc_buf_index + 1) % RLC_MAX_BUF_NUM; - - q6_param->luma_addr = buf->paddr; - q6_param->chroma_addr = q6_param->luma_addr + enc_param->uv_offset; - pr_debug("luma_addr=0x%08x chroma_addr=0x%08x\n", q6_param->luma_addr, - q6_param->chroma_addr); - - /* Ideally, each ioctl that passed in a data buffer would include the size - * of the input buffer, so we can properly flush the cache on it. Since - * userspace does not fill in the size fields, we have to assume the size - * based on the encoder configuration for now. - */ - flush_pmem_file(buf->file, enc_param->y_addr.offset, - q6venc->enc_buf_size); - - ret = dal_call_f5(q6venc->venc, VENC_DALRPC_ENCODE, q6_param, - sizeof(struct q6_encode_param)); - if (ret) { - pr_err("%s: encode rpc failed\n", __func__); - goto done; - } - - ret = 0; - -done: - mutex_unlock(&q6venc->lock); - fput(file); - return ret; -} - -static int q6venc_ioctl(struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg) -{ - struct q6venc_dev *q6venc = file->private_data; - struct init_config config; - struct encode_param encode_param; - struct intra_refresh intra_refresh; - struct rc_config rc_config; - struct frame_type frame_done; - unsigned int id; - unsigned long flags; - int err = 0; - - if (!q6venc) { - pr_err("%s: file has no private data\n", __func__); - return -ENODEV; - } - - pr_debug("%s\n", __func__); - - switch (cmd) { - case VENC_IOCTL_INITIALIZE: - pr_debug("%s: VENC_IOCTL_INITIALIZE\n", __func__); - if (copy_from_user(&config, (void __user *)arg, sizeof(config))) - return -EFAULT; - err = q6_config_encode(q6venc, VENC_DALRPC_INITIALIZE, &config); - break; - - case VENC_IOCTL_ENCODE_CONFIG: - pr_debug("%s: VENC_IOCTL_ENCODE_CONFIG\n", __func__); - if (copy_from_user(&config, (void __user *)arg, sizeof(config))) - return -EFAULT; - - err = q6_config_encode(q6venc, VENC_DALRPC_ENCODE_CONFIG, - &config); - break; - - case VENC_IOCTL_ENCODE: - pr_debug("%s: VENC_IOCTL_ENCODE\n", __func__); - if (copy_from_user(&encode_param, (void __user *)arg, - sizeof(encode_param))) - return -EFAULT; - err = q6_encode(q6venc, &encode_param); - break; - - case VENC_IOCTL_INTRA_REFRESH: - pr_debug("%s: VENC_IOCTL_INTRA_REFRESH\n", __func__); - if (copy_from_user(&intra_refresh, (void __user *)arg, - sizeof(intra_refresh))) - return -EFAULT; - - mutex_lock(&q6venc->lock); - err = dal_call_f5(q6venc->venc, VENC_DALRPC_INTRA_REFRESH, - &intra_refresh, sizeof(struct intra_refresh)); - mutex_unlock(&q6venc->lock); - if (err) - pr_err("%s: intra_refresh rpc failed\n", __func__); - break; - - case VENC_IOCTL_RC_CONFIG: - pr_debug("%s: VENC_IOCTL_RC_CONFIG\n", __func__); - if (copy_from_user(&rc_config, (void __user *)arg, - sizeof(rc_config))) - return -EFAULT; - - mutex_lock(&q6venc->lock); - err = dal_call_f5(q6venc->venc, VENC_DALRPC_RC_CONFIG, - &rc_config, sizeof(rc_config)); - mutex_unlock(&q6venc->lock); - if (err) - pr_err("%s: dal_call_f5 failed\n", __func__); - break; - - case VENC_IOCTL_STOP: - pr_debug("%s: VENC_IOCTL_STOP\n", __func__); - - mutex_lock(&q6venc->lock); - err = dal_call_f0(q6venc->venc, VENC_DALRPC_STOP, 1); - if (err) - pr_err("%s: dal_rpc STOP call failed\n", __func__); - - /* XXX: if the dal call fails we still want to continue to free - * the buffers. Is this correct? */ - for (id = 0; id < q6venc->num_enc_bufs; id++) - put_buf_info(&q6venc->enc_bufs[id]); - put_buf_info(&q6venc->rlc_bufs[0]); - put_buf_info(&q6venc->rlc_bufs[1]); - q6venc->num_enc_bufs = 0; - q6venc->stop_encode = true; - mutex_unlock(&q6venc->lock); - break; - - case VENC_IOCTL_WAIT_FOR_ENCODE: - pr_debug("%s: waiting for encode done event \n", __func__); - err = wait_event_interruptible(q6venc->encode_wq, - (q6venc->encode_done || q6venc->stop_encode)); - if (err < 0) { - err = -ERESTARTSYS; - break; - } - - mutex_lock(&q6venc->lock); - if (q6venc->stop_encode) { - q6venc->stop_encode = false; - mutex_unlock(&q6venc->lock); - pr_debug("%s: Received Stop encode event \n", __func__); - err = -EINTR; - break; - } - - spin_lock_irqsave(&q6venc->done_lock, flags); - if (!q6venc->encode_done) { - spin_unlock_irqrestore(&q6venc->done_lock, flags); - pr_err("%s: encoding not stopped, and is not done.\n", - __func__); - err = -EIO; - break; - } - - memcpy(&frame_done, &q6venc->done_frame, - sizeof(struct frame_type)); - q6venc->encode_done = false; - spin_unlock_irqrestore(&q6venc->done_lock, flags); - mutex_unlock(&q6venc->lock); - - if (frame_done.q6_frame_type.frame_len == 0) { - pr_debug("%s: got incorrect address from q6\n", - __func__); - err = -EIO; - break; - } - - pr_debug("%s: done encoding \n", __func__); - if (copy_to_user((void __user *)arg, &frame_done, - sizeof(struct frame_type))) - err = -EFAULT; - break; - - case VENC_IOCTL_STOP_ENCODE: - pr_debug("%s: Stop encode event \n", __func__); - mutex_lock(&q6venc->lock); - q6venc->stop_encode = true; - wake_up_interruptible(&q6venc->encode_wq); - mutex_unlock(&q6venc->lock); - break; - - default: - err = -ENOTTY; - break; - } - - return err; -} - -static const struct file_operations q6venc_dev_fops = { - .owner = THIS_MODULE, - .open = q6venc_open, - .release = q6venc_release, - .ioctl = q6venc_ioctl, -}; - -static struct miscdevice q6venc_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "q6venc", - .fops = &q6venc_dev_fops, +const struct file_operations q6venc_fops = { + .owner = THIS_MODULE, + .open = q6venc_open, + .release = q6venc_release, + .unlocked_ioctl = q6venc_ioctl, }; static int __init q6venc_init(void) { - int rc = 0; + int ret = 0; - rc = misc_register(&q6venc_misc); - if (rc) - pr_err("%s: Unable to register q6venc misc device\n", __func__); - return rc; + wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "venc_idle"); + wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "venc_suspend"); + + venc_device_p = kzalloc(sizeof(struct venc_dev), GFP_KERNEL); + if (!venc_device_p) { + pr_err("%s: unable to allocate memory for venc_device_p\n", + __func__); + return -ENOMEM; + } + ret = alloc_chrdev_region(&venc_dev_num, 0, 1, VENC_NAME); + if (ret < 0) { + pr_err("%s: alloc_chrdev_region failed (%d)\n", __func__, + ret); + return ret; + } + venc_class = class_create(THIS_MODULE, VENC_NAME); + if (IS_ERR(venc_class)) { + ret = PTR_ERR(venc_class); + pr_err("%s: failed to create venc_class (%d)\n", + __func__, ret); + goto err_venc_class_create; + } + venc_device_p->class_devp = + device_create(venc_class, NULL, venc_dev_num, NULL, + VENC_NAME); + if (IS_ERR(venc_device_p->class_devp)) { + ret = PTR_ERR(venc_device_p->class_devp); + pr_err("%s: failed to create class_device (%d)\n", __func__, + ret); + goto err_venc_class_device_create; + } + cdev_init(&cdev, &q6venc_fops); + cdev.owner = THIS_MODULE; + ret = cdev_add(&cdev, venc_dev_num, 1); + if (ret < 0) { + pr_err("%s: cdev_add failed (%d)\n", __func__, ret); + goto err_venc_cdev_add; + } + init_waitqueue_head(&venc_device_p->venc_msg_evt); + return ret; + +err_venc_cdev_add: + device_destroy(venc_class, venc_dev_num); +err_venc_class_device_create: + class_destroy(venc_class); +err_venc_class_create: + unregister_chrdev_region(venc_dev_num, 1); + return ret; } static void __exit q6venc_exit(void) { - misc_deregister(&q6venc_misc); + cdev_del(&(cdev)); + device_destroy(venc_class, venc_dev_num); + class_destroy(venc_class); + unregister_chrdev_region(venc_dev_num, 1); } -MODULE_DESCRIPTION("video encoder driver for QSD platform"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Video encoder driver for QDSP6"); MODULE_VERSION("2.0"); - module_init(q6venc_init); module_exit(q6venc_exit); diff --git a/arch/arm/mach-msm/qdsp6/pcm_in.c b/arch/arm/mach-msm/qdsp6/pcm_in.c index 60ef98df..3b3d23bf 100644 --- a/arch/arm/mach-msm/qdsp6/pcm_in.c +++ b/arch/arm/mach-msm/qdsp6/pcm_in.c @@ -26,12 +26,12 @@ #include -#define BUFSZ (4096) -#define DMASZ (BUFSZ * 2) +#define BUFSZ (256) static DEFINE_MUTEX(pcm_in_lock); static uint32_t sample_rate = 8000; static uint32_t channel_count = 1; +static uint32_t buffer_size = BUFSZ; static int pcm_in_opened = 0; void audio_client_dump(struct audio_client *ac); @@ -66,7 +66,7 @@ static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg) rc = -EBUSY; } else { file->private_data = q6audio_open_pcm( - BUFSZ, sample_rate, channel_count, + buffer_size, sample_rate, channel_count, AUDIO_FLAG_READ, acdb_id); if (!file->private_data) rc = -ENOMEM; @@ -84,13 +84,26 @@ static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg) rc = -EFAULT; break; } + if (!config.channel_count || config.channel_count > 2) { + rc = -EINVAL; + break; + } + if (config.sample_rate < 8000 || config.sample_rate > 48000) { + rc = -EINVAL; + break; + } + if (config.buffer_size < 128 || config.buffer_size > 8192) { + rc = -EINVAL; + break; + } sample_rate = config.sample_rate; channel_count = config.channel_count; + buffer_size = config.buffer_size; break; } case AUDIO_GET_CONFIG: { struct msm_audio_config config; - config.buffer_size = BUFSZ; + config.buffer_size = buffer_size; config.buffer_count = 2; config.sample_rate = sample_rate; config.channel_count = channel_count; @@ -147,7 +160,7 @@ static ssize_t q6_in_read(struct file *file, char __user *buf, if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) { audio_client_dump(ac); pr_err("pcm_read: timeout. dsp dead?\n"); -// BUG(); + BUG(); } xfer = count; diff --git a/arch/arm/mach-msm/qdsp6/pcm_out.c b/arch/arm/mach-msm/qdsp6/pcm_out.c index 814216f1..efe22f21 100644 --- a/arch/arm/mach-msm/qdsp6/pcm_out.c +++ b/arch/arm/mach-msm/qdsp6/pcm_out.c @@ -25,33 +25,24 @@ #include #include -#include "dal_audio.h" - -#if 0 -#define AUDIO_INFO(x...) pr_info("Audio: "x) -#else -#define AUDIO_INFO(x...) do{}while(0) -#endif void audio_client_dump(struct audio_client *ac); -#define BUFSZ (4096) //(3072) -#define DMASZ (BUFSZ * 2) +#define BUFSZ (3072) struct pcm { struct mutex lock; struct audio_client *ac; uint32_t sample_rate; uint32_t channel_count; + size_t buffer_size; }; static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct pcm *pcm = file->private_data; - struct cad_audio_eq_cfg eq_cfg; int rc = 0; - AUDIO_INFO("%s: %X %X\n", __func__, cmd, arg); if (cmd == AUDIO_GET_STATS) { struct msm_audio_stats stats; memset(&stats, 0, sizeof(stats)); @@ -71,14 +62,6 @@ static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) rc = q6audio_set_stream_volume(pcm->ac, vol); break; } - case AUDIO_SET_EQ: { - if (copy_from_user(&eq_cfg, (void *)arg, sizeof(struct cad_audio_eq_cfg))) { - rc = -EFAULT; - break; - } - rc = q6audio_set_stream_eq(pcm->ac, &eq_cfg); - break; - } case AUDIO_START: { uint32_t acdb_id; if (arg == 0) { @@ -91,7 +74,7 @@ static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (pcm->ac) { rc = -EBUSY; } else { - pcm->ac = q6audio_open_pcm(BUFSZ, pcm->sample_rate, + pcm->ac = q6audio_open_pcm(pcm->buffer_size, pcm->sample_rate, pcm->channel_count, AUDIO_FLAG_WRITE, acdb_id); if (!pcm->ac) @@ -117,13 +100,22 @@ static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) rc = -EINVAL; break; } + if (config.sample_rate < 8000 || config.sample_rate > 48000) { + rc = -EINVAL; + break; + } + if (config.buffer_size < 128 || config.buffer_size > 8192) { + rc = -EINVAL; + break; + } pcm->sample_rate = config.sample_rate; pcm->channel_count = config.channel_count; + pcm->buffer_size = config.buffer_size; break; } case AUDIO_GET_CONFIG: { struct msm_audio_config config; - config.buffer_size = BUFSZ; + config.buffer_size = pcm->buffer_size; config.buffer_count = 2; config.sample_rate = pcm->sample_rate; config.channel_count = pcm->channel_count; @@ -146,7 +138,6 @@ static int pcm_open(struct inode *inode, struct file *file) { struct pcm *pcm; - AUDIO_INFO("%s\n", __func__); pr_info("pcm_out: open\n"); pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL); @@ -156,6 +147,7 @@ static int pcm_open(struct inode *inode, struct file *file) mutex_init(&pcm->lock); pcm->channel_count = 2; pcm->sample_rate = 44100; + pcm->buffer_size = BUFSZ; file->private_data = pcm; return 0; @@ -184,7 +176,7 @@ static ssize_t pcm_write(struct file *file, const char __user *buf, if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) { audio_client_dump(ac); pr_err("pcm_write: timeout. dsp dead?\n"); -// BUG(); + BUG(); } xfer = count; @@ -207,7 +199,6 @@ static ssize_t pcm_write(struct file *file, const char __user *buf, static int pcm_release(struct inode *inode, struct file *file) { - AUDIO_INFO("%s\n", __func__); struct pcm *pcm = file->private_data; if (pcm->ac) q6audio_close(pcm->ac); diff --git a/arch/arm/mach-msm/qdsp6/q6audio.c b/arch/arm/mach-msm/qdsp6/q6audio.c index ecac00e6..2df5b244 100644 --- a/arch/arm/mach-msm/qdsp6/q6audio.c +++ b/arch/arm/mach-msm/qdsp6/q6audio.c @@ -31,7 +31,8 @@ #include "dal_acdb.h" #include "dal_adie.h" #include - +#include +#include #include #include "q6audio_devices.h" @@ -347,7 +348,7 @@ static int audio_ioctl(struct audio_client *ac, void *ptr, uint32_t len) if (!wait_event_timeout(ac->wait, (ac->cb_status != -EBUSY), 5*HZ)) { dal_trace_dump(ac->client); pr_err("audio_ioctl: timeout. dsp dead?\n"); - q6audio_dsp_not_responding(); + BUG(); } return ac->cb_status; } @@ -437,6 +438,156 @@ static int audio_mp3_open(struct audio_client *ac, uint32_t bufsz, return audio_ioctl(ac, &rpc, sizeof(rpc)); } +static int audio_aac_open(struct audio_client *ac, uint32_t bufsz, + void *data) +{ + struct aac_format *af = data; + struct adsp_open_command rpc; + uint32_t *aac_type; + int idx = sizeof(uint32_t); + struct adsp_audio_binary_format *fmt = &(rpc.format.binary); + + memset(&rpc, 0, sizeof(rpc)); + + fmt->format = ADSP_AUDIO_FORMAT_MPEG4_AAC; + aac_type = (uint32_t *)(fmt->data); + switch (af->block_formats) { + case 0xffff: + if (ac->flags & AUDIO_FLAG_WRITE) + *aac_type = ADSP_AUDIO_AAC_ADTS; + else + *aac_type = ADSP_AUDIO_AAC_MPEG4_ADTS; + break; + case 0: + if (ac->flags & AUDIO_FLAG_WRITE) + *aac_type = ADSP_AUDIO_AAC_ADIF; + else + *aac_type = ADSP_AUDIO_AAC_RAW; + break; + case 1: + *aac_type = ADSP_AUDIO_AAC_RAW; + break; + case 2: + *aac_type = ADSP_AUDIO_AAC_LOAS; + break; + case 3: + *aac_type = ADSP_AUDIO_AAC_FRAMED_RAW; + break; + case 4: + *aac_type = ADSP_AUDIO_AAC_RAW; + break; + default: + pr_err("unsupported AAC type %d\n", af->block_formats); + return -EINVAL; + } + + TRACE("aac_open: type %x, obj %d, idx %d\n", + *aac_type, af->audio_object_type, idx); + fmt->data[idx++] = (u8)(((af->audio_object_type & 0x1F) << 3) | + ((af->sample_rate >> 1) & 0x7)); + fmt->data[idx] = (u8)(((af->sample_rate & 0x1) << 7) | + ((af->channel_config & 0x7) << 3)); + + switch (af->audio_object_type) { + case AAC_OBJECT_ER_LC: + case AAC_OBJECT_ER_LTP: + case AAC_OBJECT_ER_LD: + /* extension flag */ + fmt->data[idx++] |= 0x1; + fmt->data[idx] = (u8)( + ((af->aac_section_data_resilience_flag & 0x1) << 7) | + ((af->aac_scalefactor_data_resilience_flag & 0x1) << 6) | + ((af->aac_spectral_data_resilience_flag & 0x1) << 5) | + ((af->ep_config & 0x3) << 2)); + break; + + case AAC_OBJECT_ER_SCALABLE: + fmt->data[idx++] |= 0x1; + /* extension flag */ + fmt->data[idx++] = (u8)( + ((af->aac_section_data_resilience_flag & 0x1) << 4) | + ((af->aac_scalefactor_data_resilience_flag & 0x1) << 3) | + ((af->aac_spectral_data_resilience_flag & 0x1) << 2) | + ((af->ep_config >> 1) & 0x1)); + fmt->data[idx] = (u8)((af->ep_config & 0x1) + << 7); + break; + + case AAC_OBJECT_BSAC: + fmt->data[++idx] = (u8)((af->ep_config & 0x3) + << 6); + break; + + default: + pr_err("dbg unknown object type \n"); + break; + } + fmt->num_bytes = idx + 1; + + TRACE("aac_open: format %x%x %x%x%x%x %x%x, \n", + fmt->data[0], fmt->data[1], fmt->data[2], fmt->data[3], + fmt->data[4], fmt->data[5], fmt->data[6], fmt->data[7]); + + rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT; + rpc.config.aac.bit_rate = af->bit_rate; + if (ac->flags & AUDIO_FLAG_WRITE) { + rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE; + rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK; + } else { + rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ; + rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD; + } + + if ((af->sbr_on_flag == 0) && (af->sbr_ps_on_flag == 0)) { + rpc.config.aac.encoder_mode = + ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE; + } else if ((af->sbr_on_flag == 1) && (af->sbr_ps_on_flag == 0)) { + rpc.config.aac.encoder_mode = + ADSP_AUDIO_ENC_AAC_PLUS_MODE; + } else if ((af->sbr_on_flag == 1) && (af->sbr_ps_on_flag == 1)) { + rpc.config.aac.encoder_mode = + ADSP_AUDIO_ENC_ENHANCED_AAC_PLUS_MODE; + } else { + pr_err("unsupported SBR flag\n"); + return -EINVAL; + } + rpc.buf_max_size = bufsz; /* XXX ??? */ + rpc.hdr.response_type = 0; + + TRACE("aac_open: opcode %x, stream_context 0x%x, " + "mode %d, bytes %d, bbuffer size %d\n", + rpc.hdr.opcode, rpc.stream_context, + rpc.config.aac.encoder_mode, fmt->num_bytes, bufsz); + + return audio_ioctl(ac, &rpc, sizeof(rpc)); +} + +static int audio_qcelp_open(struct audio_client *ac, uint32_t bufsz, + void *data) +{ + struct msm_audio_qcelp_config *qf = data; + struct adsp_open_command rpc; + struct adsp_audio_standard_format *fmt = &(rpc.format.standard); + + memset(&rpc, 0, sizeof(rpc)); + + fmt->format = ADSP_AUDIO_FORMAT_V13K_FS; + fmt->sampling_rate = 8000; + fmt->channels = 1; + fmt->bits_per_sample = 16; + fmt->is_signed = 1; + fmt->is_interleaved = 0; + + rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT; + rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ; + rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD; + rpc.config.qcelp13k.min_rate = (uint16_t) qf->min_bit_rate; + rpc.config.qcelp13k.max_rate = (uint16_t) qf->max_bit_rate; + rpc.buf_max_size = bufsz; /* XXX ??? */ + + return audio_ioctl(ac, &rpc, sizeof(rpc)); +} + static int audio_close(struct audio_client *ac) { TRACE("%p: close\n", ac); @@ -583,7 +734,10 @@ static void callback(void *data, int len, void *cookie) { struct adsp_event_hdr *e = data; struct audio_client *ac; + struct adsp_buffer_event *abe = data; + TRACE("audio callback: context %d, event 0x%x, status %d\n", + e->context, e->event_id, e->status); if (e->context >= SESSION_MAX) { pr_err("audio callback: bogus session %d\n", @@ -610,6 +764,9 @@ static void callback(void *data, int len, void *cookie) if (e->event_id == ADSP_AUDIO_EVT_STATUS_BUF_DONE) { TRACE("%p: CB done (%d)\n", ac, e->status); + TRACE("%p: actual_size %d, buffer_size %d\n", + ac, abe->buffer.actual_size, ac->buf[ac->dsp_buf].size); + if (e->status) pr_err("buffer status %d\n", e->status); ac->buf[ac->dsp_buf].used = 0; @@ -891,6 +1048,10 @@ static void audio_rx_analog_enable(int en) if (analog_ops->receiver_enable) analog_ops->receiver_enable(en); break; + case ADSP_AUDIO_DEVICE_ID_I2S_SPKR: + if (analog_ops->i2s_enable) + analog_ops->i2s_enable(en); + break; } } @@ -936,7 +1097,8 @@ static int audio_update_acdb(uint32_t adev, uint32_t acdb_id) return -EINVAL; } - audio_set_table(ac_control, adev, sz); + if (sz > 0) + audio_set_table(ac_control, adev, sz); return 0; } @@ -1213,7 +1375,7 @@ int q6audio_reinit_acdb(char* filename) { return 0; mutex_lock(&audio_path_lock); - if (strlen(filename) < 0 || !strcmp(filename, acdb_file)) { + if (strlen(filename) < 0) { res = -EINVAL; goto done; } @@ -1447,7 +1609,7 @@ struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate, if (rc == 0) break; if (retry == 0) - q6audio_dsp_not_responding(); + BUG(); pr_err("q6audio: open pcm error %d, retrying\n", rc); msleep(1); } @@ -1472,7 +1634,7 @@ struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate, if (rc == 0) break; if (retry == 0) - q6audio_dsp_not_responding(); + BUG(); pr_err("q6audio: stream start error %d, retrying\n", rc); } @@ -1512,9 +1674,10 @@ struct audio_client *q6voice_open(uint32_t flags, uint32_t acdb_id) return 0; ac->flags = flags; - if (ac->flags & AUDIO_FLAG_WRITE) + if (ac->flags & AUDIO_FLAG_WRITE) { audio_rx_path_enable(1, acdb_id); - else { + audio_rx_mute(ac_control, ADSP_AUDIO_DEVICE_ID_VOICE, 0); + } else { tx_clk_freq = 8000; audio_tx_path_enable(1, acdb_id); } @@ -1524,9 +1687,10 @@ struct audio_client *q6voice_open(uint32_t flags, uint32_t acdb_id) int q6voice_close(struct audio_client *ac) { - if (ac->flags & AUDIO_FLAG_WRITE) + if (ac->flags & AUDIO_FLAG_WRITE) { + audio_rx_mute(ac_control, ADSP_AUDIO_DEVICE_ID_VOICE, 1); audio_rx_path_enable(0, 0); - else + } else audio_tx_path_enable(0, 0); audio_client_free(ac); @@ -1572,3 +1736,122 @@ int q6audio_async(struct audio_client *ac) rpc.response_type = ADSP_AUDIO_RESPONSE_ASYNC; return audio_ioctl(ac, &rpc, sizeof(rpc)); } + +struct audio_client *q6audio_open_aac(uint32_t bufsz, uint32_t rate, + uint32_t flags, void *data, uint32_t acdb_id) +{ + struct audio_client *ac; + + TRACE("q6audio_open_aac flags=%d rate=%d\n", flags, rate); + + if (q6audio_init()) + return 0; + + ac = audio_client_alloc(bufsz); + if (!ac) + return 0; + + ac->flags = flags; + if (ac->flags & AUDIO_FLAG_WRITE) + audio_rx_path_enable(1, acdb_id); + else { + /* TODO: consider concourrency with voice call */ + tx_clk_freq = rate; + audio_tx_path_enable(1, acdb_id); + } + + audio_aac_open(ac, bufsz, data); + audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START); + + if (!(ac->flags & AUDIO_FLAG_WRITE)) { + ac->buf[0].used = 1; + ac->buf[1].used = 1; + q6audio_read(ac, &ac->buf[0]); + q6audio_read(ac, &ac->buf[1]); + } + audio_prevent_sleep(); + return ac; +} + +int q6audio_aac_close(struct audio_client *ac) +{ + audio_close(ac); + if (ac->flags & AUDIO_FLAG_WRITE) + audio_rx_path_enable(0, 0); + else + audio_tx_path_enable(0, 0); + + audio_client_free(ac); + audio_allow_sleep(); + return 0; +} + +struct audio_client *q6fm_open(void) +{ + struct audio_client *ac; + + printk("q6fm_open()\n"); + + if (q6audio_init()) + return 0; + + if (audio_rx_device_id != ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO && + audio_rx_device_id != ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO) + return 0; + + ac = audio_client_alloc(0); + if (!ac) + return 0; + + ac->flags = AUDIO_FLAG_WRITE; + audio_rx_path_enable(1, 0); + enable_aux_loopback(1); + + return ac; +} + +int q6fm_close(struct audio_client *ac) +{ + audio_rx_path_enable(0, 0); + enable_aux_loopback(0); + audio_client_free(ac); + return 0; +} + +struct audio_client *q6audio_open_qcelp(uint32_t bufsz, uint32_t rate, + void *data, uint32_t acdb_id) +{ + struct audio_client *ac; + + if (q6audio_init()) + return 0; + + ac = audio_client_alloc(bufsz); + if (!ac) + return 0; + + ac->flags = AUDIO_FLAG_READ; + tx_clk_freq = rate; + audio_tx_path_enable(1, acdb_id); + + audio_qcelp_open(ac, bufsz, data); + audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START); + + ac->buf[0].used = 1; + ac->buf[1].used = 1; + q6audio_read(ac, &ac->buf[0]); + q6audio_read(ac, &ac->buf[1]); + + audio_prevent_sleep(); + return ac; +} + +int q6audio_qcelp_close(struct audio_client *ac) +{ + audio_close(ac); + audio_tx_path_enable(0, 0); + audio_client_free(ac); + audio_allow_sleep(); + return 0; +} + diff --git a/arch/arm/mach-msm/qdsp6/q6audio_htcleo.c b/arch/arm/mach-msm/qdsp6/q6audio_htcleo.c deleted file mode 100644 index e5b75a2c..00000000 --- a/arch/arm/mach-msm/qdsp6/q6audio_htcleo.c +++ /dev/null @@ -1,2634 +0,0 @@ -/* arch/arm/mach-msm/qdsp6_10/q6audio.c - * - * Copyright (C) 2010 Cotulla - * Copyright (C) 2009 Google, Inc. - * Author: Brian Swetland - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "dal.h" -#include "dal_audio.h" -#include "dal_audio_format.h" -#include "dal_acdb.h" -#include "dal_adie.h" -#include -#include -#include -#include - -#include - -#include "q6audio_devices.h" -#include "../dex_comm.h" - -#if 0 -#define TRACE(x...) pr_info("Q6: "x) -#else -#define TRACE(x...) do{}while(0) -#endif - -#if 0 -#define AUDIO_INFO(x...) pr_info("Audio: "x) -#else -#define AUDIO_INFO(x...) do{}while(0) -#endif - - -#define CB_EVENT_COOKIE 0xC00CE13E - - -#if 1 - -// LEO -static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = -{ - [Q6_HW_HANDSET] = - { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_HEADSET] = - { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_SPEAKER] = - { - .min_gain = -1000, - .max_gain = 500, - }, - [Q6_HW_TTY] = - { - .min_gain = 0, - .max_gain = 0, - }, - [Q6_HW_BT_SCO] = - { - .min_gain = -1100, - .max_gain = 400, - }, - [Q6_HW_BT_A2DP] = - { - .min_gain = -1100, - .max_gain = 400, - }, -}; - -#else - -// Old one (from Desire) -static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = -{ - [Q6_HW_HANDSET] = { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_HEADSET] = { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_SPEAKER] = { - .min_gain = -1500, - .max_gain = 0, - }, - [Q6_HW_TTY] = { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_BT_SCO] = { - .min_gain = -2000, - .max_gain = 0, - }, - [Q6_HW_BT_A2DP] = { - .min_gain = -2000, - .max_gain = 0, - }, -}; -#endif - -extern int global_now_phone_call; - -static struct audio_client * audio_test(void); -static void callback(void *data, int len, void *cookie); -static int audio_init(struct audio_client *ac); -static int audio_info(struct audio_client *ac); -static int q6audio_init_rx_volumes(); - -static struct wake_lock wakelock; -static struct wake_lock idlelock; -static int idlecount; -static DEFINE_MUTEX(idlecount_lock); - -void audio_prevent_sleep(void) -{ - mutex_lock(&idlecount_lock); - if (++idlecount == 1) { - wake_lock(&wakelock); - wake_lock(&idlelock); - } - mutex_unlock(&idlecount_lock); -} - -void audio_allow_sleep(void) -{ - mutex_lock(&idlecount_lock); - if (--idlecount == 0) { - wake_unlock(&idlelock); - wake_unlock(&wakelock); - } - mutex_unlock(&idlecount_lock); -} - -static struct clk *icodec_rx_clk; -static struct clk *icodec_tx_clk; -static struct clk *ecodec_clk; -static struct clk *sdac_clk; - -static struct q6audio_analog_ops default_analog_ops; -static struct q6audio_analog_ops *analog_ops = &default_analog_ops; -static uint32_t tx_clk_freq = 8000; -static int tx_mute_status = 0; -static int rx_vol_level = 100; -static char acdb_file[64] = "default.acdb"; -static uint32_t tx_acdb = 0; -static uint32_t rx_acdb = 0; -static int acdb_use_rpc = 0; - -///////////////////////////////////////////////////////////////////////////////// -// helper functions for device parameters -///////////////////////////////////////////////////////////////////////////////// - -void q6audio_register_analog_ops(struct q6audio_analog_ops *ops) -{ - pr_info("register analog ops = %p\n", ops); - analog_ops = ops; -} - -void q6audio_set_acdb_file(char* filename) -{ - if (filename) { - pr_info("audio: set acdb file as %s\n", filename); - strncpy(acdb_file, filename, sizeof(acdb_file)-1); - } -} - -static struct q6_device_info *q6_lookup_device(uint32_t device_id) -{ - struct q6_device_info *di = q6_audio_devices; - for (;;) { - if (di->id == device_id) - return di; - if (di->id == 0) { - pr_err("q6_lookup_device: bogus id 0x%08x\n", - device_id); - return di; - } - di++; - } -} - -static uint32_t q6_device_to_codec(uint32_t device_id) -{ - struct q6_device_info *di = q6_lookup_device(device_id); - return di->codec; -} - -static uint32_t q6_device_to_dir(uint32_t device_id) -{ - struct q6_device_info *di = q6_lookup_device(device_id); - return di->dir; -} - -static uint32_t q6_device_to_cad_id(uint32_t device_id) -{ - struct q6_device_info *di = q6_lookup_device(device_id); - return di->cad_id; -} - -static uint32_t q6_device_to_path(uint32_t device_id) -{ - struct q6_device_info *di = q6_lookup_device(device_id); - return di->path; -} - -static uint32_t q6_device_to_rate(uint32_t device_id) -{ - struct q6_device_info *di = q6_lookup_device(device_id); - return di->rate; -} - -int q6_device_volume(uint32_t device_id, int level) -{ - struct q6_device_info *di = q6_lookup_device(device_id); - if (analog_ops->get_rx_vol) - return analog_ops->get_rx_vol(di->hw, level); - else { - struct q6_hw_info *hw; - hw = &q6_audio_hw[di->hw]; - return hw->min_gain + ((hw->max_gain - hw->min_gain) * level) / 100; - } -} - -///////////////////////////////////////////////////////////////////////////////// -// ADIE functions -///////////////////////////////////////////////////////////////////////////////// - -static inline int adie_open(struct dal_client *client) -{ - return dal_call_f0(client, DAL_OP_OPEN, 0); -} - -static inline int adie_close(struct dal_client *client) -{ - return dal_call_f0(client, DAL_OP_CLOSE, 0); -} - -static inline int adie_set_path(struct dal_client *client, - uint32_t id, uint32_t path_type) -{ - return dal_call_f1(client, ADIE_OP_SET_PATH, id, path_type); -} - -static inline int adie_set_path_freq_plan(struct dal_client *client, - uint32_t path_type, uint32_t plan) -{ - return dal_call_f1(client, ADIE_OP_SET_PATH_FREQUENCY_PLAN, - path_type, plan); -} - -static inline int adie_proceed_to_stage(struct dal_client *client, - uint32_t path_type, uint32_t stage) -{ - return dal_call_f1(client, ADIE_OP_PROCEED_TO_STAGE, - path_type, stage); -} - -static inline int adie_mute_path(struct dal_client *client, - uint32_t path_type, uint32_t mute_state) -{ - return dal_call_f1(client, ADIE_OP_MUTE_PATH, path_type, mute_state); -} - -static int adie_refcount; - -static struct dal_client *adie; -static struct dal_client *adsp; -static struct dal_client *acdb; - -static int adie_enable(void) -{ - adie_refcount++; - if (adie_refcount == 1) - adie_open(adie); - return 0; -} - -static int adie_disable(void) -{ - adie_refcount--; - if (adie_refcount == 0) - adie_close(adie); - return 0; -} - -/* 4k DMA scratch page used for exchanging acdb device config tables - * and stream format descriptions with the DSP. - */ -static void *audio_data; -static dma_addr_t audio_phys; -// this memory used to pass open params into DSP -static void *params_data; -static dma_addr_t params_phys; - - -#define SESSION_MIN 0 -#define SESSION_MAX 64 - -static DEFINE_MUTEX(session_lock); -static DEFINE_MUTEX(audio_lock); -static DEFINE_MUTEX(open_mem_lock); - - -static struct audio_client *session[SESSION_MAX]; - -static int session_alloc(struct audio_client *ac) -{ - int n; - - mutex_lock(&session_lock); - for (n = SESSION_MIN; n < SESSION_MAX; n++) { - if (!session[n]) { - session[n] = ac; - mutex_unlock(&session_lock); - return n; - } - } - mutex_unlock(&session_lock); - return -ENOMEM; -} - -static void session_free(int n, struct audio_client *ac) -{ - mutex_lock(&session_lock); - if (session[n] == ac) - session[n] = 0; - mutex_unlock(&session_lock); -} - -void audio_client_dump(struct audio_client *ac) -{ - dal_trace_dump(ac->client); -} - - -static void audio_client_free(struct audio_client *ac) -{ - AUDIO_INFO("%s: session %d\n", __func__, ac->session); - - session_free(ac->session, ac); - - if (ac->buf[0].data) - dma_free_coherent(NULL, ac->buf[0].size, ac->buf[0].data, ac->buf[0].phys); - if (ac->buf[1].data) - dma_free_coherent(NULL, ac->buf[1].size, ac->buf[1].data, ac->buf[1].phys); - - if (ac->client) - dal_detach(ac->client); - kfree(ac); -} - -static struct audio_client *audio_client_alloc(unsigned bufsz) -{ - struct audio_client *ac; - struct dal_client *dsp; - int n; - - AUDIO_INFO("%s\n", __func__); - ac = kzalloc(sizeof(*ac), GFP_KERNEL); - if (!ac) - { - AUDIO_INFO("%s: alloc error\n", __func__); - return 0; - } - - n = session_alloc(ac); - if (n < 0) - { - AUDIO_INFO("%s: session alloc error\n", __func__); - goto fail_session; - } - ac->session = n; - AUDIO_INFO("%s: session %d\n", __func__, ac->session); - - if (bufsz > 0) - { - ac->buf[0].data = dma_alloc_coherent(NULL, bufsz, &ac->buf[0].phys, GFP_KERNEL); - if (!ac->buf[0].data) - { - goto fail; - } - - ac->buf[1].data = dma_alloc_coherent(NULL, bufsz, &ac->buf[1].phys, GFP_KERNEL); - if (!ac->buf[1].data) - { - goto fail; - } - - ac->buf[0].size = bufsz; - ac->buf[1].size = bufsz; - } - - init_waitqueue_head(&ac->wait); - - -// dsp = dal_attach(AUDIO_DAL_DEVICE, AUDIO_DAL_PORT, callback, 0); - dsp = dal_attach_ex(AUDIO_DAL_DEVICE, "AudioQdsp", AUDIO_DAL_PORT, callback, 0); - if (!dsp) - { - pr_err("audio_client_alloc: cannot attach to adsp\n"); - goto fail; - } - ac->client = dsp; - - audio_init(ac); - audio_info(ac); - audio_client_dump(ac); - - return ac; - -fail: - if (ac->buf[0].data) - dma_free_coherent(NULL, ac->buf[0].size, ac->buf[0].data, ac->buf[0].phys); - if (ac->buf[1].data) - dma_free_coherent(NULL, ac->buf[1].size, ac->buf[1].data, ac->buf[1].phys); - session_free(n, ac); -fail_session: - audio_client_free(ac); - return 0; -} - - -static int audio_ioctl(struct audio_client *ac, uint32_t cmd, void *ptr, uint32_t len) -{ - int r; - r = dal_call_f6(ac->client, AUDIO_OP_IOCTL, cmd, ptr, len); - return r; -} - -static int audio_command(struct audio_client *ac, uint32_t cmd) -{ - struct adsp_command_hdr rpc; - memset(&rpc, 0, sizeof(rpc)); - return audio_ioctl(ac, cmd, NULL, 0); -} - -static int audio_open_control(struct audio_client *ac) -{ - int r; - struct adsp_open_command rpc; - - memset(&rpc, 0, sizeof(rpc)); - - rpc.opcode = ADSP_AUDIO_OPCODE_OPEN_DEV; - - // reset flag before call, callback() will set it later - ac->open_done = 0; - r = dal_call_f5(ac->client, AUDIO_OP_OPEN, &rpc, sizeof(rpc)); - if (r != 0) - return r; - -// wait for async event - if (!wait_event_timeout(ac->wait, (ac->open_done == 1), 3 * HZ)) - { - pr_err("wait for open async event failed!\n"); - return -1; - } - return ac->open_status; -} - -static int audio_out_open(struct audio_client *ac, uint32_t bufsz, - uint32_t rate, uint32_t channels) -{ - int r; - struct adsp_open_command rpc; - union adsp_audio_format *ptr; - - printk("audio_out_open: %x %d %d\n", bufsz, rate, channels); - mutex_lock(&open_mem_lock); - - memset(&rpc, 0, sizeof(rpc)); - ptr = (union adsp_audio_format*)params_data; - memset(ptr, 0, sizeof(union adsp_audio_format)); - - rpc.numdev = 1; -// rpc.dev[0] = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO; - rpc.dev[0] = ADSP_AUDIO_DEVICE_ID_DEFAULT; - rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK; - rpc.buf_max_size = bufsz; - - rpc.format = ADSP_AUDIO_FORMAT_PCM; - rpc.pblock = params_phys; - rpc.blocklen = sizeof(struct adsp_audio_standard_format); -// rpc.pblock = 0; -// rpc.blocklen = 0; - - rpc.opcode = ADSP_AUDIO_OPCODE_OPEN_WRITE; - - ptr->standard.channels = channels; - ptr->standard.bits_per_sample = 16; - ptr->standard.sampling_rate = rate; - ptr->standard.is_signed = 1; - ptr->standard.is_interleaved = 1; - - AUDIO_INFO("open out %p\n", ac); - ac->open_done = 0; - r = dal_call_f5(ac->client, AUDIO_OP_OPEN, &rpc, sizeof(rpc)); - -// wait for async event - if (!wait_event_timeout(ac->wait, (ac->open_done == 1), 3 * HZ)) - { - mutex_unlock(&open_mem_lock); - pr_err("wait for open async event failed!\n"); - return -1; - } - mutex_unlock(&open_mem_lock); -// return r; - return ac->open_status; -} - -static int audio_in_open(struct audio_client *ac, uint32_t bufsz, - uint32_t rate, uint32_t channels) -{ - int r; - struct adsp_open_command rpc; - union adsp_audio_format *ptr; - - printk("audio_in_open: %x %d %d\n", bufsz, rate, channels); - mutex_lock(&open_mem_lock); - memset(&rpc, 0, sizeof(rpc)); - ptr = (union adsp_audio_format*)params_data; - memset(ptr, 0, sizeof(union adsp_audio_format)); - - rpc.numdev = 1; - rpc.dev[0] = ADSP_AUDIO_DEVICE_ID_DEFAULT; - rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD; - rpc.buf_max_size = bufsz; - - rpc.format = ADSP_AUDIO_FORMAT_PCM; - rpc.pblock = params_phys; - rpc.blocklen = sizeof(struct adsp_audio_standard_format); - rpc.opcode = ADSP_AUDIO_OPCODE_OPEN_READ; - - ptr->standard.channels = channels; - ptr->standard.bits_per_sample = 16; - ptr->standard.sampling_rate = rate; - ptr->standard.is_signed = 1; - ptr->standard.is_interleaved = 1; - - AUDIO_INFO("%p: open in\n", ac); - ac->open_done = 0; - r = dal_call_f5(ac->client, AUDIO_OP_OPEN, &rpc, sizeof(rpc)); -// wait for async event - if (!wait_event_timeout(ac->wait, (ac->open_done == 1), 3 * HZ)) - { - mutex_unlock(&open_mem_lock); - pr_err("wait for open async event failed (IN)!\n"); - return -1; - } - mutex_unlock(&open_mem_lock); -// return r; - return ac->open_status; -} - -static int audio_mp3_open(struct audio_client *ac, uint32_t bufsz, - uint32_t rate, uint32_t channels) -{ - int r; - struct adsp_open_command rpc; - union adsp_audio_format *ptr; - - printk("audio_mp3_open: %x %d %d\n", bufsz, rate, channels); - mutex_lock(&open_mem_lock); - memset(&rpc, 0, sizeof(rpc)); - ptr = (union adsp_audio_format*)params_data; - memset(ptr, 0, sizeof(union adsp_audio_format)); - - rpc.numdev = 1; - rpc.dev[0] = ADSP_AUDIO_DEVICE_ID_DEFAULT; - rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK; - rpc.buf_max_size = bufsz; - - rpc.format = ADSP_AUDIO_FORMAT_MP3; - rpc.pblock = params_phys; - rpc.blocklen = sizeof(struct adsp_audio_standard_format); - rpc.opcode = ADSP_AUDIO_OPCODE_OPEN_WRITE; - - ptr->standard.channels = channels; - ptr->standard.bits_per_sample = 16; - ptr->standard.sampling_rate = rate; - ptr->standard.is_signed = 1; - ptr->standard.is_interleaved = 1; - - r = dal_call_f5(ac->client, AUDIO_OP_OPEN, &rpc, sizeof(rpc)); -// wait for async event - if (!wait_event_timeout(ac->wait, (ac->open_done == 1), 3 * HZ)) - { - mutex_unlock(&open_mem_lock); - pr_err("wait for open async event failed (MP3)!\n"); - return -1; - } - mutex_unlock(&open_mem_lock); -// return r; - return ac->open_status; -} - -static int audio_aac_open(struct audio_client *ac, uint32_t bufsz, void *data) -{ - int r; - struct aac_format *af = data; - struct adsp_open_command rpc; - uint32_t *aac_type; - int idx = 0; // sizeof(uint32_t); - struct adsp_audio_binary_format *fmt = (struct adsp_audio_binary_format *)params_data; - union adsp_audio_format *ptr; - - - mutex_lock(&open_mem_lock); - memset(&rpc, 0, sizeof(rpc)); - ptr = (union adsp_audio_format*)params_data; - memset(ptr, 0, sizeof(union adsp_audio_format)); - - rpc.numdev = 1; - rpc.dev[0] = ADSP_AUDIO_DEVICE_ID_DEFAULT; - - rpc.format = ADSP_AUDIO_FORMAT_MPEG4_AAC; - rpc.pblock = params_phys; - - aac_type = (uint32_t *)(fmt->data); - switch (af->block_formats) - { - case 0xffff: - if (ac->flags & AUDIO_FLAG_WRITE) - *aac_type = ADSP_AUDIO_AAC_ADTS; - else - *aac_type = ADSP_AUDIO_AAC_MPEG4_ADTS; - break; - case 0: - if (ac->flags & AUDIO_FLAG_WRITE) - *aac_type = ADSP_AUDIO_AAC_ADIF; - else - *aac_type = ADSP_AUDIO_AAC_RAW; - break; - case 1: - *aac_type = ADSP_AUDIO_AAC_RAW; - break; - case 2: - *aac_type = ADSP_AUDIO_AAC_LOAS; - break; - case 3: - *aac_type = ADSP_AUDIO_AAC_FRAMED_RAW; - break; - case 4: - *aac_type = ADSP_AUDIO_AAC_RAW; - break; - default: - pr_err("unsupported AAC type %d\n", af->block_formats); - mutex_unlock(&open_mem_lock); - return -EINVAL; - } - - AUDIO_INFO("aac_open: type %x, obj %d, idx %d\n", - *aac_type, af->audio_object_type, idx); - fmt->data[idx++] = (u8)(((af->audio_object_type & 0x1F) << 3) | - ((af->sample_rate >> 1) & 0x7)); - fmt->data[idx] = (u8)(((af->sample_rate & 0x1) << 7) | - ((af->channel_config & 0x7) << 3)); - - switch (af->audio_object_type) { - case AAC_OBJECT_ER_LC: - case AAC_OBJECT_ER_LTP: - case AAC_OBJECT_ER_LD: - /* extension flag */ - fmt->data[idx++] |= 0x1; - fmt->data[idx] = (u8)( - ((af->aac_section_data_resilience_flag & 0x1) << 7) | - ((af->aac_scalefactor_data_resilience_flag & 0x1) << 6) | - ((af->aac_spectral_data_resilience_flag & 0x1) << 5) | - ((af->ep_config & 0x3) << 2)); - break; - - case AAC_OBJECT_ER_SCALABLE: - fmt->data[idx++] |= 0x1; - /* extension flag */ - fmt->data[idx++] = (u8)( - ((af->aac_section_data_resilience_flag & 0x1) << 4) | - ((af->aac_scalefactor_data_resilience_flag & 0x1) << 3) | - ((af->aac_spectral_data_resilience_flag & 0x1) << 2) | - ((af->ep_config >> 1) & 0x1)); - fmt->data[idx] = (u8)((af->ep_config & 0x1) << 7); - break; - - case AAC_OBJECT_BSAC: - fmt->data[++idx] = (u8)((af->ep_config & 0x3) << 6); - break; - - default: - pr_err("dbg unknown object type \n"); - break; - } -// fmt->num_bytes = idx + 1; - rpc.blocklen = idx + 1; - - TRACE("aac_open: format %x%x %x%x%x%x %x%x, \n", - fmt->data[0], fmt->data[1], fmt->data[2], fmt->data[3], - fmt->data[4], fmt->data[5], fmt->data[6], fmt->data[7]); - - rpc.config.aac.bit_rate = af->bit_rate; - if (ac->flags & AUDIO_FLAG_WRITE) - { - rpc.opcode = ADSP_AUDIO_OPCODE_OPEN_WRITE; - rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK; - } - else - { - rpc.opcode = ADSP_AUDIO_OPCODE_OPEN_READ; - rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD; - } - - if ((af->sbr_on_flag == 0) && (af->sbr_ps_on_flag == 0)) - { - rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE; - } - else if ((af->sbr_on_flag == 1) && (af->sbr_ps_on_flag == 0)) - { - rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_AAC_PLUS_MODE; - } - else if ((af->sbr_on_flag == 1) && (af->sbr_ps_on_flag == 1)) - { - rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_ENHANCED_AAC_PLUS_MODE; - } - else - { - pr_err("unsupported SBR flag\n"); - mutex_unlock(&open_mem_lock); - return -EINVAL; - } - rpc.buf_max_size = bufsz; /* XXX ??? */ - - TRACE("aac_open: opcode %x, stream_context 0x%x, " - "mode %d, bytes %d, bbuffer size %d\n", - rpc.opcode, rpc.stream_context, - rpc.config.aac.encoder_mode, rpc.blocklen, bufsz); - - r = dal_call_f5(ac->client, AUDIO_OP_OPEN, &rpc, sizeof(rpc)); - mutex_unlock(&open_mem_lock); - return r; -} - -static int audio_qcelp_open(struct audio_client *ac, uint32_t bufsz, - void *data) -{ - int r; - struct msm_audio_qcelp_config *qf = data; - struct adsp_open_command rpc; - struct adsp_audio_standard_format *fmt; - union adsp_audio_format *ptr; - - - mutex_lock(&open_mem_lock); - memset(&rpc, 0, sizeof(rpc)); - fmt = (struct adsp_audio_standard_format *)params_data; - memset(ptr, 0, sizeof(struct adsp_audio_standard_format)); - - rpc.numdev = 1; - rpc.dev[0] = ADSP_AUDIO_DEVICE_ID_DEFAULT; - rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD; - - rpc.format = ADSP_AUDIO_FORMAT_V13K_FS; - rpc.pblock = params_phys; - rpc.blocklen = sizeof(struct adsp_audio_standard_format); - rpc.opcode = ADSP_AUDIO_OPCODE_OPEN_READ; - - fmt->sampling_rate = 8000; - fmt->channels = 1; - fmt->bits_per_sample = 16; - fmt->is_signed = 1; - fmt->is_interleaved = 0; - - rpc.config.qcelp13k.min_rate = (uint16_t) qf->min_bit_rate; - rpc.config.qcelp13k.max_rate = (uint16_t) qf->max_bit_rate; - rpc.buf_max_size = bufsz; /* XXX ??? */ - - r = dal_call_f5(ac->client, AUDIO_OP_OPEN, &rpc, sizeof(rpc)); - - mutex_unlock(&open_mem_lock); - return r; -} - -static int audio_close(struct audio_client *ac) -{ - AUDIO_INFO("%p: close\n", ac); - audio_command(ac, ADSP_AUDIO_IOCTL_CMD_STREAM_STOP); -// audio_command(ac, ADSP_AUDIO_IOCTL_CMD_CLOSE); - - dal_call_f0(ac->client, AUDIO_OP_CLOSE, ac->session); - return 0; -} - -static int audio_set_table(struct audio_client *ac,int32_t device_id, int size) -{ - struct adsp_set_dev_cfg_table_command rpc; - - AUDIO_INFO("%s: %x %d\n", __func__, device_id, size); - -// print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, audio_data, size); - - memset(&rpc, 0, sizeof(rpc)); - if (q6_device_to_dir(device_id) == Q6_TX) - rpc.hdr.data = tx_clk_freq; - rpc.device_id = device_id; - rpc.phys_addr = audio_phys; - rpc.phys_size = size; - rpc.phys_used = size; - - TRACE("control: set table %x\n", device_id); - return audio_ioctl(ac, ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE, &rpc, sizeof(rpc)); -} - -int q6audio_read(struct audio_client *ac, struct audio_buffer *ab) -{ - struct adsp_buffer_command rpc; - int r; - - AUDIO_INFO("%s: %X %X %X\n", __func__, ab->phys , ab->size, ab->used); - memset(&rpc, 0, sizeof(rpc)); - rpc.hdr.context = ac->session; - rpc.hdr.data = (uint32_t)ab->data; - rpc.buffer.addr = ab->phys; - rpc.buffer.max_size = ab->size; - rpc.buffer.actual_size = ab->used; - rpc.buffer.flags = ADSP_AUDIO_BUFFER_FLAG_PHYS_ADDR | ADSP_AUDIO_BUFFER_FLAG_START_SET; - - TRACE("%p: read\n", ac); -// r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc), &res, sizeof(res)); - - r = dal_call_f5(ac->client, AUDIO_OP_READ, &rpc, sizeof(rpc)); - return 0; -} - -int q6audio_write(struct audio_client *ac, struct audio_buffer *ab) -{ - struct adsp_buffer_command rpc; - int r; - - AUDIO_INFO("%s: %X %X %X\n", __func__, ab->phys , ab->size, ab->used); - memset(&rpc, 0, sizeof(rpc)); -// rpc.hdr.context = ac->session; - rpc.hdr.data = (uint32_t)ab->data; - rpc.buffer.addr = ab->phys; - rpc.buffer.max_size = ab->size; - rpc.buffer.actual_size = ab->used; - rpc.buffer.start = (~0x7fffffffffffffffLL); - rpc.buffer.flags = ADSP_AUDIO_BUFFER_FLAG_PHYS_ADDR | ADSP_AUDIO_BUFFER_FLAG_START_SET; - - TRACE("%p: write\n", ac); -// r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc), &res, sizeof(res)); - - r = dal_call_f5(ac->client, AUDIO_OP_WRITE, &rpc, sizeof(rpc)); - return 0; -} - -static int audio_rx_volume(struct audio_client *ac, uint32_t dev_id, int32_t volume) -{ - struct adsp_set_dev_volume_command rpc; - - AUDIO_INFO("%s: dev_id 0x%08x, volume = %d\n", __func__, dev_id , volume); - - memset(&rpc, 0, sizeof(rpc)); - rpc.device_id = dev_id; - rpc.path = ADSP_PATH_RX; - rpc.volume = volume; - return audio_ioctl(ac, ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL, &rpc, sizeof(rpc)); -} - -static int audio_tx_volume(struct audio_client *ac, uint32_t dev_id, int32_t volume) -{ - struct adsp_set_dev_volume_command rpc; - - AUDIO_INFO("%s: dev_id 0x%08x, volume = %d\n", __func__, dev_id , volume); - - memset(&rpc, 0, sizeof(rpc)); - rpc.device_id = dev_id; - rpc.path = ADSP_PATH_TX; - rpc.volume = volume; - return audio_ioctl(ac, ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL, &rpc, sizeof(rpc)); -} - - -static int audio_rx_mute(struct audio_client *ac, uint32_t dev_id, int mute) -{ - struct adsp_set_dev_mute_command rpc; - - AUDIO_INFO("%s: dev_id 0x%08x, mute %d\n", __func__, dev_id , mute); - - memset(&rpc, 0, sizeof(rpc)); - rpc.device_id = dev_id; - rpc.path = ADSP_PATH_RX; - rpc.mute = !!mute; - return audio_ioctl(ac, ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE, &rpc, sizeof(rpc)); -} - - -static int audio_tx_mute(struct audio_client *ac, uint32_t dev_id, int mute) -{ - struct adsp_set_dev_mute_command rpc; - - AUDIO_INFO("%s: dev_id 0x%08x, mute %d\n", __func__, dev_id , mute); - - memset(&rpc, 0, sizeof(rpc)); - rpc.device_id = dev_id; - rpc.path = ADSP_PATH_TX; - rpc.mute = !!mute; - return audio_ioctl(ac, ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE, &rpc, sizeof(rpc)); -} - -static int audio_stream_volume(struct audio_client *ac, int volume) -{ - struct adsp_set_volume_command rpc; - int rc; - - AUDIO_INFO("%s: volume %d\n", __func__, volume); -// -// CotullaHACK: this function called from libaudio-qsd8k / AudioHardware.cpp -// status = ioctl(mFd, AUDIO_SET_VOLUME, &stream_volume); -// stream_volume have fixed -300 value, replace it to zero -// -// printk("$$$ audio_stream_volume(%d)\n", volume); - volume = 0; - - memset(&rpc, 0, sizeof(rpc)); - rpc.volume = volume; - rc = audio_ioctl(ac, ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL, &rpc, sizeof(rpc)); - return rc; -} - -static int audio_stream_mute(struct audio_client *ac, int mute) -{ - struct adsp_set_mute_command rpc; - int rc; - - AUDIO_INFO("%s: mute %d\n", __func__, mute); - memset(&rpc, 0, sizeof(rpc)); - rpc.mute = mute; - rc = audio_ioctl(ac, ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE, &rpc, sizeof(rpc)); - return rc; -} - -static int audio_stream_eq(struct audio_client *ac, struct cad_audio_eq_cfg *eq_cfg) -{ - struct adsp_audio_set_equalizer_command rpc; - int rc; - uint32_t i = 0; - - AUDIO_INFO("%s\n", __func__); - memset(&rpc, 0, sizeof(rpc)); - rpc.enable = eq_cfg->enable; - rpc.num_bands = eq_cfg->num_bands; - for (i = 0; i < rpc.num_bands; i++) - { - rpc.eq_bands[i].band_idx = eq_cfg->eq_bands[i].band_idx; - rpc.eq_bands[i].filter_type = eq_cfg->eq_bands[i].filter_type; - rpc.eq_bands[i].center_freq_hz = eq_cfg->eq_bands[i].center_freq_hz; - rpc.eq_bands[i].filter_gain = eq_cfg->eq_bands[i].filter_gain; - rpc.eq_bands[i].q_factor = eq_cfg->eq_bands[i].q_factor; -#if 1 - pr_info(">>>>>> band_idx = %d\n", rpc.eq_bands[i].band_idx); - pr_info(">>>>>> filter_type = %d\n", rpc.eq_bands[i].filter_type); - pr_info(">>>>>> center_freq_hz = %d\n", rpc.eq_bands[i].center_freq_hz); - pr_info(">>>>>> filter_gain = %d\n", rpc.eq_bands[i].filter_gain); - pr_info(">>>>>> q_factor = %d\n\n", rpc.eq_bands[i].q_factor); -#endif - } - rc = audio_ioctl(ac, ADSP_AUDIO_IOCTL_SET_SESSION_EQ_CONFIG, &rpc, sizeof(rpc)); - return rc; -} - -static void callback(void *data, int len, void *cookie) -{ -// struct adsp_event_hdr *e = data; - struct adsp_audio_dal_event *e = data; - struct audio_client *ac; - struct adsp_audio_event* ae; - -// printk("dal event\n"); - TRACE("audio callback: CB: %X LOC: %X SIZE=%X\n", e->cb_evt, e->loc_evt, e->size); - - if (e->cb_evt != CB_EVENT_COOKIE) - { - pr_err("audio callback: bad cb_event %X\n", e->cb_evt); - return; - } - - ae = &e->ae; - if (ae->session >= SESSION_MAX) - { - pr_err("audio callback: bogus session %d\n", ae->session); - return; - } - ac = session[ae->session]; - if (!ac) - { - pr_err("audio callback: unknown session %d\n", ae->session); - return; - } - - if (ae->event_id == ADSP_AUDIO_EVT_STATUS_OPEN) - { - pr_info("open done!\n"); - ac->open_status = ae->status; - ac->open_done = 1; - wake_up(&ac->wait); - return; - } - - if (ae->event_id == ADSP_AUDIO_IOCTL_CMD_STREAM_EOS) - { - TRACE("%p: CB stream eos\n", ac); - if (ae->status) - { - pr_err("playback status %d\n", ae->status); - } - if (ac->cb_status == -EBUSY) - { - ac->cb_status = ae->status; - wake_up(&ac->wait); - } - return; - } - - if (ae->event_id == ADSP_AUDIO_EVT_STATUS_BUF_DONE) - { - TRACE("%p: CB done (%d)\n", ac, ae->status); -// TRACE("%p: actual_size %d, buffer_size %d\n", -// ac, abe->buffer.actual_size, ac->buf[ac->dsp_buf].size); - - if (ae->status) - { - pr_err("buffer status %d\n", ae->status); - } - ac->buf[ac->dsp_buf].used = 0; - ac->dsp_buf ^= 1; - wake_up(&ac->wait); - return; - } - - TRACE("%p: CB %08x status %d\n", ac, ae->event_id, ae->status); - if (ae->status) - { - pr_warning("audio_cb: s=%d e=%08x status=%d\n", ae->session, ae->event_id, ae->status); - } - - if (ac->cb_status == -EBUSY) - { - ac->cb_status = ae->status; - wake_up(&ac->wait); - } -} - - -struct rpc_config_info -{ - u32 cb_evt; - u32 loc_evt; - u32 session_id; - u32 processor_id; -}; - -struct rpc_info -{ - uint32_t size; - uint32_t version; - char name[32]; - -}; - - - - -static int audio_init(struct audio_client *ac) -{ - - int r; - struct rpc_config_info info; - - AUDIO_INFO("%s\n", __func__); - - info.session_id = ac->session; - info.processor_id = 1; // AARM - info.cb_evt = CB_EVENT_COOKIE; - info.loc_evt = (u32)(((u32)ac->session + 1) << 16); - - r = dal_call_f5(ac->client, AUDIO_OP_INIT, &info, sizeof(info)); - return r; -} - -static int audio_info(struct audio_client *ac) -{ - int r; - struct rpc_info info; - - AUDIO_INFO("%s\n", __func__); - - r = dal_call_f9(ac->client, DAL_OP_INFO, &info, sizeof(info)); - return r; -} - -static struct audio_client *ac_control; -static int zero_already_inited; - -struct audio_config_data { - uint32_t device_id; - uint32_t sample_rate; - uint32_t offset; - uint32_t length; -}; - -struct audio_config_database { - uint8_t magic[8]; - uint32_t entry_count; - uint32_t unused; - struct audio_config_data entry[0]; -}; - -void *acdb_data; -const struct firmware *acdb_fw; -extern struct miscdevice q6_control_device; - -static int acdb_init(char *filename) -{ - const struct audio_config_database *db; - const struct firmware *fw; - int n; - - return -ENODEV; - - pr_info("acdb: load '%s'\n", filename); - if (request_firmware(&fw, filename, q6_control_device.this_device) < 0) { - pr_err("acdb: load 'default.acdb' failed...\n"); - return -ENODEV; - } - db = (void*) fw->data; - - if (fw->size < sizeof(struct audio_config_database)) { - pr_err("acdb: undersized database\n"); - goto fail; - } - if (strcmp(db->magic, "ACDB1.0")) { - pr_err("acdb: invalid magic\n"); - goto fail; - } - if (db->entry_count > 1024) { - pr_err("acdb: too many entries\n"); - goto fail; - } - if (fw->size < (sizeof(struct audio_config_database) + - db->entry_count * sizeof(struct audio_config_data))) { - pr_err("acdb: undersized TOC\n"); - goto fail; - } - for (n = 0; n < db->entry_count; n++) { - if (db->entry[n].length > 4096) { - pr_err("acdb: entry %d too large (%d)\n", - n, db->entry[n].length); - goto fail; - } - if ((db->entry[n].offset + db->entry[n].length) > fw->size) { - pr_err("acdb: entry %d outside of data\n", n); - goto fail; - } - } - if (acdb_data) - release_firmware(acdb_fw); - acdb_data = (void*) fw->data; - acdb_fw = fw; - return 0; -fail: - release_firmware(fw); - return -ENODEV; -} - -static int q6audio_init(void) -{ - struct audio_client *ac = 0; - int res; - - AUDIO_INFO("%s\n", __func__); - mutex_lock(&audio_lock); - if (ac_control) - { - res = 0; - goto done; - } - - pr_info("q6audio_init\n"); - - icodec_rx_clk = clk_get(0, "icodec_rx_clk"); - icodec_tx_clk = clk_get(0, "icodec_tx_clk"); - ecodec_clk = clk_get(0, "ecodec_clk"); - sdac_clk = clk_get(0, "sdac_clk"); - audio_data = dma_alloc_coherent(NULL, 4096, &audio_phys, GFP_KERNEL); - params_data = dma_alloc_coherent(NULL, 4096, ¶ms_phys, GFP_KERNEL); -// printk("allocated: %p %x\n", params_data, params_phys); - -// pr_info("audio: init: INIT\n"); - - if (!zero_already_inited) - { - zero_already_inited = 1; - pr_info("audio: init: first run, init dummy control\n"); - audio_client_alloc(0); - } - - ac = audio_client_alloc(0); - if (!ac) - { - pr_err("audio_init: cannot allocate client\n"); - res = -ENOMEM; - goto done; - } - -// pr_info("audio: init: OPEN control\n"); - if (audio_open_control(ac)) - { - pr_err("audio_init: cannot open control channel\n"); - res = -ENODEV; - goto done; - } - -// pr_info("audio: init: attach ACDB\n"); - acdb = dal_attach(ACDB_DAL_DEVICE, ACDB_DAL_PORT, 0, 0); - if (!acdb) - { - pr_err("audio_init: cannot attach to acdb channel\n"); - res = -ENODEV; - goto done; - } - -// pr_info("audio: init: attach ADIE\n"); - adie = dal_attach(ADIE_DAL_DEVICE, ADIE_DAL_PORT, 0, 0); - if (!adie) { - pr_err("audio_init: cannot attach to adie\n"); - res = -ENODEV; - goto done; - } - - if (analog_ops->init) - analog_ops->init(); - - if (!acdb_data && !acdb_use_rpc) - { - if (acdb_init(acdb_file)) - { - pr_info("use RPC to query ACDB.\n"); - acdb_use_rpc = 1; - } - } - - res = 0; - ac_control = ac; - - wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "audio_pcm_idle"); - wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "audio_pcm_suspend"); - - q6audio_init_rx_volumes(); - -// TEST HERE -// pr_info("START TEST\n"); -// audio_tx_mute(ac_control, ADSP_AUDIO_DEVICE_ID_DEFAULT, 1); -// pr_info("END TEST\n"); -done: - if ((res < 0) && ac) - { - audio_client_free(ac); - printk(" init failed!\n"); - } - mutex_unlock(&audio_lock); - return res; -} - - -static int map_cad_dev_to_virtual(int cd) -{ - if (global_now_phone_call) - { - return cd; - } - - switch (cd) - { - case 1: return 507; - case 2: return 208; - case 3: return 307; - case 5: return 407; - case 6: return 507; - case 7: return 607; - case 17: return 408; - default: return cd; - } - return 0; -} - -static int acdb_get_config_table(uint32_t device_id, uint32_t sample_rate) -{ - AUDIO_INFO("%s\n", __func__); - - if (q6audio_init()) - return 0; - - if (acdb_use_rpc) - { - struct acdb_cmd_device_table rpc; - struct acdb_result res; - int r; - uint32_t new_device_id; - - memset(audio_data, 0, 4096); - memset(&rpc, 0, sizeof(rpc)); - - new_device_id = map_cad_dev_to_virtual(device_id); - printk(" ACDB MAP: %d -> %d\n", device_id, new_device_id); - - rpc.size = sizeof(rpc) - (2 * sizeof(uint32_t)); - rpc.command_id = ACDB_GET_DEVICE_TABLE; - rpc.device_id = new_device_id; //0x25F; //device_id; - rpc.sample_rate_id = sample_rate; - rpc.total_bytes = 4096; - rpc.unmapped_buf = audio_phys; - rpc.res_size = sizeof(res) - (2 * sizeof(uint32_t)); - -// printk("ACDB dal call\n"); - r = dal_call(acdb, ACDB_OP_IOCTL, 8, &rpc, sizeof(rpc), &res, sizeof(res)); -// r = dal_call_f8(acdb, ACDB_OP_IOCTL, &rpc, sizeof(rpc), &res, sizeof(res)); - - pr_info("acdb ret: %d %X %X %X %d\n", res. dal_status, res.size, res.unmapped_buf, res.used_bytes, res.result); - if ((r == sizeof(res)) && (res.result == 0)) - { - pr_info("acdb: %d bytes for device %d, rate %d.\n", res.used_bytes, device_id, sample_rate); - return res.used_bytes; - } - return 0; - } - else - { - struct audio_config_database *db; - int n; - - printk("table\n"); - db = acdb_data; - for (n = 0; n < db->entry_count; n++) - { - if (db->entry[n].device_id != device_id) - continue; - if (db->entry[n].sample_rate != sample_rate) - continue; - break; - } - - if (n == db->entry_count) - { - pr_err("acdb: no entry for device %d, rate %d.\n", - device_id, sample_rate); - return 0; - } - - pr_info("acdb: %d bytes for device %d, rate %d.\n", - db->entry[n].length, device_id, sample_rate); - - memcpy(audio_data, acdb_data + db->entry[n].offset, db->entry[n].length); - return db->entry[n].length; - } -} - -//static uint32_t audio_rx_path_id = ADIE_PATH_HANDSET_RX; -//static uint32_t audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR; -static uint32_t audio_rx_path_id = ADIE_PATH_SPEAKER_RX; -static uint32_t audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO; -static uint32_t audio_rx_device_group = -1; -static uint32_t audio_tx_path_id = ADIE_PATH_HANDSET_TX; -static uint32_t audio_tx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_MIC; -static uint32_t audio_tx_device_group = -1; - -static int qdsp6_devchg_notify(struct audio_client *ac, uint32_t dev_type, uint32_t dev_id) -{ - struct adsp_device_switch_command rpc; - - AUDIO_INFO("%s\n", __func__); - - if (dev_type != ADSP_AUDIO_RX_DEVICE && dev_type != ADSP_AUDIO_TX_DEVICE) - return -EINVAL; - - memset(&rpc, 0, sizeof(rpc)); - if (dev_type == ADSP_AUDIO_RX_DEVICE) - { - rpc.old_device = audio_rx_device_id; - rpc.new_device = dev_id; - } - else - { - rpc.old_device = audio_tx_device_id; - rpc.new_device = dev_id; - } - rpc.device_class = 0; - rpc.device_type = dev_type; - return audio_ioctl(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE, &rpc, sizeof(rpc)); -} - -static int qdsp6_standby(struct audio_client *ac) -{ - AUDIO_INFO("%s\n", __func__); - return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY); -} - -static int qdsp6_start(struct audio_client *ac) -{ - AUDIO_INFO("%s\n", __func__); - return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT); -} - -static void audio_rx_analog_enable(int en) -{ - AUDIO_INFO("%s\n", __func__); - switch (audio_rx_device_id) { - case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO: - case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO: - case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR: - if (analog_ops->headset_enable) - analog_ops->headset_enable(en); - break; - case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET: - case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET: - case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET: - case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET: - if (analog_ops->headset_enable) - analog_ops->headset_enable(en); - if (analog_ops->speaker_enable) - analog_ops->speaker_enable(en); - break; - case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO: - case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO: - if (analog_ops->speaker_enable) - analog_ops->speaker_enable(en); - break; - case ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR: - if (analog_ops->bt_sco_enable) - analog_ops->bt_sco_enable(en); - break; - case ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR: - if (analog_ops->receiver_enable) - analog_ops->receiver_enable(en); - break; -/* - TODO: we need this? - case ADSP_AUDIO_DEVICE_ID_I2S_SPKR: - if (analog_ops->i2s_enable) - analog_ops->i2s_enable(en); - break; -*/ - } - -} - -static void audio_tx_analog_enable(int en) -{ - AUDIO_INFO("%s\n", __func__); - switch (audio_tx_device_id) { - case ADSP_AUDIO_DEVICE_ID_HANDSET_MIC: - case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC: - if (analog_ops->int_mic_enable) - analog_ops->int_mic_enable(en); - break; - case ADSP_AUDIO_DEVICE_ID_HEADSET_MIC: - case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC: - if (analog_ops->ext_mic_enable) - analog_ops->ext_mic_enable(en); - break; - case ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC: - if (analog_ops->bt_sco_enable) - analog_ops->bt_sco_enable(en); - break; - } -} - -static int audio_update_acdb(uint32_t adev, uint32_t acdb_id) -{ - uint32_t sample_rate; - int sz = -1; - - printk("%s (%d, %d)\n", __func__, adev, acdb_id); - AUDIO_INFO("%s (%d, %d)\n", __func__, adev, acdb_id); -// dex_comm(PCOM_UPDATE_ACDB, 0, 0); - sample_rate = q6_device_to_rate(adev); - - if (q6_device_to_dir(adev) == Q6_RX) - rx_acdb = acdb_id; - else - tx_acdb = acdb_id; - - if (acdb_id != 0) - { - sz = acdb_get_config_table(acdb_id, sample_rate); - } - printk("res1 = %d\n", sz); - if (sz <= 0) - { - acdb_id = q6_device_to_cad_id(adev); - printk(" new acdb = %d\n", acdb_id); - sz = acdb_get_config_table(acdb_id, sample_rate); - } - printk("res2 = %d\n", sz); - if (sz > 0) - { - printk("call audio_set_table\n"); - audio_set_table(ac_control, adev, sz); - } - return 0; -} - -static void _audio_rx_path_enable(int reconf, uint32_t acdb_id) -{ - AUDIO_INFO("%s\n", __func__); - adie_enable(); - adie_set_path(adie, audio_rx_path_id, ADIE_PATH_RX); - adie_set_path_freq_plan(adie, ADIE_PATH_RX, 48000); - - adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_READY); - adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_ANALOG_READY); - -// audio_update_acdb(audio_rx_device_id, acdb_id); - if (!reconf) - qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, audio_rx_device_id); - qdsp6_standby(ac_control); - qdsp6_start(ac_control); - - audio_update_acdb(audio_rx_device_id, acdb_id); - - audio_rx_analog_enable(1); -} - -static void _audio_tx_path_enable(int reconf, uint32_t acdb_id) -{ - AUDIO_INFO("%s\n", __func__); - audio_tx_analog_enable(1); - - adie_enable(); - adie_set_path(adie, audio_tx_path_id, ADIE_PATH_TX); - - if (tx_clk_freq > 8000) - adie_set_path_freq_plan(adie, ADIE_PATH_TX, 48000); - else - adie_set_path_freq_plan(adie, ADIE_PATH_TX, 8000); - - adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_DIGITAL_READY); - adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_DIGITAL_ANALOG_READY); - - audio_update_acdb(audio_tx_device_id, acdb_id); - - if (!reconf) - qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, audio_tx_device_id); - qdsp6_standby(ac_control); - qdsp6_start(ac_control); - - audio_tx_mute(ac_control, audio_tx_device_id, tx_mute_status); -} - -static void _audio_rx_path_disable(void) -{ - AUDIO_INFO("%s\n", __func__); - audio_rx_analog_enable(0); - - adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_ANALOG_OFF); - adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_OFF); - adie_disable(); -} - -static void _audio_tx_path_disable(void) -{ - AUDIO_INFO("%s\n", __func__); - audio_tx_analog_enable(0); - - adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_ANALOG_OFF); - adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_DIGITAL_OFF); - adie_disable(); -} - -static int icodec_rx_clk_refcount; -static int icodec_tx_clk_refcount; -static int ecodec_clk_refcount; -static int sdac_clk_refcount; - -static void _audio_rx_clk_enable(void) -{ - uint32_t device_group = q6_device_to_codec(audio_rx_device_id); - AUDIO_INFO("%s: device 0x%08x, group %d\n", - __func__, audio_rx_device_id, device_group); - switch(device_group) { - case Q6_ICODEC_RX: - icodec_rx_clk_refcount++; - AUDIO_INFO("%s: icodec_rx_clk_refcount = %d\n", - __func__, icodec_rx_clk_refcount); - if (icodec_rx_clk_refcount == 1) { - clk_set_rate(icodec_rx_clk, 12288000); - clk_enable(icodec_rx_clk); - AUDIO_INFO("%s: icodec_rx_clk enabled\n", __func__); - } - break; - case Q6_ECODEC_RX: - ecodec_clk_refcount++; - AUDIO_INFO("%s: ecodec_clk_refcount = %d\n", - __func__, ecodec_clk_refcount); - if (ecodec_clk_refcount == 1) { - clk_set_rate(ecodec_clk, 2048000); - clk_enable(ecodec_clk); - AUDIO_INFO("%s: ecodec_clk enabled\n", __func__); - } - break; - case Q6_SDAC_RX: - sdac_clk_refcount++; - AUDIO_INFO("%s: sdac_clk_refcount = %d\n", - __func__, sdac_clk_refcount); - if (sdac_clk_refcount == 1) { - clk_set_rate(sdac_clk, 12288000); - clk_enable(sdac_clk); - AUDIO_INFO("%s: sdac_clk enabled\n", __func__); - } - break; - default: - return; - } - audio_rx_device_group = device_group; -} - -static void _audio_tx_clk_enable(void) -{ - uint32_t device_group = q6_device_to_codec(audio_tx_device_id); - AUDIO_INFO("%s: device 0x%08x, group %d\n", - __func__, audio_tx_device_id, device_group); - switch (device_group) { - case Q6_ICODEC_TX: - icodec_tx_clk_refcount++; - AUDIO_INFO("%s: icodec_tx_clk_refcount = %d\n", - __func__, icodec_tx_clk_refcount); - if (icodec_tx_clk_refcount == 1) { - clk_set_rate(icodec_tx_clk, tx_clk_freq * 256); - clk_enable(icodec_tx_clk); - AUDIO_INFO("%s: icodec_tx_clk enabled\n", __func__); - } - break; - case Q6_ECODEC_TX: - ecodec_clk_refcount++; - AUDIO_INFO("%s: ecodec_clk_refcount = %d\n", - __func__, ecodec_clk_refcount); - if (ecodec_clk_refcount == 1) { - clk_set_rate(ecodec_clk, 2048000); - clk_enable(ecodec_clk); - AUDIO_INFO("%s: ecodec_clk enabled\n", __func__); - } - break; - case Q6_SDAC_TX: - /* TODO: In QCT BSP, clk rate was set to 20480000 */ - sdac_clk_refcount++; - AUDIO_INFO("%s: sdac_clk_refcount = %d\n", - __func__, sdac_clk_refcount); - if (sdac_clk_refcount == 1) { - clk_set_rate(sdac_clk, 12288000); - clk_enable(sdac_clk); - AUDIO_INFO("%s: sdac_clk enabled\n", __func__); - } - break; - default: - return; - } - audio_tx_device_group = device_group; -} - -static void _audio_rx_clk_disable(void) -{ - AUDIO_INFO("%s: group %d\n", __func__, audio_rx_device_group); - switch (audio_rx_device_group) { - case Q6_ICODEC_RX: - icodec_rx_clk_refcount--; - AUDIO_INFO("%s: icodec_rx_clk_refcount = %d\n", - __func__, icodec_rx_clk_refcount); - if (icodec_rx_clk_refcount == 0) { - clk_disable(icodec_rx_clk); - audio_rx_device_group = -1; - AUDIO_INFO("%s: icodec_rx_clk disabled\n", __func__); - } - break; - case Q6_ECODEC_RX: - ecodec_clk_refcount--; - AUDIO_INFO("%s: ecodec_clk_refcount = %d\n", - __func__, ecodec_clk_refcount); - if (ecodec_clk_refcount == 0) { - clk_disable(ecodec_clk); - audio_rx_device_group = -1; - AUDIO_INFO("%s: ecodec_clk disabled\n", __func__); - } - break; - case Q6_SDAC_RX: - sdac_clk_refcount--; - AUDIO_INFO("%s: sdac_clk_refcount = %d\n", - __func__, sdac_clk_refcount); - if (sdac_clk_refcount == 0) { - clk_disable(sdac_clk); - audio_rx_device_group = -1; - AUDIO_INFO("%s: sdac_clk disabled\n", __func__); - } - break; - default: - pr_err("audiolib: invalid rx device group %d\n", - audio_rx_device_group); - break; - } -} - -static void _audio_tx_clk_disable(void) -{ - AUDIO_INFO("%s: group %d\n", __func__, audio_tx_device_group); - switch (audio_tx_device_group) { - case Q6_ICODEC_TX: - icodec_tx_clk_refcount--; - AUDIO_INFO("%s: icodec_tx_clk_refcount = %d\n", - __func__, icodec_tx_clk_refcount); - if (icodec_tx_clk_refcount == 0) { - clk_disable(icodec_tx_clk); - audio_tx_device_group = -1; - AUDIO_INFO("%s: icodec_tx_clk disabled\n", __func__); - } - break; - case Q6_ECODEC_TX: - ecodec_clk_refcount--; - AUDIO_INFO("%s: ecodec_clk_refcount = %d\n", - __func__, ecodec_clk_refcount); - if (ecodec_clk_refcount == 0) { - clk_disable(ecodec_clk); - audio_tx_device_group = -1; - AUDIO_INFO("%s: ecodec_clk disabled\n", __func__); - } - break; - case Q6_SDAC_TX: - sdac_clk_refcount--; - AUDIO_INFO("%s: sdac_clk_refcount = %d\n", - __func__, sdac_clk_refcount); - if (sdac_clk_refcount == 0) { - clk_disable(sdac_clk); - audio_tx_device_group = -1; - AUDIO_INFO("%s: sdac_clk disabled\n", __func__); - } - break; - default: - pr_err("audiolib: invalid tx device group %d\n", - audio_tx_device_group); - break; - } -} - -static void _audio_rx_clk_reinit(uint32_t rx_device) -{ - uint32_t device_group = q6_device_to_codec(rx_device); - - AUDIO_INFO("%s\n", __func__); - - if (device_group != audio_rx_device_group) - _audio_rx_clk_disable(); - - audio_rx_device_id = rx_device; - audio_rx_path_id = q6_device_to_path(rx_device); - - if (device_group != audio_rx_device_group) - _audio_rx_clk_enable(); - -} - -static void _audio_tx_clk_reinit(uint32_t tx_device) -{ - uint32_t device_group = q6_device_to_codec(tx_device); - - AUDIO_INFO("%s\n", __func__); - if (device_group != audio_tx_device_group) - _audio_tx_clk_disable(); - - audio_tx_device_id = tx_device; - audio_tx_path_id = q6_device_to_path(tx_device); - - if (device_group != audio_tx_device_group) - _audio_tx_clk_enable(); -} - -static DEFINE_MUTEX(audio_path_lock); -static int audio_rx_path_refcount; -static int audio_tx_path_refcount; - -static int audio_rx_path_enable(int en, uint32_t acdb_id) -{ - AUDIO_INFO("%s\n", __func__); - mutex_lock(&audio_path_lock); - if (en) { - audio_rx_path_refcount++; - if (audio_rx_path_refcount == 1) { - _audio_rx_clk_enable(); - _audio_rx_path_enable(0, acdb_id); - } - } else { - audio_rx_path_refcount--; - if (audio_rx_path_refcount == 0) { - _audio_rx_path_disable(); - _audio_rx_clk_disable(); - } - } - mutex_unlock(&audio_path_lock); - return 0; -} - -static int audio_tx_path_enable(int en, uint32_t acdb_id) -{ - AUDIO_INFO("%s\n", __func__); - mutex_lock(&audio_path_lock); - if (en) { - audio_tx_path_refcount++; - if (audio_tx_path_refcount == 1) { - _audio_tx_clk_enable(); - _audio_tx_path_enable(0, acdb_id); - } - } else { - audio_tx_path_refcount--; - if (audio_tx_path_refcount == 0) { - _audio_tx_path_disable(); - _audio_tx_clk_disable(); - } - } - mutex_unlock(&audio_path_lock); - return 0; -} - -int q6audio_reinit_acdb(char* filename) -{ - int res; - - if (q6audio_init()) - return 0; - - mutex_lock(&audio_path_lock); - if (strlen(filename) < 0) { - res = -EINVAL; - goto done; - } - res = acdb_init(filename); - if (!res) - strcpy(acdb_file, filename); -done: - mutex_unlock(&audio_path_lock); - return res; - -} - -int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst) -{ - int res; - - if (q6audio_init()) - return 0; - - mutex_lock(&audio_path_lock); - res = audio_update_acdb(id_dst, id_src); - if (res) - goto done; - - if (q6_device_to_dir(id_dst) == Q6_RX) - qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, id_dst); - else - qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, id_dst); - qdsp6_standby(ac_control); - qdsp6_start(ac_control); -done: - mutex_unlock(&audio_path_lock); - return res; -} - -int q6audio_set_tx_mute(int mute) -{ - uint32_t adev; - int rc; - - AUDIO_INFO("%s\n", __func__); - if (q6audio_init()) - return 0; - - mutex_lock(&audio_path_lock); - - if (mute == tx_mute_status) { - mutex_unlock(&audio_path_lock); - return 0; - } - - adev = audio_tx_device_id; - rc = audio_tx_mute(ac_control, adev, mute); - tx_mute_status = mute; - mutex_unlock(&audio_path_lock); - return 0; -} - -int q6audio_set_stream_volume(struct audio_client *ac, int vol) -{ - AUDIO_INFO("%s\n", __func__); - if (vol > 1200 || vol < -4000) { - pr_err("unsupported volume level %d\n", vol); - return -EINVAL; - } - mutex_lock(&audio_path_lock); - audio_stream_mute(ac, 0); - audio_stream_volume(ac, vol); - mutex_unlock(&audio_path_lock); - return 0; -} - -int q6audio_set_stream_eq(struct audio_client *ac, struct cad_audio_eq_cfg *eq_cfg) -{ - AUDIO_INFO("%s\n", __func__); - mutex_lock(&audio_path_lock); - audio_stream_eq(ac, eq_cfg); - mutex_unlock(&audio_path_lock); - return 0; -} - - -int q6audio_set_rx_dev_volume(int level) -{ - int vol; - - AUDIO_INFO("%s\n", __func__); - - mutex_lock(&audio_path_lock); - - vol = q6_device_volume(audio_rx_device_id, level); - printk("$$ DEV=%08X: vol is %d\n", audio_rx_device_id, vol); - audio_rx_volume(ac_control, audio_rx_device_id, vol); - - mutex_unlock(&audio_path_lock); - return 0; -} - -int q6audio_set_rx_volume(int level) -{ -#if 0 - uint32_t adev; - int vol; - - AUDIO_INFO("%s\n", __func__); - if (q6audio_init()) - return 0; - - if (level < 0 || level > 100) - return -EINVAL; - - mutex_lock(&audio_path_lock); - adev = ADSP_AUDIO_DEVICE_ID_VOICE; - vol = q6_device_volume(audio_rx_device_id, level); - audio_rx_mute(ac_control, adev, 0); - printk("@@@@ rx volume: adev=%d, rx_dev_id=%d, level=%d @@@@\n", adev, audio_rx_device_id, vol); - audio_rx_volume(ac_control, adev, vol); - rx_vol_level = level; - mutex_unlock(&audio_path_lock); -#else - q6audio_set_rx_dev_volume(level); -#endif - return 0; -} - -static int q6audio_init_rx_volumes() -{ - int vol; - struct q6_device_info *di = q6_audio_devices; - - AUDIO_INFO("%s\n", __func__); - - mutex_lock(&audio_path_lock); - - printk("$$$ q6audio_init_rx_volumes\n"); - while (1) - { - if (di->id == 0) break; - - vol = q6_device_volume(di->id, 100); - audio_rx_volume(ac_control, di->id, vol); - printk("$$ DEV=%08X: vol is %d\n", di->id, vol); - - di++; - } - - mutex_unlock(&audio_path_lock); - return 0; -} - - -int q6audio_set_rx_mute(int mute) -{ - uint32_t adev; - - AUDIO_INFO("%s\n", __func__); - if (q6audio_init()) - return 0; - - if (mute < 0 || mute > 1) - return -EINVAL; - - mutex_lock(&audio_path_lock); - AUDIO_INFO("%s: set mute status %d\n", __func__, mute); - adev = ADSP_AUDIO_DEVICE_ID_VOICE; - audio_rx_mute(ac_control, adev, mute); - mutex_unlock(&audio_path_lock); - return 0; -} - -static void do_rx_routing(uint32_t device_id, uint32_t acdb_id) -{ - AUDIO_INFO("%s\n", __func__); - if (device_id == audio_rx_device_id) { - if (acdb_id != rx_acdb) { - audio_update_acdb(device_id, acdb_id); - qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, device_id); - qdsp6_standby(ac_control); - qdsp6_start(ac_control); - } - return; - } - - if (audio_rx_path_refcount > 0) { - qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, device_id); - _audio_rx_path_disable(); - _audio_rx_clk_reinit(device_id); - _audio_rx_path_enable(1, acdb_id); - } else { - audio_rx_device_id = device_id; - audio_rx_path_id = q6_device_to_path(device_id); - } -} - -static void do_tx_routing(uint32_t device_id, uint32_t acdb_id) -{ - AUDIO_INFO("%s\n", __func__); - if (device_id == audio_tx_device_id) { - if (acdb_id != tx_acdb) { - audio_update_acdb(device_id, acdb_id); - qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, device_id); - qdsp6_standby(ac_control); - qdsp6_start(ac_control); - } - return; - } - - if (audio_tx_path_refcount > 0) { - qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, device_id); - _audio_tx_path_disable(); - _audio_tx_clk_reinit(device_id); - _audio_tx_path_enable(1, acdb_id); - } else { - audio_tx_device_id = device_id; - audio_tx_path_id = q6_device_to_path(device_id); - } -} - -int q6audio_do_routing(uint32_t device_id, uint32_t acdb_id) -{ - AUDIO_INFO("%s\n", __func__); - if (q6audio_init()) - return 0; - - mutex_lock(&audio_path_lock); - - switch(q6_device_to_dir(device_id)) { - case Q6_RX: - do_rx_routing(device_id, acdb_id); - break; - case Q6_TX: - do_tx_routing(device_id, acdb_id); - break; - } - - mutex_unlock(&audio_path_lock); - return 0; -} - -int q6audio_set_route(const char *name) -{ - uint32_t route; - AUDIO_INFO("%s\n", __func__); - if (!strcmp(name, "speaker")) { - route = ADIE_PATH_SPEAKER_STEREO_RX; - } else if (!strcmp(name, "headphones")) { - route = ADIE_PATH_HEADSET_STEREO_RX; - } else if (!strcmp(name, "handset")) { - route = ADIE_PATH_HANDSET_RX; - } else { - return -EINVAL; - } - - mutex_lock(&audio_path_lock); - if (route == audio_rx_path_id) - goto done; - - audio_rx_path_id = route; - - if (audio_rx_path_refcount > 0) - { - _audio_rx_path_disable(); - _audio_rx_path_enable(1, 0); - } - if (audio_tx_path_refcount > 0) - { - _audio_tx_path_disable(); - _audio_tx_path_enable(1, 0); - } -done: - mutex_unlock(&audio_path_lock); - return 0; -} - -struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate, - uint32_t channels, uint32_t flags, uint32_t acdb_id) -{ -#if 1 - int rc, retry = 5; - struct audio_client *ac; - - AUDIO_INFO("%s\n", __func__); - if (q6audio_init()) - return 0; - -// printk("afer init();\n"); - ac = audio_client_alloc(bufsz); - if (!ac) - { - printk("audio_client_alloc failed\n"); - return 0; - } -// printk("after alloc);\n"); - ac->flags = flags; - - mutex_lock(&audio_path_lock); - - if (ac->flags & AUDIO_FLAG_WRITE) - { - audio_rx_path_refcount++; - if (audio_rx_path_refcount == 1) - { - _audio_rx_clk_enable(); -// audio_update_acdb(audio_rx_device_id, acdb_id); - qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, audio_rx_device_id); - qdsp6_standby(ac_control); - qdsp6_start(ac_control); - audio_update_acdb(audio_rx_device_id, acdb_id); - } - } - else - { - /* TODO: consider concurrency with voice call */ - tx_clk_freq = rate; - audio_tx_path_refcount++; - if (audio_tx_path_refcount == 1) - { - _audio_tx_clk_enable(); - _audio_tx_path_enable(0, acdb_id); - } - } -// printk("about to open\n"); - - for (retry = 5;;retry--) - { - if (ac->flags & AUDIO_FLAG_WRITE) - rc = audio_out_open(ac, bufsz, rate, channels); - else - rc = audio_in_open(ac, bufsz, rate, channels); - if (rc == 0) - break; - if (retry == 0) - { - // BUG(); - break; - } - pr_err("q6audio: open pcm error %d, retrying\n", rc); - msleep(1); - } - - if (retry == 0) - { - if (ac->flags & AUDIO_FLAG_WRITE) - audio_rx_path_enable(0, 0); - else - audio_tx_path_enable(0, 0); - audio_client_free(ac); - pr_err("q6audio: open pcm error\n"); - return NULL; - } - -// printk("after open\n"); - - if (ac->flags & AUDIO_FLAG_WRITE) - { - if (audio_rx_path_refcount == 1) - { - adie_enable(); - adie_set_path(adie, audio_rx_path_id, ADIE_PATH_RX); - adie_set_path_freq_plan(adie, ADIE_PATH_RX, 48000); - - adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_READY); - adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_ANALOG_READY); - - audio_rx_analog_enable(1); - } - } -// printk("about to start session\n"); - - mutex_unlock(&audio_path_lock); - - for (retry = 5;;retry--) - { - rc = audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START); - if (rc == 0) - break; - if (retry == 0) - { -// BUG(); - break; - } - pr_err("q6audio: stream start error %d, retrying\n", rc); - } - - if (retry == 0) - { - audio_close(ac); - if (ac->flags & AUDIO_FLAG_WRITE) - audio_rx_path_enable(0, 0); - else - audio_tx_path_enable(0, 0); - audio_client_free(ac); - pr_err("q6audio: open pcm error2\n"); - return NULL; - } - - if (!(ac->flags & AUDIO_FLAG_WRITE)) - { - ac->buf[0].used = 1; - ac->buf[1].used = 1; - q6audio_read(ac, &ac->buf[0]); - q6audio_read(ac, &ac->buf[1]); - } - - audio_prevent_sleep(); - return ac; -#else - return audio_test(); -#endif -} - -int q6audio_close(struct audio_client *ac) -{ - AUDIO_INFO("%s\n", __func__); - audio_close(ac); - if (ac->flags & AUDIO_FLAG_WRITE) - audio_rx_path_enable(0, 0); - else - audio_tx_path_enable(0, 0); - - audio_client_free(ac); - audio_allow_sleep(); - return 0; -} - -struct audio_client *q6voice_open(uint32_t flags, uint32_t acdb_id) -{ - struct audio_client *ac; - - AUDIO_INFO("%s\n", __func__); - if (q6audio_init()) - return 0; - - ac = audio_client_alloc(0); - if (!ac) - return 0; - - ac->flags = flags; - if (ac->flags & AUDIO_FLAG_WRITE) { - audio_rx_path_enable(1, acdb_id); - audio_rx_mute(ac_control, ADSP_AUDIO_DEVICE_ID_VOICE, 0); - } else { - tx_clk_freq = 8000; - audio_tx_path_enable(1, acdb_id); - } - - return ac; -} - -int q6voice_close(struct audio_client *ac) -{ - AUDIO_INFO("%s\n", __func__); - if (ac->flags & AUDIO_FLAG_WRITE) { - audio_rx_mute(ac_control, ADSP_AUDIO_DEVICE_ID_VOICE, 1); - audio_rx_path_enable(0, 0); - } else - audio_tx_path_enable(0, 0); - - audio_client_free(ac); - return 0; -} - -struct audio_client *q6audio_open_mp3(uint32_t bufsz, uint32_t rate, - uint32_t channels, uint32_t acdb_id) -{ - struct audio_client *ac; - - printk("q6audio_open_mp3()\n"); - - if (q6audio_init()) - return 0; - - ac = audio_client_alloc(bufsz); - if (!ac) - return 0; - - ac->flags = AUDIO_FLAG_WRITE; - audio_rx_path_enable(1, acdb_id); - - audio_mp3_open(ac, bufsz, rate, channels); - audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START); - - return ac; -} - -int q6audio_mp3_close(struct audio_client *ac) -{ - AUDIO_INFO("%s\n", __func__); - audio_close(ac); - audio_rx_path_enable(0, 0); - audio_client_free(ac); - return 0; -} - -int q6audio_async(struct audio_client *ac) -{ - struct adsp_command_hdr rpc; - memset(&rpc, 0, sizeof(rpc)); -// rpc.response_type = ADSP_AUDIO_RESPONSE_ASYNC; - return audio_ioctl(ac, ADSP_AUDIO_IOCTL_CMD_STREAM_EOS, &rpc, sizeof(rpc)); -} - - - -struct audio_client *q6audio_open_aac(uint32_t bufsz, uint32_t rate, - uint32_t flags, void *data, uint32_t acdb_id) -{ - struct audio_client *ac; - - TRACE("q6audio_open_aac flags=%d rate=%d\n", flags, rate); - - if (q6audio_init()) - return 0; - - ac = audio_client_alloc(bufsz); - if (!ac) - return 0; - - ac->flags = flags; - if (ac->flags & AUDIO_FLAG_WRITE) - audio_rx_path_enable(1, acdb_id); - else { - /* TODO: consider concourrency with voice call */ - tx_clk_freq = rate; - audio_tx_path_enable(1, acdb_id); - } - - audio_aac_open(ac, bufsz, data); - audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START); - - if (!(ac->flags & AUDIO_FLAG_WRITE)) { - ac->buf[0].used = 1; - ac->buf[1].used = 1; - q6audio_read(ac, &ac->buf[0]); - q6audio_read(ac, &ac->buf[1]); - } - audio_prevent_sleep(); - return ac; -} - -int q6audio_aac_close(struct audio_client *ac) -{ - audio_close(ac); - if (ac->flags & AUDIO_FLAG_WRITE) - audio_rx_path_enable(0, 0); - else - audio_tx_path_enable(0, 0); - - audio_client_free(ac); - audio_allow_sleep(); - return 0; -} - -struct audio_client *q6fm_open(void) -{ - struct audio_client *ac; - - printk("q6fm_open()\n"); - - if (q6audio_init()) - return 0; - - if (audio_rx_device_id != ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO && - audio_rx_device_id != ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO) - return 0; - - ac = audio_client_alloc(0); - if (!ac) - return 0; - - ac->flags = AUDIO_FLAG_WRITE; - audio_rx_path_enable(1, 0); - enable_aux_loopback(1); - - return ac; -} - -int q6fm_close(struct audio_client *ac) -{ - printk("q6fm_close\n"); - - audio_rx_path_enable(0, 0); - enable_aux_loopback(0); - audio_client_free(ac); - return 0; -} - -struct audio_client *q6audio_open_qcelp(uint32_t bufsz, uint32_t rate, - void *data, uint32_t acdb_id) -{ - struct audio_client *ac; - - AUDIO_INFO("%s\n", __func__); - if (q6audio_init()) - return 0; - - ac = audio_client_alloc(bufsz); - if (!ac) - { - return 0; - } - - ac->flags = AUDIO_FLAG_READ; - tx_clk_freq = rate; - audio_tx_path_enable(1, acdb_id); - - audio_qcelp_open(ac, bufsz, data); - audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START); - - ac->buf[0].used = 1; - ac->buf[1].used = 1; - q6audio_read(ac, &ac->buf[0]); - q6audio_read(ac, &ac->buf[1]); - - audio_prevent_sleep(); - return ac; -} - -int q6audio_qcelp_close(struct audio_client *ac) -{ - audio_close(ac); - audio_tx_path_enable(0, 0); - audio_client_free(ac); - audio_allow_sleep(); - return 0; -} - -/////////////////////////////////////////////////////////////////////////// - -int acdb_get_table(int dev_id, int sample_rate) -{ - struct acdb_cmd_device_table rpc; - struct acdb_result res; - int r; - - memset(audio_data, 0, 4096); - memset(&rpc, 0, sizeof(rpc)); - - rpc.size = sizeof(rpc) - (2 * sizeof(uint32_t)); - rpc.command_id = ACDB_GET_DEVICE_TABLE; - rpc.device_id = dev_id; - rpc.sample_rate_id = sample_rate; - rpc.total_bytes = 4096; - rpc.unmapped_buf = audio_phys; - rpc.res_size = sizeof(res) - (2 * sizeof(uint32_t)); - - r = dal_call(acdb, ACDB_OP_IOCTL, 8, &rpc, sizeof(rpc), &res, sizeof(res)); - - if ((r == sizeof(res)) && (res.dal_status == 0)) - { - pr_info("acdb: %d bytes for device %d, rate %d.\n", - res.used_bytes, dev_id, sample_rate); - return res.used_bytes; - } - return 0; -} - -static struct audio_client * audio_test(void) -{ - struct audio_client *ac = 0; - struct audio_client *ac2 = 0; - int size; - struct rpc_info info; - - pr_info("audio: init: codecs\n"); - icodec_rx_clk = clk_get(0, "icodec_rx_clk"); - icodec_tx_clk = clk_get(0, "icodec_tx_clk"); - ecodec_clk = clk_get(0, "ecodec_clk"); - sdac_clk = clk_get(0, "sdac_clk"); - audio_data = dma_alloc_coherent(NULL, 4096, &audio_phys, GFP_KERNEL); - params_data = dma_alloc_coherent(NULL, 4096, ¶ms_phys, GFP_KERNEL); - printk("allocated: %p %08X\n", params_data, params_phys); - - clk_set_rate(icodec_rx_clk, 12288000); - clk_enable(icodec_rx_clk); - clk_set_rate(ecodec_clk, 2048000); - clk_enable(ecodec_clk); - clk_set_rate(sdac_clk, 12288000); - clk_enable(sdac_clk); - - // 1. attach ADIE - adie = dal_attach_ex(ADIE_DAL_DEVICE, "NULL", ADIE_DAL_PORT , 0, 0); - if (!adie) - { - pr_err("audio_init: cannot attach to adie\n"); - return 0; - } - - if (analog_ops->init) - analog_ops->init(); - - audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO; - audio_rx_analog_enable(1); - - dal_call_f9(adie, DAL_OP_INFO, &info, sizeof(info)); - - - acdb = dal_attach(ACDB_DAL_DEVICE, ACDB_DAL_PORT, 0, 0); - if (!acdb) - { - pr_err("audio_init: cannot attach to acdb channel\n"); - return 0; - } - - dal_call_f9(acdb, DAL_OP_INFO, &info, sizeof(info)); - - audio_client_alloc(0); - - // audio_client_alloc(0); - - ac = audio_client_alloc(0); - - audio_open_control(ac); -//mdelay(1000); - - audio_rx_mute(ac, ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR, 0); - audio_rx_volume(ac, ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR, 0); - - acdb_get_table(7, 48000); - - audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR; - qdsp6_devchg_notify(ac, ADSP_AUDIO_RX_DEVICE, ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO); - - qdsp6_standby(ac); - qdsp6_start(ac); - - size = acdb_get_table(0x25F, 48000); - audio_set_table(ac, ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO, size); - - audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO; - qdsp6_devchg_notify(ac, ADSP_AUDIO_RX_DEVICE, ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO); - - qdsp6_standby(ac); - qdsp6_start(ac); - - audio_rx_mute(ac, ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO, 0); - audio_rx_volume(ac, ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO, 500); - - - size = acdb_get_table(507, 8000); - audio_set_table(ac, ADSP_AUDIO_DEVICE_ID_HANDSET_MIC, size); - - audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_MIC; - qdsp6_devchg_notify(ac, ADSP_AUDIO_TX_DEVICE, ADSP_AUDIO_DEVICE_ID_HANDSET_MIC); - - qdsp6_standby(ac); - qdsp6_start(ac); - - size = acdb_get_table(0x25F, 48000); - audio_set_table(ac, ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO, size); - - ac2 = audio_client_alloc(4096); - - audio_out_open(ac2, 4096, 44100, 2); - - adie_open(adie); - - adie_set_path(adie, ADIE_PATH_SPEAKER_RX, ADIE_PATH_RX); - adie_set_path_freq_plan(adie, ADIE_PATH_RX, 48000); - adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_READY); - adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_ANALOG_READY); - - audio_command(ac2, ADSP_AUDIO_IOCTL_CMD_SESSION_START); - - audio_rx_mute(ac, ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO, 0); - audio_rx_volume(ac, ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO, 500); - - return ac2; -} - - -// END OF FILE diff --git a/arch/arm/mach-msm/qdsp6/qcelp_in.c b/arch/arm/mach-msm/qdsp6/qcelp_in.c deleted file mode 100644 index e5843181..00000000 --- a/arch/arm/mach-msm/qdsp6/qcelp_in.c +++ /dev/null @@ -1,212 +0,0 @@ -/* arch/arm/mach-msm/qdsp6/qcelp_in.c - * - * Copyright (C) 2009 Google, Inc. - * Copyright (C) 2009 HTC Corporation - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BUFSZ (734) -#define DMASZ (BUFSZ * 2) - -#if 0 -#define TRACE(x...) pr_info("Q6: "x) -#else -#define TRACE(x...) do{}while(0) -#endif - -static DEFINE_MUTEX(qcelp_in_lock); -static int qcelp_in_opened = 0; -static struct msm_audio_qcelp_config *qf; - -void audio_client_dump(struct audio_client *ac); - -static long qcelp_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0; - - switch (cmd) { - case AUDIO_SET_VOLUME: - break; - case AUDIO_GET_STATS: { - struct msm_audio_stats stats; - memset(&stats, 0, sizeof(stats)); - if (copy_to_user((void*) arg, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - case AUDIO_START: { - uint32_t acdb_id; - rc = 0; - - if (arg == 0) { - acdb_id = 0; - } else if (copy_from_user(&acdb_id, (void*) arg, sizeof(acdb_id))) { - rc = -EFAULT; - break; - } - - mutex_lock(&qcelp_in_lock); - if (file->private_data) { - rc = -EBUSY; - } else { - file->private_data = q6audio_open_qcelp( - BUFSZ, 8000, qf, acdb_id); - if (!file->private_data) - rc = -ENOMEM; - } - mutex_unlock(&qcelp_in_lock); - break; - } - case AUDIO_STOP: - break; - case AUDIO_FLUSH: - break; - case AUDIO_GET_CONFIG: - if (copy_to_user((void *)arg, qf, - sizeof(struct msm_audio_qcelp_config))) - return -EFAULT; - break; - case AUDIO_SET_CONFIG: - if (copy_from_user(qf, (void *)arg, - sizeof(struct msm_audio_qcelp_config))) - return -EFAULT; - if (qf->min_bit_rate > 4 || qf->min_bit_rate < 1) { - pr_err("invalid min bitrate\n"); - return -EINVAL; - } - if (qf->max_bit_rate > 4 || qf->max_bit_rate < 1) { - pr_err("invalid max bitrate\n"); - return -EINVAL; - } - if (qf->cdma_rate > CDMA_RATE_ERASURE || - qf->cdma_rate < CDMA_RATE_BLANK) { - pr_err("invalid qcelp cdma rate\n"); - return -EINVAL; - } - break; - default: - rc = -EINVAL; - } - return rc; -} - -static int qcelp_in_open(struct inode *inode, struct file *file) -{ - int rc; - - pr_info("qcelp_in: open\n"); - mutex_lock(&qcelp_in_lock); - if (qcelp_in_opened) { - pr_err("qcelp_in: busy\n"); - rc = -EBUSY; - } else { - qf = kzalloc(sizeof(*qf), GFP_KERNEL); - memset(qf, 0, sizeof(struct msm_audio_qcelp_config)); - qf->channels = 1; - qf->cdma_rate = 0x04; /* CDMA_RATE_FULL */ - qf->min_bit_rate = 1; - qf->max_bit_rate = 4; - qcelp_in_opened = 1; - rc = 0; - } - mutex_unlock(&qcelp_in_lock); - return rc; -} - -static ssize_t qcelp_in_read(struct file *file, char __user *buf, size_t count, loff_t *pos) -{ - struct audio_client *ac; - struct audio_buffer *ab; - const char __user *start = buf; - int xfer, res = 0; - - mutex_lock(&qcelp_in_lock); - ac = file->private_data; - if (!ac) { - res = -ENODEV; - pr_err("qcelp_in_read ac NULL\n"); - goto fail; - } - while (count > 0) { - ab = ac->buf + ac->cpu_buf; - TRACE("qcelp_in_read wait count=%d ab=%d ac->buf=%d cpu_buf=%d ac->buf[1]=%d\n", - count, ab, ac->buf, ac->cpu_buf, &(ac->buf[1])); - if (ab->used) - wait_event(ac->wait, (ab->used == 0)); - TRACE(" qcelp_in_read event arrive ab->size=%d\n", ab->size); - xfer = count; - if (xfer > ab->size) - xfer = ab->size; - - if (copy_to_user(buf, ab->data, xfer)) { - res = -EFAULT; - pr_err("Tomdbg copy to user failed \n"); - goto fail; - } - TRACE("qcelp_in read buf = %d,xfer = %d,cnt = %d\n", buf, xfer, count); - - buf += xfer; - count -= xfer; - - ab->used = 1; - q6audio_read(ac, ab); - ac->cpu_buf ^= 1; - } -fail: - res = buf - start; - mutex_unlock(&qcelp_in_lock); - return res; -} - -static int qcelp_in_release(struct inode *inode, struct file *file) -{ - int rc = 0; - pr_info("qcelp_in: release\n"); - mutex_lock(&qcelp_in_lock); - if (file->private_data) - rc = q6audio_close(file->private_data); - kfree(qf); - qcelp_in_opened = 0; - mutex_unlock(&qcelp_in_lock); - return rc; -} - -static struct file_operations qcelp_in_fops = { - .owner = THIS_MODULE, - .open = qcelp_in_open, - .read = qcelp_in_read, - .release = qcelp_in_release, - .unlocked_ioctl = qcelp_in_ioctl, -}; - -struct miscdevice qcelp_in_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_qcelp_in", - .fops = &qcelp_in_fops, -}; - -static int __init qcelp_in_init(void) { - return misc_register(&qcelp_in_misc); -} - -device_initcall(qcelp_in_init); diff --git a/include/linux/msm_q6venc.h b/include/linux/msm_q6venc.h index 2ca4832d..097e2db8 100644 --- a/include/linux/msm_q6venc.h +++ b/include/linux/msm_q6venc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -7,119 +7,325 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + #ifndef _MSM_VENC_H_ #define _MSM_VENC_H_ #include -struct venc_buf { - unsigned int src_id; +#define VENC_MAX_RECON_BUFFERS 2 + +#define VENC_FLAG_EOS 0x00000001 +#define VENC_FLAG_END_OF_FRAME 0x00000010 +#define VENC_FLAG_SYNC_FRAME 0x00000020 +#define VENC_FLAG_EXTRA_DATA 0x00000040 +#define VENC_FLAG_CODEC_CONFIG 0x00000080 + +enum venc_flush_type { + VENC_FLUSH_INPUT, + VENC_FLUSH_OUTPUT, + VENC_FLUSH_ALL +}; + +enum venc_state_type { + VENC_STATE_PAUSE = 0x1, + VENC_STATE_START = 0x2, + VENC_STATE_STOP = 0x4 +}; + +enum venc_event_type_enum { + VENC_EVENT_START_STATUS, + VENC_EVENT_STOP_STATUS, + VENC_EVENT_SUSPEND_STATUS, + VENC_EVENT_RESUME_STATUS, + VENC_EVENT_FLUSH_STATUS, + VENC_EVENT_RELEASE_INPUT, + VENC_EVENT_DELIVER_OUTPUT, + VENC_EVENT_UNKNOWN_STATUS +}; + +enum venc_status_code { + VENC_STATUS_SUCCESS, + VENC_STATUS_ERROR, + VENC_STATUS_INVALID_STATE, + VENC_STATUS_FLUSHING, + VENC_STATUS_INVALID_PARAM, + VENC_STATUS_CMD_QUEUE_FULL, + VENC_STATUS_CRITICAL, + VENC_STATUS_INSUFFICIENT_RESOURCES, + VENC_STATUS_TIMEOUT +}; + +enum venc_msg_code { + VENC_MSG_INDICATION, + VENC_MSG_INPUT_BUFFER_DONE, + VENC_MSG_OUTPUT_BUFFER_DONE, + VENC_MSG_NEED_OUTPUT_BUFFER, + VENC_MSG_FLUSH, + VENC_MSG_START, + VENC_MSG_STOP, + VENC_MSG_PAUSE, + VENC_MSG_RESUME, + VENC_MSG_STOP_READING_MSG +}; + +enum venc_error_code { + VENC_S_SUCCESS, + VENC_S_EFAIL, + VENC_S_EFATAL, + VENC_S_EBADPARAM, + VENC_S_EINVALSTATE, + VENC_S_ENOSWRES, + VENC_S_ENOHWRES, + VENC_S_EBUFFREQ, + VENC_S_EINVALCMD, + VENC_S_ETIMEOUT, + VENC_S_ENOREATMPT, + VENC_S_ENOPREREQ, + VENC_S_ECMDQFULL, + VENC_S_ENOTSUPP, + VENC_S_ENOTIMPL, + VENC_S_ENOTPMEM, + VENC_S_EFLUSHED, + VENC_S_EINSUFBUF, + VENC_S_ESAMESTATE, + VENC_S_EINVALTRANS +}; + +enum venc_mem_region_enum { + VENC_PMEM_EBI1, + VENC_PMEM_SMI +}; + +struct venc_buf_type { + unsigned int region; + unsigned int phys; + unsigned int size; + int offset; +}; + +struct venc_qp_range { + unsigned int min_qp; + unsigned int max_qp; +}; + +struct venc_frame_rate { + unsigned int frame_rate_num; + unsigned int frame_rate_den; +}; + +struct venc_slice_info { + unsigned int slice_mode; + unsigned int units_per_slice; +}; + +struct venc_extra_data { + unsigned int slice_extra_data_flag; + unsigned int slice_client_data1; + unsigned int slice_client_data2; + unsigned int slice_client_data3; + unsigned int none_extra_data_flag; + unsigned int none_client_data1; + unsigned int none_client_data2; + unsigned int none_client_data3; +}; + +struct venc_common_config { + unsigned int standard; + unsigned int input_frame_height; + unsigned int input_frame_width; + unsigned int output_frame_height; + unsigned int output_frame_width; + unsigned int rotation_angle; + unsigned int intra_period; + unsigned int rate_control; + struct venc_frame_rate frame_rate; + unsigned int bitrate; + struct venc_qp_range qp_range; + unsigned int iframe_qp; + unsigned int pframe_qp; + struct venc_slice_info slice_config; + struct venc_extra_data extra_data; +}; + +struct venc_nonio_buf_config { + struct venc_buf_type recon_buf1; + struct venc_buf_type recon_buf2; + struct venc_buf_type wb_buf; + struct venc_buf_type cmd_buf; + struct venc_buf_type vlc_buf; +}; + +struct venc_mpeg4_config { + unsigned int profile; + unsigned int level; + unsigned int time_resolution; + unsigned int ac_prediction; + unsigned int hec_interval; + unsigned int data_partition; + unsigned int short_header; + unsigned int rvlc_enable; +}; + +struct venc_h263_config { + unsigned int profile; + unsigned int level; +}; + +struct venc_h264_config { + unsigned int profile; + unsigned int level; + unsigned int max_nal; + unsigned int idr_period; +}; + +struct venc_pmem { + int src; int fd; - unsigned long offset; - unsigned long size; + unsigned int offset; + void *virt; + void *phys; + unsigned int size; }; -struct q6_init_config { - unsigned short venc_standard; - unsigned short partial_run_length_flag; - unsigned short h263_annex_ispt; - unsigned short h263_annex_jspt; - unsigned short h263_annex_tspt; - unsigned short rc_flag; - unsigned short one_mv_flag; - unsigned short acdc_pred_enable; - unsigned short rounding_bit_ctrl; - unsigned short rotation_flag; - unsigned short max_mvx; - unsigned short max_mvy; - unsigned short enc_frame_height_inmb; - unsigned short enc_frame_width_inmb; - unsigned short dvs_frame_height; - unsigned short dvs_frame_width; +struct venc_buffer { + unsigned char *ptr_buffer; + unsigned int size; + unsigned int len; + unsigned int offset; + long long time_stamp; + unsigned int flags; + unsigned int client_data; - /* unused by userspace, filled in by kernel */ - unsigned int ref_frame_buf1_phy; - unsigned int ref_frame_buf2_phy; - unsigned int rlc_buf1_phy; - unsigned int rlc_buf2_phy; - unsigned int rlc_buf_length; }; -struct init_config { - struct venc_buf ref_frame_buf1; - struct venc_buf ref_frame_buf2; - struct venc_buf rlc_buf1; - struct venc_buf rlc_buf2; - struct q6_init_config q6_init_config; +struct venc_buffers { + struct venc_pmem recon_buf[VENC_MAX_RECON_BUFFERS]; + struct venc_pmem wb_buf; + struct venc_pmem cmd_buf; + struct venc_pmem vlc_buf; }; -struct q6_encode_param { - unsigned int luma_addr; - unsigned int chroma_addr; - unsigned int x_offset; - unsigned int y_offset; - unsigned int frame_rho_budget; - unsigned int frame_type; - unsigned int qp; +struct venc_buffer_flush { + unsigned int flush_mode; }; -struct encode_param { - struct venc_buf y_addr; - unsigned long uv_offset; - struct q6_encode_param q6_encode_param; +union venc_msg_data { + struct venc_buffer buf; + struct venc_buffer_flush flush_ret; + }; -struct intra_refresh { - unsigned int intra_refresh_enable; - unsigned int intra_mb_num; +struct venc_msg { + unsigned int status_code; + unsigned int msg_code; + union venc_msg_data msg_data; + unsigned int msg_data_size; }; -struct rc_config { - unsigned short max_frame_qp_up_delta; - unsigned short max_frame_qp_down_delta; - unsigned short min_frame_qp; - unsigned short max_frame_qp; +union venc_codec_config { + struct venc_mpeg4_config mpeg4_params; + struct venc_h263_config h263_params; + struct venc_h264_config h264_params; }; -struct q6_frame_type { - unsigned int frame_type; - unsigned int frame_len; - unsigned int frame_addr; - unsigned int map_table; +struct venc_q6_config { + struct venc_common_config config_params; + union venc_codec_config codec_params; + struct venc_nonio_buf_config buf_params; + void *callback_event; }; -struct frame_type { - struct venc_buf frame_addr; - struct q6_frame_type q6_frame_type; +struct venc_hdr_config { + struct venc_common_config config_params; + union venc_codec_config codec_params; +}; + +struct venc_init_config { + struct venc_q6_config q6_config; + struct venc_buffers q6_bufs; +}; + +struct venc_seq_config { + int size; + struct venc_pmem buf; + struct venc_q6_config q6_config; +}; + +struct venc_version { + u32 major; + u32 minor; }; #define VENC_IOCTL_MAGIC 'V' -#define VENC_IOCTL_INITIALIZE _IOW(VENC_IOCTL_MAGIC, 1, struct init_config) -#define VENC_IOCTL_ENCODE _IOW(VENC_IOCTL_MAGIC, 2, struct encode_param) -#define VENC_IOCTL_INTRA_REFRESH _IOW(VENC_IOCTL_MAGIC, 3, struct intra_refresh) -#define VENC_IOCTL_RC_CONFIG _IOW(VENC_IOCTL_MAGIC, 4, struct rc_config) -#define VENC_IOCTL_ENCODE_CONFIG _IOW(VENC_IOCTL_MAGIC, 5, struct init_config) -#define VENC_IOCTL_STOP _IO(VENC_IOCTL_MAGIC, 6) -#define VENC_IOCTL_WAIT_FOR_ENCODE _IOR(VENC_IOCTL_MAGIC, 7, struct frame_type) -#define VENC_IOCTL_STOP_ENCODE _IO(VENC_IOCTL_MAGIC, 8) +#define VENC_IOCTL_CMD_READ_NEXT_MSG \ + _IOWR(VENC_IOCTL_MAGIC, 1, struct venc_msg) -#endif /* _MSM_VENC_H_ */ +#define VENC_IOCTL_CMD_STOP_READ_MSG _IO(VENC_IOCTL_MAGIC, 2) + +#define VENC_IOCTL_SET_INPUT_BUFFER \ + _IOW(VENC_IOCTL_MAGIC, 3, struct venc_pmem) + +#define VENC_IOCTL_SET_OUTPUT_BUFFER \ + _IOW(VENC_IOCTL_MAGIC, 4, struct venc_pmem) + +#define VENC_IOCTL_CMD_START _IOW(VENC_IOCTL_MAGIC, 5, struct venc_init_config) + +#define VENC_IOCTL_CMD_ENCODE_FRAME \ + _IOW(VENC_IOCTL_MAGIC, 6, struct venc_buffer) + +#define VENC_IOCTL_CMD_FILL_OUTPUT_BUFFER \ + _IOW(VENC_IOCTL_MAGIC, 7, struct venc_buffer) + +#define VENC_IOCTL_CMD_FLUSH \ + _IOW(VENC_IOCTL_MAGIC, 8, struct venc_buffer_flush) + +#define VENC_IOCTL_CMD_PAUSE _IO(VENC_IOCTL_MAGIC, 9) + +#define VENC_IOCTL_CMD_RESUME _IO(VENC_IOCTL_MAGIC, 10) + +#define VENC_IOCTL_CMD_STOP _IO(VENC_IOCTL_MAGIC, 11) + +#define VENC_IOCTL_SET_INTRA_PERIOD \ + _IOW(VENC_IOCTL_MAGIC, 12, int) + +#define VENC_IOCTL_CMD_REQUEST_IFRAME _IO(VENC_IOCTL_MAGIC, 13) + +#define VENC_IOCTL_GET_SEQUENCE_HDR \ + _IOWR(VENC_IOCTL_MAGIC, 14, struct venc_seq_config) + +#define VENC_IOCTL_SET_INTRA_REFRESH \ + _IOW(VENC_IOCTL_MAGIC, 15, int) + +#define VENC_IOCTL_SET_FRAME_RATE \ + _IOW(VENC_IOCTL_MAGIC, 16, struct venc_frame_rate) + +#define VENC_IOCTL_SET_TARGET_BITRATE \ + _IOW(VENC_IOCTL_MAGIC, 17, int) + +#define VENC_IOCTL_SET_QP_RANGE \ + _IOW(VENC_IOCTL_MAGIC, 18, struct venc_qp_range) + +#define VENC_IOCTL_GET_VERSION \ + _IOR(VENC_IOCTL_MAGIC, 19, struct venc_version) + +#endif