root/drivers/char/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_probe
  13. lp_setup
  14. lp_init
  15. cleanup_module

   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  * Copyright (C) 1994 by Alan Cox (Modularised it)
   8  * LPCAREFUL, LPABORT, LPGETSTATUS added by Chris Metcalf, metcalf@lcs.mit.edu
   9  * Statistics and support for slow printers by Rob Janssen, rob@knoware.nl
  10  * "lp=" command line parameters added by Grant Guenther, grant@torque.net
  11  */
  12 
  13 #include <linux/module.h>
  14 
  15 #include <linux/errno.h>
  16 #include <linux/kernel.h>
  17 #include <linux/major.h>
  18 #include <linux/sched.h>
  19 #include <linux/lp.h>
  20 #include <linux/malloc.h>
  21 #include <linux/ioport.h>
  22 #include <linux/fcntl.h>
  23 #include <linux/delay.h>
  24 
  25 #include <asm/io.h>
  26 #include <asm/segment.h>
  27 #include <asm/system.h>
  28 
  29 /* the BIOS manuals say there can be up to 4 lpt devices
  30  * but I have not seen a board where the 4th address is listed
  31  * if you have different hardware change the table below
  32  * please let me know if you have different equipment
  33  * if you have more than 3 printers, remember to increase LP_NO
  34  */
  35 struct lp_struct lp_table[] = {
  36         { 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
  37         { 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
  38         { 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
  39 };
  40 #define LP_NO 3
  41 
  42 /* Test if printer is ready (and optionally has no error conditions) */
  43 #define LP_READY(minor, status) \
  44   ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : (status & LP_PBUSY))
  45 #define LP_CAREFUL_READY(minor, status) \
  46   ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : 1)
  47 #define _LP_CAREFUL_READY(status) \
  48    (status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
  49       (LP_PBUSY|LP_PSELECD|LP_PERRORP)
  50 
  51 /*
  52  * All my debugging code assumes that you debug with only one printer at
  53  * a time. RWWH
  54  * Debug info moved into stats area, so this is no longer true (Rob Janssen)
  55  */
  56 
  57 #undef LP_DEBUG
  58 
  59 static int lp_reset(int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61         outb_p(LP_PSELECP, LP_C(minor));
  62         udelay(LP_DELAY);
  63         outb_p(LP_PSELECP | LP_PINITP, LP_C(minor));
  64         return LP_S(minor);
  65 }
  66 
  67 static inline int lp_char_polled(char lpchar, int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69         int status, wait = 0;
  70         unsigned long count  = 0;
  71         struct lp_stats *stats;
  72 
  73         do {
  74                 status = LP_S(minor);
  75                 count ++;
  76                 if(need_resched)
  77                         schedule();
  78         } while(!LP_READY(minor,status) && count < LP_CHAR(minor));
  79 
  80         if (count == LP_CHAR(minor)) {
  81                 return 0;
  82                 /* we timed out, and the character was /not/ printed */
  83         }
  84         outb_p(lpchar, LP_B(minor));
  85         stats = &LP_STAT(minor);
  86         stats->chars++;
  87         /* must wait before taking strobe high, and after taking strobe
  88            low, according spec.  Some printers need it, others don't. */
  89         while(wait != LP_WAIT(minor)) wait++;
  90         /* control port takes strobe high */
  91         outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
  92         while(wait) wait--;
  93         /* take strobe low */
  94         outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
  95         /* update waittime statistics */
  96         if (count > stats->maxwait) {
  97 #ifdef LP_DEBUG
  98             printk(KERN_DEBUG "lp%d success after %d counts.\n",minor,count);
  99 #endif
 100             stats->maxwait = count;
 101         }
 102         count *= 256;
 103         wait = (count > stats->meanwait)? count - stats->meanwait :
 104                                           stats->meanwait - count;
 105         stats->meanwait = (255*stats->meanwait + count + 128) / 256;
 106         stats->mdev = ((127 * stats->mdev) + wait + 64) / 128;
 107 
 108         return 1;
 109 }
 110 
 111 static inline int lp_char_interrupt(char lpchar, int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113         int wait;
 114         unsigned long count = 0;
 115         unsigned char status;
 116         struct lp_stats *stats;
 117 
 118         do {
 119             if ((status = LP_S(minor)) & LP_PBUSY) {
 120                 if (!LP_CAREFUL_READY(minor, status))
 121                         return 0;
 122                 outb_p(lpchar, LP_B(minor));
 123                 stats = &LP_STAT(minor);
 124                 stats->chars++;
 125                 /* must wait before taking strobe high, and after taking strobe
 126                    low, according spec.  Some printers need it, others don't. */
 127                 wait = 0;
 128                 while(wait != LP_WAIT(minor)) wait++;
 129                 /* control port takes strobe high */
 130                 outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
 131                 while(wait) wait--;
 132                 /* take strobe low */
 133                 outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
 134                 /* update waittime statistics */
 135                 if (count) {
 136                     if (count > stats->maxwait)
 137                         stats->maxwait = count;
 138                     count *= 256;
 139                     wait = (count > stats->meanwait)? count - stats->meanwait :
 140                                                       stats->meanwait - count;
 141                     stats->meanwait = (255*stats->meanwait + count + 128) / 256;
 142                     stats->mdev = ((127 * stats->mdev) + wait + 64) / 128;
 143                 }
 144                 return 1;
 145             }
 146         } while (count++ < LP_CHAR(minor));
 147 
 148         return 0;
 149 }
 150 
 151 static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153         struct lp_struct *lp = &lp_table[0];
 154 
 155         while (irq != lp->irq) {
 156                 if (++lp >= &lp_table[LP_NO])
 157                         return;
 158         }
 159 
 160         wake_up(&lp->lp_wait_q);
 161 }
 162 
 163 static inline int lp_write_interrupt(unsigned int minor, const char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 {
 165         unsigned long copy_size;
 166         unsigned long total_bytes_written = 0;
 167         unsigned long bytes_written;
 168         struct lp_struct *lp = &lp_table[minor];
 169         unsigned char status;
 170 
 171         do {
 172                 bytes_written = 0;
 173                 copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
 174                 memcpy_fromfs(lp->lp_buffer, buf, copy_size);
 175 
 176                 while (copy_size) {
 177                         if (lp_char_interrupt(lp->lp_buffer[bytes_written], minor)) {
 178                                 --copy_size;
 179                                 ++bytes_written;
 180                                 lp_table[minor].runchars++;
 181                         } else {
 182                                 int rc = total_bytes_written + bytes_written;
 183                                 if (lp_table[minor].runchars > LP_STAT(minor).maxrun)
 184                                          LP_STAT(minor).maxrun = lp_table[minor].runchars;
 185                                 status = LP_S(minor);
 186                                 if ((status & LP_POUTPA)) {
 187                                         printk(KERN_INFO "lp%d out of paper\n", minor);
 188                                         if (LP_F(minor) & LP_ABORT)
 189                                                 return rc?rc:-ENOSPC;
 190                                 } else if (!(status & LP_PSELECD)) {
 191                                         printk(KERN_INFO "lp%d off-line\n", minor);
 192                                         if (LP_F(minor) & LP_ABORT)
 193                                                 return rc?rc:-EIO;
 194                                 } else if (!(status & LP_PERRORP)) {
 195                                         printk(KERN_ERR "lp%d printer error\n", minor);
 196                                         if (LP_F(minor) & LP_ABORT)
 197                                                 return rc?rc:-EIO;
 198                                 }
 199                                 LP_STAT(minor).sleeps++;
 200                                 cli();
 201                                 outb_p((LP_PSELECP|LP_PINITP|LP_PINTEN), (LP_C(minor)));
 202                                 status = LP_S(minor);
 203                                 if ((!(status & LP_PACK) || (status & LP_PBUSY))
 204                                   && LP_CAREFUL_READY(minor, status)) {
 205                                         outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
 206                                         sti();
 207                                         continue;
 208                                 }
 209                                 lp_table[minor].runchars=0;
 210                                 current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
 211                                 interruptible_sleep_on(&lp->lp_wait_q);
 212                                 outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
 213                                 sti();
 214                                 if (current->signal & ~current->blocked) {
 215                                         if (total_bytes_written + bytes_written)
 216                                                 return total_bytes_written + bytes_written;
 217                                         else
 218                                                 return -EINTR;
 219                                 }
 220                         }
 221                 }
 222 
 223                 total_bytes_written += bytes_written;
 224                 buf += bytes_written;
 225                 count -= bytes_written;
 226 
 227         } while (count > 0);
 228 
 229         return total_bytes_written;
 230 }
 231 
 232 static inline int lp_write_polled(unsigned int minor, const char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         int  retval,status;
 235         char c;
 236         const char *temp;
 237 
 238         temp = buf;
 239         while (count > 0) {
 240                 c = get_user(temp);
 241                 retval = lp_char_polled(c, minor);
 242                 /* only update counting vars if character was printed */
 243                 if (retval) {
 244                         count--; temp++;
 245                         lp_table[minor].runchars++;
 246                 } else { /* if printer timed out */
 247                         if (lp_table[minor].runchars > LP_STAT(minor).maxrun)
 248                                  LP_STAT(minor).maxrun = lp_table[minor].runchars;
 249                         status = LP_S(minor);
 250 
 251                         if (status & LP_POUTPA) {
 252                                 printk(KERN_INFO "lp%d out of paper\n", minor);
 253                                 if(LP_F(minor) & LP_ABORT)
 254                                         return temp-buf?temp-buf:-ENOSPC;
 255                                 current->state = TASK_INTERRUPTIBLE;
 256                                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
 257                                 schedule();
 258                         } else
 259                         if (!(status & LP_PSELECD)) {
 260                                 printk(KERN_INFO "lp%d off-line\n", minor);
 261                                 if(LP_F(minor) & LP_ABORT)
 262                                         return temp-buf?temp-buf:-EIO;
 263                                 current->state = TASK_INTERRUPTIBLE;
 264                                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
 265                                 schedule();
 266                         } else
 267                         /* not offline or out of paper. on fire? */
 268                         if (!(status & LP_PERRORP)) {
 269                                 printk(KERN_ERR "lp%d reported invalid error status (on fire, eh?)\n", minor);
 270                                 if(LP_F(minor) & LP_ABORT)
 271                                         return temp-buf?temp-buf:-EIO;
 272                                 current->state = TASK_INTERRUPTIBLE;
 273                                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
 274                                 schedule();
 275                         }
 276 
 277                         /* check for signals before going to sleep */
 278                         if (current->signal & ~current->blocked) {
 279                                 if (temp != buf)
 280                                         return temp-buf;
 281                                 else
 282                                         return -EINTR;
 283                         }
 284                         LP_STAT(minor).sleeps++;
 285 #ifdef LP_DEBUG
 286                         printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n",
 287                                 minor,lp_table[minor].runchars, LP_TIME(minor));
 288 #endif
 289                         lp_table[minor].runchars=0;
 290                         current->state = TASK_INTERRUPTIBLE;
 291                         current->timeout = jiffies + LP_TIME(minor);
 292                         schedule();
 293                 }
 294         }
 295         return temp-buf;
 296 }
 297 
 298 static int lp_write(struct inode * inode, struct file * file, const char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300         unsigned int minor = MINOR(inode->i_rdev);
 301 
 302         if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
 303                 lp_table[minor].runchars = 0;
 304         lp_table[minor].lastcall = jiffies;
 305 
 306         if (LP_IRQ(minor))
 307                 return lp_write_interrupt(minor, buf, count);
 308         else
 309                 return lp_write_polled(minor, buf, count);
 310 }
 311 
 312 static int lp_lseek(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 313                     off_t offset, int origin)
 314 {
 315         return -ESPIPE;
 316 }
 317 
 318 static int lp_open(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 319 {
 320         unsigned int minor = MINOR(inode->i_rdev);
 321         int ret;
 322         unsigned int irq;
 323 
 324         if (minor >= LP_NO)
 325                 return -ENODEV;
 326         if ((LP_F(minor) & LP_EXIST) == 0)
 327                 return -ENODEV;
 328         if (LP_F(minor) & LP_BUSY)
 329                 return -EBUSY;
 330 
 331         MOD_INC_USE_COUNT;
 332 
 333         /* If ABORTOPEN is set and the printer is offline or out of paper,
 334            we may still want to open it to perform ioctl()s.  Therefore we
 335            have commandeered O_NONBLOCK, even though it is being used in
 336            a non-standard manner.  This is strictly a Linux hack, and
 337            should most likely only ever be used by the tunelp application. */
 338         if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) {
 339                 int status = LP_S(minor);
 340                 if (status & LP_POUTPA) {
 341                         printk(KERN_INFO "lp%d out of paper\n", minor);
 342                         MOD_DEC_USE_COUNT;
 343                         return -ENOSPC;
 344                 } else if (!(status & LP_PSELECD)) {
 345                         printk(KERN_INFO "lp%d off-line\n", minor);
 346                         MOD_DEC_USE_COUNT;
 347                         return -EIO;
 348                 } else if (!(status & LP_PERRORP)) {
 349                         printk(KERN_ERR "lp%d printer error\n", minor);
 350                         MOD_DEC_USE_COUNT;
 351                         return -EIO;
 352                 }
 353         }
 354 
 355         if ((irq = LP_IRQ(minor))) {
 356                 lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
 357                 if (!lp_table[minor].lp_buffer) {
 358                         MOD_DEC_USE_COUNT;
 359                         return -ENOMEM;
 360                 }
 361 
 362                 ret = request_irq(irq, lp_interrupt, SA_INTERRUPT, "printer", NULL);
 363                 if (ret) {
 364                         kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
 365                         lp_table[minor].lp_buffer = NULL;
 366                         printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret);
 367                         MOD_DEC_USE_COUNT;
 368                         return ret;
 369                 }
 370         }
 371 
 372         LP_F(minor) |= LP_BUSY;
 373         return 0;
 374 }
 375 
 376 static void lp_release(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 377 {
 378         unsigned int minor = MINOR(inode->i_rdev);
 379         unsigned int irq;
 380 
 381         if ((irq = LP_IRQ(minor))) {
 382                 free_irq(irq, NULL);
 383                 kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
 384                 lp_table[minor].lp_buffer = NULL;
 385         }
 386 
 387         LP_F(minor) &= ~LP_BUSY;
 388         MOD_DEC_USE_COUNT;
 389 }
 390 
 391 
 392 static int lp_ioctl(struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 393                     unsigned int cmd, unsigned long arg)
 394 {
 395         unsigned int minor = MINOR(inode->i_rdev);
 396         int retval = 0;
 397 
 398 #ifdef LP_DEBUG
 399         printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
 400 #endif
 401         if (minor >= LP_NO)
 402                 return -ENODEV;
 403         if ((LP_F(minor) & LP_EXIST) == 0)
 404                 return -ENODEV;
 405         switch ( cmd ) {
 406                 case LPTIME:
 407                         LP_TIME(minor) = arg * HZ/100;
 408                         break;
 409                 case LPCHAR:
 410                         LP_CHAR(minor) = arg;
 411                         break;
 412                 case LPABORT:
 413                         if (arg)
 414                                 LP_F(minor) |= LP_ABORT;
 415                         else
 416                                 LP_F(minor) &= ~LP_ABORT;
 417                         break;
 418                 case LPABORTOPEN:
 419                         if (arg)
 420                                 LP_F(minor) |= LP_ABORTOPEN;
 421                         else
 422                                 LP_F(minor) &= ~LP_ABORTOPEN;
 423                         break;
 424                 case LPCAREFUL:
 425                         if (arg)
 426                                 LP_F(minor) |= LP_CAREFUL;
 427                         else
 428                                 LP_F(minor) &= ~LP_CAREFUL;
 429                         break;
 430                 case LPWAIT:
 431                         LP_WAIT(minor) = arg;
 432                         break;
 433                 case LPSETIRQ: {
 434                         int oldirq;
 435                         int newirq = arg;
 436                         struct lp_struct *lp = &lp_table[minor];
 437 
 438                         if (!suser())
 439                                 return -EPERM;
 440 
 441                         oldirq = LP_IRQ(minor);
 442 
 443                         /* Allocate buffer now if we are going to need it */
 444                         if (!oldirq && newirq) {
 445                                 lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
 446                                 if (!lp->lp_buffer)
 447                                         return -ENOMEM;
 448                         }
 449 
 450                         if (oldirq) {
 451                                 free_irq(oldirq, NULL);
 452                         }
 453                         if (newirq) {
 454                                 /* Install new irq */
 455                                 if ((retval = request_irq(newirq, lp_interrupt, SA_INTERRUPT, "printer", NULL))) {
 456                                         if (oldirq) {
 457                                                 /* restore old irq */
 458                                                 request_irq(oldirq, lp_interrupt, SA_INTERRUPT, "printer", NULL);
 459                                         } else {
 460                                                 /* We don't need the buffer */
 461                                                 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
 462                                                 lp->lp_buffer = NULL;
 463                                         }
 464                                         return retval;
 465                                 }
 466                         }
 467                         if (oldirq && !newirq) {
 468                                 /* We don't need the buffer */
 469                                 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
 470                                 lp->lp_buffer = NULL;
 471                         }
 472                         LP_IRQ(minor) = newirq;
 473                         lp_reset(minor);
 474                         break;
 475                 }
 476                 case LPGETIRQ:
 477                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 478                             sizeof(int));
 479                         if (retval)
 480                                 return retval;
 481                         memcpy_tofs((int *) arg, &LP_IRQ(minor), sizeof(int));
 482                         break;
 483                 case LPGETSTATUS:
 484                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 485                             sizeof(int));
 486                         if (retval)
 487                                 return retval;
 488                         else {
 489                                 int status = LP_S(minor);
 490                                 memcpy_tofs((int *) arg, &status, sizeof(int));
 491                         }
 492                         break;
 493                 case LPRESET:
 494                         lp_reset(minor);
 495                         break;
 496                 case LPGETSTATS:
 497                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 498                             sizeof(struct lp_stats));
 499                         if (retval)
 500                                 return retval;
 501                         else {
 502                                 memcpy_tofs((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats));
 503                                 if (suser())
 504                                         memset(&LP_STAT(minor), 0, sizeof(struct lp_stats));
 505                         }
 506                         break;
 507                 case LPGETFLAGS:
 508                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 509                             sizeof(int));
 510                         if (retval)
 511                                 return retval;
 512                         else {
 513                                 int status = LP_F(minor);
 514                                 memcpy_tofs((int *) arg, &status, sizeof(int));
 515                         }
 516                         break;
 517                 default:
 518                         retval = -EINVAL;
 519         }
 520         return retval;
 521 }
 522 
 523 
 524 static struct file_operations lp_fops = {
 525         lp_lseek,
 526         NULL,           /* lp_read */
 527         lp_write,
 528         NULL,           /* lp_readdir */
 529         NULL,           /* lp_select */
 530         lp_ioctl,
 531         NULL,           /* lp_mmap */
 532         lp_open,
 533         lp_release
 534 };
 535 
 536 static int lp_probe(int offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 537 {
 538         int base, size;
 539         unsigned int testvalue;
 540 
 541         base = LP_B(offset);
 542         if (base == 0) 
 543                 return -1;              /* de-configured by command line */
 544         if (LP_IRQ(offset) > 15) 
 545                 return -1;              /* bogus interrupt value */
 546         size = (base == 0x3bc)? 3 : 8;
 547         if (check_region(base, size) < 0)
 548                 return -1;
 549         /* write to port & read back to check */
 550         outb_p(LP_DUMMY, base);
 551         udelay(LP_DELAY);
 552         testvalue = inb_p(base);
 553         if (testvalue == LP_DUMMY) {
 554                 LP_F(offset) |= LP_EXIST;
 555                 lp_reset(offset);
 556                 printk(KERN_INFO "lp%d at 0x%04x, ", offset, base);
 557                 request_region(base, size, "lp");
 558                 if (LP_IRQ(offset))
 559                         printk("(irq = %d)\n", LP_IRQ(offset));
 560                 else
 561                         printk("(polling)\n");
 562                 return 1;
 563         } else
 564                 return 0;
 565 }
 566 
 567 /* Command line parameters:
 568 
 569    When the lp driver is built in to the kernel, you may use the
 570    LILO/LOADLIN command line to set the port addresses and interrupts
 571    that the driver will use.
 572 
 573    Syntax:      lp=port0[,irq0[,port1[,irq1[,port2[,irq2]]]]]
 574 
 575    For example:   lp=0x378,0   or   lp=0x278,5,0x378,7
 576 
 577    Note that if this feature is used, you must specify *all* the ports
 578    you want considered, there are no defaults.  You can disable a
 579    built-in driver with lp=0 .
 580 
 581 */
 582 
 583 void    lp_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
 584 
 585 {       
 586         LP_B(0)   = ((ints[0] > 0) ? ints[1] : 0 );
 587         LP_IRQ(0) = ((ints[0] > 1) ? ints[2] : 0 );
 588         LP_B(1)   = ((ints[0] > 2) ? ints[3] : 0 );
 589         LP_IRQ(1) = ((ints[0] > 3) ? ints[4] : 0 );
 590         LP_B(2)   = ((ints[0] > 4) ? ints[5] : 0 );
 591         LP_IRQ(2) = ((ints[0] > 5) ? ints[6] : 0 );
 592 }
 593 
 594 #ifdef MODULE
 595 static int io[] = {0, 0, 0};
 596 static int irq[] = {0, 0, 0};
 597 
 598 #define lp_init init_module
 599 #endif
 600 
 601 int lp_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 602 {
 603         int offset = 0;
 604         int count = 0;
 605 #ifdef MODULE
 606         int failed = 0;
 607 #endif
 608 
 609         if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
 610                 printk("lp: unable to get major %d\n", LP_MAJOR);
 611                 return -EIO;
 612         }
 613 #ifdef MODULE
 614         /* When user feeds parameters, use them */
 615         for (offset=0; offset < LP_NO; offset++) {
 616                 int specified=0;
 617 
 618                 if (io[offset] != 0) {
 619                         LP_B(offset) = io[offset];
 620                         specified++;
 621                 }
 622                 if (irq[offset] != 0) {
 623                         LP_IRQ(offset) = irq[offset];
 624                         specified++;
 625                 }
 626                 if (specified) {
 627                         if (lp_probe(offset) <= 0) {
 628                                 printk(KERN_INFO "lp%d: Not found\n", offset);
 629                                 failed++;
 630                         } else
 631                                 count++;
 632                 }
 633         }
 634         /* Successful specified devices increase count
 635          * Unsuccessful specified devices increase failed
 636          */
 637         if (count)
 638                 return 0;
 639         if (failed) {
 640                 printk(KERN_INFO "lp: No override devices found.\n");
 641                 unregister_chrdev(LP_MAJOR,"lp");
 642                 return -EIO;
 643         }
 644         /* Only get here if there were no specified devices. To continue 
 645          * would be silly since the above code has scribbled all over the
 646          * probe list.
 647          */
 648 #endif
 649         /* take on all known port values */
 650         for (offset = 0; offset < LP_NO; offset++) {
 651                 int ret = lp_probe(offset);
 652                 if (ret < 0)
 653                         continue;
 654                 count += ret;
 655         }
 656         if (count == 0)
 657                 printk("lp: Driver configured but no interfaces found.\n");
 658 
 659         return 0;
 660 }
 661 
 662 #ifdef MODULE
 663 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 664 {
 665         int offset;
 666 
 667         unregister_chrdev(LP_MAJOR,"lp");
 668         for (offset = 0; offset < LP_NO; offset++) {
 669                 int base, size;
 670                 base = LP_B(offset);
 671                 size = (base == 0x3bc)? 3 : 8;
 672                 if (LP_F(offset) & LP_EXIST)
 673                         release_region(LP_B(offset),size);
 674         }
 675 }
 676 #endif

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