0120--ARM-goldfish-Add-audio-driver-for-goldfish.patch 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. From aefe5257bf3ed9bf950ad962a63e5315566c2f97 Mon Sep 17 00:00:00 2001
  2. From: Mike Lockwood <[email protected]>
  3. Date: Mon, 23 Jul 2007 09:31:54 -0400
  4. Subject: [PATCH 120/134] [ARM] goldfish: Add audio driver for goldfish.
  5. Signed-off-by: Mike A. Chan <[email protected]>
  6. ---
  7. arch/arm/mach-goldfish/Makefile | 2 +-
  8. arch/arm/mach-goldfish/audio.c | 379 +++++++++++++++++++++++++++++++++++++++
  9. 2 files changed, 380 insertions(+), 1 deletions(-)
  10. create mode 100644 arch/arm/mach-goldfish/audio.c
  11. --- a/arch/arm/mach-goldfish/Makefile
  12. +++ b/arch/arm/mach-goldfish/Makefile
  13. @@ -4,6 +4,6 @@
  14. # Object file lists.
  15. -obj-y := pdev_bus.o timer.o
  16. +obj-y := pdev_bus.o timer.o audio.o
  17. obj-$(CONFIG_MACH_GOLDFISH) += board-goldfish.o
  18. --- /dev/null
  19. +++ b/arch/arm/mach-goldfish/audio.c
  20. @@ -0,0 +1,379 @@
  21. +/* arch/arm/mach-goldfish/audio.c
  22. +**
  23. +** Copyright (C) 2007 Google, Inc.
  24. +**
  25. +** This software is licensed under the terms of the GNU General Public
  26. +** License version 2, as published by the Free Software Foundation, and
  27. +** may be copied, distributed, and modified under those terms.
  28. +**
  29. +** This program is distributed in the hope that it will be useful,
  30. +** but WITHOUT ANY WARRANTY; without even the implied warranty of
  31. +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  32. +** GNU General Public License for more details.
  33. +**
  34. +*/
  35. +
  36. +#include <linux/module.h>
  37. +#include <linux/miscdevice.h>
  38. +#include <linux/fs.h>
  39. +#include <linux/platform_device.h>
  40. +
  41. +#include <linux/types.h>
  42. +#include <linux/pci.h>
  43. +#include <linux/interrupt.h>
  44. +
  45. +#include <asm/types.h>
  46. +#include <asm/io.h>
  47. +#include <asm/uaccess.h>
  48. +
  49. +
  50. +MODULE_AUTHOR("Google, Inc.");
  51. +MODULE_DESCRIPTION("Android QEMU Audio Driver");
  52. +MODULE_LICENSE("GPL");
  53. +MODULE_VERSION("1.0");
  54. +
  55. +struct goldfish_audio {
  56. + uint32_t reg_base;
  57. + int irq;
  58. + spinlock_t lock;
  59. + wait_queue_head_t wait;
  60. +
  61. + char __iomem *buffer_virt; /* combined buffer virtual address */
  62. + unsigned long buffer_phys; /* combined buffer physical address */
  63. +
  64. + char __iomem *write_buffer1; /* write buffer 1 virtual address */
  65. + char __iomem *write_buffer2; /* write buffer 2 virtual address */
  66. + char __iomem *read_buffer; /* read buffer virtual address */
  67. + int buffer_status;
  68. + int read_supported; /* true if we have audio input support */
  69. +};
  70. +
  71. +/* We will allocate two read buffers and two write buffers.
  72. + Having two read buffers facilitate stereo -> mono conversion.
  73. + Having two write buffers facilitate interleaved IO.
  74. +*/
  75. +#define READ_BUFFER_SIZE 16384
  76. +#define WRITE_BUFFER_SIZE 16384
  77. +#define COMBINED_BUFFER_SIZE ((2 * READ_BUFFER_SIZE) + (2 * WRITE_BUFFER_SIZE))
  78. +
  79. +#define GOLDFISH_AUDIO_READ(data, addr) (readl(data->reg_base + addr))
  80. +#define GOLDFISH_AUDIO_WRITE(data, addr, x) (writel(x, data->reg_base + addr))
  81. +
  82. +/* temporary variable used between goldfish_audio_probe() and goldfish_audio_open() */
  83. +static struct goldfish_audio* audio_data;
  84. +
  85. +enum {
  86. + /* audio status register */
  87. + AUDIO_INT_STATUS = 0x00,
  88. + /* set this to enable IRQ */
  89. + AUDIO_INT_ENABLE = 0x04,
  90. + /* set these to specify buffer addresses */
  91. + AUDIO_SET_WRITE_BUFFER_1 = 0x08,
  92. + AUDIO_SET_WRITE_BUFFER_2 = 0x0C,
  93. + /* set number of bytes in buffer to write */
  94. + AUDIO_WRITE_BUFFER_1 = 0x10,
  95. + AUDIO_WRITE_BUFFER_2 = 0x14,
  96. +
  97. + /* true if audio input is supported */
  98. + AUDIO_READ_SUPPORTED = 0x18,
  99. + /* buffer to use for audio input */
  100. + AUDIO_SET_READ_BUFFER = 0x1C,
  101. +
  102. + /* driver writes number of bytes to read */
  103. + AUDIO_START_READ = 0x20,
  104. +
  105. + /* number of bytes available in read buffer */
  106. + AUDIO_READ_BUFFER_AVAILABLE = 0x24,
  107. +
  108. + /* AUDIO_INT_STATUS bits */
  109. +
  110. + /* this bit set when it is safe to write more bytes to the buffer */
  111. + AUDIO_INT_WRITE_BUFFER_1_EMPTY = 1U << 0,
  112. + AUDIO_INT_WRITE_BUFFER_2_EMPTY = 1U << 1,
  113. + AUDIO_INT_READ_BUFFER_FULL = 1U << 2,
  114. +
  115. + AUDIO_INT_MASK = AUDIO_INT_WRITE_BUFFER_1_EMPTY |
  116. + AUDIO_INT_WRITE_BUFFER_2_EMPTY |
  117. + AUDIO_INT_READ_BUFFER_FULL,
  118. +};
  119. +
  120. +
  121. +static atomic_t open_count = ATOMIC_INIT(0);
  122. +
  123. +
  124. +static ssize_t goldfish_audio_read(struct file *fp, char __user *buf,
  125. + size_t count, loff_t *pos)
  126. +{
  127. + struct goldfish_audio* data = fp->private_data;
  128. + int length;
  129. + int result = 0;
  130. +
  131. + if (!data->read_supported)
  132. + return -ENODEV;
  133. +
  134. + while (count > 0) {
  135. + length = (count > READ_BUFFER_SIZE ? READ_BUFFER_SIZE : count);
  136. + GOLDFISH_AUDIO_WRITE(data, AUDIO_START_READ, length);
  137. +
  138. + wait_event_interruptible(data->wait, (data->buffer_status & AUDIO_INT_READ_BUFFER_FULL));
  139. +
  140. + length = GOLDFISH_AUDIO_READ(data, AUDIO_READ_BUFFER_AVAILABLE);
  141. +
  142. + /* copy data to user space */
  143. + if (copy_to_user(buf, data->read_buffer, length))
  144. + {
  145. + printk("copy_from_user failed!\n");
  146. + return -EFAULT;
  147. + }
  148. +
  149. + result += length;
  150. + buf += length;
  151. + count -= length;
  152. + }
  153. +
  154. + return result;
  155. +}
  156. +
  157. +static ssize_t goldfish_audio_write(struct file *fp, const char __user *buf,
  158. + size_t count, loff_t *pos)
  159. +{
  160. + struct goldfish_audio* data = fp->private_data;
  161. + unsigned long irq_flags;
  162. + ssize_t result = 0;
  163. + char __iomem *kbuf;
  164. +
  165. + while (count > 0)
  166. + {
  167. + ssize_t copy = count;
  168. + if (copy > WRITE_BUFFER_SIZE)
  169. + copy = WRITE_BUFFER_SIZE;
  170. + wait_event_interruptible(data->wait,
  171. + (data->buffer_status & (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY)));
  172. +
  173. + if ((data->buffer_status & AUDIO_INT_WRITE_BUFFER_1_EMPTY) != 0) {
  174. + kbuf = data->write_buffer1;
  175. + } else {
  176. + kbuf = data->write_buffer2;
  177. + }
  178. +
  179. + /* copy from user space to the appropriate buffer */
  180. + if (copy_from_user(kbuf, buf, copy))
  181. + {
  182. + printk("copy_from_user failed!\n");
  183. + result = -EFAULT;
  184. + break;
  185. + }
  186. + else
  187. + {
  188. + spin_lock_irqsave(&data->lock, irq_flags);
  189. +
  190. + /* clear the buffer empty flag, and signal the emulator to start writing the buffer */
  191. + if (kbuf == data->write_buffer1) {
  192. + data->buffer_status &= ~AUDIO_INT_WRITE_BUFFER_1_EMPTY;
  193. + GOLDFISH_AUDIO_WRITE(data, AUDIO_WRITE_BUFFER_1, copy);
  194. + } else {
  195. + data->buffer_status &= ~AUDIO_INT_WRITE_BUFFER_2_EMPTY;
  196. + GOLDFISH_AUDIO_WRITE(data, AUDIO_WRITE_BUFFER_2, copy);
  197. + }
  198. +
  199. + spin_unlock_irqrestore(&data->lock, irq_flags);
  200. + }
  201. +
  202. + buf += copy;
  203. + result += copy;
  204. + count -= copy;
  205. + }
  206. +
  207. + return result;
  208. +}
  209. +
  210. +static int goldfish_audio_open(struct inode *ip, struct file *fp)
  211. +{
  212. + if (!audio_data)
  213. + return -ENODEV;
  214. +
  215. + if (atomic_inc_return(&open_count) == 1)
  216. + {
  217. + fp->private_data = audio_data;
  218. + audio_data->buffer_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY);
  219. + GOLDFISH_AUDIO_WRITE(audio_data, AUDIO_INT_ENABLE, AUDIO_INT_MASK);
  220. + return 0;
  221. + }
  222. + else
  223. + {
  224. + atomic_dec(&open_count);
  225. + return -EBUSY;
  226. + }
  227. +}
  228. +
  229. +static int goldfish_audio_release(struct inode *ip, struct file* fp)
  230. +{
  231. + atomic_dec(&open_count);
  232. + GOLDFISH_AUDIO_WRITE(audio_data, AUDIO_INT_ENABLE, 0);
  233. + return 0;
  234. +}
  235. +
  236. +static int goldfish_audio_ioctl(struct inode* ip, struct file* fp, unsigned int cmd, unsigned long arg)
  237. +{
  238. + /* temporary workaround, until we switch to the ALSA API */
  239. + if (cmd == 315)
  240. + return -1;
  241. + else
  242. + return 0;
  243. +}
  244. +
  245. +static irqreturn_t
  246. +goldfish_audio_interrupt(int irq, void *dev_id)
  247. +{
  248. + unsigned long irq_flags;
  249. + struct goldfish_audio *data = dev_id;
  250. + uint32_t status;
  251. +
  252. + spin_lock_irqsave(&data->lock, irq_flags);
  253. +
  254. + /* read buffer status flags */
  255. + status = GOLDFISH_AUDIO_READ(data, AUDIO_INT_STATUS);
  256. + status &= AUDIO_INT_MASK;
  257. + /* if buffers are newly empty, wake up blocked goldfish_audio_write() call */
  258. + if(status) {
  259. + data->buffer_status = status;
  260. + wake_up(&data->wait);
  261. + }
  262. +
  263. + spin_unlock_irqrestore(&data->lock, irq_flags);
  264. + return status ? IRQ_HANDLED : IRQ_NONE;
  265. +}
  266. +
  267. +/* file operations for /dev/eac */
  268. +static struct file_operations goldfish_audio_fops = {
  269. + .owner = THIS_MODULE,
  270. + .read = goldfish_audio_read,
  271. + .write = goldfish_audio_write,
  272. + .open = goldfish_audio_open,
  273. + .release = goldfish_audio_release,
  274. + .ioctl = goldfish_audio_ioctl,
  275. +
  276. +};
  277. +
  278. +static struct miscdevice goldfish_audio_device = {
  279. + .minor = MISC_DYNAMIC_MINOR,
  280. + .name = "eac",
  281. + .fops = &goldfish_audio_fops,
  282. +};
  283. +
  284. +static int goldfish_audio_probe(struct platform_device *pdev)
  285. +{
  286. + int ret;
  287. + struct resource *r;
  288. + struct goldfish_audio *data;
  289. + dma_addr_t buf_addr;
  290. +
  291. +printk("goldfish_audio_probe\n");
  292. + data = kzalloc(sizeof(*data), GFP_KERNEL);
  293. + if(data == NULL) {
  294. + ret = -ENOMEM;
  295. + goto err_data_alloc_failed;
  296. + }
  297. + spin_lock_init(&data->lock);
  298. + init_waitqueue_head(&data->wait);
  299. + platform_set_drvdata(pdev, data);
  300. +
  301. + r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  302. + if(r == NULL) {
  303. + printk("platform_get_resource failed\n");
  304. + ret = -ENODEV;
  305. + goto err_no_io_base;
  306. + }
  307. + data->reg_base = IO_ADDRESS(r->start - IO_START);
  308. +
  309. + data->irq = platform_get_irq(pdev, 0);
  310. + if(data->irq < 0) {
  311. + printk("platform_get_irq failed\n");
  312. + ret = -ENODEV;
  313. + goto err_no_irq;
  314. + }
  315. +
  316. + data->buffer_virt = dma_alloc_writecombine(&pdev->dev, COMBINED_BUFFER_SIZE,
  317. + &buf_addr, GFP_KERNEL);
  318. + if(data->buffer_virt == 0) {
  319. + ret = -ENOMEM;
  320. + goto err_alloc_write_buffer_failed;
  321. + }
  322. + data->buffer_phys = buf_addr;
  323. + data->write_buffer1 = data->buffer_virt;
  324. + data->write_buffer2 = data->buffer_virt + WRITE_BUFFER_SIZE;
  325. + data->read_buffer = data->buffer_virt + 2 * WRITE_BUFFER_SIZE;
  326. +
  327. + ret = request_irq(data->irq, goldfish_audio_interrupt, IRQF_SHARED, pdev->name, data);
  328. + if(ret)
  329. + goto err_request_irq_failed;
  330. +
  331. + if((ret = misc_register(&goldfish_audio_device)))
  332. + {
  333. + printk("misc_register returned %d in goldfish_audio_init\n", ret);
  334. + goto err_misc_register_failed;
  335. + }
  336. +
  337. +
  338. + GOLDFISH_AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_1, buf_addr);
  339. + GOLDFISH_AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_2, buf_addr + WRITE_BUFFER_SIZE);
  340. +
  341. + data->read_supported = GOLDFISH_AUDIO_READ(data, AUDIO_READ_SUPPORTED);
  342. + if (data->read_supported)
  343. + GOLDFISH_AUDIO_WRITE(data, AUDIO_SET_READ_BUFFER, buf_addr + 2 * WRITE_BUFFER_SIZE);
  344. +
  345. + audio_data = data;
  346. + return 0;
  347. +
  348. +err_misc_register_failed:
  349. +err_request_irq_failed:
  350. + dma_free_writecombine(&pdev->dev, COMBINED_BUFFER_SIZE, data->buffer_virt, data->buffer_phys);
  351. +err_alloc_write_buffer_failed:
  352. +err_no_irq:
  353. +err_no_io_base:
  354. + kfree(data);
  355. +err_data_alloc_failed:
  356. + return ret;
  357. +}
  358. +
  359. +static int goldfish_audio_remove(struct platform_device *pdev)
  360. +{
  361. + struct goldfish_audio *data = platform_get_drvdata(pdev);
  362. +
  363. + misc_deregister(&goldfish_audio_device);
  364. + free_irq(data->irq, data);
  365. + dma_free_writecombine(&pdev->dev, COMBINED_BUFFER_SIZE, data->buffer_virt, data->buffer_phys);
  366. + kfree(data);
  367. + audio_data = NULL;
  368. + return 0;
  369. +}
  370. +
  371. +static struct platform_driver goldfish_audio_driver = {
  372. + .probe = goldfish_audio_probe,
  373. + .remove = goldfish_audio_remove,
  374. + .driver = {
  375. + .name = "goldfish_audio"
  376. + }
  377. +};
  378. +
  379. +static int __init goldfish_audio_init(void)
  380. +{
  381. + int ret;
  382. +
  383. + ret = platform_driver_register(&goldfish_audio_driver);
  384. + if (ret < 0)
  385. + {
  386. + printk("platform_driver_register returned %d\n", ret);
  387. + return ret;
  388. + }
  389. +
  390. + return ret;
  391. +}
  392. +
  393. +static void __exit goldfish_audio_exit(void)
  394. +{
  395. + platform_driver_unregister(&goldfish_audio_driver);
  396. +}
  397. +
  398. +module_init(goldfish_audio_init);
  399. +module_exit(goldfish_audio_exit);