htc_acoustic_qsd.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /* arch/arm/mach-msm/htc_acoustic_qsd.c
  2. *
  3. * Copyright (C) 2009 HTC Corporation
  4. *
  5. * This software is licensed under the terms of the GNU General Public
  6. * License version 2, as published by the Free Software Foundation, and
  7. * may be copied, distributed, and modified under those terms.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. */
  15. #include <linux/device.h>
  16. #include <linux/fs.h>
  17. #include <linux/module.h>
  18. #include <linux/miscdevice.h>
  19. #include <linux/mm.h>
  20. #include <linux/err.h>
  21. #include <linux/delay.h>
  22. #include <linux/kernel.h>
  23. #include <linux/uaccess.h>
  24. #include <linux/mutex.h>
  25. #include <linux/gpio.h>
  26. #include <mach/msm_smd.h>
  27. #include <mach/msm_rpcrouter.h>
  28. #include <mach/msm_iomap.h>
  29. #include <mach/htc_acoustic_qsd.h>
  30. #include <mach/msm_qdsp6_audio.h>
  31. #include "smd_private.h"
  32. #define ACOUSTIC_IOCTL_MAGIC 'p'
  33. #define ACOUSTIC_UPDATE_ADIE \
  34. _IOW(ACOUSTIC_IOCTL_MAGIC, 24, unsigned int)
  35. #define HTCACOUSTICPROG 0x30100003
  36. #define HTCACOUSTICVERS 0
  37. #define ONCRPC_ALLOC_ACOUSTIC_MEM_PROC (1)
  38. #define ONCRPC_UPDATE_ADIE_PROC (2)
  39. #define ONCRPC_ENABLE_AUX_PGA_LOOPBACK_PROC (3)
  40. #define ONCRPC_FORCE_HEADSET_SPEAKER_PROC (4)
  41. #define HTC_ACOUSTIC_TABLE_SIZE (0x20000)
  42. #define D(fmt, args...) printk(KERN_INFO "htc-acoustic: "fmt, ##args)
  43. #define E(fmt, args...) printk(KERN_ERR "htc-acoustic: "fmt, ##args)
  44. static uint32_t htc_acoustic_vir_addr;
  45. static struct msm_rpc_endpoint *endpoint;
  46. static struct mutex api_lock;
  47. static struct mutex rpc_connect_lock;
  48. static struct qsd_acoustic_ops *the_ops;
  49. void acoustic_register_ops(struct qsd_acoustic_ops *ops)
  50. {
  51. the_ops = ops;
  52. }
  53. static int is_rpc_connect(void)
  54. {
  55. mutex_lock(&rpc_connect_lock);
  56. if (endpoint == NULL) {
  57. endpoint = msm_rpc_connect(HTCACOUSTICPROG,
  58. HTCACOUSTICVERS, 0);
  59. if (IS_ERR(endpoint)) {
  60. pr_err("%s: init rpc failed! rc = %ld\n",
  61. __func__, PTR_ERR(endpoint));
  62. mutex_unlock(&rpc_connect_lock);
  63. return -1;
  64. }
  65. }
  66. mutex_unlock(&rpc_connect_lock);
  67. return 0;
  68. }
  69. int turn_mic_bias_on(int on)
  70. {
  71. D("%s called %d\n", __func__, on);
  72. if (the_ops->enable_mic_bias)
  73. the_ops->enable_mic_bias(on);
  74. return 0;
  75. }
  76. EXPORT_SYMBOL(turn_mic_bias_on);
  77. int force_headset_speaker_on(int enable)
  78. {
  79. struct speaker_headset_req {
  80. struct rpc_request_hdr hdr;
  81. uint32_t enable;
  82. } spkr_req;
  83. D("%s called %d\n", __func__, enable);
  84. if (is_rpc_connect() == -1)
  85. return -1;
  86. spkr_req.enable = cpu_to_be32(enable);
  87. return msm_rpc_call(endpoint,
  88. ONCRPC_FORCE_HEADSET_SPEAKER_PROC,
  89. &spkr_req, sizeof(spkr_req), 5 * HZ);
  90. }
  91. EXPORT_SYMBOL(force_headset_speaker_on);
  92. int enable_aux_loopback(uint32_t enable)
  93. {
  94. struct aux_loopback_req {
  95. struct rpc_request_hdr hdr;
  96. uint32_t enable;
  97. } aux_req;
  98. D("%s called %d\n", __func__, enable);
  99. if (is_rpc_connect() == -1)
  100. return -1;
  101. aux_req.enable = cpu_to_be32(enable);
  102. return msm_rpc_call(endpoint,
  103. ONCRPC_ENABLE_AUX_PGA_LOOPBACK_PROC,
  104. &aux_req, sizeof(aux_req), 5 * HZ);
  105. }
  106. EXPORT_SYMBOL(enable_aux_loopback);
  107. static int acoustic_mmap(struct file *file, struct vm_area_struct *vma)
  108. {
  109. unsigned long pgoff;
  110. int rc = -EINVAL;
  111. size_t size;
  112. D("mmap\n");
  113. mutex_lock(&api_lock);
  114. size = vma->vm_end - vma->vm_start;
  115. if (vma->vm_pgoff != 0) {
  116. E("mmap failed: page offset %lx\n", vma->vm_pgoff);
  117. goto done;
  118. }
  119. if (!htc_acoustic_vir_addr) {
  120. E("mmap failed: smem region not allocated\n");
  121. rc = -EIO;
  122. goto done;
  123. }
  124. pgoff = MSM_SHARED_RAM_PHYS +
  125. (htc_acoustic_vir_addr - (uint32_t)MSM_SHARED_RAM_BASE);
  126. pgoff = ((pgoff + 4095) & ~4095);
  127. htc_acoustic_vir_addr = ((htc_acoustic_vir_addr + 4095) & ~4095);
  128. if (pgoff <= 0) {
  129. E("pgoff wrong. %ld\n", pgoff);
  130. goto done;
  131. }
  132. if (size <= HTC_ACOUSTIC_TABLE_SIZE) {
  133. pgoff = pgoff >> PAGE_SHIFT;
  134. } else {
  135. E("size > HTC_ACOUSTIC_TABLE_SIZE %d\n", size);
  136. goto done;
  137. }
  138. vma->vm_flags |= VM_IO | VM_RESERVED;
  139. rc = io_remap_pfn_range(vma, vma->vm_start, pgoff,
  140. size, vma->vm_page_prot);
  141. if (rc < 0)
  142. E("mmap failed: remap error %d\n", rc);
  143. done: mutex_unlock(&api_lock);
  144. return rc;
  145. }
  146. static int acoustic_open(struct inode *inode, struct file *file)
  147. {
  148. int reply_value;
  149. int rc = -EIO;
  150. struct set_smem_req {
  151. struct rpc_request_hdr hdr;
  152. uint32_t size;
  153. } req_smem;
  154. struct set_smem_rep {
  155. struct rpc_reply_hdr hdr;
  156. int n;
  157. } rep_smem;
  158. D("open\n");
  159. mutex_lock(&api_lock);
  160. if (!htc_acoustic_vir_addr) {
  161. if (is_rpc_connect() == -1)
  162. goto done;
  163. req_smem.size = cpu_to_be32(HTC_ACOUSTIC_TABLE_SIZE);
  164. rc = msm_rpc_call_reply(endpoint,
  165. ONCRPC_ALLOC_ACOUSTIC_MEM_PROC,
  166. &req_smem, sizeof(req_smem),
  167. &rep_smem, sizeof(rep_smem),
  168. 5 * HZ);
  169. reply_value = be32_to_cpu(rep_smem.n);
  170. if (reply_value != 0 || rc < 0) {
  171. E("open failed: ALLOC_ACOUSTIC_MEM_PROC error %d.\n",
  172. rc);
  173. goto done;
  174. }
  175. htc_acoustic_vir_addr =
  176. (uint32_t)smem_alloc(SMEM_ID_VENDOR1,
  177. HTC_ACOUSTIC_TABLE_SIZE);
  178. if (!htc_acoustic_vir_addr) {
  179. E("open failed: smem_alloc error\n");
  180. goto done;
  181. }
  182. }
  183. rc = 0;
  184. done:
  185. mutex_unlock(&api_lock);
  186. return rc;
  187. }
  188. static int acoustic_release(struct inode *inode, struct file *file)
  189. {
  190. D("release\n");
  191. return 0;
  192. }
  193. static long acoustic_ioctl(struct file *file, unsigned int cmd,
  194. unsigned long arg)
  195. {
  196. int rc, reply_value;
  197. D("ioctl\n");
  198. mutex_lock(&api_lock);
  199. switch (cmd) {
  200. case ACOUSTIC_UPDATE_ADIE: {
  201. struct update_adie_req {
  202. struct rpc_request_hdr hdr;
  203. int id;
  204. } adie_req;
  205. struct update_adie_rep {
  206. struct rpc_reply_hdr hdr;
  207. int ret;
  208. } adie_rep;
  209. D("ioctl: ACOUSTIC_UPDATE_ADIE called %d.\n", current->pid);
  210. adie_req.id = cpu_to_be32(-1); /* update all codecs */
  211. rc = msm_rpc_call_reply(endpoint,
  212. ONCRPC_UPDATE_ADIE_PROC, &adie_req,
  213. sizeof(adie_req), &adie_rep,
  214. sizeof(adie_rep), 5 * HZ);
  215. reply_value = be32_to_cpu(adie_rep.ret);
  216. if (reply_value != 0 || rc < 0) {
  217. E("ioctl failed: ONCRPC_UPDATE_ADIE_PROC "\
  218. "error %d.\n", rc);
  219. if (rc >= 0)
  220. rc = -EIO;
  221. break;
  222. }
  223. D("ioctl: ONCRPC_UPDATE_ADIE_PROC success.\n");
  224. break;
  225. }
  226. default:
  227. E("ioctl: invalid command\n");
  228. rc = -EINVAL;
  229. }
  230. mutex_unlock(&api_lock);
  231. return rc;
  232. }
  233. struct rpc_set_uplink_mute_args {
  234. int mute;
  235. };
  236. static struct file_operations acoustic_fops = {
  237. .owner = THIS_MODULE,
  238. .open = acoustic_open,
  239. .release = acoustic_release,
  240. .mmap = acoustic_mmap,
  241. .unlocked_ioctl = acoustic_ioctl,
  242. };
  243. static struct miscdevice acoustic_misc = {
  244. .minor = MISC_DYNAMIC_MINOR,
  245. .name = "htc-acoustic",
  246. .fops = &acoustic_fops,
  247. };
  248. static int __init acoustic_init(void)
  249. {
  250. mutex_init(&api_lock);
  251. mutex_init(&rpc_connect_lock);
  252. return misc_register(&acoustic_misc);
  253. }
  254. static void __exit acoustic_exit(void)
  255. {
  256. misc_deregister(&acoustic_misc);
  257. }
  258. module_init(acoustic_init);
  259. module_exit(acoustic_exit);