M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@ -0,0 +1,12 @@
obj-y += q6audio.o
obj-y += aac_in.o
obj-y += voice.o
obj-y += pcm_out.o
obj-y += pcm_in.o
obj-y += mp3.o
obj-y += audio_ctl.o
obj-y += analog_audio.o
obj-y += routing.o
obj-y += evrc_in.o
obj-y += qcelp_in.o
obj-y += amrnb_in.o

View File

@ -0,0 +1,266 @@
/*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation
* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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 <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/msm_audio_aac.h>
#include <mach/msm_qdsp6_audiov2.h>
#include "dal_audio.h"
#include "dal_audio_format.h"
struct aac {
struct mutex lock;
struct msm_audio_aac_enc_config cfg;
struct msm_audio_stream_config str_cfg;
struct audio_client *audio_client;
};
static long q6_aac_in_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct aac *aac = file->private_data;
struct adsp_open_command rpc;
int sample_rate;
int audio_object_type;
int index = sizeof(u32);
int rc = 0;
u32 *aac_type = NULL;
mutex_lock(&aac->lock);
switch (cmd) {
case AUDIO_START:
if (aac->audio_client) {
rc = -EBUSY;
break;
} else {
tx_clk_freq = 48000;
aac->audio_client = q6audio_open(AUDIO_FLAG_READ,
aac->str_cfg.buffer_size);
if (aac->audio_client < 0) {
tx_clk_freq = 8000;
rc = -ENOMEM;
break;
}
}
memset(&rpc, 0, sizeof(rpc));
rpc.format_block.binary.format = ADSP_AUDIO_FORMAT_MPEG4_AAC;
/* only 48k sample rate is supported */
sample_rate = 3;
/* AAC OBJECT LC */
audio_object_type = 2;
aac_type = (u32 *)rpc.format_block.binary.data;
switch (aac->cfg.stream_format) {
case AUDIO_AAC_FORMAT_ADTS:
/* AAC Encoder expect MPEG4_ADTS media type */
*aac_type = ADSP_AUDIO_AAC_MPEG4_ADTS;
break;
case AUDIO_AAC_FORMAT_RAW:
/* for ADIF recording */
*aac_type = ADSP_AUDIO_AAC_RAW;
break;
}
rpc.format_block.binary.data[index++] = (u8)(
((audio_object_type & 0x1F) << 3) |
((sample_rate >> 1) & 0x7));
rpc.format_block.binary.data[index] = (u8)(
((sample_rate & 0x1) << 7) |
((aac->cfg.channels & 0x7) << 3));
rpc.format_block.binary.num_bytes = index + 1;
rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
rpc.buf_max_size = aac->str_cfg.buffer_size;
rpc.config.aac.bit_rate = aac->cfg.bit_rate;
rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE;
q6audio_start(aac->audio_client, &rpc, sizeof(rpc));
break;
case AUDIO_STOP:
break;
case AUDIO_FLUSH:
break;
case AUDIO_SET_VOLUME:
break;
case AUDIO_GET_STREAM_CONFIG:
if (copy_to_user((void *)arg, &aac->str_cfg,
sizeof(struct msm_audio_stream_config)))
rc = -EFAULT;
break;
case AUDIO_SET_STREAM_CONFIG:
if (copy_from_user(&aac->str_cfg, (void *)arg,
sizeof(struct msm_audio_stream_config))) {
rc = -EFAULT;
break;
}
if (aac->str_cfg.buffer_size < 519) {
pr_err("Buffer size too small\n");
rc = -EINVAL;
break;
}
if (aac->str_cfg.buffer_count != 2)
pr_info("Buffer count set to 2\n");
break;
case AUDIO_SET_AAC_ENC_CONFIG:
if (copy_from_user(&aac->cfg, (void *) arg,
sizeof(struct msm_audio_aac_enc_config))) {
rc = -EFAULT;
}
if (aac->cfg.channels != 1) {
pr_err("only mono is supported\n");
rc = -EINVAL;
}
if (aac->cfg.sample_rate != 48000) {
pr_err("only 48KHz is supported\n");
rc = -EINVAL;
}
if (aac->cfg.stream_format != AUDIO_AAC_FORMAT_RAW &&
aac->cfg.stream_format != AUDIO_AAC_FORMAT_ADTS) {
pr_err("unsupported AAC format\n");
rc = -EINVAL;
}
break;
case AUDIO_GET_AAC_ENC_CONFIG:
if (copy_to_user((void *) arg, &aac->cfg,
sizeof(struct msm_audio_aac_enc_config))) {
rc = -EFAULT;
}
break;
default:
rc = -EINVAL;
}
mutex_unlock(&aac->lock);
return rc;
}
static int q6_aac_in_open(struct inode *inode, struct file *file)
{
struct aac *aac;
aac = kmalloc(sizeof(struct aac), GFP_KERNEL);
if (aac == NULL) {
pr_err("Could not allocate memory for aac driver\n");
return -ENOMEM;
}
mutex_init(&aac->lock);
file->private_data = aac;
aac->audio_client = NULL;
aac->str_cfg.buffer_size = 519;
aac->str_cfg.buffer_count = 2;
aac->cfg.channels = 1;
aac->cfg.bit_rate = 192000;
aac->cfg.stream_format = AUDIO_AAC_FORMAT_ADTS;
aac->cfg.sample_rate = 48000;
return 0;
}
static ssize_t q6_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;
struct aac *aac = file->private_data;
int xfer = 0;
int res;
mutex_lock(&aac->lock);
ac = aac->audio_client;
if (!ac) {
res = -ENODEV;
goto fail;
}
while (count > xfer) {
ab = ac->buf + ac->cpu_buf;
if (ab->used)
wait_event(ac->wait, (ab->used == 0));
xfer = ab->actual_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;
}
res = buf - start;
fail:
mutex_unlock(&aac->lock);
return res;
}
static int q6_aac_in_release(struct inode *inode, struct file *file)
{
int rc = 0;
struct aac *aac = file->private_data;
mutex_lock(&aac->lock);
if (aac->audio_client)
rc = q6audio_close(aac->audio_client);
mutex_unlock(&aac->lock);
kfree(aac);
tx_clk_freq = 8000;
return rc;
}
static const struct file_operations q6_aac_in_fops = {
.owner = THIS_MODULE,
.open = q6_aac_in_open,
.read = q6_aac_in_read,
.release = q6_aac_in_release,
.unlocked_ioctl = q6_aac_in_ioctl,
};
struct miscdevice q6_aac_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_aac_in",
.fops = &q6_aac_in_fops,
};
static int __init q6_aac_in_init(void)
{
return misc_register(&q6_aac_in_misc);
}
device_initcall(q6_aac_in_init);

View File

@ -0,0 +1,237 @@
/*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation
* Copyright (c) 2010, The Linux Foundation. All rights reserved.
*
* 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 <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/msm_audio_amrnb.h>
#include <mach/msm_qdsp6_audiov2.h>
#include "dal_audio.h"
#include "dal_audio_format.h"
#include <mach/debug_mm.h>
struct amrnb {
struct mutex lock;
struct msm_audio_amrnb_enc_config_v2 cfg;
struct msm_audio_stream_config str_cfg;
struct audio_client *audio_client;
};
static long q6_amrnb_in_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct amrnb *amrnb = file->private_data;
struct adsp_open_command rpc;
int rc = 0;
if (cmd == 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;
}
mutex_lock(&amrnb->lock);
switch (cmd) {
case AUDIO_START:
if (amrnb->audio_client) {
rc = -EBUSY;
break;
} else {
amrnb->audio_client = q6audio_open(AUDIO_FLAG_READ,
amrnb->str_cfg.buffer_size);
if (!amrnb->audio_client) {
kfree(amrnb);
rc = -ENOMEM;
break;
}
}
tx_clk_freq = 8000;
memset(&rpc, 0, sizeof(rpc));
rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_AMRNB_FS;
rpc.format_block.standard.channels = 1;
rpc.format_block.standard.bits_per_sample = 16;
rpc.format_block.standard.sampling_rate = 8000;
rpc.format_block.standard.is_signed = 1;
rpc.format_block.standard.is_interleaved = 0;
rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
rpc.buf_max_size = amrnb->str_cfg.buffer_size;
rpc.config.amr.mode = amrnb->cfg.band_mode;
rpc.config.amr.dtx_mode = amrnb->cfg.dtx_enable;
rpc.config.amr.enable = 1;
q6audio_start(amrnb->audio_client, &rpc, sizeof(rpc));
break;
case AUDIO_STOP:
break;
case AUDIO_FLUSH:
break;
case AUDIO_SET_VOLUME:
break;
case AUDIO_GET_STREAM_CONFIG:
if (copy_to_user((void *)arg, &amrnb->str_cfg,
sizeof(struct msm_audio_stream_config)))
rc = -EFAULT;
break;
case AUDIO_SET_STREAM_CONFIG:
if (copy_from_user(&amrnb->str_cfg, (void *)arg,
sizeof(struct msm_audio_stream_config))) {
rc = -EFAULT;
break;
}
if (amrnb->str_cfg.buffer_size < 768) {
pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
__func__);
rc = -EINVAL;
break;
}
if (amrnb->str_cfg.buffer_count != 2)
pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
__func__);
break;
case AUDIO_SET_AMRNB_ENC_CONFIG:
if (copy_from_user(&amrnb->cfg, (void *) arg,
sizeof(struct msm_audio_amrnb_enc_config_v2)))
rc = -EFAULT;
break;
case AUDIO_GET_AMRNB_ENC_CONFIG:
if (copy_to_user((void *) arg, &amrnb->cfg,
sizeof(struct msm_audio_amrnb_enc_config_v2)))
rc = -EFAULT;
break;
default:
rc = -EINVAL;
}
mutex_unlock(&amrnb->lock);
return rc;
}
static int q6_amrnb_in_open(struct inode *inode, struct file *file)
{
struct amrnb *amrnb;
amrnb = kmalloc(sizeof(struct amrnb), GFP_KERNEL);
if (amrnb == NULL) {
pr_err("[%s:%s] Could not allocate memory for amrnb driver\n",
__MM_FILE__, __func__);
return -ENOMEM;
}
mutex_init(&amrnb->lock);
file->private_data = amrnb;
amrnb->audio_client = NULL;
amrnb->str_cfg.buffer_size = 768;
amrnb->str_cfg.buffer_count = 2;
amrnb->cfg.band_mode = ADSP_AUDIO_AMR_MR475;
amrnb->cfg.dtx_enable = ADSP_AUDIO_AMR_DTX_MODE_ON_AUTO;
amrnb->cfg.frame_format = ADSP_AUDIO_FORMAT_AMRNB_FS;
return 0;
}
static ssize_t q6_amrnb_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;
struct amrnb *amrnb = file->private_data;
int xfer = 0;
int res;
mutex_lock(&amrnb->lock);
ac = amrnb->audio_client;
if (!ac) {
res = -ENODEV;
goto fail;
}
while (count > xfer) {
ab = ac->buf + ac->cpu_buf;
if (ab->used)
wait_event(ac->wait, (ab->used == 0));
xfer = ab->actual_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;
}
res = buf - start;
fail:
mutex_unlock(&amrnb->lock);
return res;
}
static int q6_amrnb_in_release(struct inode *inode, struct file *file)
{
int rc = 0;
struct amrnb *amrnb = file->private_data;
mutex_lock(&amrnb->lock);
if (amrnb->audio_client)
rc = q6audio_close(amrnb->audio_client);
mutex_unlock(&amrnb->lock);
kfree(amrnb);
return rc;
}
static const struct file_operations q6_amrnb_in_fops = {
.owner = THIS_MODULE,
.open = q6_amrnb_in_open,
.read = q6_amrnb_in_read,
.release = q6_amrnb_in_release,
.unlocked_ioctl = q6_amrnb_in_ioctl,
};
struct miscdevice q6_amrnb_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_amr_in",
.fops = &q6_amrnb_in_fops,
};
static int __init q6_amrnb_in_init(void)
{
return misc_register(&q6_amrnb_in_misc);
}
device_initcall(q6_amrnb_in_init);

View File

@ -0,0 +1,85 @@
/* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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 <linux/gpio.h>
#include <mach/pmic.h>
#include <mach/msm_qdsp6_audiov2.h>
#define GPIO_HEADSET_AMP 157
void analog_init(void)
{
/* stereo pmic init */
pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB);
pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB);
pmic_mic_set_volt(MIC_VOLT_1_80V);
gpio_direction_output(GPIO_HEADSET_AMP, 1);
gpio_set_value(GPIO_HEADSET_AMP, 0);
}
void analog_headset_enable(int en)
{
/* enable audio amp */
gpio_set_value(GPIO_HEADSET_AMP, !!en);
}
void analog_speaker_enable(int en)
{
struct spkr_config_mode scm;
memset(&scm, 0, sizeof(scm));
if (en) {
scm.is_right_chan_en = 1;
scm.is_left_chan_en = 1;
scm.is_stereo_en = 1;
scm.is_hpf_en = 1;
pmic_spkr_en_mute(LEFT_SPKR, 0);
pmic_spkr_en_mute(RIGHT_SPKR, 0);
pmic_set_spkr_configuration(&scm);
pmic_spkr_en(LEFT_SPKR, 1);
pmic_spkr_en(RIGHT_SPKR, 1);
/* unmute */
pmic_spkr_en_mute(LEFT_SPKR, 1);
pmic_spkr_en_mute(RIGHT_SPKR, 1);
} else {
pmic_spkr_en_mute(LEFT_SPKR, 0);
pmic_spkr_en_mute(RIGHT_SPKR, 0);
pmic_spkr_en(LEFT_SPKR, 0);
pmic_spkr_en(RIGHT_SPKR, 0);
pmic_set_spkr_configuration(&scm);
}
}
void analog_mic_enable(int en)
{
pmic_mic_en(en);
}
static struct q6audio_analog_ops ops = {
.init = analog_init,
.speaker_enable = analog_speaker_enable,
.headset_enable = analog_headset_enable,
.int_mic_enable = analog_mic_enable,
};
static int __init init(void)
{
q6audio_register_analog_ops(&ops);
return 0;
}
device_initcall(init);

