audio_comp.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987
  1. /****************************************************************************
  2. * audio/audio_comp.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <stdarg.h>
  24. #include <nuttx/audio/audio.h>
  25. #include <nuttx/audio/audio_comp.h>
  26. #include <nuttx/kmalloc.h>
  27. /****************************************************************************
  28. * Pre-processor Definitions
  29. ****************************************************************************/
  30. /****************************************************************************
  31. * Private Types
  32. ****************************************************************************/
  33. /* This structure describes the internal state of the audio composite */
  34. struct audio_comp_priv_s
  35. {
  36. /* This is is our appearance to the outside world. This *MUST* be the
  37. * first element of the structure so that we can freely cast between
  38. * types struct audio_lowerhalf and struct audio_comp_dev_s.
  39. */
  40. struct audio_lowerhalf_s export;
  41. /* This is the contained, low-level audio device array and count. */
  42. FAR struct audio_lowerhalf_s **lower;
  43. int count;
  44. };
  45. /****************************************************************************
  46. * Private Function Prototypes
  47. ****************************************************************************/
  48. static int audio_comp_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
  49. FAR struct audio_caps_s *caps);
  50. #ifdef CONFIG_AUDIO_MULTI_SESSION
  51. static int audio_comp_configure(FAR struct audio_lowerhalf_s *dev,
  52. FAR void *session,
  53. FAR const struct audio_caps_s *caps);
  54. #else
  55. static int audio_comp_configure(FAR struct audio_lowerhalf_s *dev,
  56. FAR const struct audio_caps_s *caps);
  57. #endif
  58. static int audio_comp_shutdown(FAR struct audio_lowerhalf_s *dev);
  59. #ifdef CONFIG_AUDIO_MULTI_SESSION
  60. static int audio_comp_start(FAR struct audio_lowerhalf_s *dev,
  61. FAR void *session);
  62. #else
  63. static int audio_comp_start(FAR struct audio_lowerhalf_s *dev);
  64. #endif
  65. #ifndef CONFIG_AUDIO_EXCLUDE_STOP
  66. #ifdef CONFIG_AUDIO_MULTI_SESSION
  67. static int audio_comp_stop(FAR struct audio_lowerhalf_s *dev,
  68. FAR void *session);
  69. #else
  70. static int audio_comp_stop(FAR struct audio_lowerhalf_s *dev);
  71. #endif
  72. #endif
  73. #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
  74. #ifdef CONFIG_AUDIO_MULTI_SESSION
  75. static int audio_comp_pause(FAR struct audio_lowerhalf_s *dev,
  76. FAR void *session);
  77. static int audio_comp_resume(FAR struct audio_lowerhalf_s *dev,
  78. FAR void *session);
  79. #else
  80. static int audio_comp_pause(FAR struct audio_lowerhalf_s *dev);
  81. static int audio_comp_resume(FAR struct audio_lowerhalf_s *dev);
  82. #endif
  83. #endif
  84. static int audio_comp_allocbuffer(FAR struct audio_lowerhalf_s *dev,
  85. FAR struct audio_buf_desc_s *bufdesc);
  86. static int audio_comp_freebuffer(FAR struct audio_lowerhalf_s *dev,
  87. FAR struct audio_buf_desc_s *bufdesc);
  88. static int audio_comp_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
  89. FAR struct ap_buffer_s *apb);
  90. static int audio_comp_cancelbuffer(FAR struct audio_lowerhalf_s *dev,
  91. FAR struct ap_buffer_s *apb);
  92. static int audio_comp_ioctl(FAR struct audio_lowerhalf_s *dev, int cmd,
  93. unsigned long arg);
  94. static int audio_comp_read(FAR struct audio_lowerhalf_s *dev,
  95. FAR char *buffer, size_t buflen);
  96. static int audio_comp_write(FAR struct audio_lowerhalf_s *dev,
  97. FAR const char *buffer, size_t buflen);
  98. #ifdef CONFIG_AUDIO_MULTI_SESSION
  99. static int audio_comp_reserve(FAR struct audio_lowerhalf_s *dev,
  100. FAR void **session);
  101. #else
  102. static int audio_comp_reserve(FAR struct audio_lowerhalf_s *dev);
  103. #endif
  104. #ifdef CONFIG_AUDIO_MULTI_SESSION
  105. static int audio_comp_release(FAR struct audio_lowerhalf_s *dev,
  106. FAR void *session);
  107. #else
  108. static int audio_comp_release(FAR struct audio_lowerhalf_s *dev);
  109. #endif
  110. #ifdef CONFIG_AUDIO_MULTI_SESSION
  111. static void audio_comp_callback(FAR void *arg, uint16_t reason,
  112. FAR struct ap_buffer_s *apb,
  113. uint16_t status,
  114. FAR void *session);
  115. #else
  116. static void audio_comp_callback(FAR void *arg, uint16_t reason,
  117. FAR struct ap_buffer_s *apb,
  118. uint16_t status);
  119. #endif
  120. /****************************************************************************
  121. * Private Data
  122. ****************************************************************************/
  123. static const struct audio_ops_s g_audio_comp_ops =
  124. {
  125. audio_comp_getcaps, /* getcaps */
  126. audio_comp_configure, /* configure */
  127. audio_comp_shutdown, /* shutdown */
  128. audio_comp_start, /* start */
  129. #ifndef CONFIG_AUDIO_EXCLUDE_STOP
  130. audio_comp_stop, /* stop */
  131. #endif
  132. #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
  133. audio_comp_pause, /* pause */
  134. audio_comp_resume, /* resume */
  135. #endif
  136. audio_comp_allocbuffer, /* allocbuffer */
  137. audio_comp_freebuffer, /* freebuffer */
  138. audio_comp_enqueuebuffer, /* enqueue_buffer */
  139. audio_comp_cancelbuffer, /* cancel_buffer */
  140. audio_comp_ioctl, /* ioctl */
  141. audio_comp_read, /* read */
  142. audio_comp_write, /* write */
  143. audio_comp_reserve, /* reserve */
  144. audio_comp_release /* release */
  145. };
  146. /****************************************************************************
  147. * Private Functions
  148. ****************************************************************************/
  149. /****************************************************************************
  150. * Name: audio_comp_getcaps
  151. *
  152. * Description: Get the audio device capabilities
  153. *
  154. ****************************************************************************/
  155. static int audio_comp_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
  156. FAR struct audio_caps_s *caps)
  157. {
  158. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  159. FAR struct audio_lowerhalf_s **lower = priv->lower;
  160. int ret = -ENOTTY;
  161. int i;
  162. caps->ac_channels = 0;
  163. caps->ac_format.hw = 0;
  164. caps->ac_controls.w = 0;
  165. for (i = 0; i < priv->count; i++)
  166. {
  167. if (lower[i]->ops->getcaps)
  168. {
  169. FAR struct audio_caps_s dup = *caps;
  170. int tmp = lower[i]->ops->getcaps(lower[i], type, &dup);
  171. if (tmp == -ENOTTY)
  172. {
  173. continue;
  174. }
  175. ret = tmp;
  176. if (ret < 0)
  177. {
  178. break;
  179. }
  180. if (caps->ac_channels < dup.ac_channels)
  181. {
  182. caps->ac_channels = dup.ac_channels;
  183. }
  184. caps->ac_format.hw |= dup.ac_format.hw;
  185. caps->ac_controls.w |= dup.ac_controls.w;
  186. }
  187. }
  188. return ret;
  189. }
  190. /****************************************************************************
  191. * Name: audio_comp_configure
  192. *
  193. * Description:
  194. * Configure the audio device for the specified mode of operation.
  195. *
  196. ****************************************************************************/
  197. #ifdef CONFIG_AUDIO_MULTI_SESSION
  198. static int audio_comp_configure(FAR struct audio_lowerhalf_s *dev,
  199. FAR void *session,
  200. FAR const struct audio_caps_s *caps)
  201. #else
  202. static int audio_comp_configure(FAR struct audio_lowerhalf_s *dev,
  203. FAR const struct audio_caps_s *caps)
  204. #endif
  205. {
  206. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  207. FAR struct audio_lowerhalf_s **lower = priv->lower;
  208. #ifdef CONFIG_AUDIO_MULTI_SESSION
  209. FAR void **sess = session;
  210. #endif
  211. int ret = -ENOTTY;
  212. int i;
  213. for (i = 0; i < priv->count; i++)
  214. {
  215. if (lower[i]->ops->configure)
  216. {
  217. #ifdef CONFIG_AUDIO_MULTI_SESSION
  218. int tmp = lower[i]->ops->configure(lower[i], sess[i], caps);
  219. #else
  220. int tmp = lower[i]->ops->configure(lower[i], caps);
  221. #endif
  222. if (tmp == -ENOTTY)
  223. {
  224. continue;
  225. }
  226. ret = tmp;
  227. if (ret < 0)
  228. {
  229. break;
  230. }
  231. }
  232. }
  233. return ret;
  234. }
  235. /****************************************************************************
  236. * Name: audio_comp_shutdown
  237. *
  238. * Description:
  239. * Shutdown the driver and put it in the lowest power state possible.
  240. *
  241. ****************************************************************************/
  242. static int audio_comp_shutdown(FAR struct audio_lowerhalf_s *dev)
  243. {
  244. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  245. FAR struct audio_lowerhalf_s **lower = priv->lower;
  246. int ret = -ENOTTY;
  247. int i;
  248. for (i = priv->count - 1; i >= 0; i--)
  249. {
  250. if (lower[i]->ops->shutdown)
  251. {
  252. int tmp = lower[i]->ops->shutdown(lower[i]);
  253. if (tmp == -ENOTTY)
  254. {
  255. continue;
  256. }
  257. if (tmp < 0 || ret == -ENOTTY || ret >= 0)
  258. {
  259. ret = tmp;
  260. }
  261. }
  262. }
  263. return ret;
  264. }
  265. /****************************************************************************
  266. * Name: audio_comp_start
  267. *
  268. * Description:
  269. * Start the configured operation (audio streaming, volume enabled, etc.).
  270. *
  271. ****************************************************************************/
  272. #ifdef CONFIG_AUDIO_MULTI_SESSION
  273. static int audio_comp_start(FAR struct audio_lowerhalf_s *dev,
  274. FAR void *session)
  275. #else
  276. static int audio_comp_start(FAR struct audio_lowerhalf_s *dev)
  277. #endif
  278. {
  279. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  280. FAR struct audio_lowerhalf_s **lower = priv->lower;
  281. #ifdef CONFIG_AUDIO_MULTI_SESSION
  282. FAR void **sess = session;
  283. #endif
  284. int ret = -ENOTTY;
  285. int i;
  286. for (i = 0; i < priv->count; i++)
  287. {
  288. if (lower[i]->ops->start)
  289. {
  290. #ifdef CONFIG_AUDIO_MULTI_SESSION
  291. int tmp = lower[i]->ops->start(lower[i], sess[i]);
  292. #else
  293. int tmp = lower[i]->ops->start(lower[i]);
  294. #endif
  295. if (tmp == -ENOTTY)
  296. {
  297. continue;
  298. }
  299. ret = tmp;
  300. if (ret >= 0)
  301. {
  302. continue;
  303. }
  304. while (--i >= 0)
  305. {
  306. if (lower[i]->ops->stop)
  307. {
  308. #ifdef CONFIG_AUDIO_MULTI_SESSION
  309. lower[i]->ops->stop(lower[i], sess[i]);
  310. #else
  311. lower[i]->ops->stop(lower[i]);
  312. #endif
  313. }
  314. }
  315. break;
  316. }
  317. }
  318. return ret;
  319. }
  320. /****************************************************************************
  321. * Name: audio_comp_stop
  322. *
  323. * Description: Stop the configured operation (audio streaming, volume
  324. * disabled, etc.).
  325. *
  326. ****************************************************************************/
  327. #ifndef CONFIG_AUDIO_EXCLUDE_STOP
  328. #ifdef CONFIG_AUDIO_MULTI_SESSION
  329. static int audio_comp_stop(FAR struct audio_lowerhalf_s *dev,
  330. FAR void *session)
  331. #else
  332. static int audio_comp_stop(FAR struct audio_lowerhalf_s *dev)
  333. #endif
  334. {
  335. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  336. FAR struct audio_lowerhalf_s **lower = priv->lower;
  337. #ifdef CONFIG_AUDIO_MULTI_SESSION
  338. FAR void **sess = session;
  339. #endif
  340. int ret = -ENOTTY;
  341. int i;
  342. for (i = priv->count - 1; i >= 0; i--)
  343. {
  344. if (lower[i]->ops->stop)
  345. {
  346. #ifdef CONFIG_AUDIO_MULTI_SESSION
  347. int tmp = lower[i]->ops->stop(lower[i], sess[i]);
  348. #else
  349. int tmp = lower[i]->ops->stop(lower[i]);
  350. #endif
  351. if (tmp == -ENOTTY)
  352. {
  353. continue;
  354. }
  355. if (tmp < 0 || ret == -ENOTTY || ret >= 0)
  356. {
  357. ret = tmp;
  358. }
  359. }
  360. }
  361. return ret;
  362. }
  363. #endif
  364. /****************************************************************************
  365. * Name: audio_comp_pause
  366. *
  367. * Description: Pauses the playback.
  368. *
  369. ****************************************************************************/
  370. #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
  371. #ifdef CONFIG_AUDIO_MULTI_SESSION
  372. static int audio_comp_pause(FAR struct audio_lowerhalf_s *dev,
  373. FAR void *session)
  374. #else
  375. static int audio_comp_pause(FAR struct audio_lowerhalf_s *dev)
  376. #endif
  377. {
  378. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  379. FAR struct audio_lowerhalf_s **lower = priv->lower;
  380. #ifdef CONFIG_AUDIO_MULTI_SESSION
  381. FAR void **sess = session;
  382. #endif
  383. int ret = -ENOTTY;
  384. int i;
  385. for (i = priv->count - 1; i >= 0; i--)
  386. {
  387. if (lower[i]->ops->pause)
  388. {
  389. #ifdef CONFIG_AUDIO_MULTI_SESSION
  390. int tmp = lower[i]->ops->pause(lower[i], sess[i]);
  391. #else
  392. int tmp = lower[i]->ops->pause(lower[i]);
  393. #endif
  394. if (tmp == -ENOTTY)
  395. {
  396. continue;
  397. }
  398. if (tmp < 0 || ret == -ENOTTY || ret >= 0)
  399. {
  400. ret = tmp;
  401. }
  402. }
  403. }
  404. return ret;
  405. }
  406. #endif /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
  407. /****************************************************************************
  408. * Name: audio_comp_resume
  409. *
  410. * Description: Resumes the playback.
  411. *
  412. ****************************************************************************/
  413. #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
  414. #ifdef CONFIG_AUDIO_MULTI_SESSION
  415. static int audio_comp_resume(FAR struct audio_lowerhalf_s *dev,
  416. FAR void *session)
  417. #else
  418. static int audio_comp_resume(FAR struct audio_lowerhalf_s *dev)
  419. #endif
  420. {
  421. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  422. FAR struct audio_lowerhalf_s **lower = priv->lower;
  423. #ifdef CONFIG_AUDIO_MULTI_SESSION
  424. FAR void **sess = session;
  425. #endif
  426. int ret = -ENOTTY;
  427. int i;
  428. for (i = 0; i < priv->count; i++)
  429. {
  430. if (lower[i]->ops->resume)
  431. {
  432. #ifdef CONFIG_AUDIO_MULTI_SESSION
  433. int tmp = lower[i]->ops->resume(lower[i], sess[i]);
  434. #else
  435. int tmp = lower[i]->ops->resume(lower[i]);
  436. #endif
  437. if (tmp == -ENOTTY)
  438. {
  439. continue;
  440. }
  441. ret = tmp;
  442. if (ret >= 0)
  443. {
  444. continue;
  445. }
  446. while (--i >= 0)
  447. {
  448. if (lower[i]->ops->pause)
  449. {
  450. #ifdef CONFIG_AUDIO_MULTI_SESSION
  451. lower[i]->ops->pause(lower[i], sess[i]);
  452. #else
  453. lower[i]->ops->pause(lower[i]);
  454. #endif
  455. }
  456. }
  457. break;
  458. }
  459. }
  460. return ret;
  461. }
  462. #endif /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
  463. /****************************************************************************
  464. * Name: audio_comp_allocbuffer
  465. *
  466. * Description: Allocate an audio pipeline buffer.
  467. *
  468. ****************************************************************************/
  469. static int audio_comp_allocbuffer(FAR struct audio_lowerhalf_s *dev,
  470. FAR struct audio_buf_desc_s *bufdesc)
  471. {
  472. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  473. FAR struct audio_lowerhalf_s **lower = priv->lower;
  474. int ret = -ENOTTY;
  475. int i;
  476. for (i = 0; i < priv->count; i++)
  477. {
  478. if (lower[i]->ops->allocbuffer)
  479. {
  480. ret = lower[i]->ops->allocbuffer(lower[i], bufdesc);
  481. if (ret != -ENOTTY)
  482. {
  483. break;
  484. }
  485. }
  486. }
  487. if (ret == -ENOTTY)
  488. {
  489. ret = apb_alloc(bufdesc);
  490. }
  491. return ret;
  492. }
  493. /****************************************************************************
  494. * Name: audio_comp_freebuffer
  495. *
  496. * Description: Free an audio pipeline buffer.
  497. *
  498. ****************************************************************************/
  499. static int audio_comp_freebuffer(FAR struct audio_lowerhalf_s *dev,
  500. FAR struct audio_buf_desc_s *bufdesc)
  501. {
  502. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  503. FAR struct audio_lowerhalf_s **lower = priv->lower;
  504. int ret = -ENOTTY;
  505. int i;
  506. for (i = 0; i < priv->count; i++)
  507. {
  508. if (lower[i]->ops->freebuffer)
  509. {
  510. ret = lower[i]->ops->freebuffer(lower[i], bufdesc);
  511. if (ret != -ENOTTY)
  512. {
  513. break;
  514. }
  515. }
  516. }
  517. if (ret == -ENOTTY)
  518. {
  519. apb_free(bufdesc->u.buffer);
  520. ret = sizeof(*bufdesc);
  521. }
  522. return ret;
  523. }
  524. /****************************************************************************
  525. * Name: audio_comp_enqueuebuffer
  526. *
  527. * Description: Enqueue an Audio Pipeline Buffer for playback/ processing.
  528. *
  529. ****************************************************************************/
  530. static int audio_comp_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
  531. FAR struct ap_buffer_s *apb)
  532. {
  533. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  534. FAR struct audio_lowerhalf_s **lower = priv->lower;
  535. int ret = -ENOTTY;
  536. int i;
  537. for (i = 0; i < priv->count; i++)
  538. {
  539. if (lower[i]->ops->enqueuebuffer)
  540. {
  541. ret = lower[i]->ops->enqueuebuffer(lower[i], apb);
  542. if (ret != -ENOTTY)
  543. {
  544. break;
  545. }
  546. }
  547. }
  548. return ret;
  549. }
  550. /****************************************************************************
  551. * Name: audio_comp_cancelbuffer
  552. *
  553. * Description: Called when an enqueued buffer is being cancelled.
  554. *
  555. ****************************************************************************/
  556. static int audio_comp_cancelbuffer(FAR struct audio_lowerhalf_s *dev,
  557. FAR struct ap_buffer_s *apb)
  558. {
  559. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  560. FAR struct audio_lowerhalf_s **lower = priv->lower;
  561. int ret = -ENOTTY;
  562. int i;
  563. for (i = 0; i < priv->count; i++)
  564. {
  565. if (lower[i]->ops->cancelbuffer)
  566. {
  567. ret = lower[i]->ops->cancelbuffer(lower[i], apb);
  568. if (ret != -ENOTTY)
  569. {
  570. break;
  571. }
  572. }
  573. }
  574. return ret;
  575. }
  576. /****************************************************************************
  577. * Name: audio_comp_ioctl
  578. *
  579. * Description: Perform a device ioctl
  580. *
  581. ****************************************************************************/
  582. static int audio_comp_ioctl(FAR struct audio_lowerhalf_s *dev, int cmd,
  583. unsigned long arg)
  584. {
  585. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  586. FAR struct audio_lowerhalf_s **lower = priv->lower;
  587. int ret = -ENOTTY;
  588. int i;
  589. for (i = 0; i < priv->count; i++)
  590. {
  591. if (lower[i]->ops->ioctl)
  592. {
  593. int tmp = lower[i]->ops->ioctl(lower[i], cmd, arg);
  594. if (tmp == -ENOTTY)
  595. {
  596. continue;
  597. }
  598. ret = tmp;
  599. if (ret < 0)
  600. {
  601. break;
  602. }
  603. }
  604. }
  605. return ret;
  606. }
  607. /****************************************************************************
  608. * Name: audio_comp_read
  609. *
  610. * Description: Lower-half logic for read commands.
  611. *
  612. ****************************************************************************/
  613. static int audio_comp_read(FAR struct audio_lowerhalf_s *dev,
  614. FAR char *buffer, size_t buflen)
  615. {
  616. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  617. FAR struct audio_lowerhalf_s **lower = priv->lower;
  618. int ret = -ENOTTY;
  619. int i;
  620. for (i = 0; i < priv->count; i++)
  621. {
  622. if (lower[i]->ops->read)
  623. {
  624. ret = lower[i]->ops->read(lower[i], buffer, buflen);
  625. if (ret != -ENOTTY)
  626. {
  627. break;
  628. }
  629. }
  630. }
  631. return ret;
  632. }
  633. /****************************************************************************
  634. * Name: audio_comp_write
  635. *
  636. * Description: Lower-half logic for write commands.
  637. *
  638. ****************************************************************************/
  639. static int audio_comp_write(FAR struct audio_lowerhalf_s *dev,
  640. FAR const char *buffer, size_t buflen)
  641. {
  642. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  643. FAR struct audio_lowerhalf_s **lower = priv->lower;
  644. int ret = -ENOTTY;
  645. int i;
  646. for (i = 0; i < priv->count; i++)
  647. {
  648. if (lower[i]->ops->write)
  649. {
  650. ret = lower[i]->ops->write(lower[i], buffer, buflen);
  651. if (ret != -ENOTTY)
  652. {
  653. break;
  654. }
  655. }
  656. }
  657. return ret;
  658. }
  659. /****************************************************************************
  660. * Name: audio_comp_reserve
  661. *
  662. * Description: Reserves a session.
  663. *
  664. ****************************************************************************/
  665. #ifdef CONFIG_AUDIO_MULTI_SESSION
  666. static int audio_comp_reserve(FAR struct audio_lowerhalf_s *dev,
  667. FAR void **session)
  668. #else
  669. static int audio_comp_reserve(FAR struct audio_lowerhalf_s *dev)
  670. #endif
  671. {
  672. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  673. FAR struct audio_lowerhalf_s **lower = priv->lower;
  674. #ifdef CONFIG_AUDIO_MULTI_SESSION
  675. FAR void **sess;
  676. #endif
  677. int ret = OK;
  678. int i;
  679. #ifdef CONFIG_AUDIO_MULTI_SESSION
  680. sess = kmm_calloc(priv->count, sizeof(*sess));
  681. if (sess == NULL)
  682. {
  683. return -ENOMEM;
  684. }
  685. #endif
  686. for (i = 0; i < priv->count; i++)
  687. {
  688. if (lower[i]->ops->reserve)
  689. {
  690. #ifdef CONFIG_AUDIO_MULTI_SESSION
  691. int tmp = lower[i]->ops->reserve(lower[i], &sess[i]);
  692. #else
  693. int tmp = lower[i]->ops->reserve(lower[i]);
  694. #endif
  695. if (tmp == -ENOTTY)
  696. {
  697. continue;
  698. }
  699. ret = tmp;
  700. if (ret >= 0)
  701. {
  702. continue;
  703. }
  704. while (--i >= 0)
  705. {
  706. if (lower[i]->ops->release)
  707. {
  708. #ifdef CONFIG_AUDIO_MULTI_SESSION
  709. lower[i]->ops->release(lower[i], sess[i]);
  710. #else
  711. lower[i]->ops->release(lower[i]);
  712. #endif
  713. }
  714. }
  715. #ifdef CONFIG_AUDIO_MULTI_SESSION
  716. kmm_free(sess);
  717. sess = NULL;
  718. #endif
  719. break;
  720. }
  721. }
  722. #ifdef CONFIG_AUDIO_MULTI_SESSION
  723. *session = sess;
  724. #endif
  725. return ret;
  726. }
  727. /****************************************************************************
  728. * Name: audio_comp_release
  729. *
  730. * Description: Releases the session.
  731. *
  732. ****************************************************************************/
  733. #ifdef CONFIG_AUDIO_MULTI_SESSION
  734. static int audio_comp_release(FAR struct audio_lowerhalf_s *dev,
  735. FAR void *session)
  736. #else
  737. static int audio_comp_release(FAR struct audio_lowerhalf_s *dev)
  738. #endif
  739. {
  740. FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
  741. FAR struct audio_lowerhalf_s **lower = priv->lower;
  742. #ifdef CONFIG_AUDIO_MULTI_SESSION
  743. FAR void **sess = session;
  744. #endif
  745. int ret = OK;
  746. int i;
  747. for (i = priv->count - 1; i >= 0; i--)
  748. {
  749. if (lower[i]->ops->release)
  750. {
  751. #ifdef CONFIG_AUDIO_MULTI_SESSION
  752. int tmp = lower[i]->ops->release(lower[i], sess[i]);
  753. #else
  754. int tmp = lower[i]->ops->release(lower[i]);
  755. #endif
  756. if (tmp == -ENOTTY)
  757. {
  758. continue;
  759. }
  760. if (tmp < 0 || ret >= 0)
  761. {
  762. ret = tmp;
  763. }
  764. }
  765. }
  766. #ifdef CONFIG_AUDIO_MULTI_SESSION
  767. kmm_free(sess);
  768. #endif
  769. return ret;
  770. }
  771. /****************************************************************************
  772. * Name: audio_comp_callback
  773. *
  774. * Description:
  775. * Lower-to-upper level callback for buffer dequeueing.
  776. *
  777. * Input Parameters:
  778. * arg - The value of the 'priv' field from audio_lowerhalf_s.
  779. *
  780. * Returned Value:
  781. * None
  782. *
  783. ****************************************************************************/
  784. #ifdef CONFIG_AUDIO_MULTI_SESSION
  785. static void audio_comp_callback(FAR void *arg, uint16_t reason,
  786. FAR struct ap_buffer_s *apb, uint16_t status,
  787. FAR void *session)
  788. #else
  789. static void audio_comp_callback(FAR void *arg, uint16_t reason,
  790. FAR struct ap_buffer_s *apb, uint16_t status)
  791. #endif
  792. {
  793. FAR struct audio_comp_priv_s *priv = arg;
  794. #ifdef CONFIG_AUDIO_MULTI_SESSION
  795. priv->export.upper(priv->export.priv, reason, apb, status, session);
  796. #else
  797. priv->export.upper(priv->export.priv, reason, apb, status);
  798. #endif
  799. }
  800. /****************************************************************************
  801. * Public Functions
  802. ****************************************************************************/
  803. /****************************************************************************
  804. * Name: audio_comp_initialize
  805. *
  806. * Description:
  807. * Initialize the composite audio device.
  808. *
  809. * Input Parameters:
  810. * name - The name of the audio device.
  811. * ... - The list of the lower half audio driver.
  812. *
  813. * Returned Value:
  814. * Zero on success; a negated errno value on failure.
  815. *
  816. * Note
  817. * The variable argument list must be NULL terminated.
  818. *
  819. ****************************************************************************/
  820. int audio_comp_initialize(FAR const char *name, ...)
  821. {
  822. FAR struct audio_comp_priv_s *priv;
  823. va_list ap;
  824. va_list cp;
  825. int ret = -ENOMEM;
  826. int i;
  827. va_start(ap, name);
  828. va_copy(cp, ap);
  829. priv = kmm_zalloc(sizeof(struct audio_comp_priv_s));
  830. if (priv == NULL)
  831. {
  832. goto end_va;
  833. }
  834. priv->export.ops = &g_audio_comp_ops;
  835. while (va_arg(ap, FAR struct audio_lowerhalf_s *))
  836. {
  837. priv->count++;
  838. }
  839. priv->lower = kmm_calloc(priv->count,
  840. sizeof(FAR struct audio_lowerhalf_s *));
  841. if (priv->lower == NULL)
  842. {
  843. goto free_priv;
  844. }
  845. for (i = 0; i < priv->count; i++)
  846. {
  847. FAR struct audio_lowerhalf_s *tmp;
  848. tmp = va_arg(cp, FAR struct audio_lowerhalf_s *);
  849. tmp->upper = audio_comp_callback;
  850. tmp->priv = priv;
  851. priv->lower[i] = tmp;
  852. }
  853. ret = audio_register(name, &priv->export);
  854. if (ret < 0)
  855. {
  856. goto free_lower;
  857. }
  858. va_end(ap);
  859. return OK;
  860. free_lower:
  861. kmm_free(priv->lower);
  862. free_priv:
  863. kmm_free(priv);
  864. end_va:
  865. va_end(ap);
  866. return ret;
  867. }