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