audio_wmapro.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /* wmapro audio output device
  2. *
  3. * Copyright (C) 2008 Google, Inc.
  4. * Copyright (C) 2008 HTC Corporation
  5. * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
  6. *
  7. * This software is licensed under the terms of the GNU General Public
  8. * License version 2, as published by the Free Software Foundation, and
  9. * may be copied, distributed, and modified under those terms.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. */
  17. #include <linux/types.h>
  18. #include <linux/msm_audio_wmapro.h>
  19. #include <linux/compat.h>
  20. #include "audio_utils_aio.h"
  21. static struct miscdevice audio_wmapro_misc;
  22. static struct ws_mgr audio_wmapro_ws_mgr;
  23. #ifdef CONFIG_DEBUG_FS
  24. static const struct file_operations audio_wmapro_debug_fops = {
  25. .read = audio_aio_debug_read,
  26. .open = audio_aio_debug_open,
  27. };
  28. #endif
  29. static long audio_ioctl_shared(struct file *file, unsigned int cmd,
  30. void *arg)
  31. {
  32. struct q6audio_aio *audio = file->private_data;
  33. int rc = 0;
  34. switch (cmd) {
  35. case AUDIO_START: {
  36. struct asm_wmapro_cfg wmapro_cfg;
  37. struct msm_audio_wmapro_config *wmapro_config;
  38. pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
  39. audio->ac->session);
  40. if (audio->feedback == NON_TUNNEL_MODE) {
  41. /* Configure PCM output block */
  42. rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
  43. audio->pcm_cfg.sample_rate,
  44. audio->pcm_cfg.channel_count,
  45. 16, /* bits per sample */
  46. true, /* use default channel map */
  47. true, /* use back channel map flavor */
  48. NULL);
  49. if (rc < 0) {
  50. pr_err("pcm output block config failed\n");
  51. break;
  52. }
  53. }
  54. wmapro_config = (struct msm_audio_wmapro_config *)
  55. audio->codec_cfg;
  56. if ((wmapro_config->formattag == 0x162) ||
  57. (wmapro_config->formattag == 0x163) ||
  58. (wmapro_config->formattag == 0x166) ||
  59. (wmapro_config->formattag == 0x167)) {
  60. wmapro_cfg.format_tag = wmapro_config->formattag;
  61. } else {
  62. pr_err("%s:AUDIO_START failed: formattag = %d\n",
  63. __func__, wmapro_config->formattag);
  64. rc = -EINVAL;
  65. break;
  66. }
  67. if (wmapro_config->numchannels > 0) {
  68. wmapro_cfg.ch_cfg = wmapro_config->numchannels;
  69. } else {
  70. pr_err("%s:AUDIO_START failed: channels = %d\n",
  71. __func__, wmapro_config->numchannels);
  72. rc = -EINVAL;
  73. break;
  74. }
  75. if (wmapro_config->samplingrate > 0) {
  76. wmapro_cfg.sample_rate = wmapro_config->samplingrate;
  77. } else {
  78. pr_err("%s:AUDIO_START failed: sample_rate = %d\n",
  79. __func__, wmapro_config->samplingrate);
  80. rc = -EINVAL;
  81. break;
  82. }
  83. wmapro_cfg.avg_bytes_per_sec =
  84. wmapro_config->avgbytespersecond;
  85. if ((wmapro_config->asfpacketlength <= 13376) ||
  86. (wmapro_config->asfpacketlength > 0)) {
  87. wmapro_cfg.block_align =
  88. wmapro_config->asfpacketlength;
  89. } else {
  90. pr_err("%s:AUDIO_START failed: block_align = %d\n",
  91. __func__, wmapro_config->asfpacketlength);
  92. rc = -EINVAL;
  93. break;
  94. }
  95. if ((wmapro_config->validbitspersample == 16) ||
  96. (wmapro_config->validbitspersample == 24)) {
  97. wmapro_cfg.valid_bits_per_sample =
  98. wmapro_config->validbitspersample;
  99. } else {
  100. pr_err("%s:AUDIO_START failed: bitspersample = %d\n",
  101. __func__, wmapro_config->validbitspersample);
  102. rc = -EINVAL;
  103. break;
  104. }
  105. wmapro_cfg.ch_mask = wmapro_config->channelmask;
  106. wmapro_cfg.encode_opt = wmapro_config->encodeopt;
  107. wmapro_cfg.adv_encode_opt =
  108. wmapro_config->advancedencodeopt;
  109. wmapro_cfg.adv_encode_opt2 =
  110. wmapro_config->advancedencodeopt2;
  111. /* Configure Media format block */
  112. rc = q6asm_media_format_block_wmapro(audio->ac, &wmapro_cfg,
  113. audio->ac->stream_id);
  114. if (rc < 0) {
  115. pr_err("cmd media format block failed\n");
  116. break;
  117. }
  118. rc = audio_aio_enable(audio);
  119. audio->eos_rsp = 0;
  120. audio->eos_flag = 0;
  121. if (!rc) {
  122. audio->enabled = 1;
  123. } else {
  124. audio->enabled = 0;
  125. pr_err("Audio Start procedure failed rc=%d\n", rc);
  126. break;
  127. }
  128. pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
  129. if (audio->stopped == 1)
  130. audio->stopped = 0;
  131. break;
  132. }
  133. default:
  134. pr_err("%s: Unknown ioctl cmd %d\n", __func__, cmd);
  135. rc = -EINVAL;
  136. break;
  137. }
  138. return rc;
  139. }
  140. static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  141. {
  142. struct q6audio_aio *audio = file->private_data;
  143. int rc = 0;
  144. switch (cmd) {
  145. case AUDIO_GET_WMAPRO_CONFIG: {
  146. if (copy_to_user((void *)arg, audio->codec_cfg,
  147. sizeof(struct msm_audio_wmapro_config))) {
  148. pr_err("%s: copy_to_user for AUDIO_GET_WMAPRO_CONFIG failed\n",
  149. __func__);
  150. rc = -EFAULT;
  151. }
  152. break;
  153. }
  154. case AUDIO_SET_WMAPRO_CONFIG: {
  155. if (copy_from_user(audio->codec_cfg, (void *)arg,
  156. sizeof(struct msm_audio_wmapro_config))) {
  157. pr_err("%s: copy_from_user for AUDIO_SET_WMAPRO_CONFIG_V2 failed\n",
  158. __func__);
  159. rc = -EFAULT;
  160. break;
  161. }
  162. break;
  163. }
  164. case AUDIO_START: {
  165. rc = audio_ioctl_shared(file, cmd, (void *)arg);
  166. break;
  167. }
  168. default: {
  169. pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
  170. rc = audio->codec_ioctl(file, cmd, arg);
  171. if (rc)
  172. pr_err("Failed in utils_ioctl: %d\n", rc);
  173. break;
  174. }
  175. }
  176. return rc;
  177. }
  178. #ifdef CONFIG_COMPAT
  179. struct msm_audio_wmapro_config32 {
  180. u16 armdatareqthr;
  181. u8 validbitspersample;
  182. u8 numchannels;
  183. u16 formattag;
  184. u32 samplingrate;
  185. u32 avgbytespersecond;
  186. u16 asfpacketlength;
  187. u32 channelmask;
  188. u16 encodeopt;
  189. u16 advancedencodeopt;
  190. u32 advancedencodeopt2;
  191. };
  192. enum {
  193. AUDIO_GET_WMAPRO_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
  194. (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_wmapro_config32),
  195. AUDIO_SET_WMAPRO_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
  196. (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_wmapro_config32)
  197. };
  198. static long audio_compat_ioctl(struct file *file, unsigned int cmd,
  199. unsigned long arg)
  200. {
  201. struct q6audio_aio *audio = file->private_data;
  202. int rc = 0;
  203. switch (cmd) {
  204. case AUDIO_GET_WMAPRO_CONFIG_32: {
  205. struct msm_audio_wmapro_config *wmapro_config;
  206. struct msm_audio_wmapro_config32 wmapro_config_32;
  207. memset(&wmapro_config_32, 0, sizeof(wmapro_config_32));
  208. wmapro_config =
  209. (struct msm_audio_wmapro_config *)audio->codec_cfg;
  210. wmapro_config_32.armdatareqthr = wmapro_config->armdatareqthr;
  211. wmapro_config_32.validbitspersample =
  212. wmapro_config->validbitspersample;
  213. wmapro_config_32.numchannels = wmapro_config->numchannels;
  214. wmapro_config_32.formattag = wmapro_config->formattag;
  215. wmapro_config_32.samplingrate = wmapro_config->samplingrate;
  216. wmapro_config_32.avgbytespersecond =
  217. wmapro_config->avgbytespersecond;
  218. wmapro_config_32.asfpacketlength =
  219. wmapro_config->asfpacketlength;
  220. wmapro_config_32.channelmask = wmapro_config->channelmask;
  221. wmapro_config_32.encodeopt = wmapro_config->encodeopt;
  222. wmapro_config_32.advancedencodeopt =
  223. wmapro_config->advancedencodeopt;
  224. wmapro_config_32.advancedencodeopt2 =
  225. wmapro_config->advancedencodeopt2;
  226. if (copy_to_user((void *)arg, &wmapro_config_32,
  227. sizeof(struct msm_audio_wmapro_config32))) {
  228. pr_err("%s: copy_to_user for AUDIO_GET_WMAPRO_CONFIG_V2_32 failed\n",
  229. __func__);
  230. rc = -EFAULT;
  231. }
  232. break;
  233. }
  234. case AUDIO_SET_WMAPRO_CONFIG_32: {
  235. struct msm_audio_wmapro_config *wmapro_config;
  236. struct msm_audio_wmapro_config32 wmapro_config_32;
  237. if (copy_from_user(&wmapro_config_32, (void *)arg,
  238. sizeof(struct msm_audio_wmapro_config32))) {
  239. pr_err(
  240. "%s: copy_from_user for AUDIO_SET_WMAPRO_CONFG_V2_32 failed\n",
  241. __func__);
  242. rc = -EFAULT;
  243. break;
  244. }
  245. wmapro_config =
  246. (struct msm_audio_wmapro_config *)audio->codec_cfg;
  247. wmapro_config->armdatareqthr = wmapro_config_32.armdatareqthr;
  248. wmapro_config->validbitspersample =
  249. wmapro_config_32.validbitspersample;
  250. wmapro_config->numchannels = wmapro_config_32.numchannels;
  251. wmapro_config->formattag = wmapro_config_32.formattag;
  252. wmapro_config->samplingrate = wmapro_config_32.samplingrate;
  253. wmapro_config->avgbytespersecond =
  254. wmapro_config_32.avgbytespersecond;
  255. wmapro_config->asfpacketlength =
  256. wmapro_config_32.asfpacketlength;
  257. wmapro_config->channelmask = wmapro_config_32.channelmask;
  258. wmapro_config->encodeopt = wmapro_config_32.encodeopt;
  259. wmapro_config->advancedencodeopt =
  260. wmapro_config_32.advancedencodeopt;
  261. wmapro_config->advancedencodeopt2 =
  262. wmapro_config_32.advancedencodeopt2;
  263. break;
  264. }
  265. case AUDIO_START: {
  266. rc = audio_ioctl_shared(file, cmd, (void *)arg);
  267. break;
  268. }
  269. default: {
  270. pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
  271. rc = audio->codec_compat_ioctl(file, cmd, arg);
  272. if (rc)
  273. pr_err("Failed in utils_ioctl: %d\n", rc);
  274. break;
  275. }
  276. }
  277. return rc;
  278. }
  279. #else
  280. #define audio_compat_ioctl NULL
  281. #endif
  282. static int audio_open(struct inode *inode, struct file *file)
  283. {
  284. struct q6audio_aio *audio = NULL;
  285. int rc = 0;
  286. #ifdef CONFIG_DEBUG_FS
  287. /* 4 bytes represents decoder number, 1 byte for terminate string */
  288. char name[sizeof "msm_wmapro_" + 5];
  289. #endif
  290. audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
  291. if (audio == NULL)
  292. return -ENOMEM;
  293. audio->codec_cfg = kzalloc(sizeof(struct msm_audio_wmapro_config),
  294. GFP_KERNEL);
  295. if (audio->codec_cfg == NULL) {
  296. kfree(audio);
  297. return -ENOMEM;
  298. }
  299. audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
  300. audio->miscdevice = &audio_wmapro_misc;
  301. audio->wakelock_voted = false;
  302. audio->audio_ws_mgr = &audio_wmapro_ws_mgr;
  303. audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
  304. (void *)audio);
  305. if (!audio->ac) {
  306. pr_err("Could not allocate memory for audio client\n");
  307. kfree(audio->codec_cfg);
  308. kfree(audio);
  309. return -ENOMEM;
  310. }
  311. rc = audio_aio_open(audio, file);
  312. if (rc < 0) {
  313. pr_err("%s: audio_aio_open rc=%d\n",
  314. __func__, rc);
  315. goto fail;
  316. }
  317. /* open in T/NT mode */
  318. if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
  319. rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
  320. FORMAT_WMA_V10PRO);
  321. if (rc < 0) {
  322. pr_err("NT mode Open failed rc=%d\n", rc);
  323. rc = -ENODEV;
  324. goto fail;
  325. }
  326. audio->feedback = NON_TUNNEL_MODE;
  327. /* open WMA decoder, expected frames is always 1*/
  328. audio->buf_cfg.frames_per_buf = 0x01;
  329. audio->buf_cfg.meta_info_enable = 0x01;
  330. } else if ((file->f_mode & FMODE_WRITE) &&
  331. !(file->f_mode & FMODE_READ)) {
  332. rc = q6asm_open_write(audio->ac, FORMAT_WMA_V10PRO);
  333. if (rc < 0) {
  334. pr_err("T mode Open failed rc=%d\n", rc);
  335. rc = -ENODEV;
  336. goto fail;
  337. }
  338. audio->feedback = TUNNEL_MODE;
  339. audio->buf_cfg.meta_info_enable = 0x00;
  340. } else {
  341. pr_err("Not supported mode\n");
  342. rc = -EACCES;
  343. goto fail;
  344. }
  345. #ifdef CONFIG_DEBUG_FS
  346. snprintf(name, sizeof(name), "msm_wmapro_%04x", audio->ac->session);
  347. audio->dentry = debugfs_create_file(name, S_IFREG | 0444,
  348. NULL, (void *)audio,
  349. &audio_wmapro_debug_fops);
  350. if (IS_ERR(audio->dentry))
  351. pr_debug("debugfs_create_file failed\n");
  352. #endif
  353. pr_info("%s:wmapro decoder open success, session_id = %d\n", __func__,
  354. audio->ac->session);
  355. return rc;
  356. fail:
  357. q6asm_audio_client_free(audio->ac);
  358. kfree(audio->codec_cfg);
  359. kfree(audio);
  360. return rc;
  361. }
  362. static const struct file_operations audio_wmapro_fops = {
  363. .owner = THIS_MODULE,
  364. .open = audio_open,
  365. .release = audio_aio_release,
  366. .unlocked_ioctl = audio_ioctl,
  367. .fsync = audio_aio_fsync,
  368. .compat_ioctl = audio_compat_ioctl
  369. };
  370. static struct miscdevice audio_wmapro_misc = {
  371. .minor = MISC_DYNAMIC_MINOR,
  372. .name = "msm_wmapro",
  373. .fops = &audio_wmapro_fops,
  374. };
  375. static int __init audio_wmapro_init(void)
  376. {
  377. int ret = misc_register(&audio_wmapro_misc);
  378. if (ret == 0)
  379. device_init_wakeup(audio_wmapro_misc.this_device, true);
  380. audio_wmapro_ws_mgr.ref_cnt = 0;
  381. mutex_init(&audio_wmapro_ws_mgr.ws_lock);
  382. return ret;
  383. }
  384. device_initcall(audio_wmapro_init);