PageRenderTime 76ms CodeModel.GetById 15ms app.highlight 55ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/char/dsp56k.c

https://bitbucket.org/evzijst/gittest
C | 547 lines | 429 code | 79 blank | 39 comment | 52 complexity | cb9bf0ec0f78a321d98bfa89c4ebef39 MD5 | raw file
  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/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/devfs_fs_kernel.h>
 37#include <linux/smp_lock.h>
 38#include <linux/device.h>
 39
 40#include <asm/atarihw.h>
 41#include <asm/traps.h>
 42#include <asm/uaccess.h>	/* For put_user and get_user */
 43
 44#include <asm/dsp56k.h>
 45
 46/* minor devices */
 47#define DSP56K_DEV_56001        0    /* The only device so far */
 48
 49#define TIMEOUT    10   /* Host port timeout in number of tries */
 50#define MAXIO    2048   /* Maximum number of words before sleep */
 51#define DSP56K_MAX_BINARY_LENGTH (3*64*1024)
 52
 53#define DSP56K_TX_INT_ON	dsp56k_host_interface.icr |=  DSP56K_ICR_TREQ
 54#define DSP56K_RX_INT_ON	dsp56k_host_interface.icr |=  DSP56K_ICR_RREQ
 55#define DSP56K_TX_INT_OFF	dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ
 56#define DSP56K_RX_INT_OFF	dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ
 57
 58#define DSP56K_TRANSMIT		(dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
 59#define DSP56K_RECEIVE		(dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
 60
 61#define handshake(count, maxio, timeout, ENABLE, f) \
 62{ \
 63	long i, t, m; \
 64	while (count > 0) { \
 65		m = min_t(unsigned long, count, maxio); \
 66		for (i = 0; i < m; i++) { \
 67			for (t = 0; t < timeout && !ENABLE; t++) \
 68				msleep(20); \
 69			if(!ENABLE) \
 70				return -EIO; \
 71			f; \
 72		} \
 73		count -= m; \
 74		if (m == maxio) msleep(20); \
 75	} \
 76}
 77
 78#define tx_wait(n) \
 79{ \
 80	int t; \
 81	for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
 82		msleep(10); \
 83	if(!DSP56K_TRANSMIT) { \
 84		return -EIO; \
 85	} \
 86}
 87
 88#define rx_wait(n) \
 89{ \
 90	int t; \
 91	for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
 92		msleep(10); \
 93	if(!DSP56K_RECEIVE) { \
 94		return -EIO; \
 95	} \
 96}
 97
 98/* DSP56001 bootstrap code */
 99static char bootstrap[] = {
100	0x0c, 0x00, 0x40, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119	0x00, 0x00, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4,
120	0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47,
121	0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00,
122	0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe,
123	0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0,
124	0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a,
125	0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4,
126	0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01,
127	0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08,
128	0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46,
129	0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa,
130	0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00,
131	0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9,
132	0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80,
133	0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a,
134	0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0,
135	0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4,
136	0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a,
137	0xf0, 0x80, 0x00, 0x7e, 0xad};
138static int sizeof_bootstrap = 375;
139
140
141static struct dsp56k_device {
142	long in_use;
143	long maxio, timeout;
144	int tx_wsize, rx_wsize;
145} dsp56k;
146
147static struct class_simple *dsp56k_class;
148
149static int dsp56k_reset(void)
150{
151	u_char status;
152	
153	/* Power down the DSP */
154	sound_ym.rd_data_reg_sel = 14;
155	status = sound_ym.rd_data_reg_sel & 0xef;
156	sound_ym.wd_data = status;
157	sound_ym.wd_data = status | 0x10;
158  
159	udelay(10);
160  
161	/* Power up the DSP */
162	sound_ym.rd_data_reg_sel = 14;
163	sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
164
165	return 0;
166}
167
168static int dsp56k_upload(u_char *bin, int len)
169{
170	int i;
171	u_char *p;
172	
173	dsp56k_reset();
174  
175	p = bootstrap;
176	for (i = 0; i < sizeof_bootstrap/3; i++) {
177		/* tx_wait(10); */
178		dsp56k_host_interface.data.b[1] = *p++;
179		dsp56k_host_interface.data.b[2] = *p++;
180		dsp56k_host_interface.data.b[3] = *p++;
181	}
182	for (; i < 512; i++) {
183		/* tx_wait(10); */
184		dsp56k_host_interface.data.b[1] = 0;
185		dsp56k_host_interface.data.b[2] = 0;
186		dsp56k_host_interface.data.b[3] = 0;
187	}
188  
189	for (i = 0; i < len; i++) {
190		tx_wait(10);
191		get_user(dsp56k_host_interface.data.b[1], bin++);
192		get_user(dsp56k_host_interface.data.b[2], bin++);
193		get_user(dsp56k_host_interface.data.b[3], bin++);
194	}
195
196	tx_wait(10);
197	dsp56k_host_interface.data.l = 3;    /* Magic execute */
198
199	return 0;
200}
201
202static ssize_t dsp56k_read(struct file *file, char *buf, size_t count,
203			   loff_t *ppos)
204{
205	struct inode *inode = file->f_dentry->d_inode;
206	int dev = iminor(inode) & 0x0f;
207
208	switch(dev)
209	{
210	case DSP56K_DEV_56001:
211	{
212
213		long n;
214
215		/* Don't do anything if nothing is to be done */
216		if (!count) return 0;
217
218		n = 0;
219		switch (dsp56k.rx_wsize) {
220		case 1:  /* 8 bit */
221		{
222			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
223				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
224			return n;
225		}
226		case 2:  /* 16 bit */
227		{
228			short *data;
229
230			count /= 2;
231			data = (short*) buf;
232			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
233				  put_user(dsp56k_host_interface.data.w[1], data+n++));
234			return 2*n;
235		}
236		case 3:  /* 24 bit */
237		{
238			count /= 3;
239			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
240				  put_user(dsp56k_host_interface.data.b[1], buf+n++);
241				  put_user(dsp56k_host_interface.data.b[2], buf+n++);
242				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
243			return 3*n;
244		}
245		case 4:  /* 32 bit */
246		{
247			long *data;
248
249			count /= 4;
250			data = (long*) buf;
251			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
252				  put_user(dsp56k_host_interface.data.l, data+n++));
253			return 4*n;
254		}
255		}
256		return -EFAULT;
257	}
258
259	default:
260		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
261		return -ENXIO;
262	}
263}
264
265static ssize_t dsp56k_write(struct file *file, const char *buf, size_t count,
266			    loff_t *ppos)
267{
268	struct inode *inode = file->f_dentry->d_inode;
269	int dev = iminor(inode) & 0x0f;
270
271	switch(dev)
272	{
273	case DSP56K_DEV_56001:
274	{
275		long n;
276
277		/* Don't do anything if nothing is to be done */
278		if (!count) return 0;
279
280		n = 0;
281		switch (dsp56k.tx_wsize) {
282		case 1:  /* 8 bit */
283		{
284			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
285				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
286			return n;
287		}
288		case 2:  /* 16 bit */
289		{
290			const short *data;
291
292			count /= 2;
293			data = (const short *)buf;
294			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
295				  get_user(dsp56k_host_interface.data.w[1], data+n++));
296			return 2*n;
297		}
298		case 3:  /* 24 bit */
299		{
300			count /= 3;
301			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
302				  get_user(dsp56k_host_interface.data.b[1], buf+n++);
303				  get_user(dsp56k_host_interface.data.b[2], buf+n++);
304				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
305			return 3*n;
306		}
307		case 4:  /* 32 bit */
308		{
309			const long *data;
310
311			count /= 4;
312			data = (const long *)buf;
313			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
314				  get_user(dsp56k_host_interface.data.l, data+n++));
315			return 4*n;
316		}
317		}
318
319		return -EFAULT;
320	}
321	default:
322		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
323		return -ENXIO;
324	}
325}
326
327static int dsp56k_ioctl(struct inode *inode, struct file *file,
328			unsigned int cmd, unsigned long arg)
329{
330	int dev = iminor(inode) & 0x0f;
331
332	switch(dev)
333	{
334	case DSP56K_DEV_56001:
335
336		switch(cmd) {
337		case DSP56K_UPLOAD:
338		{
339			char *bin;
340			int r, len;
341			struct dsp56k_upload *binary = (struct dsp56k_upload *) arg;
342    
343			if(get_user(len, &binary->len) < 0)
344				return -EFAULT;
345			if(get_user(bin, &binary->bin) < 0)
346				return -EFAULT;
347		
348			if (len == 0) {
349				return -EINVAL;      /* nothing to upload?!? */
350			}
351			if (len > DSP56K_MAX_BINARY_LENGTH) {
352				return -EINVAL;
353			}
354    
355			r = dsp56k_upload(bin, len);
356			if (r < 0) {
357				return r;
358			}
359    
360			break;
361		}
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:
373		{
374			int dir, out, status;
375			struct dsp56k_host_flags *hf = (struct dsp56k_host_flags*) arg;
376    
377			if(get_user(dir, &hf->dir) < 0)
378				return -EFAULT;
379			if(get_user(out, &hf->out) < 0)
380				return -EFAULT;
381
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;
390
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;
396
397			return put_user(status, &hf->status);
398		}
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;
407		}
408		return 0;
409
410	default:
411		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
412		return -ENXIO;
413	}
414}
415
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???
419 */
420#if 0
421static unsigned int dsp56k_poll(struct file *file, poll_table *wait)
422{
423	int dev = iminor(file->f_dentry->d_inode) & 0x0f;
424
425	switch(dev)
426	{
427	case DSP56K_DEV_56001:
428		/* poll_wait(file, ???, wait); */
429		return POLLIN | POLLRDNORM | POLLOUT;
430
431	default:
432		printk("DSP56k driver: Unknown minor device: %d\n", dev);
433		return 0;
434	}
435}
436#endif
437
438static int dsp56k_open(struct inode *inode, struct file *file)
439{
440	int dev = iminor(inode) & 0x0f;
441
442	switch(dev)
443	{
444	case DSP56K_DEV_56001:
445
446		if (test_and_set_bit(0, &dsp56k.in_use))
447			return -EBUSY;
448
449		dsp56k.timeout = TIMEOUT;
450		dsp56k.maxio = MAXIO;
451		dsp56k.rx_wsize = dsp56k.tx_wsize = 4; 
452
453		DSP56K_TX_INT_OFF;
454		DSP56K_RX_INT_OFF;
455
456		/* Zero host flags */
457		dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
458		dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
459
460		break;
461
462	default:
463		return -ENODEV;
464	}
465
466	return 0;
467}
468
469static int dsp56k_release(struct inode *inode, struct file *file)
470{
471	int dev = iminor(inode) & 0x0f;
472
473	switch(dev)
474	{
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;
481	}
482
483	return 0;
484}
485
486static 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,
493};
494
495
496/****** Init and module functions ******/
497
498static char banner[] __initdata = KERN_INFO "DSP56k driver installed\n";
499
500static int __init dsp56k_init_driver(void)
501{
502	int err = 0;
503
504	if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
505		printk("DSP56k driver: Hardware not present\n");
506		return -ENODEV;
507	}
508
509	if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
510		printk("DSP56k driver: Unable to register driver\n");
511		return -ENODEV;
512	}
513	dsp56k_class = class_simple_create(THIS_MODULE, "dsp56k");
514	if (IS_ERR(dsp56k_class)) {
515		err = PTR_ERR(dsp56k_class);
516		goto out_chrdev;
517	}
518	class_simple_device_add(dsp56k_class, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
519
520	err = devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0),
521		      S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k");
522	if(err)
523		goto out_class;
524
525	printk(banner);
526	goto out;
527
528out_class:
529	class_simple_device_remove(MKDEV(DSP56K_MAJOR, 0));
530	class_simple_destroy(dsp56k_class);
531out_chrdev:
532	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
533out:
534	return err;
535}
536module_init(dsp56k_init_driver);
537
538static void __exit dsp56k_cleanup_driver(void)
539{
540	class_simple_device_remove(MKDEV(DSP56K_MAJOR, 0));
541	class_simple_destroy(dsp56k_class);
542	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
543	devfs_remove("dsp56k");
544}
545module_exit(dsp56k_cleanup_driver);
546
547MODULE_LICENSE("GPL");