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

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