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 current->timeout = jiffies + n; \
70 #define handshake(count, maxio, timeout, ENABLE, f) \
74 m = min(count, maxio); \
75 for (i = 0; i < m; i++) { \
76 for (t = 0; t < timeout && !ENABLE; t++) \
83 if (m == maxio) wait_some(2); \
90 for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
92 if(!DSP56K_TRANSMIT) { \
100 for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
102 if(!DSP56K_RECEIVE) { \
107 /* DSP56001 bootstrap code */
108 static char bootstrap
[] = {
109 0x0c, 0x00, 0x40, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128 0x00, 0x00, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4,
129 0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47,
130 0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00,
131 0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe,
132 0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0,
133 0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a,
134 0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4,
135 0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01,
136 0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08,
137 0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46,
138 0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa,
139 0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00,
140 0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9,
141 0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80,
142 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a,
143 0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0,
144 0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4,
145 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a,
146 0xf0, 0x80, 0x00, 0x7e, 0xad};
147 static int sizeof_bootstrap
= 375;
150 static struct dsp56k_device
{
153 int tx_wsize
, rx_wsize
;
156 static int dsp56k_reset(void)
160 /* Power down the DSP */
161 sound_ym
.rd_data_reg_sel
= 14;
162 status
= sound_ym
.rd_data_reg_sel
& 0xef;
163 sound_ym
.wd_data
= status
;
164 sound_ym
.wd_data
= status
| 0x10;
168 /* Power up the DSP */
169 sound_ym
.rd_data_reg_sel
= 14;
170 sound_ym
.wd_data
= sound_ym
.rd_data_reg_sel
& 0xef;
175 static int dsp56k_upload(u_char
*bin
, int len
)
183 for (i
= 0; i
< sizeof_bootstrap
/3; i
++) {
185 dsp56k_host_interface
.data
.b
[1] = *p
++;
186 dsp56k_host_interface
.data
.b
[2] = *p
++;
187 dsp56k_host_interface
.data
.b
[3] = *p
++;
189 for (; i
< 512; i
++) {
191 dsp56k_host_interface
.data
.b
[1] = 0;
192 dsp56k_host_interface
.data
.b
[2] = 0;
193 dsp56k_host_interface
.data
.b
[3] = 0;
196 for (i
= 0; i
< len
; i
++) {
198 get_user(dsp56k_host_interface
.data
.b
[1], bin
++);
199 get_user(dsp56k_host_interface
.data
.b
[2], bin
++);
200 get_user(dsp56k_host_interface
.data
.b
[3], bin
++);
204 dsp56k_host_interface
.data
.l
= 3; /* Magic execute */
209 static ssize_t
dsp56k_read(struct file
*file
, char *buf
, size_t count
,
212 struct inode
*inode
= file
->f_dentry
->d_inode
;
213 int dev
= MINOR(inode
->i_rdev
) & 0x0f;
217 case DSP56K_DEV_56001
:
222 /* Don't do anything if nothing is to be done */
223 if (!count
) return 0;
226 switch (dsp56k
.rx_wsize
) {
229 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_RECEIVE
,
230 put_user(dsp56k_host_interface
.data
.b
[3], buf
+n
++));
239 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_RECEIVE
,
240 put_user(dsp56k_host_interface
.data
.w
[1], data
+n
++));
246 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_RECEIVE
,
247 put_user(dsp56k_host_interface
.data
.b
[1], buf
+n
++);
248 put_user(dsp56k_host_interface
.data
.b
[2], buf
+n
++);
249 put_user(dsp56k_host_interface
.data
.b
[3], buf
+n
++));
258 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_RECEIVE
,
259 put_user(dsp56k_host_interface
.data
.l
, data
+n
++));
267 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
272 static ssize_t
dsp56k_write(struct file
*file
, const char *buf
, size_t count
,
275 struct inode
*inode
= file
->f_dentry
->d_inode
;
276 int dev
= MINOR(inode
->i_rdev
) & 0x0f;
280 case DSP56K_DEV_56001
:
284 /* Don't do anything if nothing is to be done */
285 if (!count
) return 0;
288 switch (dsp56k
.tx_wsize
) {
291 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_TRANSMIT
,
292 get_user(dsp56k_host_interface
.data
.b
[3], buf
+n
++));
301 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_TRANSMIT
,
302 get_user(dsp56k_host_interface
.data
.w
[1], data
+n
++));
308 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_TRANSMIT
,
309 get_user(dsp56k_host_interface
.data
.b
[1], buf
+n
++);
310 get_user(dsp56k_host_interface
.data
.b
[2], buf
+n
++);
311 get_user(dsp56k_host_interface
.data
.b
[3], buf
+n
++));
320 handshake(count
, dsp56k
.maxio
, dsp56k
.timeout
, DSP56K_TRANSMIT
,
321 get_user(dsp56k_host_interface
.data
.l
, data
+n
++));
329 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
334 static int dsp56k_ioctl(struct inode
*inode
, struct file
*file
,
335 unsigned int cmd
, unsigned long arg
)
337 int dev
= MINOR(inode
->i_rdev
) & 0x0f;
341 case DSP56K_DEV_56001
:
348 struct dsp56k_upload
*binary
= (struct dsp56k_upload
*) arg
;
350 if(get_user(len
, &binary
->len
) < 0)
352 if(get_user(bin
, &binary
->bin
) < 0)
356 return -EINVAL
; /* nothing to upload?!? */
358 if (len
> DSP56K_MAX_BINARY_LENGTH
) {
362 r
= dsp56k_upload(bin
, len
);
369 case DSP56K_SET_TX_WSIZE
:
370 if (arg
> 4 || arg
< 1)
372 dsp56k
.tx_wsize
= (int) arg
;
374 case DSP56K_SET_RX_WSIZE
:
375 if (arg
> 4 || arg
< 1)
377 dsp56k
.rx_wsize
= (int) arg
;
379 case DSP56K_HOST_FLAGS
:
381 int dir
, out
, status
;
382 struct dsp56k_host_flags
*hf
= (struct dsp56k_host_flags
*) arg
;
384 if(get_user(dir
, &hf
->dir
) < 0)
386 if(get_user(out
, &hf
->out
) < 0)
389 if ((dir
& 0x1) && (out
& 0x1))
390 dsp56k_host_interface
.icr
|= DSP56K_ICR_HF0
;
392 dsp56k_host_interface
.icr
&= ~DSP56K_ICR_HF0
;
393 if ((dir
& 0x2) && (out
& 0x2))
394 dsp56k_host_interface
.icr
|= DSP56K_ICR_HF1
;
396 dsp56k_host_interface
.icr
&= ~DSP56K_ICR_HF1
;
399 if (dsp56k_host_interface
.icr
& DSP56K_ICR_HF0
) status
|= 0x1;
400 if (dsp56k_host_interface
.icr
& DSP56K_ICR_HF1
) status
|= 0x2;
401 if (dsp56k_host_interface
.isr
& DSP56K_ISR_HF2
) status
|= 0x4;
402 if (dsp56k_host_interface
.isr
& DSP56K_ISR_HF3
) status
|= 0x8;
404 return put_user(status
, &hf
->status
);
406 case DSP56K_HOST_CMD
:
407 if (arg
> 31 || arg
< 0)
409 dsp56k_host_interface
.cvr
= (u_char
)((arg
& DSP56K_CVR_HV_MASK
) |
418 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
423 /* As of 2.1.26 this should be dsp56k_poll,
424 * but how do I then check device minor number?
425 * Do I need this function at all???
428 static unsigned int dsp56k_poll(struct file
*file
, poll_table
*wait
)
430 int dev
= MINOR(file
->f_dentry
->d_inode
->i_rdev
) & 0x0f;
434 case DSP56K_DEV_56001
:
435 /* poll_wait(file, ???, wait); */
436 return POLLIN
| POLLRDNORM
| POLLOUT
;
439 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
445 static int dsp56k_open(struct inode
*inode
, struct file
*file
)
447 int dev
= MINOR(inode
->i_rdev
) & 0x0f;
451 case DSP56K_DEV_56001
:
457 dsp56k
.timeout
= TIMEOUT
;
458 dsp56k
.maxio
= MAXIO
;
459 dsp56k
.rx_wsize
= dsp56k
.tx_wsize
= 4;
464 /* Zero host flags */
465 dsp56k_host_interface
.icr
&= ~DSP56K_ICR_HF0
;
466 dsp56k_host_interface
.icr
&= ~DSP56K_ICR_HF1
;
471 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
482 static int dsp56k_release(struct inode
*inode
, struct file
*file
)
484 int dev
= MINOR(inode
->i_rdev
) & 0x0f;
488 case DSP56K_DEV_56001
:
494 printk("DSP56k driver: Unknown minor device: %d\n", dev
);
504 static struct file_operations dsp56k_fops
= {
505 NULL
, /* no special dsp56k_lseek */
508 NULL
, /* no special dsp56k_readdir */
509 NULL
, /* dsp56k_poll? */
511 NULL
, /* no special dsp56k_mmap */
515 NULL
, /* no special dsp56k_fsync */
516 NULL
, /* no special dsp56k_fasync */
517 NULL
, /* no special dsp56k_check_media_change */
518 NULL
/* no special dsp56k_revalidate */
522 /****** Init and module functions ******/
524 __initfunc(int dsp56k_init(void))
526 if(!MACH_IS_ATARI
|| !ATARIHW_PRESENT(DSP56K
)) {
527 printk("DSP56k driver: Hardware not present\n");
531 if(register_chrdev(DSP56K_MAJOR
, "dsp56k", &dsp56k_fops
)) {
532 printk("DSP56k driver: Unable to register driver\n");
538 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");