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