root/kernel/chr_drv/lp.c

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

DEFINITIONS

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

   1 /*
   2  * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
   3  * Copyright (C) 1992,1993 by Michael K. Johnson
   4  * - Thanks much to Gunter Windau for pointing out to me where the error
   5  *   checking ought to be.
   6  * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
   7  */
   8 
   9 #include <linux/errno.h>
  10 #include <linux/kernel.h>
  11 #include <linux/sched.h>
  12 #include <linux/lp.h>
  13 
  14 #include <asm/io.h>
  15 #include <asm/segment.h>
  16 #include <asm/system.h>
  17 
  18 /* 
  19  * All my debugging code assumes that you debug with only one printer at
  20  * a time. RWWH
  21  */
  22 
  23 #undef LP_DEBUG
  24 
  25 static int lp_reset(int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
  26 {
  27         int testvalue;
  28         unsigned char command;
  29 
  30         command = LP_PSELECP | LP_PINITP;
  31 
  32         /* reset value */
  33         outb_p(0, LP_C(minor));
  34         for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
  35                 ;
  36         outb_p(command, LP_C(minor));
  37         return LP_S(minor);
  38 }
  39 
  40 #ifdef LP_DEBUG
  41 static int lp_max_count = 1;
  42 #endif
  43 
  44 static int lp_char_polled(char lpchar, int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46         int status = 0, wait = 0;
  47         unsigned long count  = 0; 
  48 
  49         do {
  50                 status = LP_S(minor);
  51                 count ++;
  52                 if(need_resched)
  53                         schedule();
  54         } while(!(status & LP_PBUSY) && count < LP_CHAR(minor));
  55 
  56         if (count == LP_CHAR(minor)) {
  57                 return 0;
  58                 /* we timed out, and the character was /not/ printed */
  59         }
  60 #ifdef LP_DEBUG
  61         if (count > lp_max_count) {
  62                 printk("lp success after %d counts.\n",count);
  63                 lp_max_count=count;
  64         }
  65 #endif
  66         outb_p(lpchar, LP_B(minor));
  67         /* must wait before taking strobe high, and after taking strobe
  68            low, according spec.  Some printers need it, others don't. */
  69         while(wait != LP_WAIT(minor)) wait++;
  70         /* control port takes strobe high */
  71         outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
  72         while(wait) wait--;
  73         /* take strobe low */
  74         outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
  75 
  76         return 1;
  77 }
  78 
  79 static int lp_char_interrupt(char lpchar, int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
  80 {
  81         int wait = 0;
  82         unsigned char status;
  83 
  84 
  85         if (!((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
  86         || !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
  87         || !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)) {
  88 
  89                 outb_p(lpchar, LP_B(minor));
  90                 /* must wait before taking strobe high, and after taking strobe
  91                    low, according spec.  Some printers need it, others don't. */
  92                 while(wait != LP_WAIT(minor)) wait++;
  93                 /* control port takes strobe high */
  94                 outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
  95                 while(wait) wait--;
  96                 /* take strobe low */
  97                 outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
  98                 return 1;
  99         }
 100 
 101         return 0;
 102 }
 103 
 104 #ifdef LP_DEBUG
 105         unsigned int lp_total_chars = 0;
 106         unsigned int lp_last_call = 0;
 107 #endif
 108 
 109 static void lp_interrupt(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111         struct lp_struct *lp = &lp_table[0];
 112         struct lp_struct *lp_end = &lp_table[LP_NO];
 113 
 114         while (irq != lp->irq) {
 115                 if (++lp >= lp_end)
 116                         return;
 117         }
 118 
 119         wake_up(&lp->lp_wait_q);
 120 }
 121 
 122 static int lp_write_interrupt(struct inode * inode, struct file * file, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124         unsigned int minor = MINOR(inode->i_rdev);
 125         unsigned long copy_size;
 126         unsigned long total_bytes_written = 0;
 127         unsigned long bytes_written;
 128         struct lp_struct *lp = &lp_table[minor];
 129         unsigned char status;
 130 
 131         do {
 132                 bytes_written = 0;
 133                 copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
 134                 memcpy_fromfs(lp->lp_buffer, buf, copy_size);
 135 
 136                 while (copy_size) {
 137                         if (lp_char_interrupt(lp->lp_buffer[bytes_written], minor)) {
 138                                 --copy_size;
 139                                 ++bytes_written;
 140                         } else {
 141                                 if (!((status = LP_S(minor)) & LP_PERRORP)) {
 142                                         int rc = total_bytes_written + bytes_written;
 143 
 144                                         if ((status & LP_POUTPA)) {
 145                                                 printk("lp%d out of paper\n", minor);
 146                                                 if (!rc)
 147                                                         rc = -ENOSPC;
 148                                         } else if (!(status & LP_PSELECD)) {
 149                                                 printk("lp%d off-line\n", minor);
 150                                                 if (!rc)
 151                                                         rc = -EIO;
 152                                         } else {
 153                                                 printk("lp%d printer error\n", minor);
 154                                                 if (!rc)
 155                                                         rc = -EIO;
 156                                         }
 157                                         if(LP_F(minor) & LP_ABORT)
 158                                                 return rc;
 159                                 }
 160                                 cli();
 161                                 outb_p((LP_PSELECP|LP_PINITP|LP_PINTEN), (LP_C(minor)));
 162                                 status = LP_S(minor);
 163                                 if (!(status & LP_PACK) || (status & LP_PBUSY)) {
 164                                         outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
 165                                         sti();
 166                                         continue;
 167                                 }
 168                                 current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
 169                                 interruptible_sleep_on(&lp->lp_wait_q);
 170                                 outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
 171                                 if (current->signal & ~current->blocked) {
 172                                         if (total_bytes_written + bytes_written)
 173                                                 return total_bytes_written + bytes_written;
 174                                         else
 175                                                 return -EINTR;
 176                                 }
 177                         }
 178                 }
 179 
 180                 total_bytes_written += bytes_written;
 181                 buf += bytes_written;
 182                 count -= bytes_written;
 183 
 184         } while (count > 0);
 185 
 186         return total_bytes_written;
 187 }
 188 
 189 static int lp_write_polled(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 190                            char * buf, int count)
 191 {
 192         int  retval;
 193         unsigned int minor = MINOR(inode->i_rdev);
 194         char c, *temp = buf;
 195 
 196 #ifdef LP_DEBUG
 197         if (jiffies-lp_last_call > LP_TIME(minor)) {
 198                 lp_total_chars = 0;
 199                 lp_max_count = 1;
 200         }
 201         lp_last_call = jiffies;
 202 #endif
 203 
 204         temp = buf;
 205         while (count > 0) {
 206                 c = get_fs_byte(temp);
 207                 retval = lp_char_polled(c, minor);
 208                 /* only update counting vars if character was printed */
 209                 if (retval) { count--; temp++;
 210 #ifdef LP_DEBUG
 211                         lp_total_chars++;
 212 #endif
 213                 }
 214                 if (!retval) { /* if printer timed out */
 215                         int status = LP_S(minor);
 216 
 217                         if (status & LP_POUTPA) {
 218                                 printk("lp%d out of paper\n", minor);
 219                                 if(LP_F(minor) & LP_ABORT)
 220                                         return temp-buf?temp-buf:-ENOSPC;
 221                                 current->state = TASK_INTERRUPTIBLE;
 222                                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
 223                                 schedule();
 224                         } else
 225                         if (!(status & LP_PSELECD)) {
 226                                 printk("lp%d off-line\n", minor);
 227                                 if(LP_F(minor) & LP_ABORT)
 228                                         return temp-buf?temp-buf:-EIO;
 229                                 current->state = TASK_INTERRUPTIBLE;
 230                                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
 231                                 schedule();
 232                         } else
 233                         /* not offline or out of paper. on fire? */
 234                         if (!(status & LP_PERRORP)) {
 235                                 printk("lp%d on fire\n", minor);
 236                                 if(LP_F(minor) & LP_ABORT)
 237                                         return temp-buf?temp-buf:-EFAULT;
 238                                 current->state = TASK_INTERRUPTIBLE;
 239                                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
 240                                 schedule();
 241                         }
 242 
 243                         /* check for signals before going to sleep */
 244                         if (current->signal & ~current->blocked) {
 245                                 if (temp != buf)
 246                                         return temp-buf;
 247                                 else
 248                                         return -EINTR;
 249                         }
 250 #ifdef LP_DEBUG
 251                         printk("lp sleeping at %d characters for %d jiffies\n",
 252                                 lp_total_chars, LP_TIME(minor));
 253                         lp_total_chars=0;
 254 #endif
 255                         current->state = TASK_INTERRUPTIBLE;
 256                         current->timeout = jiffies + LP_TIME(minor);
 257                         schedule();
 258                 }
 259         }
 260         return temp-buf;
 261 }
 262 
 263 static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 264 {
 265         if (LP_IRQ(MINOR(inode->i_rdev)))
 266                 return lp_write_interrupt(inode, file, buf, count);
 267         else
 268                 return lp_write_polled(inode, file, buf, count);
 269 }
 270 
 271 static int lp_lseek(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 272                     off_t offset, int origin)
 273 {
 274         return -ESPIPE;
 275 }
 276 
 277 static int lp_open(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 278 {
 279         unsigned int minor = MINOR(inode->i_rdev);
 280         int ret;
 281         unsigned int irq;
 282         struct sigaction sa;
 283 
 284         if (minor >= LP_NO)
 285                 return -ENODEV;
 286         if ((LP_F(minor) & LP_EXIST) == 0)
 287                 return -ENODEV;
 288         if (LP_F(minor) & LP_BUSY)
 289                 return -EBUSY;
 290 
 291         if ((irq = LP_IRQ(minor))) {
 292                 lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
 293                 if (!lp_table[minor].lp_buffer)
 294                         return -ENOMEM;
 295 
 296                 sa.sa_handler = lp_interrupt;
 297                 sa.sa_flags = SA_INTERRUPT;
 298                 sa.sa_mask = 0;
 299                 sa.sa_restorer = NULL;
 300                 ret = irqaction(irq, &sa);
 301                 if (ret) {
 302                         kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
 303                         lp_table[minor].lp_buffer = NULL;
 304                         printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret);
 305                         return ret;
 306                 }
 307         }
 308 
 309         LP_F(minor) |= LP_BUSY;
 310 
 311         return 0;
 312 }
 313 
 314 static void lp_release(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 315 {
 316         unsigned int minor = MINOR(inode->i_rdev);
 317         unsigned int irq;
 318 
 319         if ((irq = LP_IRQ(minor))) {
 320                 free_irq(irq);
 321                 kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
 322                 lp_table[minor].lp_buffer = NULL;
 323         }
 324 
 325         LP_F(minor) &= ~LP_BUSY;
 326 }
 327 
 328 
 329 static int lp_ioctl(struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 330                     unsigned int cmd, unsigned long arg)
 331 {
 332         unsigned int minor = MINOR(inode->i_rdev);
 333         int retval = 0;
 334 
 335 #ifdef LP_DEBUG
 336         printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
 337 #endif
 338         if (minor >= LP_NO)
 339                 return -ENODEV;
 340         if ((LP_F(minor) & LP_EXIST) == 0)
 341                 return -ENODEV;
 342         switch ( cmd ) {
 343                 case LPTIME:
 344                         LP_TIME(minor) = arg;
 345                         break;
 346                 case LPCHAR:
 347                         LP_CHAR(minor) = arg;
 348                         break;
 349                 case LPABORT:
 350                         if (arg)
 351                                 LP_F(minor) |= LP_ABORT;
 352                         else
 353                                 LP_F(minor) &= ~LP_ABORT;
 354                         break;
 355                 case LPWAIT:
 356                         LP_WAIT(minor) = arg;
 357                         break;
 358                 case LPSETIRQ: {
 359                         int oldirq;
 360                         int newirq = arg;
 361                         struct lp_struct *lp = &lp_table[minor];
 362                         struct sigaction sa;
 363 
 364                         if (!suser())
 365                                 return -EPERM;
 366 
 367                         oldirq = LP_IRQ(minor);
 368 
 369                         /* Allocate buffer now if we are going to need it */
 370                         if (!oldirq && newirq) {
 371                                 lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
 372                                 if (!lp->lp_buffer)
 373                                         return -ENOMEM;
 374                         }
 375 
 376                         if (oldirq) {
 377                                 free_irq(oldirq);
 378                         }
 379                         if (newirq) {
 380                                 /* Install new irq */
 381                                 sa.sa_handler = lp_interrupt;
 382                                 sa.sa_flags = SA_INTERRUPT;
 383                                 sa.sa_mask = 0;
 384                                 sa.sa_restorer = NULL;
 385                                 if ((retval = irqaction(newirq, &sa))) {
 386                                         if (oldirq) {
 387                                                 /* restore old irq */
 388                                                 irqaction(oldirq, &sa);
 389                                         } else {
 390                                                 /* We don't need the buffer */
 391                                                 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
 392                                                 lp->lp_buffer = NULL;
 393                                         }
 394                                         return retval;
 395                                 }
 396                         }
 397                         if (oldirq && !newirq) {
 398                                 /* We don't need the buffer */
 399                                 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
 400                                 lp->lp_buffer = NULL;
 401                         }
 402                         LP_IRQ(minor) = newirq;
 403                         lp_reset(minor);
 404                         break;
 405                 }
 406                 case LPGETIRQ:
 407                         retval = LP_IRQ(minor);
 408                         break;
 409                 default:
 410                         retval = -EINVAL;
 411         }
 412         return retval;
 413 }
 414 
 415 
 416 static struct file_operations lp_fops = {
 417         lp_lseek,
 418         NULL,           /* lp_read */
 419         lp_write,
 420         NULL,           /* lp_readdir */
 421         NULL,           /* lp_select */
 422         lp_ioctl,
 423         NULL,           /* lp_mmap */
 424         lp_open,
 425         lp_release
 426 };
 427 
 428 long lp_init(long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 429 {
 430         int offset = 0;
 431         unsigned int testvalue = 0;
 432         int count = 0;
 433 
 434         if (register_chrdev(6,"lp",&lp_fops)) {
 435                 printk("unable to get major 6 for line printer\n");
 436                 return kmem_start;
 437         }
 438         /* take on all known port values */
 439         for (offset = 0; offset < LP_NO; offset++) {
 440                 /* write to port & read back to check */
 441                 outb_p( LP_DUMMY, LP_B(offset));
 442                 for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
 443                         ;
 444                 testvalue = inb_p(LP_B(offset));
 445                 if (testvalue != 255) {
 446                         LP_F(offset) |= LP_EXIST;
 447                         lp_reset(offset);
 448                         printk("lp_init: lp%d exists (%d), ", offset, testvalue);
 449                         if (LP_IRQ(offset))
 450                                 printk("using IRQ%d\n", LP_IRQ(offset));
 451                         else
 452                                 printk("using polling driver\n");
 453                         count++;
 454                 }
 455         }
 456         if (count == 0)
 457                 printk("lp_init: no lp devices found\n");
 458         return kmem_start;
 459 }

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