OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [dsp56k.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * The DSP56001 Device Driver, saviour of the Free World(tm)
3
 *
4
 * Authors: Fredrik Noring   <noring@nocrew.org>
5
 *          lars brinkhoff   <lars@nocrew.org>
6
 *          Tomas Berndtsson <tomas@nocrew.org>
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/version.h>
28
#include <linux/slab.h> /* for kmalloc() and kfree() */
29
#include <linux/sched.h>        /* for struct wait_queue etc */
30
#include <linux/major.h>
31
#include <linux/types.h>
32
#include <linux/errno.h>
33
#include <linux/delay.h>        /* guess what */
34
#include <linux/fs.h>
35
#include <linux/mm.h>
36
#include <linux/init.h>
37
#include <linux/devfs_fs_kernel.h>
38
#include <linux/smp_lock.h>
39
 
40
#include <asm/segment.h>
41
#include <asm/atarihw.h>
42
#include <asm/traps.h>
43
#include <asm/uaccess.h>        /* For put_user and get_user */
44
 
45
#include <asm/dsp56k.h>
46
 
47
/* minor devices */
48
#define DSP56K_DEV_56001        0    /* The only device so far */
49
 
50
#define TIMEOUT    10   /* Host port timeout in number of tries */
51
#define MAXIO    2048   /* Maximum number of words before sleep */
52
#define DSP56K_MAX_BINARY_LENGTH (3*64*1024)
53
 
54
#define DSP56K_TX_INT_ON        dsp56k_host_interface.icr |=  DSP56K_ICR_TREQ
55
#define DSP56K_RX_INT_ON        dsp56k_host_interface.icr |=  DSP56K_ICR_RREQ
56
#define DSP56K_TX_INT_OFF       dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ
57
#define DSP56K_RX_INT_OFF       dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ
58
 
59
#define DSP56K_TRANSMIT         (dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
60
#define DSP56K_RECEIVE          (dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
61
 
62
#define wait_some(n) \
63
{ \
64
        set_current_state(TASK_INTERRUPTIBLE); \
65
        schedule_timeout(n); \
66
}
67
 
68
#define handshake(count, maxio, timeout, ENABLE, f) \
69
{ \
70
        long i, t, m; \
71
        while (count > 0) { \
72
                m = min_t(unsigned long, count, maxio); \
73
                for (i = 0; i < m; i++) { \
74
                        for (t = 0; t < timeout && !ENABLE; t++) \
75
                                wait_some(HZ/50); \
76
                        if(!ENABLE) \
77
                                return -EIO; \
78
                        f; \
79
                } \
80
                count -= m; \
81
                if (m == maxio) wait_some(HZ/50); \
82
        } \
83
}
84
 
85
#define tx_wait(n) \
86
{ \
87
        int t; \
88
        for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
89
                wait_some(HZ/100); \
90
        if(!DSP56K_TRANSMIT) { \
91
                return -EIO; \
92
        } \
93
}
94
 
95
#define rx_wait(n) \
96
{ \
97
        int t; \
98
        for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
99
                wait_some(HZ/100); \
100
        if(!DSP56K_RECEIVE) { \
101
                return -EIO; \
102
        } \
103
}
104
 
105
/* DSP56001 bootstrap code */
106
static char bootstrap[] = {
107
        0x0c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126
        0x00, 0x00, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4,
127
        0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47,
128
        0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00,
129
        0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe,
130
        0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0,
131
        0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a,
132
        0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4,
133
        0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01,
134
        0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08,
135
        0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46,
136
        0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa,
137
        0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00,
138
        0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9,
139
        0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80,
140
        0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a,
141
        0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0,
142
        0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4,
143
        0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a,
144
        0xf0, 0x80, 0x00, 0x7e, 0xad};
145
static int sizeof_bootstrap = 375;
146
 
147
 
148
static struct dsp56k_device {
149
        long in_use;
150
        long maxio, timeout;
151
        int tx_wsize, rx_wsize;
152
} dsp56k;
153
 
154
static int dsp56k_reset(void)
155
{
156
        u_char status;
157
 
158
        /* Power down the DSP */
159
        sound_ym.rd_data_reg_sel = 14;
160
        status = sound_ym.rd_data_reg_sel & 0xef;
161
        sound_ym.wd_data = status;
162
        sound_ym.wd_data = status | 0x10;
163
 
164
        udelay(10);
165
 
166
        /* Power up the DSP */
167
        sound_ym.rd_data_reg_sel = 14;
168
        sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
169
 
170
        return 0;
171
}
172
 
173
static int dsp56k_upload(u_char *bin, int len)
174
{
175
        int i;
176
        u_char *p;
177
 
178
        dsp56k_reset();
179
 
180
        p = bootstrap;
181
        for (i = 0; i < sizeof_bootstrap/3; i++) {
182
                /* tx_wait(10); */
183
                dsp56k_host_interface.data.b[1] = *p++;
184
                dsp56k_host_interface.data.b[2] = *p++;
185
                dsp56k_host_interface.data.b[3] = *p++;
186
        }
187
        for (; i < 512; i++) {
188
                /* tx_wait(10); */
189
                dsp56k_host_interface.data.b[1] = 0;
190
                dsp56k_host_interface.data.b[2] = 0;
191
                dsp56k_host_interface.data.b[3] = 0;
192
        }
193
 
194
        for (i = 0; i < len; i++) {
195
                tx_wait(10);
196
                get_user(dsp56k_host_interface.data.b[1], bin++);
197
                get_user(dsp56k_host_interface.data.b[2], bin++);
198
                get_user(dsp56k_host_interface.data.b[3], bin++);
199
        }
200
 
201
        tx_wait(10);
202
        dsp56k_host_interface.data.l = 3;    /* Magic execute */
203
 
204
        return 0;
205
}
206
 
207
static ssize_t dsp56k_read(struct file *file, char *buf, size_t count,
208
                           loff_t *ppos)
209
{
210
        struct inode *inode = file->f_dentry->d_inode;
211
        int dev = MINOR(inode->i_rdev) & 0x0f;
212
 
213
        switch(dev)
214
        {
215
        case DSP56K_DEV_56001:
216
        {
217
 
218
                long n;
219
 
220
                /* Don't do anything if nothing is to be done */
221
                if (!count) return 0;
222
 
223
                n = 0;
224
                switch (dsp56k.rx_wsize) {
225
                case 1:  /* 8 bit */
226
                {
227
                        handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
228
                                  put_user(dsp56k_host_interface.data.b[3], buf+n++));
229
                        return n;
230
                }
231
                case 2:  /* 16 bit */
232
                {
233
                        short *data;
234
 
235
                        count /= 2;
236
                        data = (short*) buf;
237
                        handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
238
                                  put_user(dsp56k_host_interface.data.w[1], data+n++));
239
                        return 2*n;
240
                }
241
                case 3:  /* 24 bit */
242
                {
243
                        count /= 3;
244
                        handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
245
                                  put_user(dsp56k_host_interface.data.b[1], buf+n++);
246
                                  put_user(dsp56k_host_interface.data.b[2], buf+n++);
247
                                  put_user(dsp56k_host_interface.data.b[3], buf+n++));
248
                        return 3*n;
249
                }
250
                case 4:  /* 32 bit */
251
                {
252
                        long *data;
253
 
254
                        count /= 4;
255
                        data = (long*) buf;
256
                        handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
257
                                  put_user(dsp56k_host_interface.data.l, data+n++));
258
                        return 4*n;
259
                }
260
                }
