xref: /linux/drivers/char/dsp56k.c (revision 14b42963f64b98ab61fa9723c03d71aa5ef4f862)
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/smp_lock.h>
37 #include <linux/device.h>
38 
39 #include <asm/atarihw.h>
40 #include <asm/traps.h>
41 #include <asm/uaccess.h>	/* For put_user and get_user */
42 
43 #include <asm/dsp56k.h>
44 
45 /* minor devices */
46 #define DSP56K_DEV_56001        0    /* The only device so far */
47 
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)
51 
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
56 
57 #define DSP56K_TRANSMIT		(dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
58 #define DSP56K_RECEIVE		(dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
59 
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 	} \
75 }
76 
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 	} \
85 }
86 
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 	} \
95 }
96 
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;
138 
139 
140 static struct dsp56k_device {
141 	long in_use;
142 	long maxio, timeout;
143 	int tx_wsize, rx_wsize;
144 } dsp56k;
145 
146 static struct class *dsp56k_class;
147 
148 static int dsp56k_reset(void)
149 {
150 	u_char status;
151 
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;
157 
158 	udelay(10);
159 
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;
163 
164 	return 0;
165 }
166 
167 static int dsp56k_upload(u_char __user *bin, int len)
168 {
169 	int i;
170 	u_char *p;
171 
172 	dsp56k_reset();
173 
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++;
180 	}
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;
186 	}
187 
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++);
193 	}
194 
195 	tx_wait(10);
196 	dsp56k_host_interface.data.l = 3;    /* Magic execute */
197 
198 	return 0;
199 }
200 
201 static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count,
202 			   loff_t *ppos)
203 {
204 	struct inode *inode = file->f_dentry->d_inode;
205 	int dev = iminor(inode) & 0x0f;
206 
207 	switch(dev)
208 	{
209 	case DSP56K_DEV_56001:
210 	{
211 
212 		long n;
213 
214 		/* Don't do anything if nothing is to be done */
215 		if (!count) return 0;
216 
217 		n = 0;
218 		switch (dsp56k.rx_wsize) {
219 		case 1:  /* 8 bit */
220 		{
221 			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
222 				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
223 			return n;
224 		}
225 		case 2:  /* 16 bit */
226 		{
227 			short __user *data;
228 
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;
234 		}
235 		case 3:  /* 24 bit */
236 		{
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;
243 		}
244 		case 4:  /* 32 bit */
245 		{
246 			long __user *data;
247 
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;
253 		}
254 		}
255 		return -EFAULT;
256 	}
257 
258 	default:
259 		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
260 		return -ENXIO;
261 	}
262 }
263 
264 static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count,
265 			    loff_t *ppos)
266 {
267 	struct inode *inode = file->f_dentry->d_inode;
268 	int dev = iminor(inode) & 0x0f;
269 
270 	switch(dev)
271 	{
272 	case DSP56K_DEV_56001:
273 	{
274 		long n;
275 
276 		/* Don't do anything if nothing is to be done */
277 		if (!count) return 0;
278 
279 		n = 0;
280 		switch (dsp56k.tx_wsize) {
281 		case 1:  /* 8 bit */
282 		{
283 			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
284 				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
285 			return n;
286 		}
287 		case 2:  /* 16 bit */
288 		{
289 			const short __user *data;
290 
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;
296 		}
297 		case 3:  /* 24 bit */
298 		{
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;
305 		}
306 		case 4:  /* 32 bit */
307 		{
308 			const long __user *data;
309 
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;
315 		}
316 		}
317 
318 		return -EFAULT;
319 	}
320 	default:
321 		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
322 		return -ENXIO;
323 	}
324 }
325 
326 static int dsp56k_ioctl(struct inode *inode, struct file *file,
327 			unsigned int cmd, unsigned long arg)
328 {
329 	int dev = iminor(inode) & 0x0f;
330 	void __user *argp = (void __user *)arg;
331 
332 	switch(dev)
333 	{
334 	case DSP56K_DEV_56001:
335 
336 		switch(cmd) {
337 		case DSP56K_UPLOAD:
338 		{
339 			char __user *bin;
340 			int r, len;
341 			struct dsp56k_upload __user *binary = argp;
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 __user *hf = argp;
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
421 static 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 
438 static 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 
469 static 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 
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,
493 };
494 
495 
496 /****** Init and module functions ******/
497 
498 static char banner[] __initdata = KERN_INFO "DSP56k driver installed\n";
499 
500 static 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_create(THIS_MODULE, "dsp56k");
514 	if (IS_ERR(dsp56k_class)) {
515 		err = PTR_ERR(dsp56k_class);
516 		goto out_chrdev;
517 	}
518 	class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
519 
520 	printk(banner);
521 	goto out;
522 
523 out_chrdev:
524 	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
525 out:
526 	return err;
527 }
528 module_init(dsp56k_init_driver);
529 
530 static void __exit dsp56k_cleanup_driver(void)
531 {
532 	class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
533 	class_destroy(dsp56k_class);
534 	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
535 }
536 module_exit(dsp56k_cleanup_driver);
537 
538 MODULE_LICENSE("GPL");
539