msm7kv2-dsp.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /* Copyright (C) 2008 Google, Inc.
  2. * Copyright (C) 2008 HTC Corporation
  3. * Copyright (c) 2008-2010, The Linux Foundation. All rights reserved.
  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.
  12. *
  13. * See the GNU General Public License for more details.
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, you can find it at http://www.fsf.org.
  16. */
  17. #include <linux/init.h>
  18. #include <linux/err.h>
  19. #include <linux/module.h>
  20. #include <linux/moduleparam.h>
  21. #include <linux/time.h>
  22. #include <linux/wait.h>
  23. #include <linux/platform_device.h>
  24. #include <sound/core.h>
  25. #include <sound/soc.h>
  26. #include <sound/pcm.h>
  27. #include <sound/initval.h>
  28. #include <asm/dma.h>
  29. #include <linux/dma-mapping.h>
  30. #include <mach/qdsp5v2/audio_dev_ctl.h>
  31. #include <mach/debug_mm.h>
  32. #include "msm7kv2-pcm.h"
  33. /* Audrec Queue command sent macro's */
  34. #define audrec_send_bitstreamqueue(audio, cmd, len) \
  35. msm_adsp_write(audio->audrec, ((audio->queue_id & 0xFFFF0000) >> 16),\
  36. cmd, len)
  37. #define audrec_send_audrecqueue(audio, cmd, len) \
  38. msm_adsp_write(audio->audrec, (audio->queue_id & 0x0000FFFF),\
  39. cmd, len)
  40. static int alsa_dsp_read_buffer(struct msm_audio *audio,
  41. uint32_t read_cnt);
  42. static void alsa_get_dsp_frames(struct msm_audio *prtd);
  43. static int alsa_in_param_config(struct msm_audio *audio);
  44. static int alsa_in_mem_config(struct msm_audio *audio);
  45. static int alsa_in_enc_config(struct msm_audio *audio, int enable);
  46. int intcnt;
  47. struct audio_frame {
  48. uint16_t count_low;
  49. uint16_t count_high;
  50. uint16_t bytes;
  51. uint16_t unknown;
  52. unsigned char samples[];
  53. } __attribute__ ((packed));
  54. void alsa_dsp_event(void *data, unsigned id, uint16_t *msg)
  55. {
  56. struct msm_audio *prtd = data;
  57. struct buffer *frame;
  58. unsigned long flag = 0;
  59. MM_DBG("\n");
  60. switch (id) {
  61. case AUDPP_MSG_HOST_PCM_INTF_MSG: {
  62. unsigned id = msg[3];
  63. unsigned idx = msg[4] - 1;
  64. MM_DBG("HOST_PCM id %d idx %d\n", id, idx);
  65. if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
  66. MM_ERR("bogus id\n");
  67. break;
  68. }
  69. if (idx > 1) {
  70. MM_ERR("bogus buffer idx\n");
  71. break;
  72. }
  73. /* Update with actual sent buffer size */
  74. if (prtd->out[idx].used != BUF_INVALID_LEN)
  75. prtd->pcm_irq_pos += prtd->out[idx].used;
  76. if (prtd->pcm_irq_pos > prtd->pcm_size)
  77. prtd->pcm_irq_pos = prtd->pcm_count;
  78. if (prtd->ops->playback)
  79. prtd->ops->playback(prtd);
  80. if (prtd->mmap_flag)
  81. break;
  82. spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
  83. if (prtd->running) {
  84. prtd->out[idx].used = 0;
  85. frame = prtd->out + prtd->out_tail;
  86. if (frame->used) {
  87. alsa_dsp_send_buffer(
  88. prtd, prtd->out_tail, frame->used);
  89. /* Reset eos_ack flag to avoid stale
  90. * PCMDMAMISS been considered
  91. */
  92. prtd->eos_ack = 0;
  93. prtd->out_tail ^= 1;
  94. } else {
  95. prtd->out_needed++;
  96. }
  97. wake_up(&the_locks.write_wait);
  98. }
  99. spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
  100. break;
  101. }
  102. case AUDPP_MSG_PCMDMAMISSED:
  103. MM_INFO("PCMDMAMISSED %d\n", msg[0]);
  104. prtd->eos_ack++;
  105. MM_DBG("PCMDMAMISSED Count per Buffer %d\n", prtd->eos_ack);
  106. wake_up(&the_locks.eos_wait);
  107. break;
  108. case AUDPP_MSG_CFG_MSG:
  109. if (msg[0] == AUDPP_MSG_ENA_ENA) {
  110. MM_DBG("CFG_MSG ENABLE\n");
  111. prtd->out_needed = 0;
  112. prtd->running = 1;
  113. audpp_dsp_set_vol_pan(prtd->session_id, &prtd->vol_pan,
  114. POPP);
  115. audpp_route_stream(prtd->session_id,
  116. msm_snddev_route_dec(prtd->session_id));
  117. audio_dsp_out_enable(prtd, 1);
  118. } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
  119. MM_DBG("CFG_MSG DISABLE\n");
  120. prtd->running = 0;
  121. } else {
  122. MM_DBG("CFG_MSG %d?\n", msg[0]);
  123. }
  124. break;
  125. default:
  126. MM_DBG("UNKNOWN (%d)\n", id);
  127. }
  128. }
  129. static void audpreproc_dsp_event(void *data, unsigned id, void *msg)
  130. {
  131. struct msm_audio *prtd = data;
  132. switch (id) {
  133. case AUDPREPROC_ERROR_MSG: {
  134. struct audpreproc_err_msg *err_msg = msg;
  135. MM_ERR("ERROR_MSG: stream id %d err idx %d\n",
  136. err_msg->stream_id, err_msg->aud_preproc_err_idx);
  137. /* Error case */
  138. break;
  139. }
  140. case AUDPREPROC_CMD_CFG_DONE_MSG: {
  141. MM_DBG("CMD_CFG_DONE_MSG\n");
  142. break;
  143. }
  144. case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
  145. struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg;
  146. MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
  147. 0x%8x\n", enc_cfg_msg->stream_id,
  148. enc_cfg_msg->rec_enc_type);
  149. /* Encoder enable success */
  150. if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE)
  151. alsa_in_param_config(prtd);
  152. else { /* Encoder disable success */
  153. prtd->running = 0;
  154. alsa_in_record_config(prtd, 0);
  155. }
  156. break;
  157. }
  158. case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
  159. MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG\n");
  160. alsa_in_mem_config(prtd);
  161. break;
  162. }
  163. case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
  164. MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG\n");
  165. wake_up(&the_locks.enable_wait);
  166. break;
  167. }
  168. default:
  169. MM_DBG("Unknown Event id %d\n", id);
  170. }
  171. }
  172. static void audrec_dsp_event(void *data, unsigned id, size_t len,
  173. void (*getevent) (void *ptr, size_t len))
  174. {
  175. struct msm_audio *prtd = data;
  176. unsigned long flag = 0;
  177. switch (id) {
  178. case AUDREC_CMD_MEM_CFG_DONE_MSG: {
  179. MM_DBG("AUDREC_CMD_MEM_CFG_DONE_MSG\n");
  180. prtd->running = 1;
  181. alsa_in_record_config(prtd, 1);
  182. break;
  183. }
  184. case AUDREC_FATAL_ERR_MSG: {
  185. struct audrec_fatal_err_msg fatal_err_msg;
  186. getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN);
  187. MM_ERR("FATAL_ERR_MSG: err id %d\n",
  188. fatal_err_msg.audrec_err_id);
  189. /* Error stop the encoder */
  190. prtd->stopped = 1;
  191. wake_up(&the_locks.read_wait);
  192. break;
  193. }
  194. case AUDREC_UP_PACKET_READY_MSG: {
  195. struct audrec_up_pkt_ready_msg pkt_ready_msg;
  196. MM_DBG("AUDREC_UP_PACKET_READY_MSG\n");
  197. getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN);
  198. MM_DBG("UP_PACKET_READY_MSG: write cnt lsw %d \
  199. write cnt msw %d read cnt lsw %d read cnt msw %d \n",\
  200. pkt_ready_msg.audrec_packet_write_cnt_lsw, \
  201. pkt_ready_msg.audrec_packet_write_cnt_msw, \
  202. pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \
  203. pkt_ready_msg.audrec_up_prev_read_cnt_msw);
  204. alsa_get_dsp_frames(prtd);
  205. ++intcnt;
  206. if (prtd->channel_mode == 1) {
  207. spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
  208. if (prtd->pcm_irq_pos >= prtd->pcm_size)
  209. prtd->pcm_irq_pos = 0;
  210. spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
  211. if (prtd->ops->capture)
  212. prtd->ops->capture(prtd);
  213. } else if ((prtd->channel_mode == 0) && (intcnt % 2 == 0)) {
  214. spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
  215. if (prtd->pcm_irq_pos >= prtd->pcm_size)
  216. prtd->pcm_irq_pos = 0;
  217. spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
  218. if (prtd->ops->capture)
  219. prtd->ops->capture(prtd);
  220. }
  221. break;
  222. }
  223. default:
  224. MM_DBG("Unknown Event id %d\n", id);
  225. }
  226. }
  227. struct msm_adsp_ops alsa_audrec_adsp_ops = {
  228. .event = audrec_dsp_event,
  229. };
  230. int alsa_audio_configure(struct msm_audio *prtd)
  231. {
  232. if (prtd->enabled)
  233. return 0;
  234. MM_DBG("\n");
  235. if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
  236. prtd->out_weight = 100;
  237. if (audpp_enable(-1, alsa_dsp_event, prtd)) {
  238. MM_ERR("audpp_enable() failed\n");
  239. return -ENODEV;
  240. }
  241. }
  242. if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE) {
  243. if (audpreproc_enable(prtd->session_id,
  244. &audpreproc_dsp_event, prtd)) {
  245. MM_ERR("audpreproc_enable failed\n");
  246. return -ENODEV;
  247. }
  248. if (msm_adsp_enable(prtd->audrec)) {
  249. MM_ERR("msm_adsp_enable(audrec) enable failed\n");
  250. audpreproc_disable(prtd->session_id, prtd);
  251. return -ENODEV;
  252. }
  253. alsa_in_enc_config(prtd, 1);
  254. }
  255. prtd->enabled = 1;
  256. return 0;
  257. }
  258. EXPORT_SYMBOL(alsa_audio_configure);
  259. ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
  260. size_t count, loff_t *pos)
  261. {
  262. unsigned long flag = 0;
  263. const char __user *start = buf;
  264. struct buffer *frame;
  265. size_t xfer;
  266. int ret = 0;
  267. MM_DBG("\n");
  268. mutex_lock(&the_locks.write_lock);
  269. while (count > 0) {
  270. frame = prtd->out + prtd->out_head;
  271. ret = wait_event_interruptible(the_locks.write_wait,
  272. (frame->used == 0)
  273. || (prtd->stopped));
  274. if (ret < 0)
  275. break;
  276. if (prtd->stopped) {
  277. ret = -EBUSY;
  278. break;
  279. }
  280. xfer = count > frame->size ? frame->size : count;
  281. if (copy_from_user(frame->data, buf, xfer)) {
  282. ret = -EFAULT;
  283. break;
  284. }
  285. frame->used = xfer;
  286. prtd->out_head ^= 1;
  287. count -= xfer;
  288. buf += xfer;
  289. spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
  290. frame = prtd->out + prtd->out_tail;
  291. if (frame->used && prtd->out_needed) {
  292. alsa_dsp_send_buffer(prtd, prtd->out_tail,
  293. frame->used);
  294. /* Reset eos_ack flag to avoid stale
  295. * PCMDMAMISS been considered
  296. */
  297. prtd->eos_ack = 0;
  298. prtd->out_tail ^= 1;
  299. prtd->out_needed--;
  300. }
  301. spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
  302. }
  303. mutex_unlock(&the_locks.write_lock);
  304. if (buf > start)
  305. return buf - start;
  306. return ret;
  307. }
  308. EXPORT_SYMBOL(alsa_send_buffer);
  309. int alsa_audio_disable(struct msm_audio *prtd)
  310. {
  311. if (prtd->enabled) {
  312. MM_DBG("\n");
  313. mutex_lock(&the_locks.lock);
  314. prtd->enabled = 0;
  315. audio_dsp_out_enable(prtd, 0);
  316. wake_up(&the_locks.write_wait);
  317. audpp_disable(-1, prtd);
  318. prtd->out_needed = 0;
  319. mutex_unlock(&the_locks.lock);
  320. }
  321. return 0;
  322. }
  323. EXPORT_SYMBOL(alsa_audio_disable);
  324. int alsa_audrec_disable(struct msm_audio *prtd)
  325. {
  326. if (prtd->enabled) {
  327. prtd->enabled = 0;
  328. alsa_in_enc_config(prtd, 0);
  329. wake_up(&the_locks.read_wait);
  330. msm_adsp_disable(prtd->audrec);
  331. prtd->out_needed = 0;
  332. audpreproc_disable(prtd->session_id, prtd);
  333. }
  334. return 0;
  335. }
  336. EXPORT_SYMBOL(alsa_audrec_disable);
  337. static int alsa_in_enc_config(struct msm_audio *prtd, int enable)
  338. {
  339. struct audpreproc_audrec_cmd_enc_cfg cmd;
  340. int i;
  341. unsigned short *ptrmem = (unsigned short *)&cmd;
  342. memset(&cmd, 0, sizeof(cmd));
  343. cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
  344. cmd.stream_id = prtd->session_id;
  345. if (enable)
  346. cmd.audrec_enc_type = prtd->type | ENCODE_ENABLE;
  347. else
  348. cmd.audrec_enc_type &= ~(ENCODE_ENABLE);
  349. for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
  350. MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
  351. return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
  352. }
  353. static int alsa_in_param_config(struct msm_audio *prtd)
  354. {
  355. struct audpreproc_audrec_cmd_parm_cfg_wav cmd;
  356. int i;
  357. unsigned short *ptrmem = (unsigned short *)&cmd;
  358. memset(&cmd, 0, sizeof(cmd));
  359. cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
  360. cmd.common.stream_id = prtd->session_id;
  361. cmd.aud_rec_samplerate_idx = prtd->samp_rate;
  362. cmd.aud_rec_stereo_mode = prtd->channel_mode;
  363. for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
  364. MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
  365. return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
  366. }
  367. int alsa_in_record_config(struct msm_audio *prtd, int enable)
  368. {
  369. struct audpreproc_afe_cmd_audio_record_cfg cmd;
  370. int i;
  371. unsigned short *ptrmem = (unsigned short *)&cmd;
  372. memset(&cmd, 0, sizeof(cmd));
  373. cmd.cmd_id = AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG;
  374. cmd.stream_id = prtd->session_id;
  375. if (enable)
  376. cmd.destination_activity = AUDIO_RECORDING_TURN_ON;
  377. else
  378. cmd.destination_activity = AUDIO_RECORDING_TURN_OFF;
  379. cmd.source_mix_mask = prtd->source;
  380. if (prtd->session_id == 2) {
  381. if ((cmd.source_mix_mask &
  382. INTERNAL_CODEC_TX_SOURCE_MIX_MASK) ||
  383. (cmd.source_mix_mask & AUX_CODEC_TX_SOURCE_MIX_MASK) ||
  384. (cmd.source_mix_mask & VOICE_UL_SOURCE_MIX_MASK) ||
  385. (cmd.source_mix_mask & VOICE_DL_SOURCE_MIX_MASK)) {
  386. cmd.pipe_id = SOURCE_PIPE_1;
  387. }
  388. if (cmd.source_mix_mask &
  389. AUDPP_A2DP_PIPE_SOURCE_MIX_MASK)
  390. cmd.pipe_id |= SOURCE_PIPE_0;
  391. }
  392. for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
  393. MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
  394. return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
  395. }
  396. static int alsa_in_mem_config(struct msm_audio *prtd)
  397. {
  398. struct audrec_cmd_arecmem_cfg cmd;
  399. uint16_t *data = (void *) prtd->data;
  400. int n;
  401. int i;
  402. unsigned short *ptrmem = (unsigned short *)&cmd;
  403. memset(&cmd, 0, sizeof(cmd));
  404. cmd.cmd_id = AUDREC_CMD_MEM_CFG_CMD;
  405. cmd.audrec_up_pkt_intm_count = 1;
  406. cmd.audrec_ext_pkt_start_addr_msw = prtd->phys >> 16;
  407. cmd.audrec_ext_pkt_start_addr_lsw = prtd->phys;
  408. cmd.audrec_ext_pkt_buf_number = FRAME_NUM;
  409. /* prepare buffer pointers:
  410. * Mono: 1024 samples + 4 halfword header
  411. * Stereo: 2048 samples + 4 halfword header
  412. */
  413. for (n = 0; n < FRAME_NUM; n++) {
  414. prtd->in[n].data = data + 4;
  415. data += (4 + (prtd->channel_mode ? 2048 : 1024));
  416. MM_DBG("0x%8x\n", (int)(prtd->in[n].data - 8));
  417. }
  418. for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
  419. MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
  420. return audrec_send_audrecqueue(prtd, &cmd, sizeof(cmd));
  421. }
  422. int audio_dsp_out_enable(struct msm_audio *prtd, int yes)
  423. {
  424. struct audpp_cmd_pcm_intf cmd;
  425. memset(&cmd, 0, sizeof(cmd));
  426. cmd.cmd_id = AUDPP_CMD_PCM_INTF;
  427. cmd.stream = AUDPP_CMD_POPP_STREAM;
  428. cmd.stream_id = prtd->session_id;
  429. cmd.config = AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
  430. cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
  431. if (yes) {
  432. cmd.write_buf1LSW = prtd->out[0].addr;
  433. cmd.write_buf1MSW = prtd->out[0].addr >> 16;
  434. cmd.write_buf1_len = prtd->out[0].size;
  435. cmd.write_buf2LSW = prtd->out[1].addr;
  436. cmd.write_buf2MSW = prtd->out[1].addr >> 16;
  437. if (prtd->out[1].used)
  438. cmd.write_buf2_len = prtd->out[1].used;
  439. else
  440. cmd.write_buf2_len = prtd->out[1].size;
  441. cmd.arm_to_rx_flag = AUDPP_CMD_PCM_INTF_ENA_V;
  442. cmd.weight_decoder_to_rx = prtd->out_weight;
  443. cmd.weight_arm_to_rx = 1;
  444. cmd.partition_number_arm_to_dsp = 0;
  445. cmd.sample_rate = prtd->out_sample_rate;
  446. cmd.channel_mode = prtd->out_channel_mode;
  447. }
  448. return audpp_send_queue2(&cmd, sizeof(cmd));
  449. }
  450. int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
  451. size_t count, loff_t *pos)
  452. {
  453. unsigned long flag;
  454. void *data;
  455. uint32_t index;
  456. uint32_t size;
  457. int ret = 0;
  458. mutex_lock(&the_locks.read_lock);
  459. while (count > 0) {
  460. ret = wait_event_interruptible(the_locks.read_wait,
  461. (prtd->in_count > 0)
  462. || prtd->stopped ||
  463. prtd->abort);
  464. if (ret < 0)
  465. break;
  466. if (prtd->stopped) {
  467. ret = -EBUSY;
  468. break;
  469. }
  470. if (prtd->abort) {
  471. MM_DBG(" prtd->abort !\n");
  472. ret = -EPERM; /* Not permitted due to abort */
  473. break;
  474. }
  475. index = prtd->in_tail;
  476. data = (uint8_t *) prtd->in[index].data;
  477. size = prtd->in[index].size;
  478. if (count >= size) {
  479. if (copy_to_user(buf, data, size)) {
  480. ret = -EFAULT;
  481. break;
  482. }
  483. spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
  484. if (index != prtd->in_tail) {
  485. /* overrun: data is invalid, we need to retry */
  486. spin_unlock_irqrestore(&the_locks.read_dsp_lock,
  487. flag);
  488. continue;
  489. }
  490. prtd->in[index].size = 0;
  491. prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
  492. prtd->in_count--;
  493. spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
  494. count -= size;
  495. buf += size;
  496. } else {
  497. break;
  498. }
  499. }
  500. mutex_unlock(&the_locks.read_lock);
  501. return ret;
  502. }
  503. EXPORT_SYMBOL(alsa_buffer_read);
  504. int alsa_dsp_send_buffer(struct msm_audio *prtd,
  505. unsigned idx, unsigned len)
  506. {
  507. struct audpp_cmd_pcm_intf_send_buffer cmd;
  508. int i;
  509. unsigned short *ptrmem = (unsigned short *)&cmd;
  510. cmd.cmd_id = AUDPP_CMD_PCM_INTF;
  511. cmd.stream = AUDPP_CMD_POPP_STREAM;
  512. cmd.stream_id = prtd->session_id;
  513. cmd.config = AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
  514. cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
  515. cmd.dsp_to_arm_buf_id = 0;
  516. cmd.arm_to_dsp_buf_id = idx + 1;
  517. cmd.arm_to_dsp_buf_len = len;
  518. for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
  519. MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
  520. return audpp_send_queue2(&cmd, sizeof(cmd));
  521. }
  522. static int alsa_dsp_read_buffer(struct msm_audio *audio, uint32_t read_cnt)
  523. {
  524. struct up_audrec_packet_ext_ptr cmd;
  525. int i;
  526. unsigned short *ptrmem = (unsigned short *)&cmd;
  527. memset(&cmd, 0, sizeof(cmd));
  528. cmd.cmd_id = UP_AUDREC_PACKET_EXT_PTR;
  529. cmd.audrec_up_curr_read_count_msw = read_cnt >> 16;
  530. cmd.audrec_up_curr_read_count_lsw = read_cnt;
  531. for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
  532. MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
  533. return audrec_send_bitstreamqueue(audio, &cmd, sizeof(cmd));
  534. }
  535. static void alsa_get_dsp_frames(struct msm_audio *prtd)
  536. {
  537. struct audio_frame *frame;
  538. uint32_t index = 0;
  539. unsigned long flag;
  540. if (prtd->type == ENC_TYPE_WAV) {
  541. index = prtd->in_head;
  542. frame =
  543. (void *)(((char *)prtd->in[index].data) - sizeof(*frame));
  544. spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
  545. prtd->in[index].size = frame->bytes;
  546. MM_DBG("frame = %08x\n", (unsigned int) frame);
  547. MM_DBG("prtd->in[index].size = %08x\n",
  548. (unsigned int) prtd->in[index].size);
  549. prtd->in_head = (prtd->in_head + 1) & (FRAME_NUM - 1);
  550. /* If overflow, move the tail index foward. */
  551. if (prtd->in_head == prtd->in_tail)
  552. prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
  553. else
  554. prtd->in_count++;
  555. prtd->pcm_irq_pos += frame->bytes;
  556. alsa_dsp_read_buffer(prtd, prtd->dsp_cnt++);
  557. spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
  558. wake_up(&the_locks.read_wait);
  559. }
  560. }