261
                return -EFAULT;
262
        }
263
 
264
        default:
265
                printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
266
                return -ENXIO;
267
        }
268
}
269
 
270
static ssize_t dsp56k_write(struct file *file, const char *buf, size_t count,
271
                            loff_t *ppos)
272
{
273
        struct inode *inode = file->f_dentry->d_inode;
274
        int dev = MINOR(inode->i_rdev) & 0x0f;
275
 
276
        switch(dev)
277
        {
278
        case DSP56K_DEV_56001:
279
        {
280
                long n;
281
 
282
                /* Don't do anything if nothing is to be done */
283
                if (!count) return 0;
284
 
285
                n = 0;
286
                switch (dsp56k.tx_wsize) {
287
                case 1:  /* 8 bit */
288
                {
289
                        handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
290
                                  get_user(dsp56k_host_interface.data.b[3], buf+n++));
291
                        return n;
292
                }
293
                case 2:  /* 16 bit */
294
                {
295
                        short *data;
296
 
297
                        count /= 2;
298
                        data = (short*) buf;
299
                        handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
300
                                  get_user(dsp56k_host_interface.data.w[1], data+n++));
301
                        return 2*n;
302
                }
303
                case 3:  /* 24 bit */
304
                {
305
                        count /= 3;
306
                        handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
307
                                  get_user(dsp56k_host_interface.data.b[1], buf+n++);
308
                                  get_user(dsp56k_host_interface.data.b[2], buf+n++);
309
                                  get_user(dsp56k_host_interface.data.b[3], buf+n++));
310
                        return 3*n;
311
                }
312
                case 4:  /* 32 bit */
313
                {
314
                        long *data;
315
 
316
                        count /= 4;
317
                        data = (long*) buf;
318
                        handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
319
                                  get_user(dsp56k_host_interface.data.l, data+n++));
320
                        return 4*n;
321
                }
