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