Linux 2.6.20.7
[linux/fpc-iii.git] / drivers / char / dsp56k.c
blob06f2dbf17710770e5829d464e81cfb48d5e8367c
1 /*
2 * The DSP56001 Device Driver, saviour of the Free World(tm)
4 * Authors: Fredrik Noring <noring@nocrew.org>
5 * lars brinkhoff <lars@nocrew.org>
6 * Tomas Berndtsson <tomas@nocrew.org>
8 * First version May 1996
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
16 * BUGS:
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
23 * for more details.
26 #include <linux/module.h>
27 #include <linux/slab.h> /* for kmalloc() and kfree() */
28 #include <linux/sched.h> /* for struct wait_queue etc */
29 #include <linux/major.h>
30 #include <linux/types.h>
31 #include <linux/errno.h>
32 #include <linux/delay.h> /* guess what */
33 #include <linux/fs.h>
34 #include <linux/mm.h>
35 #include <linux/init.h>
36 #include <linux/smp_lock.h>
37 #include <linux/device.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>
45 /* minor devices */
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 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 } \
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 } \
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 } \
97 /* DSP56001 bootstrap code */
98 static char bootstrap[] = {
99 0x0c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x00, 0x00, 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, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4,
119 0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47,
120 0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00,
121 0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe,
122 0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0,
123 0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a,
124 0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4,
125 0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01,
126 0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08,
127 0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46,
128 0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa,
129 0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00,
130 0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9,
131 0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80,
132 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a,
133 0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0,
134 0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4,
135 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a,
136 0xf0, 0x80, 0x00, 0x7e, 0xad};
137 static int sizeof_bootstrap = 375;
140 static struct dsp56k_device {
141 long in_use;
142 long maxio, timeout;
143 int tx_wsize, rx_wsize;
144 } dsp56k;
146 static struct class *dsp56k_class;
148 static int dsp56k_reset(void)
150 u_char status;
152 /* Power down the DSP */
153 sound_ym.rd_data_reg_sel = 14;
154 status = sound_ym.rd_data_reg_sel & 0xef;
155 sound_ym.wd_data = status;
156 sound_ym.wd_data = status | 0x10;
158 udelay(10);
160 /* Power up the DSP */
161 sound_ym.rd_data_reg_sel = 14;
162 sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
164 return 0;
167 static int dsp56k_upload(u_char __user *bin, int len)
169 int i;
170 u_char *p;
172 dsp56k_reset();
174 p = bootstrap;
175 for (i = 0; i < sizeof_bootstrap/3; i++) {
176 /* tx_wait(10); */
177 dsp56k_host_interface.data.b[1] = *p++;
178 dsp56k_host_interface.data.b[2] = *p++;
179 dsp56k_host_interface.data.b[3] = *p++;
181 for (; i < 512; i++) {
182 /* tx_wait(10); */
183 dsp56k_host_interface.data.b[1] = 0;
184 dsp56k_host_interface.data.b[2] = 0;
185 dsp56k_host_interface.data.b[3] = 0;
188 for (i = 0; i < len; i++) {
189 tx_wait(10);
190 get_user(dsp56k_host_interface.data.b[1], bin++);
191 get_user(dsp56k_host_interface.data.b[2], bin++);
192 get_user(dsp56k_host_interface.data.b[3], bin++);
195 tx_wait(10);
196 dsp56k_host_interface.data.l = 3; /* Magic execute */
198 return 0;
201 static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count,
202 loff_t *ppos)
204 struct inode *inode = file->f_path.dentry->d_inode;
205 int dev = iminor(inode) & 0x0f;
207 switch(dev)
209 case DSP56K_DEV_56001:
212 long n;
214 /* Don't do anything if nothing is to be done */
215 if (!count) return 0;
217 n = 0;
218 switch (dsp56k.rx_wsize) {
219 case 1: /* 8 bit */
221 handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
222 put_user(dsp56k_host_interface.data.b[3], buf+n++));
223 return n;
225 case 2: /* 16 bit */
227 short __user *data;
229 count /= 2;
230 data = (short __user *) buf;
231 handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
232 put_user(dsp56k_host_interface.data.w[1], data+n++));
233 return 2*n;
235 case 3: /* 24 bit */
237 count /= 3;
238 handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
239 put_user(dsp56k_host_interface.data.b[1], buf+n++);
240 put_user(dsp56k_host_interface.data.b[2], buf+n++);
241 put_user(dsp56k_host_interface.data.b[3], buf+n++));
242 return 3*n;
244 case 4: /* 32 bit */
246 long __user *data;
248 count /= 4;
249 data = (long __user *) buf;
250 handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
251 put_user(dsp56k_host_interface.data.l, data+n++));
252 return 4*n;
255 return -EFAULT;
258 default:
259 printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
260 return -ENXIO;
264 static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count,
265 loff_t *ppos)
267 struct inode *inode = file->f_path.dentry->d_inode;
268 int dev = iminor(inode) & 0x0f;
270 switch(dev)
272 case DSP56K_DEV_56001:
274 long n;
276 /* Don't do anything if nothing is to be done */
277 if (!count) return 0;
279 n = 0;
280 switch (dsp56k.tx_wsize) {
281 case 1: /* 8 bit */
283 handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
284 get_user(dsp56k_host_interface.data.b[3], buf+n++));
285 return n;
287 case 2: /* 16 bit */
289 const short __user *data;
291 count /= 2;
292 data = (const short __user *)buf;
293 handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
294 get_user(dsp56k_host_interface.data.w[1], data+n++));
295 return 2*n;
297 case 3: /* 24 bit */
299 count /= 3;
300 handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
301 get_user(dsp56k_host_interface.data.b[1], buf+n++);
302 get_user(dsp56k_host_interface.data.b[2], buf+n++);
303 get_user(dsp56k_host_interface.data.b[3], buf+n++));
304 return 3*n;
306 case 4: /* 32 bit */
308 const long __user *data;
310 count /= 4;
311 data = (const long __user *)buf;
312 handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
313 get_user(dsp56k_host_interface.data.l, data+n++));
314 return 4*n;
318 return -EFAULT;
320 default:
321 printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
322 return -ENXIO;
326 static int dsp56k_ioctl(struct inode *inode, struct file *file,
327 unsigned int cmd, unsigned long arg)
329 int dev = iminor(inode) & 0x0f;
330 void __user *argp = (void __user *)arg;
332 switch(dev)
334 case DSP56K_DEV_56001:
336 switch(cmd) {
337 case DSP56K_UPLOAD:
339 char __user *bin;
340 int r, len;
341 struct dsp56k_upload __user *binary = argp;
343 if(get_user(len, &binary->len) < 0)
344 return -EFAULT;
345 if(get_user(bin, &binary->bin) < 0)
346 return -EFAULT;
348 if (len == 0) {
349 return -EINVAL; /* nothing to upload?!? */
351 if (len > DSP56K_MAX_BINARY_LENGTH) {
352 return -EINVAL;
355 r = dsp56k_upload(bin, len);
356 if (r < 0) {
357 return r;
360 break;
362 case DSP56K_SET_TX_WSIZE:
363 if (arg > 4 || arg < 1)
364 return -EINVAL;
365 dsp56k.tx_wsize = (int) arg;
366 break;
367 case DSP56K_SET_RX_WSIZE:
368 if (arg > 4 || arg < 1)
369 return -EINVAL;
370 dsp56k.rx_wsize = (int) arg;
371 break;
372 case DSP56K_HOST_FLAGS:
374 int dir, out, status;
375 struct dsp56k_host_flags __user *hf = argp;
377 if(get_user(dir, &hf->dir) < 0)
378 return -EFAULT;
379 if(get_user(out, &hf->out) < 0)
380 return -EFAULT;
382 if ((dir & 0x1) && (out & 0x1))
383 dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
384 else if (dir & 0x1)
385 dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
386 if ((dir & 0x2) && (out & 0x2))
387 dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
388 else if (dir & 0x2)
389 dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
391 status = 0;
392 if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
393 if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
394 if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
395 if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
397 return put_user(status, &hf->status);
399 case DSP56K_HOST_CMD:
400 if (arg > 31 || arg < 0)
401 return -EINVAL;
402 dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
403 DSP56K_CVR_HC);
404 break;
405 default:
406 return -EINVAL;
408 return 0;
410 default:
411 printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
412 return -ENXIO;
416 /* As of 2.1.26 this should be dsp56k_poll,
417 * but how do I then check device minor number?
418 * Do I need this function at all???
420 #if 0
421 static unsigned int dsp56k_poll(struct file *file, poll_table *wait)
423 int dev = iminor(file->f_path.dentry->d_inode) & 0x0f;
425 switch(dev)
427 case DSP56K_DEV_56001:
428 /* poll_wait(file, ???, wait); */
429 return POLLIN | POLLRDNORM | POLLOUT;
431 default:
432 printk("DSP56k driver: Unknown minor device: %d\n", dev);
433 return 0;
436 #endif
438 static int dsp56k_open(struct inode *inode, struct file *file)
440 int dev = iminor(inode) & 0x0f;
442 switch(dev)
444 case DSP56K_DEV_56001:
446 if (test_and_set_bit(0, &dsp56k.in_use))
447 return -EBUSY;
449 dsp56k.timeout = TIMEOUT;
450 dsp56k.maxio = MAXIO;
451 dsp56k.rx_wsize = dsp56k.tx_wsize = 4;
453 DSP56K_TX_INT_OFF;
454 DSP56K_RX_INT_OFF;
456 /* Zero host flags */
457 dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
458 dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
460 break;
462 default:
463 return -ENODEV;
466 return 0;
469 static int dsp56k_release(struct inode *inode, struct file *file)
471 int dev = iminor(inode) & 0x0f;
473 switch(dev)
475 case DSP56K_DEV_56001:
476 clear_bit(0, &dsp56k.in_use);
477 break;
478 default:
479 printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
480 return -ENXIO;
483 return 0;
486 static const struct file_operations dsp56k_fops = {
487 .owner = THIS_MODULE,
488 .read = dsp56k_read,
489 .write = dsp56k_write,
490 .ioctl = dsp56k_ioctl,
491 .open = dsp56k_open,
492 .release = dsp56k_release,
496 /****** Init and module functions ******/
498 static char banner[] __initdata = KERN_INFO "DSP56k driver installed\n";
500 static int __init dsp56k_init_driver(void)
502 int err = 0;
504 if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
505 printk("DSP56k driver: Hardware not present\n");
506 return -ENODEV;
509 if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
510 printk("DSP56k driver: Unable to register driver\n");
511 return -ENODEV;
513 dsp56k_class = class_create(THIS_MODULE, "dsp56k");
514 if (IS_ERR(dsp56k_class)) {
515 err = PTR_ERR(dsp56k_class);
516 goto out_chrdev;
518 class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
520 printk(banner);
521 goto out;
523 out_chrdev:
524 unregister_chrdev(DSP56K_MAJOR, "dsp56k");
525 out:
526 return err;
528 module_init(dsp56k_init_driver);
530 static void __exit dsp56k_cleanup_driver(void)
532 class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
533 class_destroy(dsp56k_class);
534 unregister_chrdev(DSP56K_MAJOR, "dsp56k");
536 module_exit(dsp56k_cleanup_driver);
538 MODULE_LICENSE("GPL");