linux/drivers/staging/goldfish/goldfish_audio.c
<<
>>
Prefs
   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
  29MODULE_AUTHOR("Google, Inc.");
  30MODULE_DESCRIPTION("Android QEMU Audio Driver");
  31MODULE_LICENSE("GPL");
  32MODULE_VERSION("1.0");
  33
  34struct 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() */
  64static struct goldfish_audio *audio_data;
  65
  66enum {
  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
 102static atomic_t open_count = ATOMIC_INIT(0);
 103
 104
 105static 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
 136static 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
 182static 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
 199static 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
 207static 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
 217static 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 */
 240static 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
 249static struct miscdevice goldfish_audio_device = {
 250        .minor = MISC_DYNAMIC_MINOR,
 251        .name = "eac",
 252        .fops = &goldfish_audio_fops,
 253};
 254
 255static 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
 328err_misc_register_failed:
 329err_request_irq_failed:
 330        dma_free_coherent(&pdev->dev, COMBINED_BUFFER_SIZE,
 331                                        data->buffer_virt, data->buffer_phys);
 332err_alloc_write_buffer_failed:
 333err_no_irq:
 334        iounmap(data->reg_base);
 335err_no_io_base:
 336        kfree(data);
 337err_data_alloc_failed:
 338        return ret;
 339}
 340
 341static 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
 355static 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
 363module_platform_driver(goldfish_audio_driver);
 364
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.