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