View File

@ -0,0 +1,140 @@
/* arch/arm/mach-msm/qdsp6/audiov2/audio_ctrl.c
*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation
* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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 <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/msm_audio.h>
#include <mach/msm_qdsp6_audiov2.h>
#define BUFSZ (0)
static DEFINE_MUTEX(voice_lock);
static int voice_started;
static struct audio_client *voc_clnt;
static int q6_voice_start(void)
{
int rc = 0;
mutex_lock(&voice_lock);
if (voice_started) {
pr_err("voice: busy\n");
rc = -EBUSY;
goto done;
}
voc_clnt = q6voice_open();
if (!voc_clnt) {
pr_err("voice: open voice failed.\n");
rc = -ENOMEM;
goto done;
}
voice_started = 1;
done:
mutex_unlock(&voice_lock);
return rc;
}
static int q6_voice_stop(void)
{
mutex_lock(&voice_lock);
if (voice_started) {
q6voice_close(voc_clnt);
voice_started = 0;
}
mutex_unlock(&voice_lock);
return 0;
}
static int q6_open(struct inode *inode, struct file *file)
{
return 0;
}
static int q6_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int rc;
uint32_t n;
uint32_t id[2];
switch (cmd) {
case AUDIO_SWITCH_DEVICE:
rc = copy_from_user(&n, (void *)arg, sizeof(n));
if (!rc)
rc = q6audio_do_routing(n);
break;
case AUDIO_SET_VOLUME:
rc = copy_from_user(&n, (void *)arg, sizeof(n));
if (!rc)
rc = q6audio_set_rx_volume(n);
break;
case AUDIO_SET_MUTE:
rc = copy_from_user(&n, (void *)arg, sizeof(n));
if (!rc)
rc = q6audio_set_tx_mute(n);
break;
case AUDIO_UPDATE_ACDB:
rc = copy_from_user(&id, (void *)arg, sizeof(id));
if (!rc)
rc = q6audio_update_acdb(id[0], id[1]);
break;
case AUDIO_START_VOICE:
rc = q6_voice_start();
break;
case AUDIO_STOP_VOICE:
rc = q6_voice_stop();
break;
default:
rc = -EINVAL;
}
return rc;
}
static int q6_release(struct inode *inode, struct file *file)
{
return 0;
}
static const struct file_operations q6_dev_fops = {
.owner = THIS_MODULE,
.open = q6_open,
.ioctl = q6_ioctl,
.release = q6_release,
};
struct miscdevice q6_control_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_audio_ctl",
.fops = &q6_dev_fops,
};
static int __init q6_audio_ctl_init(void)
{
return misc_register(&q6_control_device);
}
device_initcall(q6_audio_ctl_init);

View File

@ -0,0 +1,71 @@
/* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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.
*
*/
#define ACDB_DAL_DEVICE 0x02000069
#define ACDB_DAL_PORT "DAL_AM_AUD"
#define ACDB_DAL_VERSION 0x00010000
#define ACDB_OP_IOCTL DAL_OP_FIRST_DEVICE_API
/* ioctls */
#define ACDB_GET_DEVICE 0x0108bb92
#define ACDB_SET_DEVICE 0x0108bb93
#define ACDB_GET_STREAM 0x0108bb95
#define ACDB_SET_STREAM 0x0108bb96
#define ACDB_GET_DEVICE_TABLE 0x0108bb97
#define ACDB_GET_STREAM_TABLE 0x0108bb98
#define ACDB_RES_SUCCESS 0
#define ACDB_RES_FAILURE -1
#define ACDB_RES_BADPARM -2
#define ACDB_RES_BADSTATE -3
struct acdb_cmd_device {
uint32_t size;
uint32_t command_id;
uint32_t device_id;
uint32_t network_id;
uint32_t sample_rate_id;
uint32_t interface_id;
uint32_t algorithm_block_id;
/* physical page aligned buffer */
uint32_t total_bytes;
uint32_t unmapped_buf;
} __attribute__((packed));
struct acdb_cmd_device_table {
uint32_t size;
uint32_t command_id;
uint32_t device_id;
uint32_t network_id;
uint32_t sample_rate_id;
/* physical page aligned buffer */
uint32_t total_bytes;
uint32_t unmapped_buf;
uint32_t res_size;
} __attribute__((packed));
struct acdb_result {
uint32_t dal_status;
uint32_t size;
uint32_t total_devices;
uint32_t unmapped_buf;
uint32_t used_bytes;
uint32_t result;
} __attribute__((packed));

View File

@ -0,0 +1,89 @@
/* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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.
*
*/
#ifndef _MACH_MSM_QDSP6_ADIE_
#define _MACH_MSM_QDSP6_ADIE_
#include "../dal.h"
#define ADIE_DAL_DEVICE 0x02000029
#define ADIE_DAL_PORT "DAL_AM_AUD"
#define ADIE_DAL_VERSION 0x00010000
enum {
ADIE_OP_SET_PATH = DAL_OP_FIRST_DEVICE_API,
ADIE_OP_PROCEED_TO_STAGE,
ADIE_OP_IOCTL
};
/* Path IDs for normal operation. */
#define ADIE_PATH_HANDSET_TX 0x010740f6
#define ADIE_PATH_HANDSET_RX 0x010740f7
#define ADIE_PATH_HEADSET_MONO_TX 0x010740f8
#define ADIE_PATH_HEADSET_STEREO_TX 0x010740f9
#define ADIE_PATH_HEADSET_MONO_RX 0x010740fa
#define ADIE_PATH_HEADSET_STEREO_RX 0x010740fb
#define ADIE_PATH_SPEAKER_TX 0x010740fc
#define ADIE_PATH_SPEAKER_RX 0x010740fd
#define ADIE_PATH_SPEAKER_STEREO_RX 0x01074101
/* Path IDs used for TTY */
#define ADIE_PATH_TTY_HEADSET_TX 0x010740fe
#define ADIE_PATH_TTY_HEADSET_RX 0x010740ff
/* Path IDs used by Factory Test Mode. */
#define ADIE_PATH_FTM_MIC1_TX 0x01074108
#define ADIE_PATH_FTM_MIC2_TX 0x01074107
#define ADIE_PATH_FTM_HPH_L_RX 0x01074106
#define ADIE_PATH_FTM_HPH_R_RX 0x01074104
#define ADIE_PATH_FTM_EAR_RX 0x01074103
#define ADIE_PATH_FTM_SPKR_RX 0x01074102
/* Path IDs for Loopback */
/* Path IDs used for Line in -> AuxPGA -> Line Out Stereo Mode*/
#define ADIE_PATH_AUXPGA_LINEOUT_STEREO_LB 0x01074100
/* Line in -> AuxPGA -> LineOut Mono */
#define ADIE_PATH_AUXPGA_LINEOUT_MONO_LB 0x01073d82
/* Line in -> AuxPGA -> Stereo Headphone */
#define ADIE_PATH_AUXPGA_HDPH_STEREO_LB 0x01074109
/* Line in -> AuxPGA -> Mono Headphone */
#define ADIE_PATH_AUXPGA_HDPH_MONO_LB 0x01073d85
/* Line in -> AuxPGA -> Earpiece */
#define ADIE_PATH_AUXPGA_EAP_LB 0x01073d81
/* Line in -> AuxPGA -> AuxOut */
#define ADIE_PATH_AUXPGA_AUXOUT_LB 0x01073d86
/* Concurrency Profiles */
#define ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX 0x01073d83
#define ADIE_PATH_SPKR_MONO_HDPH_MONO_RX 0x01073d84
#define ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX 0x01073d88
#define ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX 0x01073d89
/* stages */
#define ADIE_STAGE_PATH_OFF 0x0050
#define ADIE_STAGE_DIGITAL_READY 0x0100
#define ADIE_STAGE_DIGITAL_ANALOG_READY 0x1000
#define ADIE_STAGE_ANALOG_OFF 0x0750
#define ADIE_STAGE_DIGITAL_OFF 0x0600
/* path types */
#define ADIE_PATH_RX 0
#define ADIE_PATH_TX 1
#define ADIE_PATH_LOOPBACK 2
/* mute states */
#define ADIE_MUTE_OFF 0
#define ADIE_MUTE_ON 1
#endif