322
                }
323
 
324
                return -EFAULT;
325
        }
326
        default:
327
                printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
328
                return -ENXIO;
329
        }
330
}
331
 
332
static int dsp56k_ioctl(struct inode *inode, struct file *file,
333
                        unsigned int cmd, unsigned long arg)
334
{
335
        int dev = MINOR(inode->i_rdev) & 0x0f;
336
 
337
        switch(dev)
338
        {
339
        case DSP56K_DEV_56001:
340
 
341
                switch(cmd) {
342
                case DSP56K_UPLOAD:
343
                {
344
                        char *bin;
345
                        int r, len;
346
                        struct dsp56k_upload *binary = (struct dsp56k_upload *) arg;
347
 
348
                        if(get_user(len, &binary->len) < 0)
349
                                return -EFAULT;
350
                        if(get_user(bin, &binary->bin) < 0)
351
                                return -EFAULT;
352
 
353
                        if (len == 0) {
354
                                return -EINVAL;      /* nothing to upload?!? */
355
                        }
356
                        if (len > DSP56K_MAX_BINARY_LENGTH) {
357
                                return -EINVAL;
358
                        }
359
 
360
                        r = dsp56k_upload(bin, len);
361
                        if (r < 0) {
362
                                return r;
363
                        }
364
 
365
                        break;
366
                }
367
                case DSP56K_SET_TX_WSIZE:
368
                        if (arg > 4 || arg < 1)
369
                                return -EINVAL;
370
                        dsp56k.tx_wsize = (int) arg;
371
                        break;
372
                case DSP56K_SET_RX_WSIZE:
373
                        if (arg > 4 || arg < 1)
374
                                return -EINVAL;
375
                        dsp56k.rx_wsize = (int) arg;
376
                        break;
377
                case DSP56K_HOST_FLAGS:
378
                {
379
                        int dir, out, status;
380
                        struct dsp56k_host_flags *hf = (struct dsp56k_host_flags*) arg;
381
 
382
                        if(get_user(dir, &hf->dir) < 0)
383
                                return -EFAULT;
384
                        if(get_user(out, &hf->out) < 0)
385
                                return -EFAULT;
386
 
387
                        if ((dir & 0x1) && (out & 0x1))
388
                                dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
389
                        else if (dir & 0x1)
390
                                dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
391
                        if ((dir & 0x2) && (out & 0x2))
392
                                dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
393
                        else if (dir & 0x2)
394
                                dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
395
 
396
                        status = 0;
397
                        if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
398
                        if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
399
                        if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
400
                        if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
401
 
402
                        return put_user(status, &hf->status);
403
                }
404
                case DSP56K_HOST_CMD:
405
                        if (arg > 31 || arg < 0)
406
                                return -EINVAL;
407
                        dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
408
                                                             DSP56K_CVR_HC);
409
                        break;
410
                default:
411
                        return -EINVAL;
412
                }
413
                return 0;
414
 
415
        default:
416
                printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
417
                return -ENXIO;
418
        }
