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(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122         unsigned int result;
 123         unsigned long flags;
 124 
 125         save_flags(flags);
 126         cli();
 127         result = queue->buf[queue->tail];
 128         queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
 129         restore_flags(flags);
 130         return result;
 131 }
 132 
 133 
 134 static inline int queue_empty(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 135 {
 136         return queue->head == queue->tail;
 137 }
 138 
 139 
 140 /*
 141  * Interrupt from the auxiliary device: a character
 142  * is waiting in the keyboard/aux controller.
 143  */
 144 
 145 static void aux_interrupt(int cpl)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147         int head = queue->head;
 148         int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
 149 
 150         queue->buf[head] = inb(AUX_INPUT_PORT);
 151         if (head != maxhead) {
 152                 head++;
 153                 head &= AUX_BUF_SIZE-1;
 154         }
 155         queue->head = head;
 156         aux_ready = 1;
 157         wake_up_interruptible(&queue->proc_list);
 158 }
 159 
 160 
 161 static void release_aux(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163         poll_status();
 164         aux_write_dev(AUX_DISABLE_DEV);         /* disable aux device */
 165         poll_status();
 166         outb_p(AUX_DISABLE,AUX_COMMAND);        /* 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         struct wait_queue wait = { current, NULL };
 226         int i = count;
 227         unsigned char c;
 228 
 229         if (queue_empty()) {
 230                 if (file->f_flags & O_NONBLOCK)
 231                         return -EAGAIN;
 232                 add_wait_queue(&queue->proc_list, &wait);
 233 repeat:
 234                 current->state = TASK_INTERRUPTIBLE;
 235                 if (queue_empty() && !(current->signal & ~current->blocked)) {
 236                         schedule();
 237                         goto repeat;
 238                 }
 239                 current->state = TASK_RUNNING;
 240                 remove_wait_queue(&queue->proc_list, &wait);                    
 241         }               
 242         while (i > 0 && !queue_empty()) {
 243                 c = get_from_queue();
 244                 put_fs_byte(c, buffer++);
 245                 i--;
 246         }
 247         aux_ready = !queue_empty();
 248         if (count-i) {
 249                 inode->i_atime = CURRENT_TIME;
 250                 return count-i;
 251         }
 252         if (current->signal & ~current->blocked)
 253                 return -ERESTARTSYS;
 254         return 0;
 255 }
 256 
 257 
 258 static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 259 {
 260         if (sel_type != SEL_IN)
 261                 return 0;
 262         if (aux_ready)
 263                 return 1;
 264         select_wait(&queue->proc_list, wait);
 265         return 0;
 266 }
 267 
 268 
 269 struct file_operations psaux_fops = {
 270         NULL,           /* seek */
 271         read_aux,
 272         write_aux,
 273         NULL,           /* readdir */
 274         aux_select,
 275         NULL,           /* ioctl */
 276         NULL,           /* mmap */
 277         open_aux,
 278         release_aux,
 279 };
 280 
 281 
 282 unsigned long psaux_init(unsigned long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 283 {
 284         if (aux_device_present != 0xaa) {
 285                 return kmem_start;
 286         }
 287         printk("PS/2 type pointing device detected and installed.\n");
 288         queue = (struct aux_queue *) kmem_start;
 289         kmem_start += sizeof (struct aux_queue);
 290         queue->head = queue->tail = 0;
 291         queue->proc_list = NULL;
 292         aux_present = 1;
 293         poll_status();
 294         outb_p(AUX_DISABLE,AUX_COMMAND);        /* Disable Aux device */
 295         aux_write_cmd(AUX_INTS_OFF);            /* disable controller ints */
 296         return kmem_start;
 297 }
 298 
 299 
 300 static int poll_status(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 301 {
 302         int retries=0;
 303 
 304         while ((inb(AUX_STATUS)&0x03) && retries++ < MAX_RETRIES) {
 305                 if (inb_p(AUX_STATUS)&0x01)
 306                         inb_p(AUX_INPUT_PORT);
 307                 current->state = TASK_INTERRUPTIBLE;
 308                 current->timeout = jiffies + 5;
 309                 schedule();
 310         }
 311         return !(retries==MAX_RETRIES);
 312 }

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