root/kernel/chr_drv/psaux.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_from_queue
  2. queue_empty
  3. aux_interrupt
  4. release_aux
  5. open_aux
  6. write_aux
  7. read_aux
  8. aux_select
  9. psaux_init
  10. poll_status

   1 /*
   2  * linux/kernel/chr_drv/psaux.c
   3  *
   4  * Driver for PS/2 type mouse by Johan Myreen.
   5  *
   6  * Supports pointing devices attached to a PS/2 type
   7  * Keyboard and Auxiliary Device Controller.
   8  *
   9  */
  10 
  11 #include <linux/timer.h>
  12 #include <linux/sched.h>
  13 #include <linux/kernel.h>
  14 #include <linux/fcntl.h>
  15 #include <linux/errno.h>
  16 
  17 #include <asm/io.h>
  18 #include <asm/segment.h>
  19 #include <asm/system.h>
  20 
  21 #define AUX_INPUT_PORT  0x60            /* Aux device output buffer */
  22 #define AUX_OUTPUT_PORT 0x60            /* Aux device input buffer */
  23 #define AUX_COMMAND     0x64            /* Aux device command buffer */
  24 #define AUX_STATUS      0x64            /* Aux device status reg */
  25 
  26 #define MAX_RETRIES     3
  27 #define AUX_IRQ         12
  28 #define AUX_BUF_SIZE    2048
  29 
  30 extern unsigned char aux_device_present;
  31 
  32 struct aux_queue {
  33         unsigned long head;
  34         unsigned long tail;
  35         struct wait_queue *proc_list;
  36         unsigned char buf[AUX_BUF_SIZE];
  37 };
  38 
  39 static struct aux_queue *queue;
  40 static int aux_ready = 0;
  41 static int aux_busy = 0;
  42 static int aux_present = 0;
  43 
  44 static int poll_status(void);
  45 
  46 
  47 static unsigned int get_from_queue()
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49         unsigned int result;
  50         unsigned long flags;
  51 
  52         __asm__ __volatile__ ("pushfl ; popl %0; cli":"=r" (flags));
  53         result = queue->buf[queue->tail];
  54         queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
  55         __asm__ __volatile__ ("pushl %0 ; popfl"::"r" (flags));
  56         return result;
  57 }
  58 
  59 
  60 static inline int queue_empty()
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62         return queue->head == queue->tail;
  63 }
  64 
  65 
  66 /*
  67  * Interrupt from the auxiliary device: a character
  68  * is waiting in the keyboard/aux controller.
  69  */
  70 
  71 static void aux_interrupt(int cpl)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73         int head = queue->head;
  74         int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
  75 
  76         queue->buf[head] = inb(AUX_INPUT_PORT);
  77         if (head != maxhead) {
  78                 head++;
  79                 head &= AUX_BUF_SIZE-1;
  80         }
  81         queue->head = head;
  82         aux_ready = 1;
  83         wake_up(&queue->proc_list);
  84 }
  85 
  86 
  87 static void release_aux(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89         poll_status();
  90         outb_p(0xa7,AUX_COMMAND);       /* Disable Aux device */
  91         poll_status();
  92         outb_p(0x60,AUX_COMMAND);
  93         poll_status();
  94         outb_p(0x65,AUX_OUTPUT_PORT);
  95         free_irq(AUX_IRQ);
  96         aux_busy = 0;
  97 }
  98 
  99 
 100 /*
 101  * Install interrupt handler.
 102  * Enable auxiliary device.
 103  */
 104 
 105 static int open_aux(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107         if (aux_busy)
 108                 return -EBUSY;
 109         if (!aux_present)
 110                 return -EINVAL;
 111         if (!poll_status())
 112                 return -EBUSY;
 113         aux_busy = 1;
 114         queue->head = queue->tail = 0;  /* Flush input queue */
 115         if (request_irq(AUX_IRQ, aux_interrupt))
 116                 return -EBUSY;
 117         outb_p(0x60,AUX_COMMAND);       /* Write command */
 118         poll_status();
 119         outb_p(0x47,AUX_OUTPUT_PORT);   /* Enable AUX and keyb interrupts */
 120         poll_status();
 121         outb_p(0xa8,AUX_COMMAND);       /* Enable AUX */
 122         return 0;
 123 }
 124 
 125 
 126 /*
 127  * Write to the aux device.
 128  */
 129 
 130 static int write_aux(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132         int i = count;
 133 
 134         while (i--) {
 135                 if (!poll_status())
 136                         return -EIO;
 137                 outb_p(0xd4,AUX_COMMAND);
 138                 if (!poll_status())
 139                         return -EIO;
 140                 outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT);
 141         }
 142         inode->i_mtime = CURRENT_TIME;
 143         return count;
 144 }
 145 
 146 
 147 /*
 148  * Put bytes from input queue to buffer.
 149  */
 150 
 151 static int read_aux(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153         int i = count;
 154         unsigned char c;
 155 
 156         if (queue_empty()) {
 157                 if (file->f_flags & O_NONBLOCK)
 158                         return -EWOULDBLOCK;
 159                 cli();
 160                 interruptible_sleep_on(&queue->proc_list);
 161                 sti();
 162         }               
 163         while (i > 0 && !queue_empty()) {
 164                 c = get_from_queue();
 165                 put_fs_byte(c, buffer++);
 166                 i--;
 167         }
 168         aux_ready = !queue_empty();
 169         if (count-i) {
 170                 inode->i_atime = CURRENT_TIME;
 171                 return count-i;
 172         }
 173         if (current->signal & ~current->blocked)
 174                 return -ERESTARTSYS;
 175         return 0;
 176 }
 177 
 178 
 179 static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 180 {
 181         if (sel_type != SEL_IN)
 182                 return 0;
 183         if (aux_ready)
 184                 return 1;
 185         select_wait(&queue->proc_list, wait);
 186         return 0;
 187 }
 188 
 189 
 190 struct file_operations psaux_fops = {
 191         NULL,           /* seek */
 192         read_aux,
 193         write_aux,
 194         NULL,           /* readdir */
 195         aux_select,
 196         NULL,           /* ioctl */
 197         open_aux,
 198         release_aux,
 199 };
 200 
 201 
 202 long psaux_init(long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204         if (aux_device_present != 0xaa) {
 205                 printk("No PS/2 type pointing device detected.\n");
 206                 return kmem_start;
 207         }
 208         printk("PS/2 type pointing device detected and installed.\n");
 209         queue = (struct aux_queue *) kmem_start;
 210         kmem_start += sizeof (struct aux_queue);
 211         queue->head = queue->tail = 0;
 212         queue->proc_list = 0;
 213         aux_present = 1;
 214         return kmem_start;
 215 }
 216 
 217 
 218 static int poll_status(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220         int retries=0;
 221 
 222         while ((inb(AUX_STATUS)&0x03) && retries++ < MAX_RETRIES) {
 223                 if (inb_p(AUX_STATUS)&0x01)
 224                         inb_p(AUX_INPUT_PORT);
 225                 current->state = TASK_INTERRUPTIBLE;
 226                 current->timeout = jiffies + 5;
 227                 schedule();
 228         }
 229         return !(retries==MAX_RETRIES);
 230 }

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