1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
42 unsigned long buffer_phys;
43
44 char __iomem *write_buffer1;
45 char __iomem *write_buffer2;
46 char __iomem *read_buffer;
47 int buffer_status;
48 int read_supported;
49};
50
51
52
53
54
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
66
67
68static struct goldfish_audio *audio_data;
69
70enum {
71
72 AUDIO_INT_STATUS = 0x00,
73
74 AUDIO_INT_ENABLE = 0x04,
75
76 AUDIO_SET_WRITE_BUFFER_1 = 0x08,
77 AUDIO_SET_WRITE_BUFFER_2 = 0x0C,
78
79 AUDIO_WRITE_BUFFER_1 = 0x10,
80 AUDIO_WRITE_BUFFER_2 = 0x14,
81
82
83 AUDIO_READ_SUPPORTED = 0x18,
84
85 AUDIO_SET_READ_BUFFER = 0x1C,
86
87
88 AUDIO_START_READ = 0x20,
89
90
91 AUDIO_READ_BUFFER_AVAILABLE = 0x24,
92
93
94
95
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
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
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
170
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
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
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
232 status = AUDIO_READ(data, AUDIO_INT_STATUS);
233 status &= AUDIO_INT_MASK;
234
235
236
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
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