419
}
420
 
421
/* As of 2.1.26 this should be dsp56k_poll,
422
 * but how do I then check device minor number?
423
 * Do I need this function at all???
424
 */
425
#if 0
426
static unsigned int dsp56k_poll(struct file *file, poll_table *wait)
427
{
428
        int dev = MINOR(file->f_dentry->d_inode->i_rdev) & 0x0f;
429
 
430
        switch(dev)
431
        {
432
        case DSP56K_DEV_56001:
433
                /* poll_wait(file, ???, wait); */
434
                return POLLIN | POLLRDNORM | POLLOUT;
435
 
436
        default:
437
                printk("DSP56k driver: Unknown minor device: %d\n", dev);
438
                return 0;
439
        }
440
}
441
#endif
442
 
443
static int dsp56k_open(struct inode *inode, struct file *file)
444
{
445
        int dev = MINOR(inode->i_rdev) & 0x0f;
446
 
447
        switch(dev)
448
        {
449
        case DSP56K_DEV_56001:
450
 
451
                if (test_and_set_bit(0, &dsp56k.in_use))
452
                        return -EBUSY;
453
 
454
                dsp56k.timeout = TIMEOUT;
455
                dsp56k.maxio = MAXIO;
456
                dsp56k.rx_wsize = dsp56k.tx_wsize = 4;
457
 
458
                DSP56K_TX_INT_OFF;
459
                DSP56K_RX_INT_OFF;
460
 
461
                /* Zero host flags */
462
                dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
463
                dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
464
 
465
                break;
466
 
467
        default:
468
                return -ENODEV;
469
        }
470
 
471
        return 0;
472
}
473
 
474
static int dsp56k_release(struct inode *inode, struct file *file)
475
{
476
        int dev = MINOR(inode->i_rdev) & 0x0f;
477
 
478
        switch(dev)
479
        {
480
        case DSP56K_DEV_56001:
481
                clear_bit(0, &dsp56k.in_use);
482
                break;
483
        default:
484
                printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
485
                return -ENXIO;
486
        }
487
 
488
        return 0;
489
}
490
 
491
static struct file_operations dsp56k_fops = {
492
        owner:          THIS_MODULE,
493
        read:           dsp56k_read,
494
        write:          dsp56k_write,
495
        ioctl:          dsp56k_ioctl,
496
        open:           dsp56k_open,
497
        release:        dsp56k_release,
498
};
499
 
500
 
501
/****** Init and module functions ******/
502
 
503
static devfs_handle_t devfs_handle;
504
 
505
static char banner[] __initdata = KERN_INFO "DSP56k driver installed\n";
506
 
507
static int __init dsp56k_init_driver(void)
508
{
509
        if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
510
                printk("DSP56k driver: Hardware not present\n");
511
                return -ENODEV;
512
        }
513
 
514
        if(devfs_register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
515
                printk("DSP56k driver: Unable to register driver\n");
516
                return -ENODEV;
517
        }
518
        devfs_handle = devfs_register(NULL, "dsp56k", DEVFS_FL_DEFAULT,
519
                                      DSP56K_MAJOR, 0,
520
                                      S_IFCHR | S_IRUSR | S_IWUSR,
521
                                      &dsp56k_fops, NULL);
522
 
523
        printk(banner);
524
        return 0;
525
}
526
module_init(dsp56k_init_driver);
527
 
528
static void __exit dsp56k_cleanup_driver(void)
529
{
530
        devfs_unregister_chrdev(DSP56K_MAJOR, "dsp56k");
531
        devfs_unregister(devfs_handle);
532
}
533
module_exit(dsp56k_cleanup_driver);
534
 
535
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.