home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / drivers / char / lp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-01  |  10.6 KB  |  462 lines

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