View File

@ -0,0 +1,546 @@
/* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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.
*
*/
#ifndef __DAL_AUDIO_H__
#define __DAL_AUDIO_H__
#include "../dal.h"
#include "dal_audio_format.h"
#define AUDIO_DAL_DEVICE 0x02000028
#define AUDIO_DAL_PORT "DAL_AQ_AUD"
#define AUDIO_DAL_VERSION 0x00030001
enum {
AUDIO_OP_CONTROL = DAL_OP_FIRST_DEVICE_API,
AUDIO_OP_DATA,
AUDIO_OP_INIT,
};
/* ---- common audio structures ---- */
/* This flag, if set, indicates that the beginning of the data in the*/
/* 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
/* 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
/* This flag, if set, indicates that a media start timestamp has been */
/* set for a buffer. */
#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
/* This flag, if set, indicates that a preroll timestamp has been set */
/* for a buffer. */
#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
struct adsp_audio_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 */
s64 preroll; /* Preroll timestamp, if any */
} __attribute__ ((packed));
/* ---- audio commands ---- */
/* Command/event response types */
#define ADSP_AUDIO_RESPONSE_COMMAND 0
#define ADSP_AUDIO_RESPONSE_ASYNC 1
struct adsp_command_hdr {
u32 size; /* sizeof(cmd) - sizeof(u32) */
u32 dest;
u32 src;
u32 opcode;
u32 response_type;
u32 seq_number;
u32 context; /* opaque to DSP */
u32 data;
u32 padding;
} __attribute__ ((packed));
#define DOMAIN_APP 0
#define DOMAIN_MODEM 1
#define DOMAIN_DSP 2
/* adsp audio addresses are (byte order) major, minor, domain */
#define AUDIO_ADDR(dmn, maj, min) (((maj & 0xff) << 16) \
| ((min & 0xff) << 24) | (dmn & 0xff))
/* AAC Encoder modes */
#define ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE 0
#define ADSP_AUDIO_ENC_AAC_PLUS_MODE 1
#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_* */
} __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_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;
u32 block_len;
u32 channel_mode;
u32 allocation_method;
u32 bit_rate;
} __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
/* 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
/* 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 */
} __attribute__ ((packed));
struct adsp_audio_qcelp13k_enc_cfg {
u16 min_rate;
u16 max_rate;
} __attribute__ ((packed));
struct adsp_audio_evrc_enc_cfg {
u16 min_rate;
u16 max_rate;
} __attribute__ ((packed));
union adsp_audio_codec_config {
struct adsp_audio_amr_enc_cfg amr;
struct adsp_audio_aac_enc_cfg aac;
struct adsp_audio_qcelp13k_enc_cfg qcelp13k;
struct adsp_audio_evrc_enc_cfg evrc;
struct adsp_audio_sbc_encoder_cfg sbc;
} __attribute__ ((packed));
/* This is the default value. */
#define ADSP_AUDIO_OPEN_STREAM_MODE_NONE 0x0000
/* This bit, if set, indicates that the AVSync mode is activated. */
#define ADSP_AUDIO_OPEN_STREAM_MODE_AVSYNC 0x0001
/* This bit, if set, indicates that the Sample Rate/Channel Mode */
/* Change Notification mode is activated. */
#define ADSP_AUDIO_OPEN_STREAM_MODE_SR_CM_NOTIFY 0x0002
#define ADSP_AUDIO_OPEN_STREAM_MODE_ENABLE_SYNC_CLOCK 0x0004
#define ADSP_AUDIO_MAX_DEVICES 1
struct adsp_open_command {
struct adsp_command_hdr hdr;
u32 device;
u32 end_point;
u32 stream_context;
u32 mode;
u32 buf_max_size;
union adsp_audio_format format_block;
union adsp_audio_codec_config config;
} __attribute__ ((packed));
/* --- audio control and stream session ioctls ---- */
/* 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
/* A device switch requires three IOCTL */
/* commands in the following sequence: PREPARE, STANDBY, COMMIT */
/* adsp_audio_device_switch_command structure is needed for */
/* DEVICE_SWITCH_PREPARE */
/* Device switch protocol step #1. Pause old device and */
/* generate silence for the old device. */
#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE 0x010815c4
/* Device switch protocol step #2. Release old device, */
/* create new device and generate silence for the new device. */
/* When client receives ack for this IOCTL, the client can */
/* start sending IOCTL commands to configure, calibrate and */
/* change filter settings on the new device. */
#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY 0x010815c5
/* Device switch protocol step #3. Start normal operations on new device */
#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT 0x01075ee7
struct adsp_device_switch_command {
struct adsp_command_hdr hdr;
u32 old_device;
u32 new_device;
u8 device_class; /* 0 = i.rx, 1 = i.tx, 2 = e.rx, 3 = e.tx */
u8 device_type; /* 0 = rx, 1 = tx, 2 = both */
} __attribute__ ((packed));
/* --- audio control session ioctls ---- */
#define ADSP_PATH_RX 0
#define ADSP_PATH_TX 1
#define ADSP_PATH_BOTH 2
/* These commands will affect a logical device and all its associated */
/* streams. */
/* Set device volume. */
#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL 0x0107605c
struct adsp_set_dev_volume_command {
struct adsp_command_hdr hdr;
u32 device_id;
u32 path; /* 0 = rx, 1 = tx, 2 = both */
s32 volume;
} __attribute__ ((packed));
/* Set Device stereo volume. This command has data payload, */
/* struct adsp_audio_set_dev_stereo_volume_command. */
#define ADSP_AUDIO_IOCTL_SET_DEVICE_STEREO_VOL 0x0108df3e
/* Set L, R cross channel gain for a Device. This command has */
/* data payload, struct adsp_audio_set_dev_x_chan_gain_command. */
#define ADSP_AUDIO_IOCTL_SET_DEVICE_XCHAN_GAIN 0x0108df40
/* Set device mute state. */
#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE 0x0107605f
struct adsp_set_dev_mute_command {
struct adsp_command_hdr hdr;
u32 device_id;
u32 path; /* 0 = rx, 1 = tx, 2 = both */
u32 mute; /* 1 = mute */
} __attribute__ ((packed));
/* Configure Equalizer for a device. */
/* This command has payload struct adsp_audio_set_dev_equalizer_command. */
#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_EQ_CONFIG 0x0108b10e
/* Set configuration data for an algorithm aspect of a device. */
/* This command has payload struct adsp_audio_set_dev_cfg_command. */
#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG 0x0108b6cb
struct adsp_set_dev_cfg_command {
struct adsp_command_hdr hdr;
u32 device_id;
u32 block_id;
u32 interface_id;
u32 phys_addr;
u32 phys_size;
u32 phys_used;
} __attribute__ ((packed));
/* Set configuration data for all interfaces of a device. */
#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE 0x0108b6bf
struct adsp_set_dev_cfg_table_command {
struct adsp_command_hdr hdr;
u32 device_id;
u32 phys_addr;
u32 phys_size;
u32 phys_used;
} __attribute__ ((packed));
/* ---- audio stream data commands ---- */
#define ADSP_AUDIO_IOCTL_CMD_DATA_TX 0x0108dd7f
#define ADSP_AUDIO_IOCTL_CMD_DATA_RX 0x0108dd80
struct adsp_buffer_command {
struct adsp_command_hdr hdr;
struct adsp_audio_buffer buffer;
} __attribute__ ((packed));
/* ---- audio stream ioctls (only affect a single stream in a session) ---- */
/* Stop stream for audio device. */
#define ADSP_AUDIO_IOCTL_CMD_STREAM_STOP 0x01075c54
/* End of stream reached. Client will not send any more data. */
#define ADSP_AUDIO_IOCTL_CMD_STREAM_EOS 0x0108b150
/* 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
/* 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 payload, */
/* struct adsp_audio_set_stereo_volume_command. */
#define ADSP_AUDIO_IOCTL_SET_STREAM_STEREO_VOL 0x0108dd7c
/* Set L, R cross channel gain for a Stream. This command has */
/* data payload, struct adsp_audio_set_x_chan_gain_command. */
#define ADSP_AUDIO_IOCTL_SET_STREAM_XCHAN_GAIN 0x0108dd7d
/* Set stream mute state. */
/* This command has data payload, struct adsp_audio_set_stream_mute. */
#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE 0x0108c0df
/* Reconfigure bit rate information. This command has data */
/* payload, struct adsp_audio_set_bit_rate_command */
#define ADSP_AUDIO_IOCTL_SET_STREAM_BITRATE 0x0108ccf1
/* Set Channel Mapping. This command has data payload, struct */
/* This command has data payload struct adsp_audio_set_channel_map_command. */
#define ADSP_AUDIO_IOCTL_SET_STREAM_CHANNELMAP 0x0108d32a
/* Enable/disable AACPlus SBR. */
/* This command has data payload struct adsp_audio_set_sbr_command */
#define ADSP_AUDIO_IOCTL_SET_STREAM_SBR 0x0108d416
/* Enable/disable WMA Pro Chex and Fex. This command has data payload */
/* struct adsp_audio_stream_set_wma_command. */
#define ADSP_AUDIO_IOCTL_SET_STREAM_WMAPRO 0x0108d417
/* ---- audio session ioctls (affect all streams in a session) --- */
/* Start stream for audio device. */
#define ADSP_AUDIO_IOCTL_CMD_SESSION_START 0x010815c6
/* Stop all stream(s) for audio session as indicated by major id. */
#define ADSP_AUDIO_IOCTL_CMD_SESSION_STOP 0x0108dd7e
/* Pause the data flow for a session as indicated by major id. */
#define ADSP_AUDIO_IOCTL_CMD_SESSION_PAUSE 0x01075ee8
/* Resume the data flow for a session as indicated by major id. */
#define ADSP_AUDIO_IOCTL_CMD_SESSION_RESUME 0x01075ee9
/* Drop any unprocessed data buffers for a session as indicated by major id. */
#define ADSP_AUDIO_IOCTL_CMD_SESSION_FLUSH 0x01075eea
/* Start Stream DTMF tone */
#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_START 0x0108c0dd
/* Stop Stream DTMF tone */
#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_STOP 0x01087554
/* Set Session volume. */
/* This command has data payload, struct adsp_audio_set_volume_command. */
#define ADSP_AUDIO_IOCTL_SET_SESSION_VOL 0x0108d8bd
/* 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
/* 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
/* Set Session mute state. */
/* This command has data payload, struct adsp_audio_set_mute_command. */
#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
/* 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
/* Get Audio Media Session time. */
/* This command returns the audioTime in adsp_audio_unsigned64_event */
#define ADSP_AUDIO_IOCTL_CMD_GET_AUDIO_TIME 0x0108c26c
/* these command structures are used for both STREAM and SESSION ioctls */
struct adsp_set_volume_command {
struct adsp_command_hdr hdr;
s32 volume;
} __attribute__ ((packed));
struct adsp_set_mute_command {
struct adsp_command_hdr hdr;
u32 mute; /* 1 == mute */
} __attribute__ ((packed));
/* ---- audio events ---- */
/* All IOCTL commands generate an event with the IOCTL opcode as the */
/* 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
/* This event is generated after a media stream session is closed. */
#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
/* 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
/* 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
/* 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
struct adsp_event_hdr {
u32 evt_handle; /* DAL common header */
u32 evt_cookie;
u32 evt_length;
u32 dest;
u32 src;
u32 event_id;
u32 response_type;
u32 seq_number;
u32 context; /* opaque to DSP */
u32 data;
u32 status;
} __attribute__ ((packed));
struct adsp_buffer_event {
struct adsp_event_hdr hdr;
struct adsp_audio_buffer buffer;
} __attribute__ ((packed));
/* ---- audio device IDs ---- */
/* Device direction Rx/Tx flag */
#define ADSP_AUDIO_RX_DEVICE 0x00
#define ADSP_AUDIO_TX_DEVICE 0x01
#define ADSP_AUDIO_DEVICE_ID_DEFAULT 0x1081679
/* Default RX or TX device */
#define ADSP_AUDIO_DEVICE_ID_HANDSET_MIC 0x107ac8d
#define ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC 0x108f9c3
#define ADSP_AUDIO_DEVICE_ID_HEADSET_MIC 0x1081510
#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC 0x1081512
#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC 0x108f9c5
#define ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC 0x1081518
#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC 0x108151b
#define ADSP_AUDIO_DEVICE_ID_I2S_MIC 0x1089bf3
/* 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
/* 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_STEREO_HEADSET 0x108c894
#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_BT_SCO_SPKR 0x1081519
#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR 0x108151c
#define ADSP_AUDIO_DEVICE_ID_I2S_SPKR 0x1089bf4
#define ADSP_AUDIO_DEVICE_ID_NULL_SINK 0x108e512
/* BT A2DP playback device. */
/* 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
/* Voice Destination identifier - specifically used for */
/* controlling Voice module from the Device Control Session */
#define ADSP_AUDIO_DEVICE_ID_VOICE 0x0108df3c
/* Audio device usage types. */
/* This is a bit mask to determine which topology to use in the */
/* device session */
#define ADSP_AUDIO_DEVICE_CONTEXT_VOICE 0x01
#define ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK 0x02
#define ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD 0x10
#define ADSP_AUDIO_DEVICE_CONTEXT_RECORD 0x20
#define ADSP_AUDIO_DEVICE_CONTEXT_PCM_LOOPBACK 0x40
#endif

