File: /usr/src/linux/drivers/char/dsp56k.c

1     /*
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");
536