~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/char/dsp56k.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.