View File

@ -0,0 +1,284 @@
/* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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.
*
*/
#ifndef __ADSP_AUDIO_MEDIA_FORMAT_H
#define __ADSP_AUDIO_MEDIA_FORMAT_H
/* Supported audio media formats */
/* format block in shmem */
#define ADSP_AUDIO_FORMAT_SHAREDMEMORY 0x01091a78
/* adsp_audio_format_raw_pcm type */
#define ADSP_AUDIO_FORMAT_PCM 0x0103d2fd
/* adsp_audio_format_raw_pcm type */
#define ADSP_AUDIO_FORMAT_DTMF 0x01087725
/* adsp_audio_format_adpcm type */
#define ADSP_AUDIO_FORMAT_ADPCM 0x0103d2ff
/* Yamaha PCM format */
#define ADSP_AUDIO_FORMAT_YADPCM 0x0108dc07
/* ISO/IEC 11172 */
#define ADSP_AUDIO_FORMAT_MP3 0x0103d308
/* ISO/IEC 14496 */
#define ADSP_AUDIO_FORMAT_MPEG4_AAC 0x010422f1
/* AMR-NB audio in FS format */
#define ADSP_AUDIO_FORMAT_AMRNB_FS 0x0105c16c
/* AMR-WB audio in FS format */
#define ADSP_AUDIO_FORMAT_AMRWB_FS 0x0105c16e
/* QCELP 13k, IS733 */
#define ADSP_AUDIO_FORMAT_V13K_FS 0x01080b8a
/* EVRC 8k, IS127 */
#define ADSP_AUDIO_FORMAT_EVRC_FS 0x01080b89
/* EVRC-B 8k, 4GV */
#define ADSP_AUDIO_FORMAT_EVRCB_FS 0x0108f2a3
/* MIDI command stream */
#define ADSP_AUDIO_FORMAT_MIDI 0x0103d300
/* A2DP SBC stream */
#define ADSP_AUDIO_FORMAT_SBC 0x0108c4d8
/* Version 10 Professional */
#define ADSP_AUDIO_FORMAT_WMA_V10PRO 0x0108aa92
/* Version 9 Starndard */
#define ADSP_AUDIO_FORMAT_WMA_V9 0x0108d430
/* AMR WideBand Plus */
#define ADSP_AUDIO_FORMAT_AMR_WB_PLUS 0x0108f3da
/* AC3 Decoder */
#define ADSP_AUDIO_FORMAT_AC3_DECODER 0x0108d5f9
/* Not yet supported audio media formats */
/* ISO/IEC 13818 */
#define ADSP_AUDIO_FORMAT_MPEG2_AAC 0x0103d309
/* 3GPP TS 26.101 Sec 4.0 */
#define ADSP_AUDIO_FORMAT_AMRNB_IF1 0x0103d305
/* 3GPP TS 26.101 Annex A */
#define ADSP_AUDIO_FORMAT_AMRNB_IF2 0x01057b31
/* 3GPP TS 26.201 */
#define ADSP_AUDIO_FORMAT_AMRWB_IF1 0x0103d306
/* 3GPP TS 26.201 */
#define ADSP_AUDIO_FORMAT_AMRWB_IF2 0x0105c16d
/* G.711 */
#define ADSP_AUDIO_FORMAT_G711 0x0106201d
/* QCELP 8k, IS96A */
#define ADSP_AUDIO_FORMAT_V8K_FS 0x01081d29
/* Version 1 codec */
#define ADSP_AUDIO_FORMAT_WMA_V1 0x01055b2b
/* Version 2, 7 & 8 codec */
#define ADSP_AUDIO_FORMAT_WMA_V8 0x01055b2c
/* Version 9 Professional codec */
#define ADSP_AUDIO_FORMAT_WMA_V9PRO 0x01055b2d
/* Version 9 Voice codec */
#define ADSP_AUDIO_FORMAT_WMA_SP1 0x01055b2e
/* Version 9 Lossless codec */
#define ADSP_AUDIO_FORMAT_WMA_LOSSLESS 0x01055b2f
/* Real Media content, low-bitrate */
#define ADSP_AUDIO_FORMAT_RA_SIPR 0x01042a0f
/* Real Media content */
#define ADSP_AUDIO_FORMAT_RA_COOK 0x01042a0e
/* For all of the audio formats, unless specified otherwise, */
/* the following apply: */
/* Format block bits are arranged in bytes and words in little-endian */
/* order, i.e., least-significant bit first and least-significant */
/* byte first. */
/* AAC Format Block. */
/* AAC format block consist of a format identifier followed by */
/* AudioSpecificConfig formatted according to ISO/IEC 14496-3 */
/* The following AAC format identifiers are supported */
#define ADSP_AUDIO_AAC_ADTS 0x010619cf
#define ADSP_AUDIO_AAC_MPEG4_ADTS 0x010619d0
#define ADSP_AUDIO_AAC_LOAS 0x010619d1
#define ADSP_AUDIO_AAC_ADIF 0x010619d2
#define ADSP_AUDIO_AAC_RAW 0x010619d3
#define ADSP_AUDIO_AAC_FRAMED_RAW 0x0108c1fb
struct adsp_audio_no_payload_format {
/* Media Format Code (must always be first element) */
u32 format;
/* no payload for this format type */
} __attribute__ ((packed));
/* Maxmum number of bytes allowed in a format block */
#define ADSP_AUDIO_FORMAT_DATA_MAX 16
/* For convenience, to be used as a standard format block */
/* for various media types that don't need a unique format block */
/* ie. PCM, DTMF, etc. */
struct adsp_audio_standard_format {
/* Media Format Code (must always be first element) */
u32 format;
/* payload */
u16 channels;
u16 bits_per_sample;
u32 sampling_rate;
u8 is_signed;
u8 is_interleaved;
} __attribute__ ((packed));
/* ADPCM format block */
struct adsp_audio_adpcm_format {
/* Media Format Code (must always be first element) */
u32 format;
/* payload */
u16 channels;
u16 bits_per_sample;
u32 sampling_rate;
u8 is_signed;
u8 is_interleaved;
u32 block_size;
} __attribute__ ((packed));
/* MIDI format block */
struct adsp_audio_midi_format {
/* Media Format Code (must always be first element) */
u32 format;
/* payload */
u32 sampling_rate;
u16 channels;
u16 mode;
} __attribute__ ((packed));
#define ADSP_AUDIO_COMPANDING_ALAW 0x10619cd
#define ADSP_AUDIO_COMPANDING_MLAW 0x10619ce
/* G711 format block */
struct adsp_audio_g711_format {
/* Media Format Code (must always be first element) */
u32 format;
/* payload */
u32 companding;
} __attribute__ ((packed));
struct adsp_audio_wma_pro_format {
/* Media Format Code (must always be first element) */
u32 format;
/* payload */
u16 format_tag;
u16 channels;
u32 samples_per_sec;
u32 avg_bytes_per_sec;
u16 block_align;
u16 valid_bits_per_sample;
u32 channel_mask;
u16 encode_opt;
u16 advanced_encode_opt;
u32 advanced_encode_opt2;
u32 drc_peak_reference;
u32 drc_peak_target;
u32 drc_average_reference;
u32 drc_average_target;
} __attribute__ ((packed));
struct adsp_audio_amrwb_plus_format {
/* Media Format Code (must always be first element) */
u32 format;
/* payload */
u32 size;
u32 version;
u32 channels;
u32 amr_band_mode;
u32 amr_dtx_mode;
u32 amr_frame_format;
u32 amr_isf_index;
} __attribute__ ((packed));
/* Binary Byte Stream Format */
/* Binary format type that defines a byte stream, */
/* can be used to specify any format (ie. AAC) */
struct adsp_audio_binary_format {
/* Media Format Code (must always be first element) */
u32 format;
/* payload */
/* number of bytes set in byte stream */
u32 num_bytes;
/* Byte stream binary data */
u8 data[ADSP_AUDIO_FORMAT_DATA_MAX];
} __attribute__ ((packed));
struct adsp_audio_shared_memory_format {
/* Media Format Code (must always be first element) */
u32 format;
/* Number of bytes in shared memory */
u32 len;
/* Phyisical address to data in shared memory */
u32 address;
} __attribute__ ((packed));
/* Union of all format types */
union adsp_audio_format {
/* Basic format block with no payload */
struct adsp_audio_no_payload_format no_payload;
/* Generic format block PCM, DTMF */
struct adsp_audio_standard_format standard;
/* ADPCM format block */
struct adsp_audio_adpcm_format adpcm;
/* MIDI format block */
struct adsp_audio_midi_format midi;
/* G711 format block */
struct adsp_audio_g711_format g711;
/* WmaPro format block */
struct adsp_audio_wma_pro_format wma_pro;
/* WmaPro format block */
struct adsp_audio_amrwb_plus_format amrwb_plus;
/* binary (byte stream) format block, used for AAC */
struct adsp_audio_binary_format binary;
/* format block in shared memory */
struct adsp_audio_shared_memory_format shared_mem;
};
#endif

