/* arch/arm/mach-msm/htc_acoustic.c * * Copyright (C) 2007-2008 HTC Corporation * Author: Laurence Chen * * 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 "smd_private.h" #define ACOUSTIC_IOCTL_MAGIC 'p' #define ACOUSTIC_ARM11_DONE _IOW(ACOUSTIC_IOCTL_MAGIC, 22, unsigned int) #define HTCRPOG 0x30100002 #define HTCVERS MSM_RPC_VERS(0,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 struct mutex rpc_connect_mutex; static int is_rpc_connect(void) { mutex_lock(&rpc_connect_mutex); if (endpoint == NULL) { endpoint = msm_rpc_connect(HTCRPOG, HTCVERS, 0); if (IS_ERR(endpoint)) { pr_err("%s: init rpc failed! rc = %ld\n", __func__, PTR_ERR(endpoint)); mutex_unlock(&rpc_connect_mutex); return 0; } } mutex_unlock(&rpc_connect_mutex); return 1; } int turn_mic_bias_on(int on) { struct mic_bias_req { struct rpc_request_hdr hdr; uint32_t on; } req; if (!is_rpc_connect()) return -1; req.on = cpu_to_be32(on); return msm_rpc_call(endpoint, ONCRPC_SET_MIC_BIAS_PROC, &req, sizeof(req), 5 * HZ); } EXPORT_SYMBOL(turn_mic_bias_on); 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 (!is_rpc_connect()) 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); mutex_init(&rpc_connect_mutex); 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 "); MODULE_DESCRIPTION("HTC acoustic driver"); MODULE_LICENSE("GPL");