Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/oss/msnd.c
10814 views
1
/*********************************************************************
2
*
3
* msnd.c - Driver Base
4
*
5
* Turtle Beach MultiSound Sound Card Driver for Linux
6
*
7
* Copyright (C) 1998 Andrew Veliath
8
*
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
13
*
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
18
*
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
*
23
********************************************************************/
24
25
#include <linux/module.h>
26
#include <linux/kernel.h>
27
#include <linux/vmalloc.h>
28
#include <linux/types.h>
29
#include <linux/delay.h>
30
#include <linux/mm.h>
31
#include <linux/init.h>
32
#include <linux/interrupt.h>
33
34
#include <asm/io.h>
35
#include <asm/uaccess.h>
36
#include <linux/spinlock.h>
37
#include <asm/irq.h>
38
#include "msnd.h"
39
40
#define LOGNAME "msnd"
41
42
#define MSND_MAX_DEVS 4
43
44
static multisound_dev_t *devs[MSND_MAX_DEVS];
45
static int num_devs;
46
47
int msnd_register(multisound_dev_t *dev)
48
{
49
int i;
50
51
for (i = 0; i < MSND_MAX_DEVS; ++i)
52
if (devs[i] == NULL)
53
break;
54
55
if (i == MSND_MAX_DEVS)
56
return -ENOMEM;
57
58
devs[i] = dev;
59
++num_devs;
60
return 0;
61
}
62
63
void msnd_unregister(multisound_dev_t *dev)
64
{
65
int i;
66
67
for (i = 0; i < MSND_MAX_DEVS; ++i)
68
if (devs[i] == dev)
69
break;
70
71
if (i == MSND_MAX_DEVS) {
72
printk(KERN_WARNING LOGNAME ": Unregistering unknown device\n");
73
return;
74
}
75
76
devs[i] = NULL;
77
--num_devs;
78
}
79
80
void msnd_init_queue(void __iomem *base, int start, int size)
81
{
82
writew(PCTODSP_BASED(start), base + JQS_wStart);
83
writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
84
writew(0, base + JQS_wHead);
85
writew(0, base + JQS_wTail);
86
}
87
88
void msnd_fifo_init(msnd_fifo *f)
89
{
90
f->data = NULL;
91
}
92
93
void msnd_fifo_free(msnd_fifo *f)
94
{
95
vfree(f->data);
96
f->data = NULL;
97
}
98
99
int msnd_fifo_alloc(msnd_fifo *f, size_t n)
100
{
101
msnd_fifo_free(f);
102
f->data = vmalloc(n);
103
f->n = n;
104
f->tail = 0;
105
f->head = 0;
106
f->len = 0;
107
108
if (!f->data)
109
return -ENOMEM;
110
111
return 0;
112
}
113
114
void msnd_fifo_make_empty(msnd_fifo *f)
115
{
116
f->len = f->tail = f->head = 0;
117
}
118
119
int msnd_fifo_write_io(msnd_fifo *f, char __iomem *buf, size_t len)
120
{
121
int count = 0;
122
123
while ((count < len) && (f->len != f->n)) {
124
125
int nwritten;
126
127
if (f->head <= f->tail) {
128
nwritten = len - count;
129
if (nwritten > f->n - f->tail)
130
nwritten = f->n - f->tail;
131
}
132
else {
133
nwritten = f->head - f->tail;
134
if (nwritten > len - count)
135
nwritten = len - count;
136
}
137
138
memcpy_fromio(f->data + f->tail, buf, nwritten);
139
140
count += nwritten;
141
buf += nwritten;
142
f->len += nwritten;
143
f->tail += nwritten;
144
f->tail %= f->n;
145
}
146
147
return count;
148
}
149
150
int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len)
151
{
152
int count = 0;
153
154
while ((count < len) && (f->len != f->n)) {
155
156
int nwritten;
157
158
if (f->head <= f->tail) {
159
nwritten = len - count;
160
if (nwritten > f->n - f->tail)
161
nwritten = f->n - f->tail;
162
}
163
else {
164
nwritten = f->head - f->tail;
165
if (nwritten > len - count)
166
nwritten = len - count;
167
}
168
169
memcpy(f->data + f->tail, buf, nwritten);
170
171
count += nwritten;
172
buf += nwritten;
173
f->len += nwritten;
174
f->tail += nwritten;
175
f->tail %= f->n;
176
}
177
178
return count;
179
}
180
181
int msnd_fifo_read_io(msnd_fifo *f, char __iomem *buf, size_t len)
182
{
183
int count = 0;
184
185
while ((count < len) && (f->len > 0)) {
186
187
int nread;
188
189
if (f->tail <= f->head) {
190
nread = len - count;
191
if (nread > f->n - f->head)
192
nread = f->n - f->head;
193
}
194
else {
195
nread = f->tail - f->head;
196
if (nread > len - count)
197
nread = len - count;
198
}
199
200
memcpy_toio(buf, f->data + f->head, nread);
201
202
count += nread;
203
buf += nread;
204
f->len -= nread;
205
f->head += nread;
206
f->head %= f->n;
207
}
208
209
return count;
210
}
211
212
int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len)
213
{
214
int count = 0;
215
216
while ((count < len) && (f->len > 0)) {
217
218
int nread;
219
220
if (f->tail <= f->head) {
221
nread = len - count;
222
if (nread > f->n - f->head)
223
nread = f->n - f->head;
224
}
225
else {
226
nread = f->tail - f->head;
227
if (nread > len - count)
228
nread = len - count;
229
}
230
231
memcpy(buf, f->data + f->head, nread);
232
233
count += nread;
234
buf += nread;
235
f->len -= nread;
236
f->head += nread;
237
f->head %= f->n;
238
}
239
240
return count;
241
}
242
243
static int msnd_wait_TXDE(multisound_dev_t *dev)
244
{
245
register unsigned int io = dev->io;
246
register int timeout = 1000;
247
248
while(timeout-- > 0)
249
if (msnd_inb(io + HP_ISR) & HPISR_TXDE)
250
return 0;
251
252
return -EIO;
253
}
254
255
static int msnd_wait_HC0(multisound_dev_t *dev)
256
{
257
register unsigned int io = dev->io;
258
register int timeout = 1000;
259
260
while(timeout-- > 0)
261
if (!(msnd_inb(io + HP_CVR) & HPCVR_HC))
262
return 0;
263
264
return -EIO;
265
}
266
267
int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd)
268
{
269
unsigned long flags;
270
271
spin_lock_irqsave(&dev->lock, flags);
272
if (msnd_wait_HC0(dev) == 0) {
273
msnd_outb(cmd, dev->io + HP_CVR);
274
spin_unlock_irqrestore(&dev->lock, flags);
275
return 0;
276
}
277
spin_unlock_irqrestore(&dev->lock, flags);
278
279
printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n");
280
281
return -EIO;
282
}
283
284
int msnd_send_word(multisound_dev_t *dev, unsigned char high,
285
unsigned char mid, unsigned char low)
286
{
287
register unsigned int io = dev->io;
288
289
if (msnd_wait_TXDE(dev) == 0) {
290
msnd_outb(high, io + HP_TXH);
291
msnd_outb(mid, io + HP_TXM);
292
msnd_outb(low, io + HP_TXL);
293
return 0;
294
}
295
296
printk(KERN_DEBUG LOGNAME ": Send host word timeout\n");
297
298
return -EIO;
299
}
300
301
int msnd_upload_host(multisound_dev_t *dev, char *bin, int len)
302
{
303
int i;
304
305
if (len % 3 != 0) {
306
printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n");
307
return -EINVAL;
308
}
309
310
for (i = 0; i < len; i += 3)
311
if (msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]) != 0)
312
return -EIO;
313
314
msnd_inb(dev->io + HP_RXL);
315
msnd_inb(dev->io + HP_CVR);
316
317
return 0;
318
}
319
320
int msnd_enable_irq(multisound_dev_t *dev)
321
{
322
unsigned long flags;
323
324
if (dev->irq_ref++)
325
return 0;
326
327
printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n");
328
329
spin_lock_irqsave(&dev->lock, flags);
330
if (msnd_wait_TXDE(dev) == 0) {
331
msnd_outb(msnd_inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
332
if (dev->type == msndClassic)
333
msnd_outb(dev->irqid, dev->io + HP_IRQM);
334
msnd_outb(msnd_inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
335
msnd_outb(msnd_inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
336
enable_irq(dev->irq);
337
msnd_init_queue(dev->DSPQ, dev->dspq_data_buff, dev->dspq_buff_size);
338
spin_unlock_irqrestore(&dev->lock, flags);
339
return 0;
340
}
341
spin_unlock_irqrestore(&dev->lock, flags);
342
343
printk(KERN_DEBUG LOGNAME ": Enable IRQ failed\n");
344
345
return -EIO;
346
}
347
348
int msnd_disable_irq(multisound_dev_t *dev)
349
{
350
unsigned long flags;
351
352
if (--dev->irq_ref > 0)
353
return 0;
354
355
if (dev->irq_ref < 0)
356
printk(KERN_DEBUG LOGNAME ": IRQ ref count is %d\n", dev->irq_ref);
357
358
printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n");
359
360
spin_lock_irqsave(&dev->lock, flags);
361
if (msnd_wait_TXDE(dev) == 0) {
362
msnd_outb(msnd_inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
363
if (dev->type == msndClassic)
364
msnd_outb(HPIRQ_NONE, dev->io + HP_IRQM);
365
disable_irq(dev->irq);
366
spin_unlock_irqrestore(&dev->lock, flags);
367
return 0;
368
}
369
spin_unlock_irqrestore(&dev->lock, flags);
370
371
printk(KERN_DEBUG LOGNAME ": Disable IRQ failed\n");
372
373
return -EIO;
374
}
375
376
#ifndef LINUX20
377
EXPORT_SYMBOL(msnd_register);
378
EXPORT_SYMBOL(msnd_unregister);
379
380
EXPORT_SYMBOL(msnd_init_queue);
381
382
EXPORT_SYMBOL(msnd_fifo_init);
383
EXPORT_SYMBOL(msnd_fifo_free);
384
EXPORT_SYMBOL(msnd_fifo_alloc);
385
EXPORT_SYMBOL(msnd_fifo_make_empty);
386
EXPORT_SYMBOL(msnd_fifo_write_io);
387
EXPORT_SYMBOL(msnd_fifo_read_io);
388
EXPORT_SYMBOL(msnd_fifo_write);
389
EXPORT_SYMBOL(msnd_fifo_read);
390
391
EXPORT_SYMBOL(msnd_send_dsp_cmd);
392
EXPORT_SYMBOL(msnd_send_word);
393
EXPORT_SYMBOL(msnd_upload_host);
394
395
EXPORT_SYMBOL(msnd_enable_irq);
396
EXPORT_SYMBOL(msnd_disable_irq);
397
#endif
398
399
#ifdef MODULE
400
MODULE_AUTHOR ("Andrew Veliath <[email protected]>");
401
MODULE_DESCRIPTION ("Turtle Beach MultiSound Driver Base");
402
MODULE_LICENSE("GPL");
403
404
405
int init_module(void)
406
{
407
return 0;
408
}
409
410
void cleanup_module(void)
411
{
412
}
413
#endif
414
415