View File

@ -0,0 +1,69 @@
/* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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.
*
*/
#ifndef __DAL_VOICE_H__
#define __DAL_VOICE_H__
#define VOICE_DAL_DEVICE 0x02000075
#define VOICE_DAL_PORT "DAL_AM_AUD"
#define VOICE_DAL_VERSION 0x00010000
#define APR_PKTV1_TYPE_EVENT_V 0
#define APR_UNDEFINED -1
#define APR_PKTV1_TYPE_MASK 0x00000010
#define APR_PKTV1_TYPE_SHFT 4
#define APR_SET_BITMASK(mask, shift, value) \
(((value) << (shift)) & (mask))
#define APR_SET_FIELD(field, value) \
APR_SET_BITMASK((field##_MASK), (field##_SHFT), (value))
enum {
VOICE_OP_INIT = DAL_OP_FIRST_DEVICE_API,
VOICE_OP_CONTROL,
};
struct apr_command_pkt {
uint32_t size;
uint32_t header;
uint16_t reserved1;
uint16_t src_addr;
uint16_t dst_addr;
uint16_t ret_addr;
uint32_t src_token;
uint32_t dst_token;
uint32_t ret_token;
uint32_t context;
uint32_t opcode;
} __attribute__ ((packed));
#define APR_IBASIC_RSP_RESULT 0x00010000
#define APR_OP_CMD_CREATE 0x0001001B
#define APR_OP_CMD_DESTROY 0x0001001C
#define VOICE_OP_CMD_BRINGUP 0x0001001E
#define VOICE_OP_CMD_TEARDOWN 0x0001001F
#define VOICE_OP_CMD_SET_NETWORK 0x0001001D
#define VOICE_OP_CMD_STREAM_SETUP 0x00010027
#define VOICE_OP_CMD_STREAM_TEARDOWN 0x00010028
#endif

View File

@ -0,0 +1,250 @@
/*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation
* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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 <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/msm_audio_qcp.h>
#include <mach/msm_qdsp6_audiov2.h>
#include "dal_audio.h"
#include "dal_audio_format.h"
#include <mach/debug_mm.h>
struct evrc {
struct mutex lock;
struct msm_audio_evrc_enc_config cfg;
struct msm_audio_stream_config str_cfg;
struct audio_client *audio_client;
};
static long q6_evrc_in_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct evrc *evrc = file->private_data;
struct adsp_open_command rpc;
int rc = 0;
if (cmd == 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;
}
mutex_lock(&evrc->lock);
switch (cmd) {
case AUDIO_START:
if (evrc->audio_client) {
rc = -EBUSY;
break;
} else {
evrc->audio_client = q6audio_open(AUDIO_FLAG_READ,
evrc->str_cfg.buffer_size);
if (!evrc->audio_client) {
kfree(evrc);
rc = -ENOMEM;
break;
}
}
tx_clk_freq = 8000;
memset(&rpc, 0, sizeof(rpc));
rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_EVRC_FS;
rpc.format_block.standard.channels = 1;
rpc.format_block.standard.bits_per_sample = 16;
rpc.format_block.standard.sampling_rate = 8000;
rpc.format_block.standard.is_signed = 1;
rpc.format_block.standard.is_interleaved = 0;
rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
rpc.buf_max_size = evrc->str_cfg.buffer_size;
rpc.config.evrc.min_rate = evrc->cfg.min_bit_rate;
rpc.config.evrc.max_rate = evrc->cfg.max_bit_rate;
q6audio_start(evrc->audio_client, &rpc, sizeof(rpc));
break;
case AUDIO_STOP:
break;
case AUDIO_FLUSH:
break;
case AUDIO_SET_VOLUME:
break;
case AUDIO_GET_STREAM_CONFIG:
if (copy_to_user((void *)arg, &evrc->str_cfg,
sizeof(struct msm_audio_stream_config)))
rc = -EFAULT;
break;
case AUDIO_SET_STREAM_CONFIG:
if (copy_from_user(&evrc->str_cfg, (void *)arg,
sizeof(struct msm_audio_stream_config))) {
rc = -EFAULT;
break;
}
if (evrc->str_cfg.buffer_size < 23) {
pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
__func__);
rc = -EINVAL;
break;
}
if (evrc->str_cfg.buffer_count != 2)
pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
__func__);
break;
case AUDIO_SET_EVRC_ENC_CONFIG:
if (copy_from_user(&evrc->cfg, (void *) arg,
sizeof(struct msm_audio_evrc_enc_config)))
rc = -EFAULT;
if (evrc->cfg.min_bit_rate > 4 || evrc->cfg.min_bit_rate < 1) {
pr_err("[%s:%s] invalid min bitrate\n", __MM_FILE__,
__func__);
rc = -EINVAL;
}
if (evrc->cfg.max_bit_rate > 4 || evrc->cfg.max_bit_rate < 1) {
pr_err("[%s:%s] invalid max bitrate\n", __MM_FILE__,
__func__);
rc = -EINVAL;
}
break;
case AUDIO_GET_EVRC_ENC_CONFIG:
if (copy_to_user((void *) arg, &evrc->cfg,
sizeof(struct msm_audio_evrc_enc_config)))
rc = -EFAULT;
break;
default:
rc = -EINVAL;
}
mutex_unlock(&evrc->lock);
return rc;
}
static int q6_evrc_in_open(struct inode *inode, struct file *file)
{
struct evrc *evrc;
evrc = kmalloc(sizeof(struct evrc), GFP_KERNEL);
if (evrc == NULL) {
pr_err("[%s:%s] Could not allocate memory for evrc driver\n",
__MM_FILE__, __func__);
return -ENOMEM;
}
mutex_init(&evrc->lock);
file->private_data = evrc;
evrc->audio_client = NULL;
evrc->str_cfg.buffer_size = 23;
evrc->str_cfg.buffer_count = 2;
evrc->cfg.cdma_rate = CDMA_RATE_FULL;
evrc->cfg.min_bit_rate = 1;
evrc->cfg.max_bit_rate = 4;
return 0;
}
static ssize_t q6_evrc_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;
struct evrc *evrc = file->private_data;
int xfer = 0;
int res;
mutex_lock(&evrc->lock);
ac = evrc->audio_client;
if (!ac) {
res = -ENODEV;
goto fail;
}
while (count > xfer) {
ab = ac->buf + ac->cpu_buf;
if (ab->used)
wait_event(ac->wait, (ab->used == 0));
xfer = ab->actual_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;
}
res = buf - start;
fail:
mutex_unlock(&evrc->lock);
return res;
}
static int q6_evrc_in_release(struct inode *inode, struct file *file)
{
int rc = 0;
struct evrc *evrc = file->private_data;
mutex_lock(&evrc->lock);
if (evrc->audio_client)
rc = q6audio_close(evrc->audio_client);
mutex_unlock(&evrc->lock);
kfree(evrc);
return rc;
}
static const struct file_operations q6_evrc_in_fops = {
.owner = THIS_MODULE,
.open = q6_evrc_in_open,
.read = q6_evrc_in_read,
.release = q6_evrc_in_release,
.unlocked_ioctl = q6_evrc_in_ioctl,
};
struct miscdevice q6_evrc_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_evrc_in",
.fops = &q6_evrc_in_fops,
};
static int __init q6_evrc_in_init(void)
{
return misc_register(&q6_evrc_in_misc);
}
device_initcall(q6_evrc_in_init);

View File

@ -0,0 +1,205 @@
/* arch/arm/mach-msm/qdsp6/audiov2/mp3.c
*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation
* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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 <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/msm_audio.h>
#include <mach/msm_qdsp6_audiov2.h>
#include "dal_audio.h"
#include "dal_audio_format.h"
#define BUFSZ (8192)
#define DMASZ (BUFSZ * 2)
struct mp3 {
struct mutex lock;
struct audio_client *ac;
struct msm_audio_config cfg;
};
static long mp3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct mp3 *mp3 = file->private_data;
struct adsp_open_command rpc;
int rc = 0;
if (cmd == 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;
}
mutex_lock(&mp3->lock);
switch (cmd) {
case AUDIO_SET_VOLUME:
break;
case AUDIO_START:
memset(&rpc, 0, sizeof(rpc));
rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_MP3;
rpc.format_block.standard.channels = mp3->cfg.channel_count;
rpc.format_block.standard.bits_per_sample = 16;
rpc.format_block.standard.sampling_rate = mp3->cfg.sample_rate;
rpc.format_block.standard.is_signed = 1;
rpc.format_block.standard.is_interleaved = 0;
rpc.buf_max_size = BUFSZ;
q6audio_start(mp3->ac, (void *) &rpc, sizeof(rpc));
break;
case AUDIO_STOP:
break;
case AUDIO_FLUSH:
break;
case AUDIO_SET_CONFIG:
if (copy_from_user(&mp3->cfg, (void *) arg,
sizeof(struct msm_audio_config))) {
rc = -EFAULT;
break;
}
if (mp3->cfg.channel_count < 1 || mp3->cfg.channel_count > 2) {
rc = -EINVAL;
break;
}
break;
case AUDIO_GET_CONFIG:
if (copy_to_user((void *) arg, &mp3->cfg,
sizeof(struct msm_audio_config))) {
rc = -EFAULT;
}
break;
default:
rc = -EINVAL;
}
mutex_unlock(&mp3->lock);
return rc;
}
static int mp3_open(struct inode *inode, struct file *file)
{
struct mp3 *mp3;
mp3 = kzalloc(sizeof(struct mp3), GFP_KERNEL);
if (!mp3)
return -ENOMEM;
mutex_init(&mp3->lock);
file->private_data = mp3;
mp3->ac = q6audio_open(AUDIO_FLAG_WRITE, BUFSZ);
if (!mp3->ac) {
kfree(mp3);
return -ENOMEM;
}
mp3->cfg.channel_count = 2;
mp3->cfg.buffer_count = 2;
mp3->cfg.buffer_size = BUFSZ;
mp3->cfg.unused[0] = 0;
mp3->cfg.unused[1] = 0;
mp3->cfg.unused[2] = 0;
mp3->cfg.sample_rate = 48000;
return 0;
}
static ssize_t mp3_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
struct mp3 *mp3 = file->private_data;
struct audio_client *ac;
struct audio_buffer *ab;
const char __user *start = buf;
int xfer;
if (!mp3->ac)
mp3_ioctl(file, AUDIO_START, 0);
ac = mp3->ac;
if (!ac)
return -ENODEV;
while (count > 0) {
ab = ac->buf + ac->cpu_buf;
if (ab->used)
wait_event(ac->wait, (ab->used == 0));
xfer = count;
if (xfer > ab->size)
xfer = ab->size;
if (copy_from_user(ab->data, buf, xfer))
return -EFAULT;
buf += xfer;
count -= xfer;
ab->used = xfer;
q6audio_write(ac, ab);
ac->cpu_buf ^= 1;
}
return buf - start;
}
static int mp3_fsync(struct file *f, int datasync)
{
struct mp3 *mp3 = f->private_data;
if (mp3->ac)
return q6audio_async(mp3->ac);
return -ENODEV;
}
static int mp3_release(struct inode *inode, struct file *file)
{
struct mp3 *mp3 = file->private_data;
if (mp3->ac)
q6audio_close(mp3->ac);
kfree(mp3);
return 0;
}
static const struct file_operations mp3_fops = {
.owner = THIS_MODULE,
.open = mp3_open,
.write = mp3_write,
.fsync = mp3_fsync,
.release = mp3_release,
.unlocked_ioctl = mp3_ioctl,
};
struct miscdevice mp3_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_mp3",
.fops = &mp3_fops,
};
static int __init mp3_init(void)
{
return misc_register(&mp3_misc);
}
device_initcall(mp3_init);

View File

@ -0,0 +1,208 @@
/* arch/arm/mach-msm/qdsp6/audiov2/pcm_in.c
*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation
* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* 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 <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/msm_audio.h>
#include <mach/msm_qdsp6_audiov2.h>
#include "dal_audio.h"
#include "dal_audio_format.h"
#define BUFSZ (4096)
#define DMASZ (BUFSZ * 2)
struct pcm {
struct mutex lock;
struct msm_audio_config cfg;
struct audio_client *audio_client;
};
static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct pcm *pcm = file->private_data;
struct adsp_open_command rpc;
int rc = 0;
if (cmd == 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;
}
mutex_lock(&pcm->lock);
switch (cmd) {
case AUDIO_START:
tx_clk_freq = pcm->cfg.sample_rate;
memset(&rpc, 0, sizeof(rpc));
rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_PCM;
rpc.format_block.standard.channels = pcm->cfg.channel_count;
rpc.format_block.standard.bits_per_sample = 16;
rpc.format_block.standard.sampling_rate = pcm->cfg.sample_rate;
rpc.format_block.standard.is_signed = 1;
rpc.format_block.standard.is_interleaved = 1;
rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
rpc.buf_max_size = BUFSZ;
q6audio_start(pcm->audio_client, &rpc, sizeof(rpc));
break;
case AUDIO_STOP:
break;
case AUDIO_FLUSH:
break;
case AUDIO_SET_VOLUME:
break;
case AUDIO_SET_CONFIG:
if (copy_from_user(&pcm->cfg, (void *) arg,
sizeof(struct msm_audio_config))) {
rc = -EFAULT;
break;
}
break;
case AUDIO_GET_CONFIG:
if (copy_to_user((void *) arg, &pcm->cfg,
sizeof(struct msm_audio_config))) {
rc = -EFAULT;
}
break;
default:
rc = -EINVAL;
}
mutex_unlock(&pcm->lock);
return rc;
}
static int q6_in_open(struct inode *inode, struct file *file)
{
struct pcm *pcm;
pcm = kmalloc(sizeof(struct pcm), GFP_KERNEL);
if (pcm == NULL) {
pr_err("Could not allocate memory for pcm driver\n");
return -ENOMEM;
}
mutex_init(&pcm->lock);
file->private_data = pcm;
pcm->audio_client = q6audio_open(AUDIO_FLAG_READ, BUFSZ);
if (!pcm->audio_client) {
kfree(pcm);
return -ENOMEM;
}
pcm->cfg.channel_count = 1;
pcm->cfg.buffer_count = 2;
pcm->cfg.buffer_size = BUFSZ;
pcm->cfg.unused[0] = 0;
pcm->cfg.unused[1] = 0;
pcm->cfg.unused[2] = 0;
pcm->cfg.sample_rate = 8000;
return 0;
}
static ssize_t q6_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;
struct pcm *pcm = file->private_data;
int xfer;
int res;
mutex_lock(&pcm->lock);
ac = pcm->audio_client;
if (!ac) {
res = -ENODEV;
goto fail;
}
while (count > 0) {
ab = ac->buf + ac->cpu_buf;
if (ab->used)
wait_event(ac->wait, (ab->used == 0));
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(&pcm->lock);
return res;
}
static int q6_in_release(struct inode *inode, struct file *file)
{
int rc = 0;
struct pcm *pcm = file->private_data;
mutex_lock(&pcm->lock);
if (pcm->audio_client)
rc = q6audio_close(pcm->audio_client);
mutex_unlock(&pcm->lock);
kfree(pcm);
return rc;
}
static const struct file_operations q6_in_fops = {
.owner = THIS_MODULE,
.open = q6_in_open,
.read = q6_in_read,
.release = q6_in_release,
.unlocked_ioctl = q6_in_ioctl,
};
struct miscdevice q6_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_pcm_in",
.fops = &q6_in_fops,
};
static int __init q6_in_init(void)
{
return misc_register(&q6_in_misc);
}
device_initcall(q6_in_init);

View File

@ -0,0 +1,196 @@
/* arch/arm/mach-msm/qdsp6/audiov2/pcm_out.c
*
* Copyright (C) 2009 Google, Inc.
* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* Author: Brian Swetland <swetland@google.com>
*
* 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 <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/msm_audio.h>
#include <mach/msm_qdsp6_audiov2.h>
#include "dal_audio.h"
#include "dal_audio_format.h"
#define BUFSZ (8192)
#define DMASZ (BUFSZ * 2)
struct pcm {
struct mutex lock;
struct audio_client *ac;
struct msm_audio_config cfg;
};
static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct pcm *pcm = file->private_data;
struct adsp_open_command rpc;
int rc = 0;
if (cmd == 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;
}
mutex_lock(&pcm->lock);
switch (cmd) {
case AUDIO_START:
memset(&rpc, 0, sizeof(rpc));
rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_PCM;
rpc.format_block.standard.channels = pcm->cfg.channel_count;
rpc.format_block.standard.bits_per_sample = 16;
rpc.format_block.standard.sampling_rate = pcm->cfg.sample_rate;
rpc.format_block.standard.is_signed = 1;
rpc.format_block.standard.is_interleaved = 1;
rpc.buf_max_size = BUFSZ;
q6audio_start(pcm->ac, (void *) &rpc, sizeof(rpc));
break;
case AUDIO_STOP:
break;
case AUDIO_FLUSH:
break;
case AUDIO_SET_CONFIG:
if (copy_from_user(&pcm->cfg, (void *) arg,
sizeof(struct msm_audio_config))) {
rc = -EFAULT;
break;
}
if (pcm->cfg.channel_count < 1 || pcm->cfg.channel_count > 2) {
rc = -EINVAL;
break;
}
break;
case AUDIO_GET_CONFIG:
if (copy_to_user((void *) arg, &pcm->cfg,
sizeof(struct msm_audio_config))) {
rc = -EFAULT;
}
break;
default:
rc = -EINVAL;
}
mutex_unlock(&pcm->lock);
return rc;
}
static int pcm_open(struct inode *inode, struct file *file)
{
struct pcm *pcm;
pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
mutex_init(&pcm->lock);
file->private_data = pcm;
pcm->ac = q6audio_open(AUDIO_FLAG_WRITE, BUFSZ);
if (!pcm->ac) {
kfree(pcm);
return -ENOMEM;
}
pcm->cfg.channel_count = 2;
pcm->cfg.buffer_count = 2;
pcm->cfg.buffer_size = BUFSZ;
pcm->cfg.unused[0] = 0;
pcm->cfg.unused[1] = 0;
pcm->cfg.unused[2] = 0;
pcm->cfg.sample_rate = 48000;
return 0;
}
static ssize_t pcm_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
struct pcm *pcm = file->private_data;
struct audio_client *ac;
struct audio_buffer *ab;
const char __user *start = buf;
int xfer;
ac = pcm->ac;
if (!ac)
return -ENODEV;
while (count > 0) {
ab = ac->buf + ac->cpu_buf;
if (ab->used)
wait_event(ac->wait, (ab->used == 0));
xfer = count;
if (xfer > ab->size)
xfer = ab->size;
if (copy_from_user(ab->data, buf, xfer))
return -EFAULT;
buf += xfer;
count -= xfer;
ab->used = 1;
ab->actual_size = xfer;
q6audio_write(ac, ab);
ac->cpu_buf ^= 1;
}
return buf - start;
}
static int pcm_release(struct inode *inode, struct file *file)
{
struct pcm *pcm = file->private_data;
if (pcm->ac)
q6audio_close(pcm->ac);
kfree(pcm);
return 0;
}
static const struct file_operations pcm_fops = {
.owner = THIS_MODULE,
.open = pcm_open,
.write = pcm_write,
.release = pcm_release,
.unlocked_ioctl = pcm_ioctl,
};
struct miscdevice pcm_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_pcm_out",
.fops = &pcm_fops,
};
static int __init pcm_init(void)
{
return misc_register(&pcm_misc);
}
device_initcall(pcm_init);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,276 @@
/* arch/arm/mach-msm/qdsp6/audiov2/q6audio_devices.h
*
* Copyright (C) 2009 Google, Inc.
* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* Author: Brian Swetland <swetland@google.com>
*
* 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.
*
*/
struct q6_device_info {
uint32_t id;
uint32_t cad_id;
uint32_t path;
uint32_t rate;
uint8_t dir;
uint8_t codec;
uint8_t hw;
};
#define Q6_ICODEC_RX 0
#define Q6_ICODEC_TX 1
#define Q6_ECODEC_RX 2
#define Q6_ECODEC_TX 3
#define Q6_SDAC_RX 6
#define Q6_SDAC_TX 7
#define Q6_CODEC_NONE 255
#define Q6_TX 1
#define Q6_RX 2
#define Q6_TX_RX 3
#define Q6_HW_HANDSET 0
#define Q6_HW_HEADSET 1
#define Q6_HW_SPEAKER 2
#define Q6_HW_TTY 3
#define Q6_HW_BT_SCO 4
#define Q6_HW_BT_A2DP 5
#define Q6_HW_COUNT 6
#define CAD_HW_DEVICE_ID_HANDSET_MIC 0x01
#define CAD_HW_DEVICE_ID_HANDSET_SPKR 0x02
#define CAD_HW_DEVICE_ID_HEADSET_MIC 0x03
#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO 0x04
#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO 0x05
#define CAD_HW_DEVICE_ID_SPKR_PHONE_MIC 0x06
#define CAD_HW_DEVICE_ID_SPKR_PHONE_MONO 0x07
#define CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO 0x08
#define CAD_HW_DEVICE_ID_BT_SCO_MIC 0x09
#define CAD_HW_DEVICE_ID_BT_SCO_SPKR 0x0A
#define CAD_HW_DEVICE_ID_BT_A2DP_SPKR 0x0B
#define CAD_HW_DEVICE_ID_TTY_HEADSET_MIC 0x0C
#define CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR 0x0D
#define CAD_HW_DEVICE_ID_DEFAULT_TX 0x0E
#define CAD_HW_DEVICE_ID_DEFAULT_RX 0x0F
/* Logical Device to indicate A2DP routing */
#define CAD_HW_DEVICE_ID_BT_A2DP_TX 0x10
#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX 0x11
#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX 0x12
#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX 0x13
#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX 0x14
#define CAD_HW_DEVICE_ID_VOICE 0x15
#define CAD_HW_DEVICE_ID_I2S_RX 0x20
#define CAD_HW_DEVICE_ID_I2S_TX 0x21
/* AUXPGA */
#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO_LB 0x22
#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO_LB 0x23
#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_STEREO_LB 0x24
#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_MONO_LB 0x25
#define CAD_HW_DEVICE_ID_NULL_RX 0x2A
#define CAD_HW_DEVICE_ID_MAX_NUM 0x2F
#define CAD_HW_DEVICE_ID_INVALID 0xFF
#define CAD_RX_DEVICE 0x00
#define CAD_TX_DEVICE 0x01
static struct q6_device_info q6_audio_devices[] = {
{
.id = ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR,
.cad_id = CAD_HW_DEVICE_ID_HANDSET_SPKR,
.path = ADIE_PATH_HANDSET_RX,
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ICODEC_RX,
.hw = Q6_HW_HANDSET,
},
{
.id = ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO,
.cad_id = CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO,
.path = ADIE_PATH_HEADSET_MONO_RX,
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ICODEC_RX,
.hw = Q6_HW_HEADSET,
},
{
.id = ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO,
.cad_id = CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO,
.path = ADIE_PATH_HEADSET_STEREO_RX,
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ICODEC_RX,
.hw = Q6_HW_HEADSET,
},
{
.id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO,
.cad_id = CAD_HW_DEVICE_ID_SPKR_PHONE_MONO,
.path = ADIE_PATH_SPEAKER_RX,
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ICODEC_RX,
.hw = Q6_HW_HEADSET,
},
{
.id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO,
.cad_id = CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO,
.path = ADIE_PATH_SPEAKER_STEREO_RX,
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ICODEC_RX,
.hw = Q6_HW_SPEAKER,
},
{
.id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET,
.cad_id = CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX,
.path = ADIE_PATH_SPKR_MONO_HDPH_MONO_RX,
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ICODEC_RX,
.hw = Q6_HW_SPEAKER,
},
{
.id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET,
.cad_id = CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX,
.path = ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX,
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ICODEC_RX,
.hw = Q6_HW_SPEAKER,
},
{
.id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET,
.cad_id = CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX,
.path = ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX,
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ICODEC_RX,
.hw = Q6_HW_SPEAKER,
},
{
.id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET,
.cad_id = CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX,
.path = ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX,
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ICODEC_RX,
.hw = Q6_HW_SPEAKER,
},
{
.id = ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR,
.cad_id = CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR,
.path = ADIE_PATH_TTY_HEADSET_RX,
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ICODEC_RX,
.hw = Q6_HW_TTY,
},
{
.id = ADSP_AUDIO_DEVICE_ID_HANDSET_MIC,
.cad_id = CAD_HW_DEVICE_ID_HANDSET_MIC,
.path = ADIE_PATH_HANDSET_TX,
.rate = 8000,
.dir = Q6_TX,
.codec = Q6_ICODEC_TX,
.hw = Q6_HW_HANDSET,
},
{
.id = ADSP_AUDIO_DEVICE_ID_HEADSET_MIC,
.cad_id = CAD_HW_DEVICE_ID_HEADSET_MIC,
.path = ADIE_PATH_HEADSET_MONO_TX,
.rate = 8000,
.dir = Q6_TX,
.codec = Q6_ICODEC_TX,
.hw = Q6_HW_HEADSET,
},
{
.id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC,
.cad_id = CAD_HW_DEVICE_ID_SPKR_PHONE_MIC,
.path = ADIE_PATH_SPEAKER_TX,
.rate = 8000,
.dir = Q6_TX,
.codec = Q6_ICODEC_TX,
.hw = Q6_HW_SPEAKER,
},
{
.id = ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC,
.cad_id = CAD_HW_DEVICE_ID_TTY_HEADSET_MIC,
.path = ADIE_PATH_TTY_HEADSET_TX,
.rate = 8000,
.dir = Q6_TX,
.codec = Q6_ICODEC_TX,
.hw = Q6_HW_HEADSET,
},
{
.id = ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR,
.cad_id = CAD_HW_DEVICE_ID_BT_SCO_SPKR,
.path = 0, /* XXX */
.rate = 8000,
.dir = Q6_RX,
.codec = Q6_ECODEC_RX,
.hw = Q6_HW_BT_SCO,
},
{
.id = ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR,
.cad_id = CAD_HW_DEVICE_ID_BT_A2DP_SPKR,
.path = 0, /* XXX */
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_ECODEC_RX,
.hw = Q6_HW_BT_A2DP,
},
{
.id = ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC,
.cad_id = CAD_HW_DEVICE_ID_BT_SCO_MIC,
.path = 0, /* XXX */
.rate = 8000,
.dir = Q6_TX,
.codec = Q6_ECODEC_TX,
.hw = Q6_HW_BT_SCO,
},
{
.id = ADSP_AUDIO_DEVICE_ID_I2S_SPKR,
.cad_id = CAD_HW_DEVICE_ID_I2S_RX,
.path = 0, /* XXX */
.rate = 48000,
.dir = Q6_RX,
.codec = Q6_SDAC_RX,
.hw = Q6_HW_SPEAKER,
},
{
.id = ADSP_AUDIO_DEVICE_ID_I2S_MIC,
.cad_id = CAD_HW_DEVICE_ID_I2S_TX,
.path = 0, /* XXX */
.rate = 16000,
.dir = Q6_TX,
.codec = Q6_SDAC_TX,
.hw = Q6_HW_SPEAKER,
},
{
.id = 0,
.cad_id = 0,
.path = 0,
.rate = 8000,
.dir = 0,
.codec = Q6_CODEC_NONE,
.hw = 0,
},
};

View File

@ -0,0 +1,255 @@
/*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation
* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* Author: Brian Swetland <swetland@google.com>
*
* 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 <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/msm_audio_qcp.h>
#include <mach/msm_qdsp6_audiov2.h>
#include "dal_audio.h"
#include "dal_audio_format.h"
#include <mach/debug_mm.h>
struct qcelp {
struct mutex lock;
struct msm_audio_qcelp_enc_config cfg;
struct msm_audio_stream_config str_cfg;
struct audio_client *audio_client;
};
static long q6_qcelp_in_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct qcelp *qcelp = file->private_data;
struct adsp_open_command rpc;
int rc = 0;
if (cmd == 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;
}
mutex_lock(&qcelp->lock);
switch (cmd) {
case AUDIO_START:
if (qcelp->audio_client) {
rc = -EBUSY;
break;
} else {
qcelp->audio_client = q6audio_open(AUDIO_FLAG_READ,
qcelp->str_cfg.buffer_size);
if (!qcelp->audio_client) {
kfree(qcelp);
rc = -ENOMEM;
break;
}
}
tx_clk_freq = 8000;
memset(&rpc, 0, sizeof(rpc));
rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_V13K_FS;
rpc.format_block.standard.channels = 1;
rpc.format_block.standard.bits_per_sample = 16;
rpc.format_block.standard.sampling_rate = 8000;
rpc.format_block.standard.is_signed = 1;
rpc.format_block.standard.is_interleaved = 0;
rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
rpc.buf_max_size = qcelp->str_cfg.buffer_size;
rpc.config.qcelp13k.min_rate = qcelp->cfg.min_bit_rate;
rpc.config.qcelp13k.max_rate = qcelp->cfg.max_bit_rate;
q6audio_start(qcelp->audio_client, &rpc, sizeof(rpc));
break;
case AUDIO_STOP:
break;
case AUDIO_FLUSH:
break;
case AUDIO_SET_VOLUME:
break;
case AUDIO_GET_STREAM_CONFIG:
if (copy_to_user((void *)arg, &qcelp->str_cfg,
sizeof(struct msm_audio_stream_config)))
rc = -EFAULT;
break;
case AUDIO_SET_STREAM_CONFIG:
if (copy_from_user(&qcelp->str_cfg, (void *)arg,
sizeof(struct msm_audio_stream_config))) {
rc = -EFAULT;
break;
}
if (qcelp->str_cfg.buffer_size < 35) {
pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
__func__);
rc = -EINVAL;
break;
}
if (qcelp->str_cfg.buffer_count != 2)
pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
__func__);
break;
case AUDIO_SET_QCELP_ENC_CONFIG:
if (copy_from_user(&qcelp->cfg, (void *) arg,
sizeof(struct msm_audio_qcelp_enc_config)))
rc = -EFAULT;
if (qcelp->cfg.min_bit_rate > 4 ||
qcelp->cfg.min_bit_rate < 1) {
pr_err("[%s:%s] invalid min bitrate\n", __MM_FILE__,
__func__);
rc = -EINVAL;
}
if (qcelp->cfg.max_bit_rate > 4 ||
qcelp->cfg.max_bit_rate < 1) {
pr_err("[%s:%s] invalid max bitrate\n", __MM_FILE__,
__func__);
rc = -EINVAL;
}
break;
case AUDIO_GET_QCELP_ENC_CONFIG:
if (copy_to_user((void *) arg, &qcelp->cfg,
sizeof(struct msm_audio_qcelp_enc_config)))
rc = -EFAULT;
break;
default:
rc = -EINVAL;
}
mutex_unlock(&qcelp->lock);
return rc;
}
static int q6_qcelp_in_open(struct inode *inode, struct file *file)
{
struct qcelp *qcelp;
qcelp = kmalloc(sizeof(struct qcelp), GFP_KERNEL);
if (qcelp == NULL) {
pr_err("[%s:%s] Could not allocate memory for qcelp driver\n",
__MM_FILE__, __func__);
return -ENOMEM;
}
mutex_init(&qcelp->lock);
file->private_data = qcelp;
qcelp->audio_client = NULL;
qcelp->str_cfg.buffer_size = 35;
qcelp->str_cfg.buffer_count = 2;
qcelp->cfg.cdma_rate = CDMA_RATE_FULL;
qcelp->cfg.min_bit_rate = 1;
qcelp->cfg.max_bit_rate = 4;
return 0;
}
static ssize_t q6_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;
struct qcelp *qcelp = file->private_data;
int xfer = 0;
int res;
mutex_lock(&qcelp->lock);
ac = qcelp->audio_client;
if (!ac) {
res = -ENODEV;
goto fail;
}
while (count > xfer) {
ab = ac->buf + ac->cpu_buf;
if (ab->used)
wait_event(ac->wait, (ab->used == 0));
xfer = ab->actual_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;
}
res = buf - start;
fail:
mutex_unlock(&qcelp->lock);
return res;
}
static int q6_qcelp_in_release(struct inode *inode, struct file *file)
{
int rc = 0;
struct qcelp *qcelp = file->private_data;
mutex_lock(&qcelp->lock);
if (qcelp->audio_client)
rc = q6audio_close(qcelp->audio_client);
mutex_unlock(&qcelp->lock);
kfree(qcelp);
return rc;
}
static const struct file_operations q6_qcelp_in_fops = {
.owner = THIS_MODULE,
.open = q6_qcelp_in_open,
.read = q6_qcelp_in_read,
.release = q6_qcelp_in_release,
.unlocked_ioctl = q6_qcelp_in_ioctl,
};
struct miscdevice q6_qcelp_in_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_qcelp_in",
.fops = &q6_qcelp_in_fops,
};
static int __init q6_qcelp_in_init(void)
{
return misc_register(&q6_qcelp_in_misc);
}
device_initcall(q6_qcelp_in_init);

View File

@ -0,0 +1,73 @@
/* arch/arm/mach-msm/qdsp6/audiov2/routing.c
*
* Copyright (C) 2009 Google, Inc.
* Copyright (c) 2009, The Linux Foundation. All rights reserved.
*
* Author: Brian Swetland <swetland@google.com>
*
* 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 <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <mach/msm_qdsp6_audiov2.h>
static int q6_open(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t q6_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
char cmd[32];
if (count >= sizeof(cmd))
return -EINVAL;
if (copy_from_user(cmd, buf, count))
return -EFAULT;
cmd[count] = 0;
if ((count > 1) && (cmd[count-1] == '\n'))
cmd[count-1] = 0;
q6audio_set_route(cmd);
return count;
}
static int q6_release(struct inode *inode, struct file *file)
{
return 0;
}
static const struct file_operations q6_fops = {
.owner = THIS_MODULE,
.open = q6_open,
.write = q6_write,
.release = q6_release,
};
static struct miscdevice q6_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msm_audio_route",
.fops = &q6_fops,
};
static int __init q6_init(void)
{
return misc_register(&q6_misc);
}
device_initcall(q6_init);

View File

@ -0,0 +1,188 @@
/* Copyright (c) 2010, The Linux Foundation. All rights reserved.
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/completion.h>
#include <linux/wait.h>
#include <mach/msm_qdsp6_audiov2.h>
#include "../dal.h"
#include "dal_voice.h"
#include <mach/debug_mm.h>
struct voice_struct {
struct dal_client *cvd;
struct apr_command_pkt apr_pkt;
struct completion compl;
};
static struct voice_struct voice;
static int cvd_send_response(void)
{
struct apr_command_pkt *pkt;
uint16_t src_addr;
uint16_t src_token;
uint16_t dst_token;
uint16_t dst_addr;
pkt = &voice.apr_pkt;
src_addr = pkt->dst_addr;
dst_addr = pkt->src_addr;
src_token = pkt->dst_token;
dst_token = pkt->src_token;
pkt->header &= ~APR_PKTV1_TYPE_MASK;
pkt->header |= APR_SET_FIELD(APR_PKTV1_TYPE, APR_PKTV1_TYPE_EVENT_V);
pkt->src_addr = src_addr;
pkt->dst_addr = dst_addr;
pkt->src_token = src_token;
pkt->dst_token = dst_token;
pkt->opcode = APR_IBASIC_RSP_RESULT;
dal_call(voice.cvd, VOICE_OP_CONTROL, 5, pkt,
sizeof(struct apr_command_pkt),
pkt, sizeof(u32));
return 0;
}
static int cvd_process_voice_setup(void)
{
q6voice_setup();
cvd_send_response();
return 0;
}
static int cvd_process_voice_teardown(void)
{
q6voice_teardown();
cvd_send_response();
return 0;
}
static int cvd_process_set_network(void)
{
cvd_send_response();
return 0;
}
static int voice_thread(void *data)
{
while (!kthread_should_stop()) {
wait_for_completion(&voice.compl);
init_completion(&voice.compl);
switch (voice.apr_pkt.opcode) {
case APR_OP_CMD_CREATE:
cvd_send_response();
break;
case VOICE_OP_CMD_BRINGUP:
cvd_process_voice_setup();
break;
case APR_OP_CMD_DESTROY:
cvd_send_response();
break;
case VOICE_OP_CMD_TEARDOWN:
cvd_process_voice_teardown();
break;
case VOICE_OP_CMD_SET_NETWORK:
cvd_process_set_network();
break;
default:
pr_err("[%s:%s] Undefined event\n", __MM_FILE__,
__func__);
}
}
return 0;
}
static void remote_cb_function(void *data, int len, void *cookie)
{
struct apr_command_pkt *apr = data + 2*sizeof(uint32_t);
memcpy(&voice.apr_pkt, apr, sizeof(struct apr_command_pkt));
if (len <= 0) {
pr_err("[%s:%s] unexpected event with length %d\n",
__MM_FILE__, __func__, len);
return;
}
pr_debug("[%s:%s] APR = %x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n", __MM_FILE__,
__func__,
apr->header,
apr->reserved1,
apr->src_addr,
apr->dst_addr,
apr->ret_addr,
apr->src_token,
apr->dst_token,
apr->ret_token,
apr->context,
apr->opcode);
complete(&voice.compl);
}
static int __init voice_init(void)
{
int res = 0;
struct task_struct *task;
u32 tmp[2];
tmp[0] = sizeof(u32);
tmp[1] = 0;
voice.cvd = dal_attach(VOICE_DAL_DEVICE, VOICE_DAL_PORT, 0,
remote_cb_function, 0);
if (!voice.cvd) {
pr_err("[%s:%s] audio_init: cannot attach to cvd\n",
__MM_FILE__, __func__);
res = -ENODEV;
goto done;
}
if (check_version(voice.cvd, VOICE_DAL_VERSION) != 0) {
pr_err("[%s:%s] Incompatible cvd version\n",
__MM_FILE__, __func__);
res = -ENODEV;
goto done;
}
dal_call(voice.cvd, VOICE_OP_INIT, 5, tmp, sizeof(tmp),
tmp, sizeof(u32));
init_completion(&voice.compl);
task = kthread_run(voice_thread, &voice, "voice_thread");
if (IS_ERR(task)) {
pr_err("[%s:%s] Cannot start the voice thread\n", __MM_FILE__,
__func__);
res = PTR_ERR(task);
task = NULL;
} else
goto done;
done:
return res;
}
late_initcall(voice_init);