/arch/arm/mach-msm/qdsp6v2/pcm_in.c

https://bitbucket.org/sammyz/iscream_thunderc-2.6.35-rebase · C · 408 lines · 345 code · 47 blank · 16 comment · 35 complexity · 7312121065e2b066ba14e823da094045 MD5 · raw file

  1. /*
  2. * Copyright (C) 2009 Google, Inc.
  3. * Copyright (C) 2009 HTC Corporation
  4. * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
  5. *
  6. * This software is licensed under the terms of the GNU General Public
  7. * License version 2, as published by the Free Software Foundation, and
  8. * may be copied, distributed, and modified under those terms.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. */
  16. #include <linux/fs.h>
  17. #include <linux/module.h>
  18. #include <linux/miscdevice.h>
  19. #include <linux/mutex.h>
  20. #include <linux/sched.h>
  21. #include <linux/uaccess.h>
  22. #include <linux/spinlock.h>
  23. #include <linux/slab.h>
  24. #include <linux/wait.h>
  25. #include <linux/msm_audio.h>
  26. #include <asm/atomic.h>
  27. #include <mach/debug_mm.h>
  28. #include <mach/qdsp6v2/audio_dev_ctl.h>
  29. #include <mach/qdsp6v2/apr_audio.h>
  30. #include <mach/qdsp6v2/q6asm.h>
  31. #define MAX_BUF 2
  32. #define BUFSZ (480 * 8)
  33. struct pcm {
  34. struct mutex lock;
  35. struct mutex read_lock;
  36. wait_queue_head_t wait;
  37. spinlock_t dsp_lock;
  38. struct audio_client *ac;
  39. uint32_t sample_rate;
  40. uint32_t channel_count;
  41. uint32_t buffer_size;
  42. uint32_t buffer_count;
  43. uint32_t rec_mode;
  44. uint32_t in_frame_info[MAX_BUF][2];
  45. atomic_t in_count;
  46. atomic_t in_enabled;
  47. atomic_t in_opened;
  48. atomic_t in_stopped;
  49. };
  50. static void pcm_in_get_dsp_buffers(struct pcm*,
  51. uint32_t token, uint32_t *payload);
  52. void pcm_in_cb(uint32_t opcode, uint32_t token,
  53. uint32_t *payload, void *priv)
  54. {
  55. struct pcm *pcm = (struct pcm *) priv;
  56. unsigned long flags;
  57. spin_lock_irqsave(&pcm->dsp_lock, flags);
  58. switch (opcode) {
  59. case ASM_DATA_EVENT_READ_DONE:
  60. pcm_in_get_dsp_buffers(pcm, token, payload);
  61. break;
  62. default:
  63. break;
  64. }
  65. spin_unlock_irqrestore(&pcm->dsp_lock, flags);
  66. }
  67. static void pcm_in_get_dsp_buffers(struct pcm *pcm,
  68. uint32_t token, uint32_t *payload)
  69. {
  70. pcm->in_frame_info[token][0] = payload[7];
  71. pcm->in_frame_info[token][1] = payload[3];
  72. if (atomic_read(&pcm->in_count) <= pcm->buffer_count)
  73. atomic_inc(&pcm->in_count);
  74. wake_up(&pcm->wait);
  75. }
  76. static int pcm_in_enable(struct pcm *pcm)
  77. {
  78. if (atomic_read(&pcm->in_enabled))
  79. return 0;
  80. return q6asm_run(pcm->ac, 0, 0, 0);
  81. }
  82. static int pcm_in_disable(struct pcm *pcm)
  83. {
  84. int rc = 0;
  85. if (atomic_read(&pcm->in_opened)) {
  86. atomic_set(&pcm->in_enabled, 0);
  87. atomic_set(&pcm->in_opened, 0);
  88. rc = q6asm_cmd(pcm->ac, CMD_CLOSE);
  89. atomic_set(&pcm->in_stopped, 1);
  90. memset(pcm->in_frame_info, 0,
  91. sizeof(char) * pcm->buffer_count * 2);
  92. wake_up(&pcm->wait);
  93. }
  94. return rc;
  95. }
  96. static int config(struct pcm *pcm)
  97. {
  98. int rc = 0;
  99. pr_debug("%s: pcm prefill\n", __func__);
  100. rc = q6asm_audio_client_buf_alloc(OUT, pcm->ac,
  101. pcm->buffer_size, pcm->buffer_count);
  102. if (rc < 0) {
  103. pr_err("Audio Start: Buffer Allocation failed \
  104. rc = %d\n", rc);
  105. goto fail;
  106. }
  107. rc = q6asm_enc_cfg_blk_pcm(pcm->ac, pcm->sample_rate,
  108. pcm->channel_count);
  109. if (rc < 0) {
  110. pr_err("%s: cmd media format block failed", __func__);
  111. goto fail;
  112. }
  113. fail:
  114. return rc;
  115. }
  116. static long pcm_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  117. {
  118. struct pcm *pcm = file->private_data;
  119. int rc = 0;
  120. mutex_lock(&pcm->lock);
  121. switch (cmd) {
  122. case AUDIO_SET_VOLUME:
  123. break;
  124. case AUDIO_GET_STATS: {
  125. struct msm_audio_stats stats;
  126. memset(&stats, 0, sizeof(stats));
  127. if (copy_to_user((void *) arg, &stats, sizeof(stats)))
  128. rc = -EFAULT;
  129. break;
  130. }
  131. case AUDIO_START: {
  132. int cnt = 0;
  133. if (atomic_read(&pcm->in_enabled)) {
  134. pr_info("%s:AUDIO_START already over\n", __func__);
  135. rc = 0;
  136. break;
  137. }
  138. rc = config(pcm);
  139. if (rc) {
  140. pr_err("%s: IN Configuration failed\n", __func__);
  141. rc = -EFAULT;
  142. break;
  143. }
  144. rc = pcm_in_enable(pcm);
  145. if (rc) {
  146. pr_err("%s: In Enable failed\n", __func__);
  147. rc = -EFAULT;
  148. break;
  149. }
  150. atomic_set(&pcm->in_enabled, 1);
  151. while (cnt++ < pcm->buffer_count)
  152. q6asm_read(pcm->ac);
  153. pr_info("%s: AUDIO_START session id[%d]\n", __func__,
  154. pcm->ac->session);
  155. break;
  156. }
  157. case AUDIO_GET_SESSION_ID: {
  158. if (copy_to_user((void *) arg, &pcm->ac->session,
  159. sizeof(unsigned short)))
  160. rc = -EFAULT;
  161. break;
  162. }
  163. case AUDIO_STOP:
  164. break;
  165. case AUDIO_FLUSH:
  166. break;
  167. case AUDIO_SET_CONFIG: {
  168. struct msm_audio_config config;
  169. if (copy_from_user(&config, (void *) arg, sizeof(config))) {
  170. rc = -EFAULT;
  171. break;
  172. }
  173. pr_debug("%s: buffer_size:%d channel_count:%d sample_rate:%d \
  174. buffer_count:%d\n", __func__, config.buffer_size,
  175. config.channel_count, config.sample_rate,
  176. config.buffer_count);
  177. if (!config.channel_count || config.channel_count > 2) {
  178. rc = -EINVAL;
  179. break;
  180. }
  181. if (config.sample_rate < 8000 || config.sample_rate > 48000) {
  182. rc = -EINVAL;
  183. break;
  184. }
  185. if (config.buffer_size % (config.channel_count * 480)) {
  186. pr_err("%s: Buffer Size should be multiple of \
  187. [480 * no. of channels]\n", __func__);
  188. rc = -EINVAL;
  189. break;
  190. }
  191. pcm->sample_rate = config.sample_rate;
  192. pcm->channel_count = config.channel_count;
  193. pcm->buffer_size = config.buffer_size;
  194. pcm->buffer_count = config.buffer_count;
  195. break;
  196. }
  197. case AUDIO_GET_CONFIG: {
  198. struct msm_audio_config config;
  199. config.buffer_size = pcm->buffer_size;
  200. config.buffer_count = pcm->buffer_count;
  201. config.sample_rate = pcm->sample_rate;
  202. config.channel_count = pcm->channel_count;
  203. config.unused[0] = 0;
  204. config.unused[1] = 0;
  205. config.unused[2] = 0;
  206. if (copy_to_user((void *) arg, &config, sizeof(config)))
  207. rc = -EFAULT;
  208. break;
  209. }
  210. case AUDIO_ENABLE_AUDPRE: {
  211. uint16_t enable_mask;
  212. if (copy_from_user(&enable_mask, (void *) arg,
  213. sizeof(enable_mask))) {
  214. rc = -EFAULT;
  215. break;
  216. }
  217. if (enable_mask & FLUENCE_ENABLE)
  218. rc = auddev_cfg_tx_copp_topology(pcm->ac->session,
  219. VPM_TX_DM_FLUENCE_COPP_TOPOLOGY);
  220. else
  221. rc = auddev_cfg_tx_copp_topology(pcm->ac->session,
  222. DEFAULT_COPP_TOPOLOGY);
  223. break;
  224. }
  225. default:
  226. rc = -EINVAL;
  227. break;
  228. }
  229. mutex_unlock(&pcm->lock);
  230. return rc;
  231. }
  232. static int pcm_in_open(struct inode *inode, struct file *file)
  233. {
  234. struct pcm *pcm;
  235. int rc = 0;
  236. pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
  237. if (!pcm)
  238. return -ENOMEM;
  239. pcm->channel_count = 1;
  240. pcm->sample_rate = 8000;
  241. pcm->buffer_size = BUFSZ;
  242. pcm->buffer_count = MAX_BUF;
  243. pcm->ac = q6asm_audio_client_alloc((app_cb)pcm_in_cb, (void *)pcm);
  244. if (!pcm->ac) {
  245. pr_err("%s: Could not allocate memory\n", __func__);
  246. rc = -ENOMEM;
  247. goto fail;
  248. }
  249. mutex_init(&pcm->lock);
  250. mutex_init(&pcm->read_lock);
  251. spin_lock_init(&pcm->dsp_lock);
  252. init_waitqueue_head(&pcm->wait);
  253. rc = q6asm_open_read(pcm->ac, FORMAT_LINEAR_PCM);
  254. if (rc < 0) {
  255. pr_err("%s: Cmd Open Failed\n", __func__);
  256. goto fail;
  257. }
  258. atomic_set(&pcm->in_stopped, 0);
  259. atomic_set(&pcm->in_enabled, 0);
  260. atomic_set(&pcm->in_count, 0);
  261. atomic_set(&pcm->in_opened, 1);
  262. file->private_data = pcm;
  263. pr_info("%s: pcm in open session id[%d]\n", __func__, pcm->ac->session);
  264. return 0;
  265. fail:
  266. if (pcm->ac)
  267. q6asm_audio_client_free(pcm->ac);
  268. kfree(pcm);
  269. return rc;
  270. }
  271. static ssize_t pcm_in_read(struct file *file, char __user *buf,
  272. size_t count, loff_t *pos)
  273. {
  274. struct pcm *pcm = file->private_data;
  275. const char __user *start = buf;
  276. void *data;
  277. uint32_t offset = 0;
  278. uint32_t size = 0;
  279. uint32_t idx;
  280. int rc = 0;
  281. if (!atomic_read(&pcm->in_enabled))
  282. return -EFAULT;
  283. mutex_lock(&pcm->read_lock);
  284. while (count > 0) {
  285. rc = wait_event_timeout(pcm->wait,
  286. (atomic_read(&pcm->in_count) ||
  287. atomic_read(&pcm->in_stopped)), 5 * HZ);
  288. if (!rc) {
  289. pr_err("%s: wait_event_timeout failed\n", __func__);
  290. goto fail;
  291. }
  292. if (atomic_read(&pcm->in_stopped) &&
  293. !atomic_read(&pcm->in_count)) {
  294. mutex_unlock(&pcm->read_lock);
  295. return 0;
  296. }
  297. data = q6asm_is_cpu_buf_avail(OUT, pcm->ac, &size, &idx);
  298. if ((count >= size) && data) {
  299. offset = pcm->in_frame_info[idx][1];
  300. if (copy_to_user(buf, data+offset, size)) {
  301. pr_err("%s copy_to_user failed\n", __func__);
  302. rc = -EFAULT;
  303. goto fail;
  304. }
  305. count -= size;
  306. buf += size;
  307. atomic_dec(&pcm->in_count);
  308. memset(&pcm->in_frame_info[idx], 0,
  309. sizeof(uint32_t) * 2);
  310. rc = q6asm_read(pcm->ac);
  311. if (rc < 0) {
  312. pr_err("%s q6asm_read faile\n", __func__);
  313. goto fail;
  314. }
  315. rmb();
  316. break;
  317. } else {
  318. pr_err("%s: short read data[%p] size[%d]\n",\
  319. __func__, data, size);
  320. break;
  321. }
  322. }
  323. rc = buf-start;
  324. fail:
  325. mutex_unlock(&pcm->read_lock);
  326. return rc;
  327. }
  328. static int pcm_in_release(struct inode *inode, struct file *file)
  329. {
  330. int rc = 0;
  331. struct pcm *pcm = file->private_data;
  332. pr_info("[%s:%s] release session id[%d]\n", __MM_FILE__,
  333. __func__, pcm->ac->session);
  334. mutex_lock(&pcm->lock);
  335. /* remove this session from topology list */
  336. auddev_cfg_tx_copp_topology(pcm->ac->session,
  337. DEFAULT_COPP_TOPOLOGY);
  338. mutex_unlock(&pcm->lock);
  339. rc = pcm_in_disable(pcm);
  340. msm_clear_session_id(pcm->ac->session);
  341. q6asm_audio_client_free(pcm->ac);
  342. kfree(pcm);
  343. return rc;
  344. }
  345. static const struct file_operations pcm_in_fops = {
  346. .owner = THIS_MODULE,
  347. .open = pcm_in_open,
  348. .read = pcm_in_read,
  349. .release = pcm_in_release,
  350. .unlocked_ioctl = pcm_in_ioctl,
  351. };
  352. struct miscdevice pcm_in_misc = {
  353. .minor = MISC_DYNAMIC_MINOR,
  354. .name = "msm_pcm_in",
  355. .fops = &pcm_in_fops,
  356. };
  357. static int __init pcm_in_init(void)
  358. {
  359. return misc_register(&pcm_in_misc);
  360. }
  361. device_initcall(pcm_in_init);