root/kernel/chr_drv/psaux.c

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

DEFINITIONS

This source file includes following definitions.
  1. aux_write_dev
  2. aux_write_ack
  3. aux_write_cmd
  4. get_from_queue
  5. queue_empty
  6. aux_interrupt
  7. release_aux
  8. open_aux
  9. write_aux
  10. read_aux
  11. aux_select
  12. psaux_init
  13. 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  * Modified by Dean Troyer (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
  10  *   to perform (some of) the hardware initialization formerly done in
  11  *   setup.S by the BIOS
  12  *
  13  * Modified by Dean Troyer (troyer@saifr00.cfsat.Honeywell.COM) 09Oct92
  14  *   to perform the hardware initialization formerly done in setup.S by
  15  *   the BIOS.  Mouse characteristic setup is now included.
  16  *
  17  */
  18 
  19 #include <linux/timer.h>
  20 #include <linux/sched.h>
  21 #include <linux/kernel.h>
  22 #include <linux/fcntl.h>
  23 #include <linux/errno.h>
  24 
  25 #include <asm/io.h>
  26 #include <asm/segment.h>
  27 #include <asm/system.h>
  28 
  29 /* aux controller ports */
  30 #define AUX_INPUT_PORT  0x60            /* Aux device output buffer */
  31 #define AUX_OUTPUT_PORT 0x60            /* Aux device input buffer */
  32 #define AUX_COMMAND     0x64            /* Aux device command buffer */
  33 #define AUX_STATUS      0x64            /* Aux device status reg */
  34 
  35 /* aux controller status bits */
  36 #define AUX_OBUF_FULL   0x01            /* output buffer (from device) full */
  37 #define AUX_IBUF_FULL   0x02            /* input buffer (to device) full */
  38 
  39 /* aux controller commands */
  40 #define AUX_CMD_WRITE   0x60            /* value to write to controller */
  41 #define AUX_MAGIC_WRITE 0xd4            /* value to send aux device data */
  42 
  43 #define AUX_INTS_ON     0x47            /* enable controller interrupts */
  44 #define AUX_INTS_OFF    0x65            /* disable controller interrupts */
  45 
  46 #define AUX_DISABLE     0xa7            /* disable aux */
  47 #define AUX_ENABLE      0xa8            /* enable aux */
  48 
  49 /* aux device commands */
  50 #define AUX_SET_RES     0xe8            /* set resolution */
  51 #define AUX_SET_SCALE   0xe9            /* set scaling factor */
  52 #define AUX_SET_STREAM  0xea            /* set stream mode */
  53 #define AUX_SET_SAMPLE  0xf3            /* set sample rate */
  54 #define AUX_ENABLE_DEV  0xf4            /* enable aux device */
  55 #define AUX_DISABLE_DEV 0xf5            /* disable aux device */
  56 #define AUX_RESET       0xff            /* reset aux device */
  57 
  58 #define MAX_RETRIES     3
  59 #define AUX_IRQ         12
  60 #define AUX_BUF_SIZE    2048
  61 
  62 extern unsigned char aux_device_present;
  63 
  64 struct aux_queue {
  65         unsigned long head;
  66         unsigned long tail;
  67         struct wait_queue *proc_list;
  68         unsigned char buf[AUX_BUF_SIZE];
  69 };
  70 
  71 static struct aux_queue *queue;
  72 static int aux_ready = 0;
  73 static int aux_busy = 0;
  74 static int aux_present = 0;
  75 
  76 static int poll_status(void);
  77 
  78 
  79 /*
  80  * Write to aux device
  81  */
  82 
  83 static void aux_write_dev(int val)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85         poll_status();
  86         outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);    /* write magic cookie */
  87         poll_status();
  88         outb_p(val,AUX_OUTPUT_PORT);            /* write data */
  89         
  90 }
  91 
  92 
  93 /*
  94  * Write to device & handle returned ack
  95  */
  96  
  97 static int aux_write_ack(int val)
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99         aux_write_dev(val);             /* write the value to the device */
 100         while ((inb(AUX_STATUS) & AUX_OBUF_FULL) == 0);  /* wait for ack */
 101         if ((inb(AUX_STATUS) & 0x20) == 0x20)
 102         {
 103                 return (inb(AUX_INPUT_PORT));
 104         }
 105         return 0;
 106 }
 107 
 108 
 109 /*
 110  * Write aux device command
 111  */
 112 
 113 static void aux_write_cmd(int val)
     /* [previous][next][first][last][top][bottom][index][help] */
 114 {
 115         poll_status();
 116         outb_p(AUX_CMD_WRITE,AUX_COMMAND);
 117         poll_status();
 118         outb_p(val,AUX_OUTPUT_PORT);
 119 }
 120 
 121 
 122 static unsigned int get_from_queue()
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124         unsigned int result;
 125         unsigned long flags;
 126 
 127         __asm__ __volatile__ ("pushfl ; popl %0; cli":"=r" (flags));
 128         result = queue->buf[queue->tail];
 129         queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
 130         __asm__ __volatile__ ("pushl %0 ; popfl"::"r" (flags));
 131         return result;
 132 }
 133 
 134 
 135 static inline int queue_empty()
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137         return queue->head == queue->tail;
 138 }
 139 
 140 
 141 /*
 142  * Interrupt from the auxiliary device: a character
 143  * is waiting in the keyboard/aux controller.
 144  */
 145 
 146 static void aux_interrupt(int cpl)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148         int head = queue->head;
 149         int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
 150 
 151         queue->buf[head] = inb(AUX_INPUT_PORT);
 152         if (head != maxhead) {
 153                 head++;
 154                 head &= AUX_BUF_SIZE-1;
 155         }
 156         queue->head = head;
 157         aux_ready = 1;
 158         wake_up(&queue->proc_list);
 159 }
 160 
 161 
 162 static void release_aux(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164         poll_status();
 165         outb_p(AUX_DISABLE,AUX_COMMAND);        /* Disable Aux device */
 166         aux_write_dev(AUX_DISABLE_DEV);         /* disable aux device */
 167         aux_write_cmd(AUX_INTS_OFF);            /* disable controller ints */
 168         free_irq(AUX_IRQ);
 169         aux_busy = 0;
 170 }
 171 
 172 
 173 /*
 174  * Install interrupt handler.
 175  * Enable auxiliary device.
 176  */
 177 
 178 static int open_aux(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 179 {
 180         if (!aux_present)
 181                 return -EINVAL;
 182         if (aux_busy)
 183                 return -EBUSY;
 184         if (!poll_status())
 185                 return -EBUSY;
 186         aux_busy = 1;
 187         queue->head = queue->tail = 0;  /* Flush input queue */
 188         if (request_irq(AUX_IRQ, aux_interrupt))
 189                 return -EBUSY;
 190         aux_write_dev(AUX_ENABLE_DEV);          /* enable aux device */
 191         aux_write_cmd(AUX_INTS_ON);             /* enable controller ints */
 192         poll_status();
 193         outb_p(AUX_ENABLE,AUX_COMMAND);         /* Enable Aux */
 194         return 0;
 195 }
 196 
 197 
 198 /*
 199  * Write to the aux device.
 200  */
 201 
 202 static int write_aux(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204         int i = count;
 205 
 206         while (i--) {
 207                 if (!poll_status())
 208                         return -EIO;
 209                 outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
 210                 if (!poll_status())
 211                         return -EIO;
 212                 outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT);
 213         }
 214         inode->i_mtime = CURRENT_TIME;
 215         return count;
 216 }
 217 
 218 
 219 /*
 220  * Put bytes from input queue to buffer.
 221  */
 222 
 223 static int read_aux(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 224 {
 225         int i = count;
 226         unsigned char c;
 227 
 228         if (queue_empty()) {
 229                 if (file->f_flags & O_NONBLOCK)
 230                         return -EAGAIN;
 231                 cli();
 232                 interruptible_sleep_on(&queue->proc_list);
 233                 sti();
 234         }               
 235         while (i > 0 && !queue_empty()) {
 236                 c = get_from_queue();
 237                 put_fs_byte(c, buffer++);
 238                 i--;
 239         }
 240         aux_ready = !queue_empty();
 241         if (count-i) {
 242                 inode->i_atime = CURRENT_TIME;
 243                 return count-i;
 244         }
 245         if (current->signal & ~current->blocked)
 246                 return -ERESTARTSYS;
 247         return 0;
 248 }
 249 
 250 
 251 static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253         if (sel_type != SEL_IN)
 254                 return 0;
 255         if (aux_ready)
 256                 return 1;
 257         select_wait(&queue->proc_list, wait);
 258         return 0;
 259 }
 260 
 261 
 262 struct file_operations psaux_fops = {
 263         NULL,           /* seek */
 264         read_aux,
 265         write_aux,
 266         NULL,           /* readdir */
 267         aux_select,
 268         NULL,           /* ioctl */
 269         NULL,           /* mmap */
 270         open_aux,
 271         release_aux,
 272 };
 273 
 274 
 275 unsigned long psaux_init(unsigned long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 276 {
 277         if (aux_device_present != 0xaa) {
 278                 return kmem_start;
 279         }
 280         printk("PS/2 type pointing device detected and installed.\n");
 281         queue = (struct aux_queue *) kmem_start;
 282         kmem_start += sizeof (struct aux_queue);
 283         queue->head = queue->tail = 0;
 284         queue->proc_list = NULL;
 285         aux_present = 1;
 286         return kmem_start;
 287 }
 288 
 289 
 290 static int poll_status(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292         int retries=0;
 293 
 294         while ((inb(AUX_STATUS)&0x03) && retries++ < MAX_RETRIES) {
 295                 if (inb_p(AUX_STATUS)&0x01)
 296                         inb_p(AUX_INPUT_PORT);
 297                 current->state = TASK_INTERRUPTIBLE;
 298                 current->timeout = jiffies + 5;
 299                 schedule();
 300         }
 301         return !(retries==MAX_RETRIES);
 302 }

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