shortprint.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:15k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * A version of the "short" driver which drives a parallel printer directly,
  3.  * with a lot of simplifying assumptions.
  4.  *
  5.  * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
  6.  * Copyright (C) 2001 O'Reilly & Associates
  7.  *
  8.  * The source code in this file can be freely used, adapted,
  9.  * and redistributed in source or binary form, so long as an
  10.  * acknowledgment appears in derived source files.  The citation
  11.  * should list that the code comes from the book "Linux Device
  12.  * Drivers" by Alessandro Rubini and Jonathan Corbet, published
  13.  * by O'Reilly & Associates.   No warranty is attached;
  14.  * we cannot take responsibility for errors or fitness for use.
  15.  *
  16.  * $Id: shortprint.c,v 1.4 2001/07/18 22:28:18 rubini Exp $
  17.  */
  18. #ifndef __KERNEL__
  19. #  define __KERNEL__
  20. #endif
  21. #ifndef MODULE
  22. #  define MODULE
  23. #endif
  24. #include <linux/config.h>
  25. #include <linux/module.h>
  26. #include <linux/sched.h>
  27. #include <linux/kernel.h> /* printk() */
  28. #include <linux/fs.h>     /* everything... */
  29. #include <linux/errno.h>  /* error codes */
  30. #include <linux/delay.h>  /* udelay */
  31. #include <linux/malloc.h>
  32. #include <linux/ioport.h>
  33. #include <linux/interrupt.h>
  34. #include <linux/tqueue.h>
  35. #include <linux/timer.h>
  36. #include <asm/io.h>
  37. #include <asm/semaphore.h>
  38. #include <asm/atomic.h>
  39. #include "sysdep.h"
  40. #include "shortprint.h"
  41. #define SHORTP_NR_PORTS 3
  42. /*
  43.  * all of the parameters have no "shortp_" prefix, to save typing when
  44.  * specifying them at load time
  45.  */
  46. static int major = 0; /* dynamic by default */
  47. MODULE_PARM(major, "i");
  48. /* default is the first printer port on PC's. "shortp_base" is there too
  49.    because it's what we want to use in the code */
  50. static unsigned long base = 0x378;
  51. unsigned long shortp_base = 0;
  52. MODULE_PARM(base, "l");
  53. /* The interrupt line is undefined by default. "shortp_irq" is as above */
  54. static int irq = -1;
  55. static int shortp_irq = -1;
  56. MODULE_PARM(irq, "i");
  57. /* Microsecond delay around strobe. */
  58. static int delay = 0;
  59. static int shortp_delay;
  60. MODULE_PARM(delay, "i");
  61. MODULE_AUTHOR ("Jonathan Corbet");
  62. /*
  63.  * Forwards.
  64.  */
  65. void shortp_cleanup ();
  66. static void shortp_timeout (unsigned long unused);
  67. /*
  68.  * Input is managed through a simple circular buffer which, among other things,
  69.  * is allowed to overrun if the reader isn't fast enough.  That makes life simple
  70.  * on the "read" interrupt side, where we don't want to block.
  71.  */
  72. static unsigned long shortp_in_buffer = 0;
  73. static unsigned long volatile shortp_in_head;
  74. static volatile unsigned long shortp_in_tail;
  75. DECLARE_WAIT_QUEUE_HEAD(shortp_in_queue);
  76. static struct timeval shortp_tv;  /* When the interrupt happened. */
  77. /*
  78.  * Atomicly increment an index into shortp_in_buffer
  79.  */
  80. static inline void shortp_incr_bp(volatile unsigned long *index, int delta)
  81. {
  82.     unsigned long new = *index + delta;
  83.     barrier ();  /* Don't optimize these two together */
  84.     *index = (new >= (shortp_in_buffer + PAGE_SIZE)) ? shortp_in_buffer : new;
  85. }
  86. /*
  87.  * On the write side we have to be more careful, since we don't want to drop
  88.  * data.  The semaphore is used to serialize write-side access to the buffer;
  89.  * there is only one consumer, so read-side access is unregulated.  The
  90.  * wait queue will be awakened when space becomes available in the buffer.
  91.  */
  92. unsigned char *shortp_out_buffer = NULL;
  93. volatile unsigned char *shortp_out_head, *shortp_out_tail;
  94. struct semaphore shortp_out_sem;
  95. DECLARE_WAIT_QUEUE_HEAD (shortp_out_queue);
  96. /*
  97.  * Available space in the output buffer; should be called with the semaphore
  98.  * held.  Returns contiguous space, so caller need not worry about wraps.
  99.  */
  100. static inline int shortp_out_space()
  101. {
  102.     if (shortp_out_head >= shortp_out_tail) {
  103. int space = PAGE_SIZE - (shortp_out_head - shortp_out_buffer);
  104. return (shortp_out_tail == shortp_out_buffer) ? space - 1 : space;
  105.     }
  106.     else
  107. return (shortp_out_tail - shortp_out_head) - 1;
  108. }
  109. static inline void shortp_incr_out_bp(volatile unsigned char **bp, int incr)
  110. {
  111. unsigned char *new = (unsigned char *) *bp + incr;
  112. if (new >= (shortp_out_buffer + PAGE_SIZE))
  113.     new -= PAGE_SIZE;
  114. *bp = new;
  115. }
  116. /*
  117.  * The output "process" is controlled by a spin lock; decisions on
  118.  * shortp_output_active or manipulation of shortp_out_tail require
  119.  * that this lock be held.
  120.  */
  121. static spinlock_t shortp_out_lock;
  122. volatile static int shortp_output_active;
  123. DECLARE_WAIT_QUEUE_HEAD (shortp_empty_queue); /* waked when queue empties */
  124. static int nwrote = 0;
  125. /*
  126.  * When output is active, the timer is too, in case we miss interrupts.  Hold
  127.  * shortp_out_lock if you mess with the timer.
  128.  */
  129. static struct timer_list shortp_timer;
  130. #define TIMEOUT 5*HZ  /* Wait a long time */
  131. /*
  132.  * Open the device.
  133.  */
  134. int shortp_open (struct inode *inode, struct file *filp)
  135. {
  136.     MOD_INC_USE_COUNT;
  137.     return 0;
  138. }
  139. int shortp_release (struct inode *inode, struct file *filp)
  140. {
  141.     /* Wait for any pending output to complete */
  142.     wait_event_interruptible(shortp_empty_queue, shortp_output_active==0);
  143.     MOD_DEC_USE_COUNT;
  144.     return 0;
  145. }
  146. #ifdef __USE_OLD_SELECT__
  147. int shortp_poll (struct inode *inode, struct file *filp,
  148.                   int mode, select_table *table)
  149. {
  150.     return mode==SEL_EX ? 0 : 1; /* readable, writable, not-exceptionable */
  151. }
  152. #define poll select
  153. #else /* Use poll */
  154. unsigned int shortp_poll(struct file *filp, poll_table *wait)
  155. {
  156.     return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
  157. }
  158. #endif /* __USE_OLD_SELECT__ */
  159. /*
  160.  * The read routine, which doesn't return data from the device; instead, it
  161.  * returns timing information just like the "short" device.
  162.  */
  163. ssize_t shortp_read (struct file *filp, char *buf, size_t count, loff_t *f_pos)
  164. {
  165.     int count0;
  166.     while (shortp_in_head == shortp_in_tail) {
  167.         interruptible_sleep_on(&shortp_in_queue);
  168.         if (signal_pending (current))  /* a signal arrived */
  169.           return -ERESTARTSYS; /* tell the fs layer to handle it */
  170.         /* else, loop */
  171.     }
  172.     /* count0 is the number of readable data bytes */
  173.     count0 = shortp_in_head - shortp_in_tail;
  174.     if (count0 < 0) /* wrapped */
  175.         count0 = shortp_in_buffer + PAGE_SIZE - shortp_in_tail;
  176.     if (count0 < count) count = count0;
  177.     if (copy_to_user(buf, (char *)shortp_in_tail, count))
  178. return -EFAULT;
  179.     shortp_incr_bp (&shortp_in_tail, count);
  180.     return count;
  181. }
  182. /*
  183.  * Write the next character from the buffer.  There should *be* a next
  184.  * character...  The spinlock should be held when this routine is called.
  185.  */
  186. static void shortp_do_write()
  187. {
  188.     unsigned char cr = inb(shortp_base + SP_CONTROL);
  189.     /* Make sure the device is ready for us */
  190.     if ((inb(shortp_base + SP_STATUS) & SP_SR_BUSY) == 0) {
  191. //      printk (KERN_INFO "shortprint: waiting for printer busyn");
  192. // printk (KERN_INFO "Status is 0x%xn", inb(shortp_base + SP_STATUS));
  193. while ((inb(shortp_base + SP_STATUS) & SP_SR_BUSY) == 0) {
  194. set_current_state(TASK_INTERRUPTIBLE);
  195. schedule_timeout(10*HZ);
  196. }
  197.     }
  198.     /* Mark output active and start up our timer if need be */
  199.     if (! shortp_output_active) {
  200. shortp_output_active = 1;
  201. shortp_timer.expires = jiffies + TIMEOUT;
  202. add_timer (&shortp_timer);
  203.     }
  204.     else
  205.         mod_timer(&shortp_timer, jiffies + TIMEOUT);
  206.     /* Strobe a byte out to the device */
  207.     outb_p(*shortp_out_tail, shortp_base+SP_DATA);
  208.     shortp_incr_out_bp(&shortp_out_tail, 1);
  209.     if (shortp_delay) udelay(shortp_delay);
  210.     outb_p(cr | SP_CR_STROBE, shortp_base+SP_CONTROL);
  211.     if (shortp_delay) udelay(shortp_delay);
  212.     outb_p(cr & ~SP_CR_STROBE, shortp_base+SP_CONTROL);
  213.     nwrote++;
  214. }
  215. /*
  216.  * Write to the device.
  217.  */
  218. ssize_t shortp_write (struct file *filp, const char *buf, size_t count,
  219.                 loff_t *f_pos)
  220. {
  221.     int space, written = 0;
  222.     unsigned long flags;
  223. /*
  224.  * Take and hold the semaphore for the entire duration of the operation.  The
  225.  * consumer side ignores it, and it will keep other data from interleaving
  226.  * with ours.
  227.  */
  228.     if (down_interruptible (&shortp_out_sem))
  229. return -ERESTARTSYS;
  230. /*
  231.  * Out with the data.
  232.  */
  233.     while (written < count) {
  234.         /* Hang out until some buffer space is available. */
  235. space = shortp_out_space();
  236. if (space <= 0) {
  237. if (wait_event_interruptible(shortp_out_queue,
  238. (space = shortp_out_space()) > 0)) {
  239.     *f_pos += written;
  240.     up(&shortp_out_sem);
  241.     return -ERESTARTSYS;
  242. }
  243. }
  244.         /* Move data into the buffer. */
  245. if ((space + written) > count)
  246.     space = count - written;
  247. if (copy_from_user((char *) shortp_out_head, buf, space)) {
  248.     up(&shortp_out_sem);
  249.     return -EFAULT;
  250. }
  251. shortp_incr_out_bp(&shortp_out_head, space);
  252. buf += space;
  253. written += space;
  254.         /* If no output is active, make it active. */
  255. spin_lock_irqsave(&shortp_out_lock, flags);
  256. if (! shortp_output_active)
  257.       shortp_do_write ();
  258. spin_unlock_irqrestore(&shortp_out_lock, flags);
  259.     }
  260.     *f_pos += written;
  261.     up(&shortp_out_sem);
  262.     return written;
  263. }
  264. /*
  265.  * The bottom-half handler.
  266.  */
  267. static struct tq_struct shortp_task;
  268. void shortp_do_task (void *unused)
  269. {
  270.     int written;
  271.     unsigned long flags;
  272.     /* Keep the output going */
  273.     spin_lock_irqsave(&shortp_out_lock, flags);
  274.     if (shortp_out_head == shortp_out_tail) { /* empty */
  275.         shortp_output_active = 0;
  276. wake_up_interruptible(&shortp_empty_queue);
  277. del_timer_sync(&shortp_timer);
  278.     }
  279.     else
  280. shortp_do_write();
  281.     /* If somebody's waiting, wake them up. */
  282.     if (((PAGE_SIZE + shortp_out_tail - shortp_out_head) % PAGE_SIZE) > SP_MIN_SPACE) {
  283.         wake_up_interruptible(&shortp_out_queue);
  284.     }
  285.     spin_unlock_irqrestore(&shortp_out_lock, flags);
  286.     /* Handle the "read" side operation */
  287.     written = sprintf((char *)shortp_in_head, "%08u.%06un",
  288. (int)(shortp_tv.tv_sec % 100000000),
  289. (int)(shortp_tv.tv_usec));
  290.     shortp_incr_bp(&shortp_in_head, written);
  291.     wake_up_interruptible(&shortp_in_queue); /* awake any reading process */
  292. }
  293. /*
  294.  * The top-half interrupt handler.
  295.  */
  296. void shortp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  297. {
  298.     if (! shortp_output_active)
  299. printk(KERN_INFO "shortprint: spurious interruptn");
  300.     /* Remember the time, and farm off the rest to the task queue function */ 
  301.     do_gettimeofday(&shortp_tv);
  302. //    schedule_task(&shortp_task);
  303.     queue_task(&shortp_task, &tq_immediate);
  304.     mark_bh(IMMEDIATE_BH);
  305. }
  306. /*
  307.  * Interrupt timeouts.  Just because we got a timeout doesn't mean that
  308.  * things have gone wrong, however; printers can spend an awful long time
  309.  * just thinking about things.
  310.  */
  311. static void shortp_timeout(unsigned long unused)
  312. {
  313.     unsigned long flags;
  314.     unsigned char status;
  315.    
  316.     spin_lock_irqsave(&shortp_out_lock, flags);
  317.     status = inb(shortp_base + SP_STATUS);
  318.     /* If the printer is still busy we just reset the timer */
  319.     if ((status & SP_SR_BUSY) == 0 || (status & SP_SR_ACK)) {
  320.         shortp_timer.expires = jiffies + TIMEOUT;
  321. add_timer(&shortp_timer);
  322. spin_unlock_irqrestore(&shortp_out_lock, flags);
  323. return;
  324.     }
  325.     /* Otherwise we must have dropped an interrupt. */
  326.     spin_unlock_irqrestore(&shortp_out_lock, flags);
  327.     shortp_interrupt (shortp_irq, NULL, NULL);
  328. }
  329.     
  330. /*
  331.  * 2.0 wrappers.
  332.  */
  333. #ifdef LINUX_20
  334. int shortp_read_20 (struct inode *inode, struct file *filp, char *buf,
  335.                 int count)
  336. {
  337.     return shortp_read (filp, buf, count, &filp->f_pos);
  338. }
  339. int shortp_write_20 (struct inode *inode, struct file *filp, const char *buf,
  340.                 int count)
  341. {
  342.     return shortp_write (filp, buf, count, &filp->f_pos);
  343. }
  344. void shortp_release_20 (struct inode *inode, struct file *filp)
  345. {
  346.     (void) shortp_release(inode, filp);
  347. }
  348. #define shortp_read  shortp_read_20
  349. #define shortp_write shortp_write_20
  350. #define shortp_release shortp_release_20
  351. #endif /* LINUX_20 */
  352. struct file_operations shortp_fops = {
  353.     read: shortp_read,
  354.     write: shortp_write,
  355.     open: shortp_open,
  356.     release: shortp_release,
  357.     /* should really implement poll too */
  358. };
  359. /*
  360.  * Module initialization
  361.  */
  362. int shortp_init(void)
  363. {
  364.     int result;
  365.     /*
  366.      * first, sort out the base/shortp_base ambiguity: we'd better
  367.      * use shortp_base in the code, for clarity, but allow setting
  368.      * just "base" at load time. Same for "irq".
  369.      */
  370.     shortp_base = base;
  371.     shortp_irq = irq;
  372.     shortp_delay = delay;
  373.     /* Set up owner pointers.*/
  374.     SET_MODULE_OWNER(&shortp_fops);
  375.     /* Get our needed resources. */
  376.     result = check_region(shortp_base, SP_NPORTS);
  377.     if (result) {
  378. printk(KERN_INFO "shortprint: can't get I/O port address 0x%lxn",
  379. shortp_base);
  380. return result;
  381.     }
  382.     request_region(shortp_base, SHORTP_NR_PORTS, "shortprint");
  383.     /* Register the device */
  384.     result = register_chrdev(major, "shortprint", &shortp_fops);
  385.     if (result < 0) {
  386.         printk(KERN_INFO "shortp: can't get major numbern");
  387.         release_region(shortp_base,SHORTP_NR_PORTS);
  388.         return result;
  389.     }
  390.     if (major == 0) major = result; /* dynamic */
  391.     /* Initialize the input buffer. */
  392.     shortp_in_buffer = __get_free_pages(GFP_KERNEL,0); /* never fails */
  393.     shortp_in_head = shortp_in_tail = shortp_in_buffer;
  394.     /* And the output buffer. */
  395.     shortp_out_buffer = (unsigned char *) __get_free_pages(GFP_KERNEL, 0);
  396.     shortp_out_head = shortp_out_tail = shortp_out_buffer;
  397.     sema_init (&shortp_out_sem, 1);
  398.     
  399.     /* And the output info */
  400.     shortp_output_active = 0;
  401.     spin_lock_init (&shortp_out_lock);
  402.     init_timer(&shortp_timer);
  403.     shortp_timer.function = shortp_timeout;
  404.     shortp_timer.data = 0;
  405.     
  406.     /* Fill the shortp_task structure, used for the bottom half handler. */
  407.     shortp_task.routine = shortp_do_task;
  408.     shortp_task.data = NULL; /* unused */
  409.     /* If no IRQ was explicitly requested, pick a default */
  410.     if (shortp_irq < 0)
  411.         switch(shortp_base) {
  412.           case 0x378: shortp_irq = 7; break;
  413.           case 0x278: shortp_irq = 2; break;
  414.           case 0x3bc: shortp_irq = 5; break;
  415.         }
  416.     /* Request the IRQ */
  417.     result = request_irq(shortp_irq, shortp_interrupt, 0, "shortprint", NULL);
  418.     if (result) {
  419.         printk(KERN_INFO "shortprint: can't get assigned irq %in",
  420. shortp_irq);
  421. shortp_irq = -1;
  422. shortp_cleanup ();
  423. return result;
  424.     }
  425.     /* Initialize the control register, turning on interrupts. */
  426.     outb (SP_CR_IRQ | SP_CR_SELECT | SP_CR_INIT, shortp_base + SP_CONTROL);
  427.     return 0;
  428. }
  429. void shortp_cleanup(void)
  430. {
  431.     /* Return the IRQ if we have one */
  432.     if (shortp_irq >= 0) {
  433.         outb(0x0, shortp_base + SP_CONTROL);   /* disable the interrupt */
  434.         free_irq(shortp_irq, NULL);
  435.     }
  436.     /* Don't leave any timers floating around.  Note that any active output
  437.        is effectively stopped by turning off the interrupt */
  438.     if (shortp_output_active)
  439.         del_timer_sync (&shortp_timer);
  440.     /* All done with the device */
  441.     unregister_chrdev(major, "shortprint");
  442.     release_region(shortp_base,SHORTP_NR_PORTS);
  443.     if (shortp_in_buffer) free_page(shortp_in_buffer);
  444. }
  445. module_init(shortp_init);
  446. module_exit(shortp_cleanup);