2 * The DSP56001 Device Driver, saviour of the Free World(tm)
4 * Authors: Fredrik Noring <noring@lysator.liu.se>
5 * lars brinkhoff <f93labr@dd.chalmers.se>
6 * Tomas Berndtsson <tobe@lysator.liu.se>
8 * First version May 1996
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
17 * Hmm... there must be something here :)
19 * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
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
26 #include <linux/module.h>
27 #include <linux/version.h>
28 #include <linux/malloc.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 */
36 #include <linux/init.h>
38 #include <asm/segment.h>
39 #include <asm/atarihw.h>
40 #include <asm/traps.h>
41 #include <asm/uaccess.h> /* For put_user and get_user */
43 #include <asm/dsp56k.h>
46 #define DSP56K_DEV_56001 0 /* The only device so far */
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)
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
57 #define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
58 #define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
60 #define max(a,b) ((a) > (b) ? (a) : (b))
61 #define min(a,b) ((a) < (b) ? (a) : (b))
63 #define wait_some(n) \
65 current->state = TASK_INTERRUPTIBLE; \
66 schedule_timeout(n); \
69 #define handshake(count, maxio, timeout, ENABLE, f) \
73 m = min(count, maxio); \
74 for (i = 0; i < m; i++) { \
75 for (t = 0; t < timeout && !ENABLE; t++) \
82 if (m == maxio) wait_some(2); \
89 for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
91 if(!DSP56K_TRANSMIT) { \
99 for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
101 if(!DSP56K_RECEIVE) { \
106 /* DSP56001 bootstrap code */
107 static char bootstrap
[] = {
108 0x0c, 0x00, 0x40, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x00, 0x00, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4,
128 0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47,
129 0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00,
130 0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe,
131 0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0,
132 0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a,
133 0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4,
134 0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01,
135 0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08,
136 0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46,
137 0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa,
138 0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00,
139 0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9,
140 0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80,
141 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a,
142 0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0,
143 0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4,
144 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a,
145 0xf0, 0x80, 0x00, 0x7e, 0xad};
146 static int sizeof_bootstrap
= 375;
149 static struct dsp56k_device
{
152 int tx_wsize
, rx_wsize
;
155 static int dsp56k_reset(void)
159 /* Power down the DSP */
160 sound_ym
.rd_data_reg_sel
= 14;
161 status
= sound_ym
.rd_data_reg_sel
& 0xef;
162 sound_ym
.wd_data
= status
;
163 sound_ym
.wd_data
= status
| 0x10;
167 /* Power up the DSP */
168 sound_ym
.rd_data_reg_sel
= 14;
169 sound_ym
.wd_data
= sound_ym
.rd_data_reg_sel
& 0xef;
174 static int dsp56k_upload(u_char
*bin
, int len
)
182 for (i
= 0; i
< sizeof_bootstrap
/3; i
++) {
184 dsp56k_host_interface
.data
.b
[1] = *p
++;
185 dsp56k_host_interface
.data
.b
[2] = *p
++;
186 dsp56k_host_interface
.data
.b
[3] = *p
++;
188 for (; i
< 512; i
++) {
190 dsp56k_host_interface
.data
.b
[1] = 0;
191 dsp56k_host_interface
.data
.b
[2] = 0;
192 dsp56k_host_interface
.data
.b
[3] = 0;
195 for (i
= 0; i
< len
; i
++) {
197 get_user(dsp56k_host_interface
.data
.b
[1], bin
++);
198 get_user(dsp56k_host_interface
.data
.b
[2], bin
++);
199 get_user(dsp56k_host_interface
.data
.b
[3], bin
++);
203 dsp56k_host_interface
.data
.l
= 3; /* Magic execute */
208 static ssize_t
dsp56k_read(struct file
*file
, char *buf
, size_t count
,
211 struct inode
*inode
= file
->f_dentry
->d_inode
;
212 int dev
= MINOR(inode
->i_rdev
) & 0x0f;
216 case DSP56K_DEV_56001
:
221 /* Don't do anything if nothing is to be done */
222 if (!count
) return 0;
225 switch (dsp56k
.rx_wsize
) {
228 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_RECEIVE
,
229 put_user(dsp56k_host_interface
.data
.b
[3], buf
+n
++));
238 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_RECEIVE
,
239 put_user(dsp56k_host_interface
.data
.w
[1], data
+n
++));
245 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_RECEIVE
,
246 put_user(dsp56k_host_interface
.data
.b
[1], buf
+n
++);
247 put_user(dsp56k_host_interface
.data
.b
[2], buf
+n
++);
248 put_user(dsp56k_host_interface
.data
.b
[3], buf
+n
++));
257 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_RECEIVE
,
258 put_user(dsp56k_host_interface
.data
.l
, data
+n
++));
266 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
271 static ssize_t
dsp56k_write(struct file
*file
, const char *buf
, size_t count
,
274 struct inode
*inode
= file
->f_dentry
->d_inode
;
275 int dev
= MINOR(inode
->i_rdev
) & 0x0f;
279 case DSP56K_DEV_56001
:
283 /* Don't do anything if nothing is to be done */
284 if (!count
) return 0;
287 switch (dsp56k
.tx_wsize
) {
290 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_TRANSMIT
,
291 get_user(dsp56k_host_interface
.data
.b
[3], buf
+n
++));
300 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_TRANSMIT
,
301 get_user(dsp56k_host_interface
.data
.w
[1], data
+n
++));
307 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_TRANSMIT
,
308 get_user(dsp56k_host_interface
.data
.b
[1], buf
+n
++);
309 get_user(dsp56k_host_interface
.data
.b
[2], buf
+n
++);
310 get_user(dsp56k_host_interface
.data
.b
[3], buf
+n
++));
319 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_TRANSMIT
,
320 get_user(dsp56k_host_interface
.data
.l
, data
+n
++));
328 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
333 static int dsp56k_ioctl(struct inode
*inode
, struct file
*file
,
334 unsigned int cmd
, unsigned long arg
)
336 int dev
= MINOR(inode
->i_rdev
) & 0x0f;
340 case DSP56K_DEV_56001
:
347 struct dsp56k_upload
*binary
= (struct dsp56k_upload
*) arg
;
349 if(get_user(len
, &binary
->len
) < 0)
351 if(get_user(bin
, &binary
->bin
) < 0)
355 return -EINVAL
; /* nothing to upload?!? */
357 if (len
> DSP56K_MAX_BINARY_LENGTH
) {
361 r
= dsp56k_upload(bin
, len
);
368 case DSP56K_SET_TX_WSIZE
:
369 if (arg
> 4 || arg
< 1)
371 dsp56k
.tx_wsize
= (int) arg
;
373 case DSP56K_SET_RX_WSIZE
:
374 if (arg
> 4 || arg
< 1)
376 dsp56k
.rx_wsize
= (int) arg
;
378 case DSP56K_HOST_FLAGS
:
380 int dir
, out
, status
;
381 struct dsp56k_host_flags
*hf
= (struct dsp56k_host_flags
*) arg
;
383 if(get_user(dir
, &hf
->dir
) < 0)
385 if(get_user(out
, &hf
->out
) < 0)
388 if ((dir
& 0x1) && (out
& 0x1))
389 dsp56k_host_interface
.icr
|= DSP56K_ICR_HF0
;
391 dsp56k_host_interface
.icr
&= ~DSP56K_ICR_HF0
;
392 if ((dir
& 0x2) && (out
& 0x2))
393 dsp56k_host_interface
.icr
|= DSP56K_ICR_HF1
;
395 dsp56k_host_interface
.icr
&= ~DSP56K_ICR_HF1
;
398 if (dsp56k_host_interface
.icr
& DSP56K_ICR_HF0
) status
|= 0x1;
399 if (dsp56k_host_interface
.icr
& DSP56K_ICR_HF1
) status
|= 0x2;
400 if (dsp56k_host_interface
.isr
& DSP56K_ISR_HF2
) status
|= 0x4;
401 if (dsp56k_host_interface
.isr
& DSP56K_ISR_HF3
) status
|= 0x8;
403 return put_user(status
, &hf
->status
);
405 case DSP56K_HOST_CMD
:
406 if (arg
> 31 || arg
< 0)
408 dsp56k_host_interface
.cvr
= (u_char
)((arg
& DSP56K_CVR_HV_MASK
) |
417 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
422 /* As of 2.1.26 this should be dsp56k_poll,
423 * but how do I then check device minor number?
424 * Do I need this function at all???
427 static unsigned int dsp56k_poll(struct file
*file
, poll_table
*wait
)
429 int dev
= MINOR(file
->f_dentry
->d_inode
->i_rdev
) & 0x0f;
433 case DSP56K_DEV_56001
:
434 /* poll_wait(file, ???, wait); */
435 return POLLIN
| POLLRDNORM
| POLLOUT
;
438 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
444 static int dsp56k_open(struct inode
*inode
, struct file
*file
)
446 int dev
= MINOR(inode
->i_rdev
) & 0x0f;
450 case DSP56K_DEV_56001
:
456 dsp56k
.timeout
= TIMEOUT
;
457 dsp56k
.maxio
= MAXIO
;
458 dsp56k
.rx_wsize
= dsp56k
.tx_wsize
= 4;
463 /* Zero host flags */
464 dsp56k_host_interface
.icr
&= ~DSP56K_ICR_HF0
;
465 dsp56k_host_interface
.icr
&= ~DSP56K_ICR_HF1
;
470 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
481 static int dsp56k_release(struct inode
*inode
, struct file
*file
)
483 int dev
= MINOR(inode
->i_rdev
) & 0x0f;
487 case DSP56K_DEV_56001
:
493 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
503 static struct file_operations dsp56k_fops
= {
504 NULL
, /* no special dsp56k_lseek */
507 NULL
, /* no special dsp56k_readdir */
508 NULL
, /* dsp56k_poll? */
510 NULL
, /* no special dsp56k_mmap */
514 NULL
, /* no special dsp56k_fsync */
515 NULL
, /* no special dsp56k_fasync */
516 NULL
, /* no special dsp56k_check_media_change */
517 NULL
/* no special dsp56k_revalidate */
521 /****** Init and module functions ******/
522 int __init
dsp56k_init(void)
524 if(!MACH_IS_ATARI
|| !ATARIHW_PRESENT(DSP56K
)) {
525 printk("DSP56k driver: Hardware not present\n");
529 if(register_chrdev(DSP56K_MAJOR
, "dsp56k", &dsp56k_fops
)) {
530 printk("DSP56k driver: Unable to register driver\n");
536 printk("DSP56k driver installed\n");
542 int init_module(void)
544 return dsp56k_init();
547 void cleanup_module(void)
549 unregister_chrdev(DSP56K_MAJOR
, "dsp56k");