root/drivers/char/dsp56k.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dsp56k_reset
  2. dsp56k_upload
  3. dsp56k_read
  4. dsp56k_write
  5. dsp56k_ioctl
  6. dsp56k_poll
  7. dsp56k_open
  8. dsp56k_release
  9. dsp56k_init_driver
  10. dsp56k_cleanup_driver

   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 struct class *dsp56k_class;
 105 
 106 static int dsp56k_reset(void)
 107 {
 108         u_char status;
 109         
 110         /* Power down the DSP */
 111         sound_ym.rd_data_reg_sel = 14;
 112         status = sound_ym.rd_data_reg_sel & 0xef;
 113         sound_ym.wd_data = status;
 114         sound_ym.wd_data = status | 0x10;
 115   
 116         udelay(10);
 117   
 118         /* Power up the DSP */
 119         sound_ym.rd_data_reg_sel = 14;
 120         sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
 121 
 122         return 0;
 123 }
 124 
 125 static int dsp56k_upload(u_char __user *bin, int len)
 126 {
 127         struct platform_device *pdev;
 128         const struct firmware *fw;
 129         const char fw_name[] = "dsp56k/bootstrap.bin";
 130         int err;
 131         int i;
 132 
 133         dsp56k_reset();
 134 
 135         pdev = platform_device_register_simple("dsp56k", 0, NULL, 0);
 136         if (IS_ERR(pdev)) {
 137                 printk(KERN_ERR "Failed to register device for \"%s\"\n",
 138                        fw_name);
 139                 return -EINVAL;
 140         }
 141         err = request_firmware(&fw, fw_name, &pdev->dev);
 142         platform_device_unregister(pdev);
 143         if (err) {
 144                 printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
 145                        fw_name, err);
 146                 return err;
 147         }
 148         if (fw->size % 3) {
 149                 printk(KERN_ERR "Bogus length %d in image \"%s\"\n",
 150                        fw->size, fw_name);
 151                 release_firmware(fw);
 152                 return -EINVAL;
 153         }
 154         for (i = 0; i < fw->size; i = i + 3) {
 155                 /* tx_wait(10); */
 156                 dsp56k_host_interface.data.b[1] = fw->data[i];
 157                 dsp56k_host_interface.data.b[2] = fw->data[i + 1];
 158                 dsp56k_host_interface.data.b[3] = fw->data[i + 2];
 159         }
 160         release_firmware(fw);
 161         for (; i < 512; i++) {
 162                 /* tx_wait(10); */
 163                 dsp56k_host_interface.data.b[1] = 0;
 164                 dsp56k_host_interface.data.b[2] = 0;
 165                 dsp56k_host_interface.data.b[3] = 0;
 166         }
 167   
 168         for (i = 0; i < len; i++) {
 169                 tx_wait(10);
 170                 get_user(dsp56k_host_interface.data.b[1], bin++);
 171                 get_user(dsp56k_host_interface.data.b[2], bin++);
 172                 get_user(dsp56k_host_interface.data.b[3], bin++);
 173         }
 174 
 175         tx_wait(10);
 176         dsp56k_host_interface.data.l = 3;    /* Magic execute */
 177 
 178         return 0;
 179 }
 180 
 181 static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count,
 182                            loff_t *ppos)
 183 {
 184         struct inode *inode = file_inode(file);
 185         int dev = iminor(inode) & 0x0f;
 186 
 187         switch(dev)
 188         {
 189         case DSP56K_DEV_56001:
 190         {
 191 
 192                 long n;
 193 
 194                 /* Don't do anything if nothing is to be done */
 195                 if (!count) return 0;
 196 
 197                 n = 0;
 198                 switch (dsp56k.rx_wsize) {
 199                 case 1:  /* 8 bit */
 200                 {
 201                         handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
 202                                   put_user(dsp56k_host_interface.data.b[3], buf+n++));
 203                         return n;
 204                 }
 205                 case 2:  /* 16 bit */
 206                 {
 207                         short __user *data;
 208 
 209                         count /= 2;
 210                         data = (short __user *) buf;
 211                         handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
 212                                   put_user(dsp56k_host_interface.data.w[1], data+n++));
 213                         return 2*n;
 214                 }
 215                 case 3:  /* 24 bit */
 216                 {
 217                         count /= 3;
 218                         handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
 219                                   put_user(dsp56k_host_interface.data.b[1], buf+n++);
 220                                   put_user(dsp56k_host_interface.data.b[2], buf+n++);
 221                                   put_user(dsp56k_host_interface.data.b[3], buf+n++));
 222                         return 3*n;
 223                 }
 224                 case 4:  /* 32 bit */
 225                 {
 226                         long __user *data;
 227 
 228                         count /= 4;
 229                         data = (long __user *) buf;
 230                         handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
 231                                   put_user(dsp56k_host_interface.data.l, data+n++));
 232                         return 4*n;
 233                 }
 234                 }
 235                 return -EFAULT;
 236         }
 237 
 238         default:
 239                 printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
 240                 return -ENXIO;
 241         }
 242 }
 243 
 244 static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count,
 245                             loff_t *ppos)
 246 {
 247         struct inode *inode = file_inode(file);
 248         int dev = iminor(inode) & 0x0f;
 249 
 250         switch(dev)
 251         {
 252         case DSP56K_DEV_56001:
 253         {
 254                 long n;
 255 
 256                 /* Don't do anything if nothing is to be done */
 257                 if (!count) return 0;
 258 
 259                 n = 0;
 260                 switch (dsp56k.tx_wsize) {
 261                 case 1:  /* 8 bit */
 262                 {
 263                         handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
 264                                   get_user(dsp56k_host_interface.data.b[3], buf+n++));
 265                         return n;
 266                 }
 267                 case 2:  /* 16 bit */
 268                 {
 269                         const short __user *data;
 270 
 271                         count /= 2;
 272                         data = (const short __user *)buf;
 273                         handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
 274                                   get_user(dsp56k_host_interface.data.w[1], data+n++));
 275                         return 2*n;
 276                 }
 277                 case 3:  /* 24 bit */
 278                 {
 279                         count /= 3;
 280                         handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
 281                                   get_user(dsp56k_host_interface.data.b[1], buf+n++);
 282                                   get_user(dsp56k_host_interface.data.b[2], buf+n++);
 283                                   get_user(dsp56k_host_interface.data.b[3], buf+n++));
 284                         return 3*n;
 285                 }
 286                 case 4:  /* 32 bit */
 287                 {
 288                         const long __user *data;
 289 
 290                         count /= 4;
 291                         data = (const long __user *)buf;
 292                         handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
 293                                   get_user(dsp56k_host_interface.data.l, data+n++));
 294                         return 4*n;
 295                 }
 296                 }
 297 
 298                 return -EFAULT;
 299         }
 300         default:
 301                 printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
 302                 return -ENXIO;
 303         }
 304 }
 305 
 306 static long dsp56k_ioctl(struct file *file, unsigned int cmd,
 307                          unsigned long arg)
 308 {
 309         int dev = iminor(file_inode(file)) & 0x0f;
 310         void __user *argp = (void __user *)arg;
 311 
 312         switch(dev)
 313         {
 314         case DSP56K_DEV_56001:
 315 
 316                 switch(cmd) {
 317                 case DSP56K_UPLOAD:
 318                 {
 319                         char __user *bin;
 320                         int r, len;
 321                         struct dsp56k_upload __user *binary = argp;
 322     
 323                         if(get_user(len, &binary->len) < 0)
 324                                 return -EFAULT;
 325                         if(get_user(bin, &binary->bin) < 0)
 326                                 return -EFAULT;
 327                 
 328                         if (len <= 0) {
 329                                 return -EINVAL;      /* nothing to upload?!? */
 330                         }
 331                         if (len > DSP56K_MAX_BINARY_LENGTH) {
 332                                 return -EINVAL;
 333                         }
 334                         mutex_lock(&dsp56k_mutex);
 335                         r = dsp56k_upload(bin, len);
 336                         mutex_unlock(&dsp56k_mutex);
 337                         if (r < 0) {
 338                                 return r;
 339                         }
 340     
 341                         break;
 342                 }
 343                 case DSP56K_SET_TX_WSIZE:
 344                         if (arg > 4 || arg < 1)
 345                                 return -EINVAL;
 346                         mutex_lock(&dsp56k_mutex);
 347                         dsp56k.tx_wsize = (int) arg;
 348                         mutex_unlock(&dsp56k_mutex);
 349                         break;
 350                 case DSP56K_SET_RX_WSIZE:
 351                         if (arg > 4 || arg < 1)
 352                                 return -EINVAL;
 353                         mutex_lock(&dsp56k_mutex);
 354                         dsp56k.rx_wsize = (int) arg;
 355                         mutex_unlock(&dsp56k_mutex);
 356                         break;
 357                 case DSP56K_HOST_FLAGS:
 358                 {
 359                         int dir, out, status;
 360                         struct dsp56k_host_flags __user *hf = argp;
 361     
 362                         if(get_user(dir, &hf->dir) < 0)
 363                                 return -EFAULT;
 364                         if(get_user(out, &hf->out) < 0)
 365                                 return -EFAULT;
 366 
 367                         mutex_lock(&dsp56k_mutex);
 368                         if ((dir & 0x1) && (out & 0x1))
 369                                 dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
 370                         else if (dir & 0x1)
 371                                 dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
 372                         if ((dir & 0x2) && (out & 0x2))
 373                                 dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
 374                         else if (dir & 0x2)
 375                                 dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
 376 
 377                         status = 0;
 378                         if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
 379                         if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
 380                         if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
 381                         if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
 382                         mutex_unlock(&dsp56k_mutex);
 383                         return put_user(status, &hf->status);
 384                 }
 385                 case DSP56K_HOST_CMD:
 386                         if (arg > 31)
 387                                 return -EINVAL;
 388                         mutex_lock(&dsp56k_mutex);
 389                         dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
 390                                                              DSP56K_CVR_HC);
 391                         mutex_unlock(&dsp56k_mutex);
 392                         break;
 393                 default:
 394                         return -EINVAL;
 395                 }
 396                 return 0;
 397 
 398         default:
 399                 printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
 400                 return -ENXIO;
 401         }
 402 }
 403 
 404 /* As of 2.1.26 this should be dsp56k_poll,
 405  * but how do I then check device minor number?
 406  * Do I need this function at all???
 407  */
 408 #if 0
 409 static __poll_t dsp56k_poll(struct file *file, poll_table *wait)
 410 {
 411         int dev = iminor(file_inode(file)) & 0x0f;
 412 
 413         switch(dev)
 414         {
 415         case DSP56K_DEV_56001:
 416                 /* poll_wait(file, ???, wait); */
 417                 return EPOLLIN | EPOLLRDNORM | EPOLLOUT;
 418 
 419         default:
 420                 printk("DSP56k driver: Unknown minor device: %d\n", dev);
 421                 return 0;
 422         }
 423 }
 424 #endif
 425 
 426 static int dsp56k_open(struct inode *inode, struct file *file)
 427 {
 428         int dev = iminor(inode) & 0x0f;
 429         int ret = 0;
 430 
 431         mutex_lock(&dsp56k_mutex);
 432         switch(dev)
 433         {
 434         case DSP56K_DEV_56001:
 435 
 436                 if (test_and_set_bit(0, &dsp56k.in_use)) {
 437                         ret = -EBUSY;
 438                         goto out;
 439                 }
 440 
 441                 dsp56k.timeout = TIMEOUT;
 442                 dsp56k.maxio = MAXIO;
 443                 dsp56k.rx_wsize = dsp56k.tx_wsize = 4; 
 444 
 445                 DSP56K_TX_INT_OFF;
 446                 DSP56K_RX_INT_OFF;
 447 
 448                 /* Zero host flags */
 449                 dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
 450                 dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
 451 
 452                 break;
 453 
 454         default:
 455                 ret = -ENODEV;
 456         }
 457 out:
 458         mutex_unlock(&dsp56k_mutex);
 459         return ret;
 460 }
 461 
 462 static int dsp56k_release(struct inode *inode, struct file *file)
 463 {
 464         int dev = iminor(inode) & 0x0f;
 465 
 466         switch(dev)
 467         {
 468         case DSP56K_DEV_56001:
 469                 clear_bit(0, &dsp56k.in_use);
 470                 break;
 471         default:
 472                 printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
 473                 return -ENXIO;
 474         }
 475 
 476         return 0;
 477 }
 478 
 479 static const struct file_operations dsp56k_fops = {
 480         .owner          = THIS_MODULE,
 481         .read           = dsp56k_read,
 482         .write          = dsp56k_write,
 483         .unlocked_ioctl = dsp56k_ioctl,
 484         .open           = dsp56k_open,
 485         .release        = dsp56k_release,
 486         .llseek         = noop_llseek,
 487 };
 488 
 489 
 490 /****** Init and module functions ******/
 491 
 492 static const char banner[] __initconst = KERN_INFO "DSP56k driver installed\n";
 493 
 494 static int __init dsp56k_init_driver(void)
 495 {
 496         int err = 0;
 497 
 498         if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
 499                 printk("DSP56k driver: Hardware not present\n");
 500                 return -ENODEV;
 501         }
 502 
 503         if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
 504                 printk("DSP56k driver: Unable to register driver\n");
 505                 return -ENODEV;
 506         }
 507         dsp56k_class = class_create(THIS_MODULE, "dsp56k");
 508         if (IS_ERR(dsp56k_class)) {
 509                 err = PTR_ERR(dsp56k_class);
 510                 goto out_chrdev;
 511         }
 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_destroy(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");

/* [<][>][^][v][top][bottom][index][help] */