root/drivers/char/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. qp_interrupt
  8. release_aux
  9. release_qp
  10. open_aux
  11. open_qp
  12. write_aux
  13. write_qp
  14. read_aux
  15. aux_select
  16. psaux_init
  17. poll_aux_status
  18. poll_qp_status
  19. read_710
  20. probe_qp

   1 /*
   2  * linux/drivers/char/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  * Corrections in device setup for some laptop mice & trackballs.
  10  * 02Feb93  (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca)
  11  *
  12  * Changed to prevent keyboard lockups on AST Power Exec.
  13  * 28Jul93  Brad Bosch - brad@lachman.com
  14  *
  15  * Modified by Johan Myreen (jem@cs.hut.fi) 04Aug93
  16  *   to include support for QuickPort mouse.
  17  *
  18  * Changed references to "QuickPort" with "82C710" since "QuickPort"
  19  * is not what this driver is all about -- QuickPort is just a
  20  * connector type, and this driver is for the mouse port on the Chips
  21  * & Technologies 82C710 interface chip. 15Nov93 jem@cs.hut.fi
  22  */
  23 
  24 /* Uncomment the following line if your mouse needs initialization. */
  25 
  26 /* #define INITIALIZE_DEVICE */
  27 
  28 #include <linux/sched.h>
  29 #include <linux/kernel.h>
  30 #include <linux/fcntl.h>
  31 #include <linux/errno.h>
  32 #include <linux/timer.h>
  33 
  34 #include <asm/io.h>
  35 #include <asm/segment.h>
  36 #include <asm/system.h>
  37 
  38 #include <linux/config.h>
  39 
  40 /* aux controller ports */
  41 #define AUX_INPUT_PORT  0x60            /* Aux device output buffer */
  42 #define AUX_OUTPUT_PORT 0x60            /* Aux device input buffer */
  43 #define AUX_COMMAND     0x64            /* Aux device command buffer */
  44 #define AUX_STATUS      0x64            /* Aux device status reg */
  45 
  46 /* aux controller status bits */
  47 #define AUX_OBUF_FULL   0x21            /* output buffer (from device) full */
  48 #define AUX_IBUF_FULL   0x02            /* input buffer (to device) full */
  49 
  50 /* aux controller commands */
  51 #define AUX_CMD_WRITE   0x60            /* value to write to controller */
  52 #define AUX_MAGIC_WRITE 0xd4            /* value to send aux device data */
  53 
  54 #define AUX_INTS_ON     0x47            /* enable controller interrupts */
  55 #define AUX_INTS_OFF    0x65            /* disable controller interrupts */
  56 
  57 #define AUX_DISABLE     0xa7            /* disable aux */
  58 #define AUX_ENABLE      0xa8            /* enable aux */
  59 
  60 /* aux device commands */
  61 #define AUX_SET_RES     0xe8            /* set resolution */
  62 #define AUX_SET_SCALE11 0xe6            /* set 1:1 scaling */
  63 #define AUX_SET_SCALE21 0xe7            /* set 2:1 scaling */
  64 #define AUX_GET_SCALE   0xe9            /* get scaling factor */
  65 #define AUX_SET_STREAM  0xea            /* set stream mode */
  66 #define AUX_SET_SAMPLE  0xf3            /* set sample rate */
  67 #define AUX_ENABLE_DEV  0xf4            /* enable aux device */
  68 #define AUX_DISABLE_DEV 0xf5            /* disable aux device */
  69 #define AUX_RESET       0xff            /* reset aux device */
  70 
  71 #define MAX_RETRIES     60              /* some aux operations take long time*/
  72 #define AUX_IRQ         12
  73 #define AUX_BUF_SIZE    2048
  74 
  75 /* 82C710 definitions */
  76 
  77 #define QP_DATA         0x310           /* Data Port I/O Address */
  78 #define QP_STATUS       0x311           /* Status Port I/O Address */
  79 
  80 #define QP_DEV_IDLE     0x01            /* Device Idle */
  81 #define QP_RX_FULL      0x02            /* Device Char received */
  82 #define QP_TX_IDLE      0x04            /* Device XMIT Idle */
  83 #define QP_RESET        0x08            /* Device Reset */
  84 #define QP_INTS_ON      0x10            /* Device Interrupt On */
  85 #define QP_ERROR_FLAG   0x20            /* Device Error */
  86 #define QP_CLEAR        0x40            /* Device Clear */
  87 #define QP_ENABLE       0x80            /* Device Enable */
  88 
  89 #define QP_IRQ          12
  90 
  91 extern unsigned char aux_device_present;
  92 extern unsigned char kbd_read_mask;     /* from keyboard.c */
  93 
  94 struct aux_queue {
  95         unsigned long head;
  96         unsigned long tail;
  97         struct wait_queue *proc_list;
  98         unsigned char buf[AUX_BUF_SIZE];
  99 };
 100 
 101 static struct aux_queue *queue;
 102 static int aux_ready = 0;
 103 static int aux_busy = 0;
 104 static int aux_present = 0;
 105 static int poll_aux_status(void);
 106 
 107 #ifdef CONFIG_82C710_MOUSE
 108 static int qp_present = 0;
 109 static int qp_busy = 0;
 110 static int qp_data = QP_DATA;
 111 static int qp_status = QP_STATUS;
 112 
 113 static int poll_qp_status(void);
 114 static int probe_qp(void);
 115 #endif
 116 
 117 
 118 /*
 119  * Write to aux device
 120  */
 121 
 122 static void aux_write_dev(int val)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124         poll_aux_status();
 125         outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);    /* write magic cookie */
 126         poll_aux_status();
 127         outb_p(val,AUX_OUTPUT_PORT);            /* write data */
 128 }
 129 
 130 /*
 131  * Write to device & handle returned ack
 132  */
 133  
 134 #if defined INITIALIZE_DEVICE
 135 static int aux_write_ack(int val)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137         int retries = 0;
 138 
 139         aux_write_dev(val);             /* write the value to the device */
 140         while ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL
 141                     && retries < MAX_RETRIES) {          /* wait for ack */
 142                 current->state = TASK_INTERRUPTIBLE;
 143                 current->timeout = jiffies + (5*HZ + 99) / 100;
 144                 schedule();
 145                 retries++;
 146         }
 147 
 148         if ((inb(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
 149         {
 150                 return (inb(AUX_INPUT_PORT));
 151         }
 152         return 0;
 153 }
 154 #endif /* INITIALIZE_DEVICE */
 155 
 156 /*
 157  * Write aux device command
 158  */
 159 
 160 static void aux_write_cmd(int val)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162         poll_aux_status();
 163         outb_p(AUX_CMD_WRITE,AUX_COMMAND);
 164         poll_aux_status();
 165         outb_p(val,AUX_OUTPUT_PORT);
 166 }
 167 
 168 
 169 static unsigned int get_from_queue(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 170 {
 171         unsigned int result;
 172         unsigned long flags;
 173 
 174         save_flags(flags);
 175         cli();
 176         result = queue->buf[queue->tail];
 177         queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
 178         restore_flags(flags);
 179         return result;
 180 }
 181 
 182 
 183 static inline int queue_empty(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 184 {
 185         return queue->head == queue->tail;
 186 }
 187 
 188 
 189 
 190 /*
 191  * Interrupt from the auxiliary device: a character
 192  * is waiting in the keyboard/aux controller.
 193  */
 194 
 195 static void aux_interrupt(int cpl, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 196 {
 197         int head = queue->head;
 198         int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
 199 
 200         queue->buf[head] = inb(AUX_INPUT_PORT);
 201         if (head != maxhead) {
 202                 head++;
 203                 head &= AUX_BUF_SIZE-1;
 204         }
 205         queue->head = head;
 206         aux_ready = 1;
 207         wake_up_interruptible(&queue->proc_list);
 208 }
 209 
 210 /*
 211  * Interrupt handler for the 82C710 mouse port. A character
 212  * is waiting in the 82C710.
 213  */
 214 
 215 #ifdef CONFIG_82C710_MOUSE
 216 static void qp_interrupt(int cpl, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 217 {
 218         int head = queue->head;
 219         int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
 220 
 221         queue->buf[head] = inb(qp_data);
 222         if (head != maxhead) {
 223                 head++;
 224                 head &= AUX_BUF_SIZE-1;
 225         }
 226         queue->head = head;
 227         aux_ready = 1;
 228         wake_up_interruptible(&queue->proc_list);
 229 }
 230 #endif
 231 
 232 
 233 static void release_aux(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 234 {
 235 #ifndef __alpha__
 236         aux_write_dev(AUX_DISABLE_DEV);         /* disable aux device */
 237 #endif
 238         aux_write_cmd(AUX_INTS_OFF);            /* disable controller ints */
 239         poll_aux_status();
 240         outb_p(AUX_DISABLE,AUX_COMMAND);        /* Disable Aux device */
 241         poll_aux_status();
 242         free_irq(AUX_IRQ);
 243         aux_busy = 0;
 244 }
 245 
 246 #ifdef CONFIG_82C710_MOUSE
 247 static void release_qp(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 248 {
 249         unsigned char status;
 250 
 251         if (!poll_qp_status())
 252                 printk("Warning: Mouse device busy in release_qp()\n");
 253         status = inb_p(qp_status);
 254         outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
 255         if (!poll_qp_status())
 256                 printk("Warning: Mouse device busy in release_qp()\n");
 257         free_irq(QP_IRQ);
 258         qp_busy = 0;
 259 }
 260 #endif
 261 
 262 /*
 263  * Install interrupt handler.
 264  * Enable auxiliary device.
 265  */
 266 
 267 static int open_aux(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 268 {
 269         if (!aux_present)
 270                 return -EINVAL;
 271         if (aux_busy)
 272                 return -EBUSY;
 273         if (!poll_aux_status())
 274                 return -EBUSY;
 275         aux_busy = 1;
 276         queue->head = queue->tail = 0;          /* Flush input queue */
 277         if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse")) {
 278                 aux_busy = 0;
 279                 return -EBUSY;
 280         }
 281         poll_aux_status();
 282         outb_p(AUX_ENABLE,AUX_COMMAND);         /* Enable Aux */
 283         aux_write_dev(AUX_ENABLE_DEV);          /* enable aux device */
 284         aux_write_cmd(AUX_INTS_ON);             /* enable controller ints */
 285         poll_aux_status();
 286         aux_ready = 0;
 287         return 0;
 288 }
 289 
 290 #ifdef CONFIG_82C710_MOUSE
 291 /*
 292  * Install interrupt handler.
 293  * Enable the device, enable interrupts. Set qp_busy
 294  * (allow only one opener at a time.)
 295  */
 296 
 297 static int open_qp(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 298 {
 299         unsigned char status;
 300 
 301         if (!qp_present)
 302                 return -EINVAL;
 303 
 304         if (qp_busy)
 305                 return -EBUSY;
 306 
 307         if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse"))
 308                 return -EBUSY;
 309 
 310         qp_busy = 1;
 311 
 312         status = inb_p(qp_status);
 313         status |= (QP_ENABLE|QP_RESET);
 314         outb_p(status, qp_status);
 315         status &= ~(QP_RESET);
 316         outb_p(status, qp_status);
 317 
 318         queue->head = queue->tail = 0;          /* Flush input queue */
 319         status |= QP_INTS_ON;
 320         outb_p(status, qp_status);              /* Enable interrupts */
 321 
 322         while (!poll_qp_status()) {
 323                 printk("Error: Mouse device busy in open_qp()\n");
 324                 return -EBUSY;
 325         }
 326 
 327         outb_p(AUX_ENABLE_DEV, qp_data);        /* Wake up mouse */
 328 
 329         return 0;
 330 }
 331 #endif
 332 
 333 /*
 334  * Write to the aux device.
 335  */
 336 
 337 static int write_aux(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 338 {
 339         int i = count;
 340 
 341         while (i--) {
 342                 if (!poll_aux_status())
 343                         return -EIO;
 344                 outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
 345                 if (!poll_aux_status())
 346                         return -EIO;
 347                 outb_p(get_user(buffer++),AUX_OUTPUT_PORT);
 348         }
 349         inode->i_mtime = CURRENT_TIME;
 350         return count;
 351 }
 352 
 353 
 354 #ifdef CONFIG_82C710_MOUSE
 355 /*
 356  * Write to the 82C710 mouse device.
 357  */
 358 
 359 static int write_qp(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 360 {
 361         int i = count;
 362 
 363         while (i--) {
 364                 if (!poll_qp_status())
 365                         return -EIO;
 366                 outb_p(get_user(buffer++), qp_data);
 367         }
 368         inode->i_mtime = CURRENT_TIME;
 369         return count;
 370 }
 371 #endif
 372 
 373 
 374 /*
 375  * Put bytes from input queue to buffer.
 376  */
 377 
 378 static int read_aux(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 379 {
 380         struct wait_queue wait = { current, NULL };
 381         int i = count;
 382         unsigned char c;
 383 
 384         if (queue_empty()) {
 385                 if (file->f_flags & O_NONBLOCK)
 386                         return -EAGAIN;
 387                 add_wait_queue(&queue->proc_list, &wait);
 388 repeat:
 389                 current->state = TASK_INTERRUPTIBLE;
 390                 if (queue_empty() && !(current->signal & ~current->blocked)) {
 391                         schedule();
 392                         goto repeat;
 393                 }
 394                 current->state = TASK_RUNNING;
 395                 remove_wait_queue(&queue->proc_list, &wait);                    
 396         }               
 397         while (i > 0 && !queue_empty()) {
 398                 c = get_from_queue();
 399                 put_user(c, buffer++);
 400                 i--;
 401         }
 402         aux_ready = !queue_empty();
 403         if (count-i) {
 404                 inode->i_atime = CURRENT_TIME;
 405                 return count-i;
 406         }
 407         if (current->signal & ~current->blocked)
 408                 return -ERESTARTSYS;
 409         return 0;
 410 }
 411 
 412 
 413 static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 414 {
 415         if (sel_type != SEL_IN)
 416                 return 0;
 417         if (aux_ready)
 418                 return 1;
 419         select_wait(&queue->proc_list, wait);
 420         return 0;
 421 }
 422 
 423 
 424 struct file_operations psaux_fops = {
 425         NULL,           /* seek */
 426         read_aux,
 427         write_aux,
 428         NULL,           /* readdir */
 429         aux_select,
 430         NULL,           /* ioctl */
 431         NULL,           /* mmap */
 432         open_aux,
 433         release_aux,
 434 };
 435 
 436 
 437 /*
 438  * Initialize driver. First check for a 82C710 chip; if found
 439  * forget about the Aux port and use the *_qp functions.
 440  */
 441 
 442 unsigned long psaux_init(unsigned long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 443 {
 444         int qp_found = 0;
 445 
 446 #ifdef CONFIG_82C710_MOUSE
 447         if ((qp_found = probe_qp())) {
 448                 printk("82C710 type pointing device detected -- driver installed.\n");
 449 /*              printk("82C710 address = %x (should be 0x310)\n", qp_data); */
 450                 qp_present = 1;
 451                 psaux_fops.write = write_qp;
 452                 psaux_fops.open = open_qp;
 453                 psaux_fops.release = release_qp;
 454                 poll_qp_status();
 455         } else
 456 #endif
 457         if (aux_device_present == 0xaa) {
 458                 printk("PS/2 auxiliary pointing device detected -- driver installed.\n");
 459                 aux_present = 1;
 460                 kbd_read_mask = AUX_OBUF_FULL;
 461                 poll_aux_status();
 462         } else {
 463                 return kmem_start;              /* No mouse at all */
 464         }
 465         queue = (struct aux_queue *) kmem_start;
 466         kmem_start += sizeof (struct aux_queue);
 467         queue->head = queue->tail = 0;
 468         queue->proc_list = NULL;
 469         if (!qp_found) {
 470 #if defined INITIALIZE_DEVICE
 471                 outb_p(AUX_ENABLE,AUX_COMMAND);         /* Enable Aux */
 472                 aux_write_ack(AUX_SET_SAMPLE);
 473                 aux_write_ack(100);                     /* 100 samples/sec */
 474                 aux_write_ack(AUX_SET_RES);
 475                 aux_write_ack(3);                       /* 8 counts per mm */
 476                 aux_write_ack(AUX_SET_SCALE21);         /* 2:1 scaling */
 477                 poll_aux_status();
 478 #endif /* INITIALIZE_DEVICE */
 479                 outb_p(AUX_DISABLE,AUX_COMMAND);   /* Disable Aux device */
 480                 aux_write_cmd(AUX_INTS_OFF);    /* disable controller ints */
 481                 poll_aux_status();
 482         }
 483         return kmem_start;
 484 }
 485 
 486 static int poll_aux_status(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 487 {
 488         int retries=0;
 489 
 490         while ((inb(AUX_STATUS)&0x03) && retries < MAX_RETRIES) {
 491                 if ((inb_p(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
 492                         inb_p(AUX_INPUT_PORT);
 493                 current->state = TASK_INTERRUPTIBLE;
 494                 current->timeout = jiffies + (5*HZ + 99) / 100;
 495                 schedule();
 496                 retries++;
 497         }
 498         return !(retries==MAX_RETRIES);
 499 }
 500 
 501 #ifdef CONFIG_82C710_MOUSE
 502 /*
 503  * Wait for device to send output char and flush any input char.
 504  */
 505 
 506 static int poll_qp_status(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 507 {
 508         int retries=0;
 509 
 510         while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
 511                        != (QP_DEV_IDLE|QP_TX_IDLE)
 512                        && retries < MAX_RETRIES) {
 513 
 514                 if (inb_p(qp_status)&(QP_RX_FULL))
 515                         inb_p(qp_data);
 516                 current->state = TASK_INTERRUPTIBLE;
 517                 current->timeout = jiffies + (5*HZ + 99) / 100;
 518                 schedule();
 519                 retries++;
 520         }
 521         return !(retries==MAX_RETRIES);
 522 }
 523 
 524 /*
 525  * Function to read register in 82C710.
 526  */
 527 
 528 static inline unsigned char read_710(unsigned char index)
     /* [previous][next][first][last][top][bottom][index][help] */
 529 {
 530         outb_p(index, 0x390);                   /* Write index */
 531         return inb_p(0x391);                    /* Read the data */
 532 }
 533 
 534 /*
 535  * See if we can find a 82C710 device. Read mouse address.
 536  */
 537 
 538 static int probe_qp(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 539 {
 540         outb_p(0x55, 0x2fa);                    /* Any value except 9, ff or 36 */
 541         outb_p(0xaa, 0x3fa);                    /* Inverse of 55 */
 542         outb_p(0x36, 0x3fa);                    /* Address the chip */
 543         outb_p(0xe4, 0x3fa);                    /* 390/4; 390 = config address */
 544         outb_p(0x1b, 0x2fa);                    /* Inverse of e4 */
 545         if (read_710(0x0f) != 0xe4)             /* Config address found? */
 546           return 0;                             /* No: no 82C710 here */
 547         qp_data = read_710(0x0d)*4;             /* Get mouse I/O address */
 548         qp_status = qp_data+1;
 549         outb_p(0x0f, 0x390);
 550         outb_p(0x0f, 0x391);                    /* Close config mode */
 551         return 1;
 552 }
 553 #endif

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