xref: /openbmc/linux/drivers/char/dsp56k.c (revision 87c2ce3b)
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 */
99 static 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};
138 static int sizeof_bootstrap = 375;
139 
140 
141 static struct dsp56k_device {
142 	long in_use;
143 	long maxio, timeout;
144 	int tx_wsize, rx_wsize;
145 } dsp56k;
146 
147 static struct class *dsp56k_class;
148 
149 static 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 
168 static 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 
202 static 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 
265 static 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 
327 static 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
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 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 	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 
528 out_class:
529 	class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
530 	class_destroy(dsp56k_class);
531 out_chrdev:
532 	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
533 out:
534 	return err;
535 }
536 module_init(dsp56k_init_driver);
537 
538 static void __exit dsp56k_cleanup_driver(void)
539 {
540 	class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
541 	class_destroy(dsp56k_class);
542 	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
543 	devfs_remove("dsp56k");
544 }
545 module_exit(dsp56k_cleanup_driver);
546 
547 MODULE_LICENSE("GPL");
548