diff options
Diffstat (limited to 'arch/arm/mach-msm/htc_acoustic.c')
-rw-r--r-- | arch/arm/mach-msm/htc_acoustic.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/arch/arm/mach-msm/htc_acoustic.c b/arch/arm/mach-msm/htc_acoustic.c new file mode 100644 index 000000000000..3de71dddb589 --- /dev/null +++ b/arch/arm/mach-msm/htc_acoustic.c @@ -0,0 +1,239 @@ +/* arch/arm/mach-msm/htc_acoustic.c + * + * Copyright (C) 2007-2008 HTC Corporation + * Author: Laurence Chen <Laurence_Chen@htc.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/device.h> +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/miscdevice.h> +#include <linux/mm.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/uaccess.h> +#include <linux/mutex.h> +#include <linux/sched.h> + +#include <mach/msm_smd.h> +#include <mach/msm_rpcrouter.h> +#include <mach/msm_iomap.h> + +#include "smd_private.h" + +#define ACOUSTIC_IOCTL_MAGIC 'p' +#define ACOUSTIC_ARM11_DONE _IOW(ACOUSTIC_IOCTL_MAGIC, 22, unsigned int) + +#define HTCRPOG 0x30100002 +#define HTCVERS 0 +#define ONCRPC_SET_MIC_BIAS_PROC (1) +#define ONCRPC_ACOUSTIC_INIT_PROC (5) +#define ONCRPC_ALLOC_ACOUSTIC_MEM_PROC (6) + +#define HTC_ACOUSTIC_TABLE_SIZE (0x10000) + +#define D(fmt, args...) printk(KERN_INFO "htc-acoustic: "fmt, ##args) +#define E(fmt, args...) printk(KERN_ERR "htc-acoustic: "fmt, ##args) + +struct set_smem_req { + struct rpc_request_hdr hdr; + uint32_t size; +}; + +struct set_smem_rep { + struct rpc_reply_hdr hdr; + int n; +}; + +struct set_acoustic_req { + struct rpc_request_hdr hdr; +}; + +struct set_acoustic_rep { + struct rpc_reply_hdr hdr; + int n; +}; + +static uint32_t htc_acoustic_vir_addr; +static struct msm_rpc_endpoint *endpoint; +static struct mutex api_lock; + +static int acoustic_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long pgoff, delta; + 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); + delta = PAGE_ALIGN(pgoff) - pgoff; + + if (size + delta > HTC_ACOUSTIC_TABLE_SIZE) { + E("mmap failed: size %d\n", size); + goto done; + } + + pgoff += delta; + vma->vm_flags |= VM_IO | VM_RESERVED; + + rc = io_remap_pfn_range(vma, vma->vm_start, pgoff >> PAGE_SHIFT, + 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; + struct set_smem_req req_smem; + struct set_smem_rep rep_smem; + + D("open\n"); + + mutex_lock(&api_lock); + + if (!htc_acoustic_vir_addr) { + if (endpoint == NULL) { + endpoint = msm_rpc_connect(HTCRPOG, HTCVERS, 0); + if (IS_ERR(endpoint)) { + E("init rpc failed! rc = %ld\n", + PTR_ERR(endpoint)); + endpoint = NULL; + goto done; + } + } + + req_smem.size = cpu_to_be32(HTC_ACOUSTIC_TABLE_SIZE); + rc = msm_rpc_call_reply(endpoint, + ONCRPC_ALLOC_ACOUSTIC_MEM_PROC, + &req_smem, sizeof(req_smem), + &rep_smem, sizeof(rep_smem), + 5 * HZ); + + if (rep_smem.n != 0 || rc < 0) { + E("open failed: ALLOC_ACOUSTIC_MEM_PROC error %d.\n", + rc); + goto done; + } + htc_acoustic_vir_addr = + (uint32_t)smem_alloc(SMEM_ID_VENDOR1, + HTC_ACOUSTIC_TABLE_SIZE); + if (!htc_acoustic_vir_addr) { + E("open failed: smem_alloc error\n"); + goto done; + } + } + + rc = 0; +done: + 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, reply_value; + struct set_acoustic_req req; + struct set_acoustic_rep rep; + + D("ioctl\n"); + + mutex_lock(&api_lock); + + switch (cmd) { + case ACOUSTIC_ARM11_DONE: + D("ioctl: ACOUSTIC_ARM11_DONE called %d.\n", current->pid); + rc = msm_rpc_call_reply(endpoint, + ONCRPC_ACOUSTIC_INIT_PROC, &req, + sizeof(req), &rep, sizeof(rep), + 5 * HZ); + + reply_value = be32_to_cpu(rep.n); + if (reply_value != 0 || rc < 0) { + E("ioctl failed: ONCRPC_ACOUSTIC_INIT_PROC "\ + "error %d.\n", rc); + if (rc >= 0) + rc = -EIO; + break; + } + D("ioctl: ONCRPC_ACOUSTIC_INIT_PROC success.\n"); + break; + default: + E("ioctl: invalid command\n"); + rc = -EINVAL; + } + + mutex_unlock(&api_lock); + return 0; +} + + +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); + +MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>"); +MODULE_DESCRIPTION("HTC acoustic driver"); +MODULE_LICENSE("GPL"); |