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