root/drivers/char/lp_m68k.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lp_char_polled
  2. lp_char_interrupt
  3. lp_interrupt
  4. lp_write
  5. lp_write
  6. lp_write
  7. lp_lseek
  8. lp_open
  9. lp_release
  10. lp_ioctl
  11. lp_init
  12. lp_setup

   1 /*
   2  * split in two parts for better support of different hardware
   3  * by Joerg Dorchain (dorchain@mpi-sb.mpg.de)
   4  *
   5  * Amiga printer device by Michael Rausch (linux@uni-koblenz.de);
   6  * Atari support added by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de);
   7  * based upon work from
   8  *
   9  * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
  10  * Copyright (C) 1992,1993 by Michael K. Johnson
  11  * - Thanks much to Gunter Windau for pointing out to me where the error
  12  *   checking ought to be.
  13  * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
  14  */
  15 
  16 /* 01/17/95: Matthias Welwarsky (dg8y@rs11.hrz.th-darmstadt.de)
  17  * lp_write(): rewritten from scratch
  18  * lp_interrupt(): fixed cli()/sti()-bug
  19  * 
  20  * 95/05/28: Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
  21  * lp_write() fixed to make it work again.
  22  * 95/08/18: Andreas Schwab
  23  * lp_write_interrupt: fix race condition
  24  *
  25  *  * CAUTION, please do check! *    
  26  * 
  27  *  on 68000-based machines sti() must NEVER appear in interrupt driven
  28  *  code. The 68k-CPU has a priority-based interrupt scheme. while an interrupt
  29  *  with a certain priority is executed, all requests with lower or same
  30  *  priority get locked out. executing the sti()-macro allows ANY interrupt
  31  *  to be served. this really causes BIG trouble!
  32  *  to protect an interrupt driven routine against being interrupted 
  33  *  (if absolutely needed!) one should use save_flags();cli()/restore_flags()!
  34  *
  35  */
  36 
  37 #include <linux/config.h>
  38 #include <linux/errno.h>
  39 #include <linux/kernel.h>
  40 #include <linux/major.h>
  41 #include <linux/sched.h>
  42 #include <asm/irq.h>
  43 
  44 #ifdef CONFIG_AMIGA
  45 #include <asm/amigaints.h>
  46 #ifdef CONFIG_MULTIFACE_III_LP
  47 #include <linux/lp_mfc.h>
  48 #endif
  49 #endif
  50 #ifdef CONFIG_ATARI
  51 #include <asm/atarihw.h>
  52 #include <asm/atariints.h>
  53 #endif
  54 
  55 #include <linux/lp_m68k.h>
  56 #include <linux/lp_intern.h>
  57 #include <linux/malloc.h>
  58 #include <linux/interrupt.h>
  59 
  60 #include <asm/segment.h>
  61 #include <asm/system.h>
  62 
  63 
  64 /*
  65  *  why bother around with the pio driver when the interrupt works;
  66  *  so, for "security" reasons only, it's configurable here.
  67  *  saves some bytes, at least ...
  68  */
  69 #define FORCE_POLLING    0
  70 #define FORCE_INTERRUPT  1
  71 #define PREFER_INTERRUPT 2
  72 
  73 #define WHICH_DRIVER    FORCE_INTERRUPT
  74 
  75 #define MAX_LP 3 /* the maximum number of devices */
  76 
  77 struct lp_struct lp_table[MAX_LP] = {{0,},};
  78 
  79 static int max_lp; /* the real number of devices */
  80 
  81 /* 
  82  * All my debugging code assumes that you debug with only one printer at
  83  * a time. RWWH
  84  */
  85 
  86 #define LP_DEBUG 
  87 #undef LP_DEBUG 
  88 
  89 
  90 #if WHICH_DRIVER != FORCE_INTERRUPT
  91 #ifdef LP_DEBUG
  92 static int lp_max_count = 1;
  93 #endif
  94 
  95 static int lp_char_polled(char lpchar, int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97         unsigned long count  = 0; 
  98 
  99         do {
 100                 count ++;
 101                 if(need_resched)
 102                         schedule();
 103         } while (lp_table[dev].lp_is_busy(dev) && count < lp_table[dev].chars);
 104 
 105         if (count == lp_table[dev].chars) {
 106                 return 0;
 107                 /* we timed out, and the character was /not/ printed */
 108         }
 109 #ifdef LP_DEBUG
 110         if (count > lp_max_count) {
 111                 printk("lp success after %d counts.\n",count);
 112                 lp_max_count = count;
 113         }
 114 #endif
 115         lp_table[dev].lp_out(lpchar, dev);
 116         return 1;
 117 }
 118 #endif
 119 
 120 
 121 #ifdef LP_DEBUG
 122 unsigned int lp_total_chars = 0;
 123 unsigned int lp_last_call = 0;
 124 #endif
 125 
 126 
 127 #if WHICH_DRIVER != FORCE_POLLING
 128 static __inline__ int lp_char_interrupt(char lpchar, int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 129 {
 130         if (!lp_table[dev].lp_is_busy(dev)) {
 131                 lp_table[dev].lp_out(lpchar,dev);
 132                 return 1;
 133         }
 134         return 0;
 135 }
 136 
 137 static int lp_error;
 138 
 139 static void lp_interrupt(int irq, struct pt_regs *fp, void *dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 140 {
 141     unsigned long flags;
 142     int dev;
 143 
 144     for (dev = 0; dev < max_lp; dev++) {
 145         if (lp_table[dev].lp_my_interrupt(dev) != 0)
 146           if (lp_table[dev].do_print)
 147           {
 148                   if (lp_table[dev].copy_size)
 149                   {
 150                           save_flags(flags);
 151                           cli();
 152                           if (lp_char_interrupt(lp_table[dev].lp_buffer[lp_table[dev].bytes_written], dev)) {
 153                                   --lp_table[dev].copy_size;
 154                                   ++lp_table[dev].bytes_written;
 155                                   restore_flags(flags);
 156                           }
 157                           else
 158                           {
 159                                   lp_table[dev].do_print = 0;
 160                                   restore_flags(flags);
 161                                   lp_error = 1;
 162                                   wake_up_interruptible(&lp_table[dev].lp_wait_q);
 163                           }
 164                   }
 165                   else
 166                   {
 167                           lp_table[dev].do_print = 0;
 168                           lp_error = 0;
 169                           wake_up_interruptible(&lp_table[dev].lp_wait_q);
 170                   }
 171 
 172           }
 173     }
 174 }
 175 
 176 #if WHICH_DRIVER == FORCE_INTERRUPT
 177 static int lp_write(struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 178                     const char *buf, int count)
 179 #else
 180 static int lp_write_interrupt(struct inode *inode, struct file *file,
 181                               const char *buf, int count)
 182 #endif
 183 {
 184   unsigned long total_bytes_written = 0;
 185   unsigned int flags;
 186   int rc;
 187   int dev = MINOR(inode->i_rdev);
 188 
 189   do {
 190     lp_table[dev].do_print = 0;         /* disable lp_interrupt()   */
 191     lp_table[dev].bytes_written = 0;    /* init buffer read-pointer */
 192     lp_error = 0;
 193     lp_table[dev].copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
 194     memcpy_fromfs(lp_table[dev].lp_buffer, buf, lp_table[dev].copy_size);
 195     while (lp_table[dev].copy_size) {
 196       save_flags(flags);
 197       cli();                            /* no interrupts now */
 198       lp_table[dev].do_print = 1;       /* enable lp_interrupt() */
 199       if (lp_char_interrupt(lp_table[dev].lp_buffer[lp_table[dev].bytes_written], dev)) {
 200         ++lp_table[dev].bytes_written;
 201         --lp_table[dev].copy_size;
 202         lp_error = 0;
 203       } else {                          /* something went wrong   */
 204         lp_table[dev].do_print = 0;     /* disable lp_interrupt() */
 205         lp_error = 1;                   /* printer caused error   */
 206       }
 207       if (lp_error) {
 208 
 209           /* something blocked printing, so we don't want to sleep too long,
 210              in case we have to rekick the interrupt */
 211 
 212           current->timeout = jiffies + LP_TIMEOUT_POLLED;
 213       } else {
 214           current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
 215       }
 216   
 217       interruptible_sleep_on(&lp_table[dev].lp_wait_q);
 218       restore_flags(flags);
 219   
 220       /* we're up again and running. we first disable lp_interrupt(), then
 221          check what happened meanwhile */
 222 
 223       lp_table[dev].do_print = 0;
 224       rc = total_bytes_written + lp_table[dev].bytes_written;
 225 
 226       if (current->signal & ~current->blocked) {
 227         if (rc)
 228           return rc;
 229         else
 230           return -EINTR;
 231       }
 232       if (lp_error) {
 233 
 234         /* an error has occurred, maybe in lp_interrupt().
 235            figure out the type of error, exit on request or if nothing has 
 236            been printed at all. */
 237         
 238         if (lp_table[dev].lp_has_pout(dev)) {
 239           printk(KERN_NOTICE "lp%d: paper-out\n",dev);
 240           if (!rc) rc = -ENOSPC;
 241         } else if (!lp_table[dev].lp_is_online(dev)) {
 242           printk(KERN_NOTICE "lp%d: off-line\n",dev);
 243           if (!rc) rc = -EIO;
 244         } else if (lp_table[dev].lp_is_busy(dev)) {
 245           printk(KERN_NOTICE "lp%d: on fire\n",dev);
 246           if (!rc) rc = -EIO;
 247         }
 248         if (lp_table[dev].flags & LP_ABORT)
 249           return rc;
 250       }
 251       /* check if our buffer was completely printed, if not, most likely
 252          an unsolved error blocks the printer. As we can`t do anything
 253          against, we start all over again. Else we set the read-pointer
 254          of the buffer and count the printed characters */
 255       
 256       if (!lp_table[dev].copy_size) {
 257         total_bytes_written += lp_table[dev].bytes_written;
 258         buf += lp_table[dev].bytes_written;
 259         count -= lp_table[dev].bytes_written;
 260       }
 261     }
 262   } while (count > 0);
 263   return total_bytes_written;
 264 }
 265 #endif
 266 
 267 #if WHICH_DRIVER != FORCE_INTERRUPT
 268 #if WHICH_DRIVER == FORCE_POLLING
 269 static int lp_write(struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 270                     const char *buf, int count)
 271 #else
 272 static int lp_write_polled(struct inode *inode, struct file *file,
 273                            const char *buf, int count)
 274 #endif
 275 {
 276         char *temp = buf;
 277         int dev = MINOR(inode->i_rdev);
 278 
 279 #ifdef LP_DEBUG
 280         if (jiffies-lp_last_call > lp_table[dev].time) {
 281                 lp_total_chars = 0;
 282                 lp_max_count = 1;
 283         }
 284         lp_last_call = jiffies;
 285 #endif
 286 
 287         temp = buf;
 288         while (count > 0) {
 289                 if (lp_char_polled(get_user(temp), dev)) {
 290                         /* only update counting vars if character was printed */
 291                         count--; temp++;
 292 #ifdef LP_DEBUG
 293                         lp_total_chars++;
 294 #endif
 295                 } else { /* if printer timed out */
 296                         if (lp_table[dev].lp_has_pout(dev)) {
 297                                 printk(KERN_NOTICE "lp%d: out of paper\n",dev);
 298                                 if (lp_table[dev].flags & LP_ABORT)
 299                                         return temp - buf ? temp-buf : -ENOSPC;
 300                                 current->state = TASK_INTERRUPTIBLE;
 301                                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
 302                                 schedule();
 303                         } else if (!lp_table[dev].lp_is_online(dev)) {
 304                                 printk(KERN_NOTICE "lp%d: off-line\n",dev);
 305                                 if (lp_table[dev].flags & LP_ABORT)
 306                                         return temp - buf ? temp-buf : -EIO;
 307                                 current->state = TASK_INTERRUPTIBLE;
 308                                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
 309                                 schedule();
 310                         } else
 311                         /* not offline or out of paper. on fire? */
 312                         if (lp_table[dev].lp_is_busy(dev)) {
 313                                 printk(KERN_NOTICE "lp%d: on fire\n",dev);
 314                                 if (lp_table[dev].flags & LP_ABORT)
 315                                         return temp - buf ? temp-buf : -EFAULT;
 316                                 current->state = TASK_INTERRUPTIBLE;
 317                                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
 318                                 schedule();
 319                         }
 320 
 321                         /* check for signals before going to sleep */
 322                         if (current->signal & ~current->blocked) {
 323                                 if (temp != buf)
 324                                         return temp-buf;
 325                                 else
 326                                         return -EINTR;
 327                         }
 328 #ifdef LP_DEBUG
 329                         printk("lp sleeping at %d characters for %d jiffies\n",
 330                                 lp_total_chars, lp_table[dev].time);
 331                         lp_total_chars = 0;
 332 #endif
 333                         current->state = TASK_INTERRUPTIBLE;
 334                         current->timeout = jiffies + lp_table[dev].time;
 335                         schedule();
 336                 }
 337         }
 338         return temp - buf;
 339 }
 340 #endif
 341 
 342 static unsigned int lp_irq = 0;
 343 
 344 #if WHICH_DRIVER == PREFER_INTERRUPT
 345 static int lp_write(struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 346                     const char *buf, int count)
 347 {
 348         if (lp_irq)
 349                 return lp_write_interrupt(inode, file, buf, count);
 350         else
 351                 return lp_write_polled(inode, file, buf, count);
 352 }
 353 #endif
 354 
 355 static int lp_lseek(struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 356                     off_t offset, int origin)
 357 {
 358         return -ESPIPE;
 359 }
 360 
 361 static int lp_open(struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 362 {
 363         int dev = MINOR(inode->i_rdev);
 364 
 365         if (dev >= max_lp)
 366                 return -ENODEV;
 367         if (!(lp_table[dev].flags & LP_EXIST))
 368                 return -ENODEV;
 369         if (lp_table[dev].flags & LP_BUSY)
 370                 return -EBUSY;
 371 
 372         lp_table[dev].flags |= LP_BUSY;
 373 
 374         return 0;
 375 }
 376 
 377 static void lp_release(struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 378 {
 379         lp_table[MINOR(inode->i_rdev)].flags &= ~LP_BUSY;
 380 }
 381 
 382 
 383 static int lp_ioctl(struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 384                     unsigned int cmd, unsigned long arg)
 385 {
 386         unsigned int minor = MINOR(inode->i_rdev);
 387         int retval = 0;
 388 
 389 #ifdef LP_DEBUG
 390         printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
 391 #endif
 392         if (minor >= max_lp)
 393                 return -ENODEV;
 394         if (!(lp_table[minor].flags & LP_EXIST))
 395                 return -ENODEV;
 396         switch (cmd) {
 397         case LPTIME:
 398                 lp_table[minor].time = arg;
 399                 break;
 400         case LPCHAR:
 401                 lp_table[minor].chars = arg;
 402                 break;
 403         case LPABORT:
 404                 if (arg)
 405                         lp_table[minor].flags |= LP_ABORT;
 406                 else
 407                         lp_table[minor].flags &= ~LP_ABORT;
 408                 break;
 409         case LPWAIT:
 410                 lp_table[minor].wait = arg;
 411                 break;
 412         case LPSETIRQ:
 413         case LPGETIRQ:
 414                 retval = lp_irq;
 415                 break;
 416         default:
 417                 retval = -EINVAL;
 418         }
 419         return retval;
 420 }
 421 
 422 
 423 static struct file_operations lp_fops = {
 424         lp_lseek,
 425         NULL,           /* lp_read */
 426         lp_write,
 427         NULL,           /* lp_readdir */
 428         NULL,           /* lp_select */
 429         lp_ioctl,
 430         NULL,           /* lp_mmap */
 431         lp_open,
 432         lp_release
 433 };
 434 
 435 
 436 int lp_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 437 {
 438         extern char m68k_debug_device[];
 439 
 440         if (!strcmp( m68k_debug_device, "par" ))
 441                 return -EBUSY;
 442 
 443         if (register_chrdev(LP_MAJOR,"lp", &lp_fops)) {
 444                 printk("unable to get major %d for line printer\n", LP_MAJOR);
 445                 return -EBUSY;
 446         }
 447 
 448 #if WHICH_DRIVER == FORCE_POLLING
 449         lp_irq = 0;
 450         printk(KERN_INFO "lp_init: lp using polling driver\n");
 451 #else
 452 
 453 #ifdef CONFIG_AMIGA
 454         if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL))
 455                 lp_irq = add_isr(IRQ_AMIGA_CIAA_FLG, lp_interrupt, 0,
 456                                  NULL, "printer");
 457 #endif
 458 #ifdef CONFIG_ATARI
 459         if (MACH_IS_ATARI)
 460                 lp_irq = add_isr(IRQ_MFP_BUSY, lp_interrupt, IRQ_TYPE_SLOW,
 461                                  NULL, "printer");
 462 #endif
 463 
 464         if (lp_irq)
 465                 printk(KERN_INFO "lp_init: lp using interrupt\n");
 466         else
 467 
 468 #if WHICH_DRIVER == PREFER_INTERRUPT
 469                 printk(KERN_INFO "lp_init: lp using polling driver\n");
 470 #else
 471                 printk(KERN_WARNING "lp_init: can't get interrupt, and polling driver not configured\n");
 472 #endif
 473 #endif
 474 
 475         max_lp = 0;
 476         max_lp += lp_internal_init(lp_table, max_lp, MAX_LP, WHICH_DRIVER);
 477 #ifdef CONFIG_MULTIFACE_III_LP
 478         max_lp += lp_mfc_init(lp_table, max_lp, MAX_LP, WHICH_DRIVER);
 479 #if WHICH_DRIVER != FORCE_POLLING
 480         add_isr(IRQ_AMIGA_PORTS, lp_interrupt, 0, NULL,
 481                 "Multiface III printer");
 482 #endif
 483 #endif
 484         return 0;
 485 }
 486 
 487 /*
 488  * Currently we do not accept any lp-parameters, but that may change.
 489  */
 490 void    lp_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
 491 {       
 492 }

/* [previous][next][first][last][top][bottom][index][help] */