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