audio_amrwbplus.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* amr-wbplus audio output device
  3. *
  4. * Copyright (C) 2008 Google, Inc.
  5. * Copyright (C) 2008 HTC Corporation
  6. * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
  7. */
  8. #include <linux/msm_audio_amrwbplus.h>
  9. #include <linux/compat.h>
  10. #include "audio_utils_aio.h"
  11. static struct miscdevice audio_amrwbplus_misc;
  12. static struct ws_mgr audio_amrwbplus_ws_mgr;
  13. #ifdef CONFIG_DEBUG_FS
  14. static const struct file_operations audio_amrwbplus_debug_fops = {
  15. .read = audio_aio_debug_read,
  16. .open = audio_aio_debug_open,
  17. };
  18. static void config_debug_fs(struct q6audio_aio *audio)
  19. {
  20. if (audio != NULL) {
  21. char name[sizeof("msm_amrwbplus_") + 5];
  22. snprintf(name, sizeof(name), "msm_amrwbplus_%04x",
  23. audio->ac->session);
  24. audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
  25. NULL, (void *)audio,
  26. &audio_amrwbplus_debug_fops);
  27. if (IS_ERR(audio->dentry))
  28. pr_debug("debugfs_create_file failed\n");
  29. }
  30. }
  31. #else
  32. static void config_debug_fs(struct q6audio_aio *audio)
  33. {
  34. }
  35. #endif
  36. static long audio_ioctl_shared(struct file *file, unsigned int cmd,
  37. void *arg)
  38. {
  39. struct asm_amrwbplus_cfg q6_amrwbplus_cfg;
  40. struct msm_audio_amrwbplus_config_v2 *amrwbplus_drv_config;
  41. struct q6audio_aio *audio = file->private_data;
  42. int rc = 0;
  43. switch (cmd) {
  44. case AUDIO_START:
  45. pr_err("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
  46. audio, audio->ac->session);
  47. if (audio->feedback == NON_TUNNEL_MODE) {
  48. /* Configure PCM output block */
  49. rc = q6asm_enc_cfg_blk_pcm(audio->ac,
  50. audio->pcm_cfg.sample_rate,
  51. audio->pcm_cfg.channel_count);
  52. if (rc < 0) {
  53. pr_err("pcm output block config failed\n");
  54. break;
  55. }
  56. }
  57. amrwbplus_drv_config =
  58. (struct msm_audio_amrwbplus_config_v2 *)audio->codec_cfg;
  59. q6_amrwbplus_cfg.size_bytes =
  60. amrwbplus_drv_config->size_bytes;
  61. q6_amrwbplus_cfg.version =
  62. amrwbplus_drv_config->version;
  63. q6_amrwbplus_cfg.num_channels =
  64. amrwbplus_drv_config->num_channels;
  65. q6_amrwbplus_cfg.amr_band_mode =
  66. amrwbplus_drv_config->amr_band_mode;
  67. q6_amrwbplus_cfg.amr_dtx_mode =
  68. amrwbplus_drv_config->amr_dtx_mode;
  69. q6_amrwbplus_cfg.amr_frame_fmt =
  70. amrwbplus_drv_config->amr_frame_fmt;
  71. q6_amrwbplus_cfg.amr_lsf_idx =
  72. amrwbplus_drv_config->amr_lsf_idx;
  73. rc = q6asm_media_format_block_amrwbplus(audio->ac,
  74. &q6_amrwbplus_cfg);
  75. if (rc < 0) {
  76. pr_err("q6asm_media_format_block_amrwb+ failed...\n");
  77. break;
  78. }
  79. rc = audio_aio_enable(audio);
  80. audio->eos_rsp = 0;
  81. audio->eos_flag = 0;
  82. if (!rc) {
  83. audio->enabled = 1;
  84. } else {
  85. audio->enabled = 0;
  86. pr_err("Audio Start procedure failed rc=%d\n", rc);
  87. break;
  88. }
  89. pr_debug("%s:AUDIO_START sessionid[%d]enable[%d]\n", __func__,
  90. audio->ac->session,
  91. audio->enabled);
  92. if (audio->stopped == 1)
  93. audio->stopped = 0;
  94. break;
  95. default:
  96. pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
  97. rc = -EINVAL;
  98. break;
  99. }
  100. return rc;
  101. }
  102. static long audio_ioctl(struct file *file, unsigned int cmd,
  103. unsigned long arg)
  104. {
  105. struct q6audio_aio *audio = file->private_data;
  106. int rc = 0;
  107. switch (cmd) {
  108. case AUDIO_START: {
  109. rc = audio_ioctl_shared(file, cmd, (void *)arg);
  110. break;
  111. }
  112. case AUDIO_GET_AMRWBPLUS_CONFIG_V2: {
  113. if ((audio) && (arg) && (audio->codec_cfg)) {
  114. if (copy_to_user((void *)arg, audio->codec_cfg,
  115. sizeof(struct msm_audio_amrwbplus_config_v2))) {
  116. rc = -EFAULT;
  117. pr_err("%s: copy_to_user for AUDIO_GET_AMRWBPLUS_CONFIG_V2 failed\n",
  118. __func__);
  119. break;
  120. }
  121. } else {
  122. pr_err("%s: wb+ config v2 invalid parameters\n"
  123. , __func__);
  124. rc = -EFAULT;
  125. break;
  126. }
  127. break;
  128. }
  129. case AUDIO_SET_AMRWBPLUS_CONFIG_V2: {
  130. if ((audio) && (arg) && (audio->codec_cfg)) {
  131. if (copy_from_user(audio->codec_cfg, (void *)arg,
  132. sizeof(struct msm_audio_amrwbplus_config_v2))) {
  133. rc = -EFAULT;
  134. pr_err("%s: copy_from_user for AUDIO_SET_AMRWBPLUS_CONFIG_V2 failed\n",
  135. __func__);
  136. break;
  137. }
  138. } else {
  139. pr_err("%s: wb+ config invalid parameters\n",
  140. __func__);
  141. rc = -EFAULT;
  142. break;
  143. }
  144. break;
  145. }
  146. default: {
  147. pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
  148. rc = audio->codec_ioctl(file, cmd, arg);
  149. break;
  150. }
  151. }
  152. return rc;
  153. }
  154. #ifdef CONFIG_COMPAT
  155. struct msm_audio_amrwbplus_config_v2_32 {
  156. u32 size_bytes;
  157. u32 version;
  158. u32 num_channels;
  159. u32 amr_band_mode;
  160. u32 amr_dtx_mode;
  161. u32 amr_frame_fmt;
  162. u32 amr_lsf_idx;
  163. };
  164. enum {
  165. AUDIO_GET_AMRWBPLUS_CONFIG_V2_32 = _IOR(AUDIO_IOCTL_MAGIC,
  166. (AUDIO_MAX_COMMON_IOCTL_NUM+2),
  167. struct msm_audio_amrwbplus_config_v2_32),
  168. AUDIO_SET_AMRWBPLUS_CONFIG_V2_32 = _IOW(AUDIO_IOCTL_MAGIC,
  169. (AUDIO_MAX_COMMON_IOCTL_NUM+3),
  170. struct msm_audio_amrwbplus_config_v2_32)
  171. };
  172. static long audio_compat_ioctl(struct file *file, unsigned int cmd,
  173. unsigned long arg)
  174. {
  175. struct q6audio_aio *audio = file->private_data;
  176. int rc = 0;
  177. switch (cmd) {
  178. case AUDIO_START: {
  179. rc = audio_ioctl_shared(file, cmd, (void *)arg);
  180. break;
  181. }
  182. case AUDIO_GET_AMRWBPLUS_CONFIG_V2_32: {
  183. if (audio && arg && (audio->codec_cfg)) {
  184. struct msm_audio_amrwbplus_config_v2 *amrwbplus_config;
  185. struct msm_audio_amrwbplus_config_v2_32
  186. amrwbplus_config_32;
  187. memset(&amrwbplus_config_32, 0,
  188. sizeof(amrwbplus_config_32));
  189. amrwbplus_config =
  190. (struct msm_audio_amrwbplus_config_v2 *)
  191. audio->codec_cfg;
  192. amrwbplus_config_32.size_bytes =
  193. amrwbplus_config->size_bytes;
  194. amrwbplus_config_32.version =
  195. amrwbplus_config->version;
  196. amrwbplus_config_32.num_channels =
  197. amrwbplus_config->num_channels;
  198. amrwbplus_config_32.amr_band_mode =
  199. amrwbplus_config->amr_band_mode;
  200. amrwbplus_config_32.amr_dtx_mode =
  201. amrwbplus_config->amr_dtx_mode;
  202. amrwbplus_config_32.amr_frame_fmt =
  203. amrwbplus_config->amr_frame_fmt;
  204. amrwbplus_config_32.amr_lsf_idx =
  205. amrwbplus_config->amr_lsf_idx;
  206. if (copy_to_user((void *)arg, &amrwbplus_config_32,
  207. sizeof(amrwbplus_config_32))) {
  208. rc = -EFAULT;
  209. pr_err("%s: copy_to_user for AUDIO_GET_AMRWBPLUS_CONFIG_V2_32 failed\n"
  210. , __func__);
  211. }
  212. } else {
  213. pr_err("%s: wb+ Get config v2 invalid parameters\n"
  214. , __func__);
  215. rc = -EFAULT;
  216. }
  217. break;
  218. }
  219. case AUDIO_SET_AMRWBPLUS_CONFIG_V2_32: {
  220. if ((audio) && (arg) && (audio->codec_cfg)) {
  221. struct msm_audio_amrwbplus_config_v2 *amrwbplus_config;
  222. struct msm_audio_amrwbplus_config_v2_32
  223. amrwbplus_config_32;
  224. if (copy_from_user(&amrwbplus_config_32, (void *)arg,
  225. sizeof(struct msm_audio_amrwbplus_config_v2_32))) {
  226. rc = -EFAULT;
  227. pr_err("%s: copy_from_user for AUDIO_SET_AMRWBPLUS_CONFIG_V2_32 failed\n"
  228. , __func__);
  229. break;
  230. }
  231. amrwbplus_config =
  232. (struct msm_audio_amrwbplus_config_v2 *)
  233. audio->codec_cfg;
  234. amrwbplus_config->size_bytes =
  235. amrwbplus_config_32.size_bytes;
  236. amrwbplus_config->version =
  237. amrwbplus_config_32.version;
  238. amrwbplus_config->num_channels =
  239. amrwbplus_config_32.num_channels;
  240. amrwbplus_config->amr_band_mode =
  241. amrwbplus_config_32.amr_band_mode;
  242. amrwbplus_config->amr_dtx_mode =
  243. amrwbplus_config_32.amr_dtx_mode;
  244. amrwbplus_config->amr_frame_fmt =
  245. amrwbplus_config_32.amr_frame_fmt;
  246. amrwbplus_config->amr_lsf_idx =
  247. amrwbplus_config_32.amr_lsf_idx;
  248. } else {
  249. pr_err("%s: wb+ config invalid parameters\n",
  250. __func__);
  251. rc = -EFAULT;
  252. }
  253. break;
  254. }
  255. default: {
  256. pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
  257. rc = audio->codec_compat_ioctl(file, cmd, arg);
  258. break;
  259. }
  260. }
  261. return rc;
  262. }
  263. #else
  264. #define audio_compat_ioctl NULL
  265. #endif
  266. static int audio_open(struct inode *inode, struct file *file)
  267. {
  268. struct q6audio_aio *audio = NULL;
  269. int rc = 0;
  270. audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
  271. if (audio == NULL)
  272. return -ENOMEM;
  273. audio->codec_cfg =
  274. kzalloc(sizeof(struct msm_audio_amrwbplus_config_v2), GFP_KERNEL);
  275. if (audio->codec_cfg == NULL) {
  276. kfree(audio);
  277. return -ENOMEM;
  278. }
  279. audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
  280. audio->miscdevice = &audio_amrwbplus_misc;
  281. audio->wakelock_voted = false;
  282. audio->audio_ws_mgr = &audio_amrwbplus_ws_mgr;
  283. audio->ac =
  284. q6asm_audio_client_alloc((app_cb) q6_audio_cb, (void *)audio);
  285. if (!audio->ac) {
  286. pr_err("Could not allocate memory for audio client\n");
  287. kfree(audio->codec_cfg);
  288. kfree(audio);
  289. return -ENOMEM;
  290. }
  291. rc = audio_aio_open(audio, file);
  292. if (rc < 0) {
  293. pr_err("%s: audio_aio_open rc=%d\n",
  294. __func__, rc);
  295. goto fail;
  296. }
  297. /* open in T/NT mode */
  298. if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
  299. rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
  300. FORMAT_AMR_WB_PLUS);
  301. if (rc < 0) {
  302. pr_err("amrwbplus NT mode Open failed rc=%d\n", rc);
  303. rc = -ENODEV;
  304. goto fail;
  305. }
  306. audio->feedback = NON_TUNNEL_MODE;
  307. audio->buf_cfg.frames_per_buf = 0x01;
  308. audio->buf_cfg.meta_info_enable = 0x01;
  309. } else if ((file->f_mode & FMODE_WRITE) &&
  310. !(file->f_mode & FMODE_READ)) {
  311. rc = q6asm_open_write(audio->ac, FORMAT_AMR_WB_PLUS);
  312. if (rc < 0) {
  313. pr_err("wb+ T mode Open failed rc=%d\n", rc);
  314. rc = -ENODEV;
  315. goto fail;
  316. }
  317. audio->feedback = TUNNEL_MODE;
  318. audio->buf_cfg.meta_info_enable = 0x00;
  319. } else {
  320. pr_err("audio_amrwbplus Not supported mode\n");
  321. rc = -EACCES;
  322. goto fail;
  323. }
  324. config_debug_fs(audio);
  325. pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
  326. audio->feedback,
  327. audio->ac->session);
  328. return 0;
  329. fail:
  330. q6asm_audio_client_free(audio->ac);
  331. kfree(audio->codec_cfg);
  332. kfree(audio);
  333. return rc;
  334. }
  335. static const struct file_operations audio_amrwbplus_fops = {
  336. .owner = THIS_MODULE,
  337. .open = audio_open,
  338. .release = audio_aio_release,
  339. .unlocked_ioctl = audio_ioctl,
  340. .fsync = audio_aio_fsync,
  341. .compat_ioctl = audio_compat_ioctl
  342. };
  343. static struct miscdevice audio_amrwbplus_misc = {
  344. .minor = MISC_DYNAMIC_MINOR,
  345. .name = "msm_amrwbplus",
  346. .fops = &audio_amrwbplus_fops,
  347. };
  348. int __init audio_amrwbplus_init(void)
  349. {
  350. int ret = misc_register(&audio_amrwbplus_misc);
  351. if (ret == 0)
  352. device_init_wakeup(audio_amrwbplus_misc.this_device, true);
  353. audio_amrwbplus_ws_mgr.ref_cnt = 0;
  354. mutex_init(&audio_amrwbplus_ws_mgr.ws_lock);
  355. return ret;
  356. }
  357. void audio_amrwbplus_exit(void)
  358. {
  359. mutex_destroy(&audio_amrwbplus_ws_mgr.ws_lock);
  360. misc_deregister(&audio_amrwbplus_misc);
  361. }