Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/char/dsp56k.c
15109 views
1
/*
2
* The DSP56001 Device Driver, saviour of the Free World(tm)
3
*
4
* Authors: Fredrik Noring <[email protected]>
5
* lars brinkhoff <[email protected]>
6
* Tomas Berndtsson <[email protected]>
7
*
8
* First version May 1996
9
*
10
* History:
11
* 97-01-29 Tomas Berndtsson,
12
* Integrated with Linux 2.1.21 kernel sources.
13
* 97-02-15 Tomas Berndtsson,
14
* Fixed for kernel 2.1.26
15
*
16
* BUGS:
17
* Hmm... there must be something here :)
18
*
19
* Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
20
*
21
* This file is subject to the terms and conditions of the GNU General Public
22
* License. See the file COPYING in the main directory of this archive
23
* for more details.
24
*/
25
26
#include <linux/module.h>
27
#include <linux/major.h>
28
#include <linux/types.h>
29
#include <linux/errno.h>
30
#include <linux/delay.h> /* guess what */
31
#include <linux/fs.h>
32
#include <linux/mm.h>
33
#include <linux/init.h>
34
#include <linux/device.h>
35
#include <linux/mutex.h>
36
#include <linux/firmware.h>
37
#include <linux/platform_device.h>
38
#include <linux/uaccess.h> /* For put_user and get_user */
39
40
#include <asm/atarihw.h>
41
#include <asm/traps.h>
42
43
#include <asm/dsp56k.h>
44
45
/* minor devices */
46
#define DSP56K_DEV_56001 0 /* The only device so far */
47
48
#define TIMEOUT 10 /* Host port timeout in number of tries */
49
#define MAXIO 2048 /* Maximum number of words before sleep */
50
#define DSP56K_MAX_BINARY_LENGTH (3*64*1024)
51
52
#define DSP56K_TX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_TREQ
53
#define DSP56K_RX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_RREQ
54
#define DSP56K_TX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ
55
#define DSP56K_RX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ
56
57
#define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
58
#define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
59
60
#define handshake(count, maxio, timeout, ENABLE, f) \
61
{ \
62
long i, t, m; \
63
while (count > 0) { \
64
m = min_t(unsigned long, count, maxio); \
65
for (i = 0; i < m; i++) { \
66
for (t = 0; t < timeout && !ENABLE; t++) \
67
msleep(20); \
68
if(!ENABLE) \
69
return -EIO; \
70
f; \
71
} \
72
count -= m; \
73
if (m == maxio) msleep(20); \
74
} \
75
}
76
77
#define tx_wait(n) \
78
{ \
79
int t; \
80
for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
81
msleep(10); \
82
if(!DSP56K_TRANSMIT) { \
83
return -EIO; \
84
} \
85
}
86
87
#define rx_wait(n) \
88
{ \
89
int t; \
90
for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
91
msleep(10); \
92
if(!DSP56K_RECEIVE) { \
93
return -EIO; \
94
} \
95
}
96
97
static DEFINE_MUTEX(dsp56k_mutex);
98
static struct dsp56k_device {
99
unsigned long in_use;
100
long maxio, timeout;
101
int tx_wsize, rx_wsize;
102
} dsp56k;
103
104
static struct class *dsp56k_class;
105
106
static int dsp56k_reset(void)
107
{
108
u_char status;
109
110
/* Power down the DSP */
111
sound_ym.rd_data_reg_sel = 14;
112
status = sound_ym.rd_data_reg_sel & 0xef;
113
sound_ym.wd_data = status;
114
sound_ym.wd_data = status | 0x10;
115
116
udelay(10);
117
118
/* Power up the DSP */
119
sound_ym.rd_data_reg_sel = 14;
120
sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
121
122
return 0;
123
}
124
125
static int dsp56k_upload(u_char __user *bin, int len)
126
{
127
struct platform_device *pdev;
128
const struct firmware *fw;
129
const char fw_name[] = "dsp56k/bootstrap.bin";
130
int err;
131
int i;
132
133
dsp56k_reset();
134
135
pdev = platform_device_register_simple("dsp56k", 0, NULL, 0);
136
if (IS_ERR(pdev)) {
137
printk(KERN_ERR "Failed to register device for \"%s\"\n",
138
fw_name);
139
return -EINVAL;
140
}
141
err = request_firmware(&fw, fw_name, &pdev->dev);
142
platform_device_unregister(pdev);
143
if (err) {
144
printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
145
fw_name, err);
146
return err;
147
}
148
if (fw->size % 3) {
149
printk(KERN_ERR "Bogus length %d in image \"%s\"\n",
150
fw->size, fw_name);
151
release_firmware(fw);
152
return -EINVAL;
153
}
154
for (i = 0; i < fw->size; i = i + 3) {
155
/* tx_wait(10); */
156
dsp56k_host_interface.data.b[1] = fw->data[i];
157
dsp56k_host_interface.data.b[2] = fw->data[i + 1];
158
dsp56k_host_interface.data.b[3] = fw->data[i + 2];
159
}
160
release_firmware(fw);
161
for (; i < 512; i++) {
162
/* tx_wait(10); */
163
dsp56k_host_interface.data.b[1] = 0;
164
dsp56k_host_interface.data.b[2] = 0;
165
dsp56k_host_interface.data.b[3] = 0;
166
}
167
168
for (i = 0; i < len; i++) {
169
tx_wait(10);
170
get_user(dsp56k_host_interface.data.b[1], bin++);
171
get_user(dsp56k_host_interface.data.b[2], bin++);
172
get_user(dsp56k_host_interface.data.b[3], bin++);
173
}
174
175
tx_wait(10);
176
dsp56k_host_interface.data.l = 3; /* Magic execute */
177
178
return 0;
179
}
180
181
static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count,
182
loff_t *ppos)
183
{
184
struct inode *inode = file->f_path.dentry->d_inode;
185
int dev = iminor(inode) & 0x0f;
186
187
switch(dev)
188
{
189
case DSP56K_DEV_56001:
190
{
191
192
long n;
193
194
/* Don't do anything if nothing is to be done */
195
if (!count) return 0;
196
197
n = 0;
198
switch (dsp56k.rx_wsize) {
199
case 1: /* 8 bit */
200
{
201
handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
202
put_user(dsp56k_host_interface.data.b[3], buf+n++));
203
return n;
204
}
205
case 2: /* 16 bit */
206
{
207
short __user *data;
208
209
count /= 2;
210
data = (short __user *) buf;
211
handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
212
put_user(dsp56k_host_interface.data.w[1], data+n++));
213
return 2*n;
214
}
215
case 3: /* 24 bit */
216
{
217
count /= 3;
218
handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
219
put_user(dsp56k_host_interface.data.b[1], buf+n++);
220
put_user(dsp56k_host_interface.data.b[2], buf+n++);
221
put_user(dsp56k_host_interface.data.b[3], buf+n++));
222
return 3*n;
223
}
224
case 4: /* 32 bit */
225
{
226
long __user *data;
227
228
count /= 4;
229
data = (long __user *) buf;
230
handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
231
put_user(dsp56k_host_interface.data.l, data+n++));
232
return 4*n;
233
}
234
}
235
return -EFAULT;
236
}
237
238
default:
239
printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
240
return -ENXIO;
241
}
242
}
243
244
static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count,
245
loff_t *ppos)
246
{
247
struct inode *inode = file->f_path.dentry->d_inode;
248
int dev = iminor(inode) & 0x0f;
249
250
switch(dev)
251
{
252
case DSP56K_DEV_56001:
253
{
254
long n;
255
256
/* Don't do anything if nothing is to be done */
257
if (!count) return 0;
258
259
n = 0;
260
switch (dsp56k.tx_wsize) {
261
case 1: /* 8 bit */
262
{
263
handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
264
get_user(dsp56k_host_interface.data.b[3], buf+n++));
265
return n;
266
}
267
case 2: /* 16 bit */
268
{
269
const short __user *data;
270
271
count /= 2;
272
data = (const short __user *)buf;
273
handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
274
get_user(dsp56k_host_interface.data.w[1], data+n++));
275
return 2*n;
276
}
277
case 3: /* 24 bit */
278
{
279
count /= 3;
280
handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
281
get_user(dsp56k_host_interface.data.b[1], buf+n++);
282
get_user(dsp56k_host_interface.data.b[2], buf+n++);
283
get_user(dsp56k_host_interface.data.b[3], buf+n++));
284
return 3*n;
285
}
286
case 4: /* 32 bit */
287
{
288
const long __user *data;
289
290
count /= 4;
291
data = (const long __user *)buf;
292
handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
293
get_user(dsp56k_host_interface.data.l, data+n++));
294
return 4*n;
295
}
296
}
297
298
return -EFAULT;
299
}
300
default:
301
printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
302
return -ENXIO;
303
}
304
}
305
306
static long dsp56k_ioctl(struct file *file, unsigned int cmd,
307
unsigned long arg)
308
{
309
int dev = iminor(file->f_path.dentry->d_inode) & 0x0f;
310
void __user *argp = (void __user *)arg;
311
312
switch(dev)
313
{
314
case DSP56K_DEV_56001:
315
316
switch(cmd) {
317
case DSP56K_UPLOAD:
318
{
319
char __user *bin;
320
int r, len;
321
struct dsp56k_upload __user *binary = argp;
322
323
if(get_user(len, &binary->len) < 0)
324
return -EFAULT;
325
if(get_user(bin, &binary->bin) < 0)
326
return -EFAULT;
327
328
if (len == 0) {
329
return -EINVAL; /* nothing to upload?!? */
330
}
331
if (len > DSP56K_MAX_BINARY_LENGTH) {
332
return -EINVAL;
333
}
334
mutex_lock(&dsp56k_mutex);
335
r = dsp56k_upload(bin, len);
336
mutex_unlock(&dsp56k_mutex);
337
if (r < 0) {
338
return r;
339
}
340
341
break;
342
}
343
case DSP56K_SET_TX_WSIZE:
344
if (arg > 4 || arg < 1)
345
return -EINVAL;
346
mutex_lock(&dsp56k_mutex);
347
dsp56k.tx_wsize = (int) arg;
348
mutex_unlock(&dsp56k_mutex);
349
break;
350
case DSP56K_SET_RX_WSIZE:
351
if (arg > 4 || arg < 1)
352
return -EINVAL;
353
mutex_lock(&dsp56k_mutex);
354
dsp56k.rx_wsize = (int) arg;
355
mutex_unlock(&dsp56k_mutex);
356
break;
357
case DSP56K_HOST_FLAGS:
358
{
359
int dir, out, status;
360
struct dsp56k_host_flags __user *hf = argp;
361
362
if(get_user(dir, &hf->dir) < 0)
363
return -EFAULT;
364
if(get_user(out, &hf->out) < 0)
365
return -EFAULT;
366
367
mutex_lock(&dsp56k_mutex);
368
if ((dir & 0x1) && (out & 0x1))
369
dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
370
else if (dir & 0x1)
371
dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
372
if ((dir & 0x2) && (out & 0x2))
373
dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
374
else if (dir & 0x2)
375
dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
376
377
status = 0;
378
if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
379
if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
380
if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
381
if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
382
mutex_unlock(&dsp56k_mutex);
383
return put_user(status, &hf->status);
384
}
385
case DSP56K_HOST_CMD:
386
if (arg > 31 || arg < 0)
387
return -EINVAL;
388
mutex_lock(&dsp56k_mutex);
389
dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
390
DSP56K_CVR_HC);
391
mutex_unlock(&dsp56k_mutex);
392
break;
393
default:
394
return -EINVAL;
395
}
396
return 0;
397
398
default:
399
printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
400
return -ENXIO;
401
}
402
}
403
404
/* As of 2.1.26 this should be dsp56k_poll,
405
* but how do I then check device minor number?
406
* Do I need this function at all???
407
*/
408
#if 0
409
static unsigned int dsp56k_poll(struct file *file, poll_table *wait)
410
{
411
int dev = iminor(file->f_path.dentry->d_inode) & 0x0f;
412
413
switch(dev)
414
{
415
case DSP56K_DEV_56001:
416
/* poll_wait(file, ???, wait); */
417
return POLLIN | POLLRDNORM | POLLOUT;
418
419
default:
420
printk("DSP56k driver: Unknown minor device: %d\n", dev);
421
return 0;
422
}
423
}
424
#endif
425
426
static int dsp56k_open(struct inode *inode, struct file *file)
427
{
428
int dev = iminor(inode) & 0x0f;
429
int ret = 0;
430
431
mutex_lock(&dsp56k_mutex);
432
switch(dev)
433
{
434
case DSP56K_DEV_56001:
435
436
if (test_and_set_bit(0, &dsp56k.in_use)) {
437
ret = -EBUSY;
438
goto out;
439
}
440
441
dsp56k.timeout = TIMEOUT;
442
dsp56k.maxio = MAXIO;
443
dsp56k.rx_wsize = dsp56k.tx_wsize = 4;
444
445
DSP56K_TX_INT_OFF;
446
DSP56K_RX_INT_OFF;
447
448
/* Zero host flags */
449
dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
450
dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
451
452
break;
453
454
default:
455
ret = -ENODEV;
456
}
457
out:
458
mutex_unlock(&dsp56k_mutex);
459
return ret;
460
}
461
462
static int dsp56k_release(struct inode *inode, struct file *file)
463
{
464
int dev = iminor(inode) & 0x0f;
465
466
switch(dev)
467
{
468
case DSP56K_DEV_56001:
469
clear_bit(0, &dsp56k.in_use);
470
break;
471
default:
472
printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
473
return -ENXIO;
474
}
475
476
return 0;
477
}
478
479
static const struct file_operations dsp56k_fops = {
480
.owner = THIS_MODULE,
481
.read = dsp56k_read,
482
.write = dsp56k_write,
483
.unlocked_ioctl = dsp56k_ioctl,
484
.open = dsp56k_open,
485
.release = dsp56k_release,
486
.llseek = noop_llseek,
487
};
488
489
490
/****** Init and module functions ******/
491
492
static char banner[] __initdata = KERN_INFO "DSP56k driver installed\n";
493
494
static int __init dsp56k_init_driver(void)
495
{
496
int err = 0;
497
498
if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
499
printk("DSP56k driver: Hardware not present\n");
500
return -ENODEV;
501
}
502
503
if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
504
printk("DSP56k driver: Unable to register driver\n");
505
return -ENODEV;
506
}
507
dsp56k_class = class_create(THIS_MODULE, "dsp56k");
508
if (IS_ERR(dsp56k_class)) {
509
err = PTR_ERR(dsp56k_class);
510
goto out_chrdev;
511
}
512
device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL,
513
"dsp56k");
514
515
printk(banner);
516
goto out;
517
518
out_chrdev:
519
unregister_chrdev(DSP56K_MAJOR, "dsp56k");
520
out:
521
return err;
522
}
523
module_init(dsp56k_init_driver);
524
525
static void __exit dsp56k_cleanup_driver(void)
526
{
527
device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
528
class_destroy(dsp56k_class);
529
unregister_chrdev(DSP56K_MAJOR, "dsp56k");
530
}
531
module_exit(dsp56k_cleanup_driver);
532
533
MODULE_LICENSE("GPL");
534
MODULE_FIRMWARE("dsp56k/bootstrap.bin");
535
536