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  * Write to aux device
  80  */
  81 static void aux_write_dev(int val)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83         poll_status();
  84         outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);    /* write magic cookie */
  85         poll_status();
  86         outb_p(val,AUX_OUTPUT_PORT);            /* write data */
  87         
  88 }
  89 
  90 #if 0
  91 /*
  92  * Write to device & handle returned ack
  93  */
  94  
  95 static int aux_write_ack(int val)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97         aux_write_dev(val);             /* write the value to the device */
  98         while ((inb(AUX_STATUS) & AUX_OBUF_FULL) == 0);  /* wait for ack */
  99         if ((inb(AUX_STATUS) & 0x20) == 0x20)
 100         {
 101                 return (inb(AUX_INPUT_PORT));
 102         }
 103         return 0;
 104 }
 105 #endif
 106 
 107 /*
 108  * Write aux device command
 109  */
 110 
 111 static void aux_write_cmd(int val)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113         poll_status();
 114         outb_p(AUX_CMD_WRITE,AUX_COMMAND);
 115         poll_status();
 116         outb_p(val,AUX_OUTPUT_PORT);
 117 }
 118 
 119 
 120 static unsigned int get_from_queue()
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122         unsigned int result;
 123         unsigned long flags;
 124 
 125         __asm__ __volatile__ ("pushfl ; popl %0; cli":"=r" (flags));
 126         result = queue->buf[queue->tail];
 127         queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
 128         __asm__ __volatile__ ("pushl %0 ; popfl"::"r" (flags));
 129         return result;
 130 }
 131 
 132 
 133 static inline int queue_empty()
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135         return queue->head == queue->tail;
 136 }
 137 
 138 
 139 /*
 140  * Interrupt from the auxiliary device: a character
 141  * is waiting in the keyboard/aux controller.
 142  */
 143 
 144 static void aux_interrupt(int cpl)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146         int head = queue->head;
 147         int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
 148 
 149         queue->buf[head] = inb(AUX_INPUT_PORT);
 150         if (head != maxhead) {
 151                 head++;
 152                 head &= AUX_BUF_SIZE-1;
 153         }
 154         queue->head = head;
 155         aux_ready = 1;
 156         wake_up_interruptible(&queue->proc_list);
 157 }
 158 
 159 
 160 static void release_aux(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162         poll_status();
 163         outb_p(AUX_DISABLE,AUX_COMMAND);        /* Disable Aux device */
 164         aux_write_dev(AUX_DISABLE_DEV);         /* disable aux device */
 165         aux_write_cmd(AUX_INTS_OFF);            /* disable controller ints */
 166         free_irq(AUX_IRQ);
 167         aux_busy = 0;
 168 }
 169 
 170 
 171 /*
 172  * Install interrupt handler.
 173  * Enable auxiliary device.
 174  */
 175 
 176 static int open_aux(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 177 {
 178         if (!aux_present)
 179                 return -EINVAL;
 180         if (aux_busy)
 181                 return -EBUSY;
 182         if (!poll_status())
 183                 return -EBUSY;
 184         aux_busy = 1;
 185         queue->head = queue->tail = 0;  /* Flush input queue */
 186         if (request_irq(AUX_IRQ, aux_interrupt))
 187                 return -EBUSY;
 188         aux_write_dev(AUX_ENABLE_DEV);          /* enable aux device */
 189         aux_write_cmd(AUX_INTS_ON);             /* enable controller ints */
 190         poll_status();
 191         outb_p(AUX_ENABLE,AUX_COMMAND);         /* Enable Aux */
 192         return 0;
 193 }
 194 
 195 
 196 /*
 197  * Write to the aux device.
 198  */
 199 
 200 static int write_aux(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202         int i = count;
 203 
 204         while (i--) {
 205                 if (!poll_status())
 206                         return -EIO;
 207                 outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
 208                 if (!poll_status())
 209                         return -EIO;
 210                 outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT);
 211         }
 212         inode->i_mtime = CURRENT_TIME;
 213         return count;
 214 }
 215 
 216 
 217 /*
 218  * Put bytes from input queue to buffer.
 219  */
 220 
 221 static int read_aux(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 222 {
 223         struct wait_queue wait = { current, NULL };
 224         int i = count;
 225         unsigned char c;
 226 
 227         if (queue_empty()) {
 228                 if (file->f_flags & O_NONBLOCK)
 229                         return -EAGAIN;
 230                 add_wait_queue(&queue->proc_list, &wait);
 231 repeat:
 232                 current->state = TASK_INTERRUPTIBLE;
 233                 if (queue_empty() && !(current->signal & ~current->blocked)) {
 234                         schedule();
 235                         goto repeat;
 236                 }
 237                 current->state = TASK_RUNNING;
 238                         
 239         }               
 240         while (i > 0 && !queue_empty()) {
 241                 c = get_from_queue();
 242                 put_fs_byte(c, buffer++);
 243                 i--;
 244         }
 245         aux_ready = !queue_empty();
 246         if (count-i) {
 247                 inode->i_atime = CURRENT_TIME;
 248                 return count-i;
 249         }
 250         if (current->signal & ~current->blocked)
 251                 return -ERESTARTSYS;
 252         return 0;
 253 }
 254 
 255 
 256 static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 257 {
 258         if (sel_type != SEL_IN)
 259                 return 0;
 260         if (aux_ready)
 261                 return 1;
 262         select_wait(&queue->proc_list, wait);
 263         return 0;
 264 }
 265 
 266 
 267 struct file_operations psaux_fops = {
 268         NULL,           /* seek */
 269         read_aux,
 270         write_aux,
 271         NULL,           /* readdir */
 272         aux_select,
 273         NULL,           /* ioctl */
 274         NULL,           /* mmap */
 275         open_aux,
 276         release_aux,
 277 };
 278 
 279 
 280 unsigned long psaux_init(unsigned long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282         if (aux_device_present != 0xaa) {
 283                 return kmem_start;
 284         }
 285         printk("PS/2 type pointing device detected and installed.\n");
 286         queue = (struct aux_queue *) kmem_start;
 287         kmem_start += sizeof (struct aux_queue);
 288         queue->head = queue->tail = 0;
 289         queue->proc_list = NULL;
 290         aux_present = 1;
 291         return kmem_start;
 292 }
 293 
 294 
 295 static int poll_status(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 296 {
 297         int retries=0;
 298 
 299         while ((inb(AUX_STATUS)&0x03) && retries++ < MAX_RETRIES) {
 300                 if (inb_p(AUX_STATUS)&0x01)
 301                         inb_p(AUX_INPUT_PORT);
 302                 current->state = TASK_INTERRUPTIBLE;
 303                 current->timeout = jiffies + 5;
 304                 schedule();
 305         }
 306         return !(retries==MAX_RETRIES);
 307 }

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