Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

goldfish: audio support

(remove change to another file that escaped into the patch set)

From: Mike Lockwood <lockwood@google.com>

Provide a simple audio channel between the kernel and the emulator that host
sit. Queued for staging right now as this ought to be an ALSA driver not
just a dumb device of its own making.

Signed-off-by: Mike A. Chan <mikechan@google.com>
[x86 support]
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Xiaohui Xin <xiaohui.xin@intel.com>
Signed-off-by: Jun Nakajima <jun.nakajima@intel.com>
Signed-off-by: Bruce Beare <bruce.j.beare@intel.com>
[Clean up]
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alan Cox and committed by
Greg Kroah-Hartman
2e82b83d 17c4c9db

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