2
0

ossaudio.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. /*
  2. * QEMU OSS audio driver
  3. *
  4. * Copyright (c) 2003-2005 Vassili Karpov (malc)
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu/osdep.h"
  25. #include <sys/ioctl.h>
  26. #include <sys/soundcard.h>
  27. #include "qemu/main-loop.h"
  28. #include "qemu/module.h"
  29. #include "qemu/host-utils.h"
  30. #include "audio.h"
  31. #include "trace.h"
  32. #define AUDIO_CAP "oss"
  33. #include "audio_int.h"
  34. #if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
  35. #define USE_DSP_POLICY
  36. #endif
  37. typedef struct OSSVoiceOut {
  38. HWVoiceOut hw;
  39. int fd;
  40. int nfrags;
  41. int fragsize;
  42. int mmapped;
  43. Audiodev *dev;
  44. } OSSVoiceOut;
  45. typedef struct OSSVoiceIn {
  46. HWVoiceIn hw;
  47. int fd;
  48. int nfrags;
  49. int fragsize;
  50. Audiodev *dev;
  51. } OSSVoiceIn;
  52. struct oss_params {
  53. int freq;
  54. int fmt;
  55. int nchannels;
  56. int nfrags;
  57. int fragsize;
  58. };
  59. static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
  60. {
  61. va_list ap;
  62. va_start (ap, fmt);
  63. AUD_vlog (AUDIO_CAP, fmt, ap);
  64. va_end (ap);
  65. AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
  66. }
  67. static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
  68. int err,
  69. const char *typ,
  70. const char *fmt,
  71. ...
  72. )
  73. {
  74. va_list ap;
  75. AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
  76. va_start (ap, fmt);
  77. AUD_vlog (AUDIO_CAP, fmt, ap);
  78. va_end (ap);
  79. AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
  80. }
  81. static void oss_anal_close (int *fdp)
  82. {
  83. int err;
  84. qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
  85. err = close (*fdp);
  86. if (err) {
  87. oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
  88. }
  89. *fdp = -1;
  90. }
  91. static void oss_helper_poll_out (void *opaque)
  92. {
  93. AudioState *s = opaque;
  94. audio_run(s, "oss_poll_out");
  95. }
  96. static void oss_helper_poll_in (void *opaque)
  97. {
  98. AudioState *s = opaque;
  99. audio_run(s, "oss_poll_in");
  100. }
  101. static void oss_poll_out (HWVoiceOut *hw)
  102. {
  103. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  104. qemu_set_fd_handler(oss->fd, NULL, oss_helper_poll_out, hw->s);
  105. }
  106. static void oss_poll_in (HWVoiceIn *hw)
  107. {
  108. OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  109. qemu_set_fd_handler(oss->fd, oss_helper_poll_in, NULL, hw->s);
  110. }
  111. static int aud_to_ossfmt (AudioFormat fmt, int endianness)
  112. {
  113. switch (fmt) {
  114. case AUDIO_FORMAT_S8:
  115. return AFMT_S8;
  116. case AUDIO_FORMAT_U8:
  117. return AFMT_U8;
  118. case AUDIO_FORMAT_S16:
  119. if (endianness) {
  120. return AFMT_S16_BE;
  121. }
  122. else {
  123. return AFMT_S16_LE;
  124. }
  125. case AUDIO_FORMAT_U16:
  126. if (endianness) {
  127. return AFMT_U16_BE;
  128. }
  129. else {
  130. return AFMT_U16_LE;
  131. }
  132. default:
  133. dolog ("Internal logic error: Bad audio format %d\n", fmt);
  134. #ifdef DEBUG_AUDIO
  135. abort ();
  136. #endif
  137. return AFMT_U8;
  138. }
  139. }
  140. static int oss_to_audfmt (int ossfmt, AudioFormat *fmt, int *endianness)
  141. {
  142. switch (ossfmt) {
  143. case AFMT_S8:
  144. *endianness = 0;
  145. *fmt = AUDIO_FORMAT_S8;
  146. break;
  147. case AFMT_U8:
  148. *endianness = 0;
  149. *fmt = AUDIO_FORMAT_U8;
  150. break;
  151. case AFMT_S16_LE:
  152. *endianness = 0;
  153. *fmt = AUDIO_FORMAT_S16;
  154. break;
  155. case AFMT_U16_LE:
  156. *endianness = 0;
  157. *fmt = AUDIO_FORMAT_U16;
  158. break;
  159. case AFMT_S16_BE:
  160. *endianness = 1;
  161. *fmt = AUDIO_FORMAT_S16;
  162. break;
  163. case AFMT_U16_BE:
  164. *endianness = 1;
  165. *fmt = AUDIO_FORMAT_U16;
  166. break;
  167. default:
  168. dolog ("Unrecognized audio format %d\n", ossfmt);
  169. return -1;
  170. }
  171. return 0;
  172. }
  173. #if defined DEBUG_MISMATCHES || defined DEBUG
  174. static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
  175. {
  176. dolog ("parameter | requested value | obtained value\n");
  177. dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
  178. dolog ("channels | %10d | %10d\n",
  179. req->nchannels, obt->nchannels);
  180. dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
  181. dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags);
  182. dolog ("fragsize | %10d | %10d\n",
  183. req->fragsize, obt->fragsize);
  184. }
  185. #endif
  186. #ifdef USE_DSP_POLICY
  187. static int oss_get_version (int fd, int *version, const char *typ)
  188. {
  189. if (ioctl (fd, OSS_GETVERSION, &version)) {
  190. #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  191. /*
  192. * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
  193. * since 7.x, but currently only on the mixer device (or in
  194. * the Linuxolator), and in the native version that part of
  195. * the code is in fact never reached so the ioctl fails anyway.
  196. * Until this is fixed, just check the errno and if its what
  197. * FreeBSD's sound drivers return atm assume they are new enough.
  198. */
  199. if (errno == EINVAL) {
  200. *version = 0x040000;
  201. return 0;
  202. }
  203. #endif
  204. oss_logerr2 (errno, typ, "Failed to get OSS version\n");
  205. return -1;
  206. }
  207. return 0;
  208. }
  209. #endif
  210. static int oss_open(int in, struct oss_params *req, audsettings *as,
  211. struct oss_params *obt, int *pfd, Audiodev *dev)
  212. {
  213. AudiodevOssOptions *oopts = &dev->u.oss;
  214. AudiodevOssPerDirectionOptions *opdo = in ? oopts->in : oopts->out;
  215. int fd;
  216. int oflags = (oopts->has_exclusive && oopts->exclusive) ? O_EXCL : 0;
  217. audio_buf_info abinfo;
  218. int fmt, freq, nchannels;
  219. int setfragment = 1;
  220. const char *dspname = opdo->has_dev ? opdo->dev : "/dev/dsp";
  221. const char *typ = in ? "ADC" : "DAC";
  222. #ifdef USE_DSP_POLICY
  223. int policy = oopts->has_dsp_policy ? oopts->dsp_policy : 5;
  224. #endif
  225. /* Kludge needed to have working mmap on Linux */
  226. oflags |= (oopts->has_try_mmap && oopts->try_mmap) ?
  227. O_RDWR : (in ? O_RDONLY : O_WRONLY);
  228. fd = open (dspname, oflags | O_NONBLOCK);
  229. if (-1 == fd) {
  230. oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
  231. return -1;
  232. }
  233. freq = req->freq;
  234. nchannels = req->nchannels;
  235. fmt = req->fmt;
  236. req->nfrags = opdo->has_buffer_count ? opdo->buffer_count : 4;
  237. req->fragsize = audio_buffer_bytes(
  238. qapi_AudiodevOssPerDirectionOptions_base(opdo), as, 23220);
  239. if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
  240. oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
  241. goto err;
  242. }
  243. if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
  244. oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
  245. req->nchannels);
  246. goto err;
  247. }
  248. if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
  249. oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
  250. goto err;
  251. }
  252. if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
  253. oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
  254. goto err;
  255. }
  256. #ifdef USE_DSP_POLICY
  257. if (policy >= 0) {
  258. int version;
  259. if (!oss_get_version (fd, &version, typ)) {
  260. trace_oss_version(version);
  261. if (version >= 0x040000) {
  262. int policy2 = policy;
  263. if (ioctl(fd, SNDCTL_DSP_POLICY, &policy2)) {
  264. oss_logerr2 (errno, typ,
  265. "Failed to set timing policy to %d\n",
  266. policy);
  267. goto err;
  268. }
  269. setfragment = 0;
  270. }
  271. }
  272. }
  273. #endif
  274. if (setfragment) {
  275. int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
  276. if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
  277. oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
  278. req->nfrags, req->fragsize);
  279. goto err;
  280. }
  281. }
  282. if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
  283. oss_logerr2 (errno, typ, "Failed to get buffer length\n");
  284. goto err;
  285. }
  286. if (!abinfo.fragstotal || !abinfo.fragsize) {
  287. AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
  288. abinfo.fragstotal, abinfo.fragsize, typ);
  289. goto err;
  290. }
  291. obt->fmt = fmt;
  292. obt->nchannels = nchannels;
  293. obt->freq = freq;
  294. obt->nfrags = abinfo.fragstotal;
  295. obt->fragsize = abinfo.fragsize;
  296. *pfd = fd;
  297. #ifdef DEBUG_MISMATCHES
  298. if ((req->fmt != obt->fmt) ||
  299. (req->nchannels != obt->nchannels) ||
  300. (req->freq != obt->freq) ||
  301. (req->fragsize != obt->fragsize) ||
  302. (req->nfrags != obt->nfrags)) {
  303. dolog ("Audio parameters mismatch\n");
  304. oss_dump_info (req, obt);
  305. }
  306. #endif
  307. #ifdef DEBUG
  308. oss_dump_info (req, obt);
  309. #endif
  310. return 0;
  311. err:
  312. oss_anal_close (&fd);
  313. return -1;
  314. }
  315. static size_t oss_get_available_bytes(OSSVoiceOut *oss)
  316. {
  317. int err;
  318. struct count_info cntinfo;
  319. assert(oss->mmapped);
  320. err = ioctl(oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
  321. if (err < 0) {
  322. oss_logerr(errno, "SNDCTL_DSP_GETOPTR failed\n");
  323. return 0;
  324. }
  325. return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
  326. }
  327. static void oss_run_buffer_out(HWVoiceOut *hw)
  328. {
  329. OSSVoiceOut *oss = (OSSVoiceOut *)hw;
  330. if (!oss->mmapped) {
  331. audio_generic_run_buffer_out(hw);
  332. }
  333. }
  334. static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
  335. {
  336. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  337. if (oss->mmapped) {
  338. *size = MIN(oss_get_available_bytes(oss), hw->size_emul - hw->pos_emul);
  339. return hw->buf_emul + hw->pos_emul;
  340. } else {
  341. return audio_generic_get_buffer_out(hw, size);
  342. }
  343. }
  344. static size_t oss_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
  345. {
  346. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  347. if (oss->mmapped) {
  348. assert(buf == hw->buf_emul + hw->pos_emul && size < hw->size_emul);
  349. hw->pos_emul = (hw->pos_emul + size) % hw->size_emul;
  350. return size;
  351. } else {
  352. return audio_generic_put_buffer_out(hw, buf, size);
  353. }
  354. }
  355. static size_t oss_write(HWVoiceOut *hw, void *buf, size_t len)
  356. {
  357. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  358. size_t pos;
  359. if (oss->mmapped) {
  360. size_t total_len;
  361. len = MIN(len, oss_get_available_bytes(oss));
  362. total_len = len;
  363. while (len) {
  364. size_t to_copy = MIN(len, hw->size_emul - hw->pos_emul);
  365. memcpy(hw->buf_emul + hw->pos_emul, buf, to_copy);
  366. hw->pos_emul = (hw->pos_emul + to_copy) % hw->size_emul;
  367. buf += to_copy;
  368. len -= to_copy;
  369. }
  370. return total_len;
  371. }
  372. pos = 0;
  373. while (len) {
  374. ssize_t bytes_written;
  375. void *pcm = advance(buf, pos);
  376. bytes_written = write(oss->fd, pcm, len);
  377. if (bytes_written < 0) {
  378. if (errno != EAGAIN) {
  379. oss_logerr(errno, "failed to write %zu bytes\n",
  380. len);
  381. }
  382. return pos;
  383. }
  384. pos += bytes_written;
  385. if (bytes_written < len) {
  386. break;
  387. }
  388. len -= bytes_written;
  389. }
  390. return pos;
  391. }
  392. static void oss_fini_out (HWVoiceOut *hw)
  393. {
  394. int err;
  395. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  396. ldebug ("oss_fini\n");
  397. oss_anal_close (&oss->fd);
  398. if (oss->mmapped && hw->buf_emul) {
  399. err = munmap(hw->buf_emul, hw->size_emul);
  400. if (err) {
  401. oss_logerr(errno, "Failed to unmap buffer %p, size %zu\n",
  402. hw->buf_emul, hw->size_emul);
  403. }
  404. hw->buf_emul = NULL;
  405. }
  406. }
  407. static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
  408. void *drv_opaque)
  409. {
  410. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  411. struct oss_params req, obt;
  412. int endianness;
  413. int err;
  414. int fd;
  415. AudioFormat effective_fmt;
  416. struct audsettings obt_as;
  417. Audiodev *dev = drv_opaque;
  418. AudiodevOssOptions *oopts = &dev->u.oss;
  419. oss->fd = -1;
  420. req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
  421. req.freq = as->freq;
  422. req.nchannels = as->nchannels;
  423. if (oss_open(0, &req, as, &obt, &fd, dev)) {
  424. return -1;
  425. }
  426. err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
  427. if (err) {
  428. oss_anal_close (&fd);
  429. return -1;
  430. }
  431. obt_as.freq = obt.freq;
  432. obt_as.nchannels = obt.nchannels;
  433. obt_as.fmt = effective_fmt;
  434. obt_as.endianness = endianness;
  435. audio_pcm_init_info (&hw->info, &obt_as);
  436. oss->nfrags = obt.nfrags;
  437. oss->fragsize = obt.fragsize;
  438. if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) {
  439. dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
  440. obt.nfrags * obt.fragsize, hw->info.bytes_per_frame);
  441. }
  442. hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame;
  443. oss->mmapped = 0;
  444. if (oopts->has_try_mmap && oopts->try_mmap) {
  445. hw->size_emul = hw->samples * hw->info.bytes_per_frame;
  446. hw->buf_emul = mmap(
  447. NULL,
  448. hw->size_emul,
  449. PROT_READ | PROT_WRITE,
  450. MAP_SHARED,
  451. fd,
  452. 0
  453. );
  454. if (hw->buf_emul == MAP_FAILED) {
  455. oss_logerr(errno, "Failed to map %zu bytes of DAC\n",
  456. hw->size_emul);
  457. hw->buf_emul = NULL;
  458. } else {
  459. int err;
  460. int trig = 0;
  461. if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  462. oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
  463. }
  464. else {
  465. trig = PCM_ENABLE_OUTPUT;
  466. if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  467. oss_logerr (
  468. errno,
  469. "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
  470. );
  471. }
  472. else {
  473. oss->mmapped = 1;
  474. }
  475. }
  476. if (!oss->mmapped) {
  477. err = munmap(hw->buf_emul, hw->size_emul);
  478. if (err) {
  479. oss_logerr(errno, "Failed to unmap buffer %p size %zu\n",
  480. hw->buf_emul, hw->size_emul);
  481. }
  482. hw->buf_emul = NULL;
  483. }
  484. }
  485. }
  486. oss->fd = fd;
  487. oss->dev = dev;
  488. return 0;
  489. }
  490. static void oss_enable_out(HWVoiceOut *hw, bool enable)
  491. {
  492. int trig;
  493. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  494. AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
  495. if (enable) {
  496. hw->poll_mode = opdo->try_poll;
  497. ldebug("enabling voice\n");
  498. if (hw->poll_mode) {
  499. oss_poll_out(hw);
  500. }
  501. if (!oss->mmapped) {
  502. return;
  503. }
  504. audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->samples);
  505. trig = PCM_ENABLE_OUTPUT;
  506. if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  507. oss_logerr(errno,
  508. "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n");
  509. return;
  510. }
  511. } else {
  512. if (hw->poll_mode) {
  513. qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
  514. hw->poll_mode = 0;
  515. }
  516. if (!oss->mmapped) {
  517. return;
  518. }
  519. ldebug ("disabling voice\n");
  520. trig = 0;
  521. if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  522. oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
  523. return;
  524. }
  525. }
  526. }
  527. static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
  528. {
  529. OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  530. struct oss_params req, obt;
  531. int endianness;
  532. int err;
  533. int fd;
  534. AudioFormat effective_fmt;
  535. struct audsettings obt_as;
  536. Audiodev *dev = drv_opaque;
  537. oss->fd = -1;
  538. req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
  539. req.freq = as->freq;
  540. req.nchannels = as->nchannels;
  541. if (oss_open(1, &req, as, &obt, &fd, dev)) {
  542. return -1;
  543. }
  544. err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
  545. if (err) {
  546. oss_anal_close (&fd);
  547. return -1;
  548. }
  549. obt_as.freq = obt.freq;
  550. obt_as.nchannels = obt.nchannels;
  551. obt_as.fmt = effective_fmt;
  552. obt_as.endianness = endianness;
  553. audio_pcm_init_info (&hw->info, &obt_as);
  554. oss->nfrags = obt.nfrags;
  555. oss->fragsize = obt.fragsize;
  556. if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) {
  557. dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
  558. obt.nfrags * obt.fragsize, hw->info.bytes_per_frame);
  559. }
  560. hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame;
  561. oss->fd = fd;
  562. oss->dev = dev;
  563. return 0;
  564. }
  565. static void oss_fini_in (HWVoiceIn *hw)
  566. {
  567. OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  568. oss_anal_close (&oss->fd);
  569. }
  570. static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
  571. {
  572. OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  573. size_t pos = 0;
  574. while (len) {
  575. ssize_t nread;
  576. void *dst = advance(buf, pos);
  577. nread = read(oss->fd, dst, len);
  578. if (nread == -1) {
  579. switch (errno) {
  580. case EINTR:
  581. case EAGAIN:
  582. break;
  583. default:
  584. oss_logerr(errno, "Failed to read %zu bytes of audio (to %p)\n",
  585. len, dst);
  586. break;
  587. }
  588. break;
  589. }
  590. pos += nread;
  591. len -= nread;
  592. }
  593. return pos;
  594. }
  595. static void oss_enable_in(HWVoiceIn *hw, bool enable)
  596. {
  597. OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  598. AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
  599. if (enable) {
  600. hw->poll_mode = opdo->try_poll;
  601. if (hw->poll_mode) {
  602. oss_poll_in(hw);
  603. }
  604. } else {
  605. if (hw->poll_mode) {
  606. qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
  607. hw->poll_mode = 0;
  608. }
  609. }
  610. }
  611. static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo)
  612. {
  613. if (!opdo->has_try_poll) {
  614. opdo->try_poll = true;
  615. opdo->has_try_poll = true;
  616. }
  617. }
  618. static void *oss_audio_init(Audiodev *dev)
  619. {
  620. AudiodevOssOptions *oopts;
  621. assert(dev->driver == AUDIODEV_DRIVER_OSS);
  622. oopts = &dev->u.oss;
  623. oss_init_per_direction(oopts->in);
  624. oss_init_per_direction(oopts->out);
  625. if (access(oopts->in->has_dev ? oopts->in->dev : "/dev/dsp",
  626. R_OK | W_OK) < 0 ||
  627. access(oopts->out->has_dev ? oopts->out->dev : "/dev/dsp",
  628. R_OK | W_OK) < 0) {
  629. return NULL;
  630. }
  631. return dev;
  632. }
  633. static void oss_audio_fini (void *opaque)
  634. {
  635. }
  636. static struct audio_pcm_ops oss_pcm_ops = {
  637. .init_out = oss_init_out,
  638. .fini_out = oss_fini_out,
  639. .write = oss_write,
  640. .run_buffer_out = oss_run_buffer_out,
  641. .get_buffer_out = oss_get_buffer_out,
  642. .put_buffer_out = oss_put_buffer_out,
  643. .enable_out = oss_enable_out,
  644. .init_in = oss_init_in,
  645. .fini_in = oss_fini_in,
  646. .read = oss_read,
  647. .enable_in = oss_enable_in
  648. };
  649. static struct audio_driver oss_audio_driver = {
  650. .name = "oss",
  651. .descr = "OSS http://www.opensound.com",
  652. .init = oss_audio_init,
  653. .fini = oss_audio_fini,
  654. .pcm_ops = &oss_pcm_ops,
  655. .can_be_default = 1,
  656. .max_voices_out = INT_MAX,
  657. .max_voices_in = INT_MAX,
  658. .voice_size_out = sizeof (OSSVoiceOut),
  659. .voice_size_in = sizeof (OSSVoiceIn)
  660. };
  661. static void register_audio_oss(void)
  662. {
  663. audio_driver_register(&oss_audio_driver);
  664. }
  665. type_init(register_audio_oss);