File indexing completed on 2025-05-11 08:23:41
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <stdlib.h>
0016 #include <stdio.h>
0017 #include <string.h>
0018 #include <errno.h>
0019 #include <sys/types.h>
0020 #include <assert.h>
0021
0022 #include <bsp.h>
0023 #include <bsp/irq.h>
0024 #include <rtems/libio.h>
0025 #include <termios.h>
0026 #include <i386_io.h>
0027 #include <rtems/mw_uid.h>
0028 #include <rtems/mouse_parser.h>
0029
0030 #define INITIALIZE_MOUSE
0031
0032 #include <rtems/ps2_drv.h>
0033 #include "ps2_mouse.h"
0034
0035 static void kbd_write_command_w(int data);
0036 #if 0
0037 static void kbd_write_output_w(int data);
0038 #endif
0039
0040 static unsigned char handle_kbd_event(void);
0041 static void ps2_set_driver_handler(int port, mouse_parser_enqueue_handler handler);
0042
0043
0044 static volatile unsigned char reply_expected = 0;
0045 static volatile unsigned char acknowledge = 0;
0046 static volatile unsigned char resend = 0;
0047
0048
0049
0050
0051 static int psaux_init(void);
0052
0053 static struct aux_queue *queue;
0054 static int aux_count = 0;
0055
0056 static unsigned char mouse_reply_expected = 0;
0057
0058 #define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
0059 #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
0060 #define MAX_RETRIES 60
0061
0062 static void ps2_mouse_interrupt(void *);
0063 static mouse_parser_enqueue_handler driver_input_handler_ps2 = NULL;
0064
0065
0066
0067
0068
0069 static void ps2_set_driver_handler(
0070 int port,
0071 mouse_parser_enqueue_handler handler
0072 )
0073 {
0074 driver_input_handler_ps2 = handler;
0075 }
0076
0077 static void mdelay( unsigned long t )
0078 {
0079 Wait_X_ms( t );
0080 }
0081
0082 static void* termios_ttyp_paux = NULL;
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 static void kb_wait(void)
0098 {
0099 unsigned long timeout = KBC_TIMEOUT;
0100
0101 do {
0102
0103
0104
0105
0106 unsigned char status = handle_kbd_event();
0107
0108 if (! (status & KBD_STAT_IBF))
0109 return;
0110
0111 mdelay(1);
0112 timeout--;
0113 } while (timeout);
0114
0115 #ifdef KBD_REPORT_TIMEOUTS
0116 printk( "Keyboard timed out[1]\n");
0117 #endif
0118 }
0119
0120 static int do_acknowledge(unsigned char scancode)
0121 {
0122 if (reply_expected) {
0123
0124
0125
0126
0127
0128
0129 if (scancode == KBD_REPLY_ACK) {
0130 acknowledge = 1;
0131 reply_expected = 0;
0132 return 0;
0133 } else if (scancode == KBD_REPLY_RESEND) {
0134 resend = 1;
0135 reply_expected = 0;
0136 return 0;
0137 }
0138
0139
0140 #if 0
0141 printk( "keyboard reply expected - got %02x\n", scancode);
0142 #endif
0143 }
0144 return 1;
0145 }
0146
0147 static inline void handle_mouse_event(unsigned char scancode)
0148 {
0149 if (mouse_reply_expected) {
0150 if (scancode == AUX_ACK) {
0151 mouse_reply_expected--;
0152 return;
0153 }
0154 mouse_reply_expected = 0;
0155 }
0156
0157 if (aux_count) {
0158 int head = queue->head;
0159 queue->buf[head] = scancode;
0160 head = (head + 1) & (AUX_BUF_SIZE-1);
0161 if (head != queue->tail) {
0162 queue->head = head;
0163 }
0164
0165
0166 if( driver_input_handler_ps2 ) {
0167 driver_input_handler_ps2( &scancode, 1 );
0168 } else {
0169
0170 rtems_termios_enqueue_raw_characters( termios_ttyp_paux, (char *)&scancode, 1 );
0171 }
0172 }
0173 }
0174
0175
0176
0177
0178
0179
0180
0181
0182 static unsigned char handle_kbd_event(void)
0183 {
0184 unsigned char status = kbd_read_status();
0185 unsigned int work = 10000;
0186
0187 while (status & KBD_STAT_OBF) {
0188 unsigned char scancode;
0189 scancode = kbd_read_input();
0190 if (status & KBD_STAT_MOUSE_OBF) {
0191 handle_mouse_event(scancode);
0192 } else {
0193 do_acknowledge(scancode);
0194 printk("pc_keyb: %X ", scancode );
0195 }
0196 status = kbd_read_status();
0197 if(!work--) {
0198 printk("pc_keyb: controller jammed (0x%02X).\n", status);
0199 break;
0200 }
0201 }
0202 return status;
0203 }
0204
0205 static void ps2_mouse_interrupt(void * unused)
0206 {
0207 handle_kbd_event();
0208 }
0209
0210 static void kbd_write_command_w(int data)
0211 {
0212 kb_wait();
0213 kbd_write_command(data);
0214 }
0215
0216 static void kbd_write_cmd(int cmd)
0217 {
0218 kb_wait();
0219 kbd_write_command(KBD_CCMD_WRITE_MODE);
0220 kb_wait();
0221 kbd_write_output(cmd);
0222 }
0223
0224
0225
0226
0227 static int detect_auxiliary_port(void)
0228 {
0229 int loops = 10;
0230 int retval = 0;
0231
0232
0233
0234
0235
0236
0237
0238
0239 kb_wait();
0240 kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF);
0241
0242 kb_wait();
0243 kbd_write_output(0x5a);
0244
0245 do {
0246 unsigned char status = kbd_read_status();
0247 if (status & KBD_STAT_OBF) {
0248 kbd_read_input();
0249 if (status & KBD_STAT_MOUSE_OBF) {
0250 printk( "Detected PS/2 Mouse Port.\n");
0251 retval = 1;
0252 }
0253 break;
0254 }
0255 mdelay(1);
0256 } while (--loops);
0257 return retval;
0258 }
0259
0260
0261
0262
0263 static void aux_write_dev(int val)
0264 {
0265 kb_wait();
0266 kbd_write_command(KBD_CCMD_WRITE_MOUSE);
0267 kb_wait();
0268 kbd_write_output(val);
0269 }
0270
0271
0272
0273
0274 static void aux_write_ack(int val)
0275 {
0276 kb_wait();
0277 kbd_write_command(KBD_CCMD_WRITE_MOUSE);
0278 kb_wait();
0279 kbd_write_output(val);
0280
0281 mouse_reply_expected++;
0282 kb_wait();
0283 }
0284
0285 static unsigned char get_from_queue(void)
0286 {
0287 unsigned char result;
0288 result = queue->buf[queue->tail];
0289 queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
0290 return result;
0291 }
0292
0293 static int queue_empty(void)
0294 {
0295 return queue->head == queue->tail;
0296 }
0297
0298
0299
0300
0301 #define AUX_DEV ((void *)queue)
0302
0303 static int release_aux(void)
0304 {
0305 rtems_status_code status;
0306 if (--aux_count)
0307 return 0;
0308 kbd_write_cmd(AUX_INTS_OFF);
0309 kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE);
0310 status = rtems_interrupt_handler_remove(
0311 AUX_IRQ,
0312 ps2_mouse_interrupt,
0313 NULL
0314 );
0315 assert(status == RTEMS_SUCCESSFUL);
0316 return 0;
0317 }
0318
0319
0320
0321
0322
0323
0324 static int open_aux(void)
0325 {
0326 rtems_status_code status;
0327
0328 if (aux_count++) {
0329 return 0;
0330 }
0331 queue->head = queue->tail = 0;
0332
0333 status = rtems_interrupt_handler_install(
0334 AUX_IRQ,
0335 "ps2_mouse",
0336 RTEMS_INTERRUPT_UNIQUE,
0337 ps2_mouse_interrupt,
0338 NULL
0339 );
0340 assert(status == RTEMS_SUCCESSFUL);
0341
0342 kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE);
0343
0344 aux_write_ack(AUX_ENABLE_DEV);
0345 kbd_write_cmd(AUX_INTS_ON);
0346 return 0;
0347 }
0348
0349
0350
0351
0352 size_t read_aux(char * buffer, size_t count )
0353 {
0354 size_t i = count;
0355 unsigned char c;
0356
0357 if (queue_empty()) {
0358 return 0;
0359 }
0360 while (i > 0 && !queue_empty()) {
0361 c = get_from_queue();
0362 *buffer++ = c;
0363 i--;
0364 }
0365 return count-i;
0366 }
0367
0368
0369
0370
0371 static int write_aux( int minor, const char * buffer, int count )
0372 {
0373 int retval = 0;
0374
0375 if (count) {
0376 int written = 0;
0377 if (count > 32)
0378 count = 32;
0379 do {
0380 char c;
0381 c = *buffer++;
0382 aux_write_dev(c);
0383 written++;
0384 } while (--count);
0385 retval = -EIO;
0386 if (written) {
0387 retval = written;
0388 }
0389 }
0390 return retval;
0391 }
0392
0393 static int psaux_init( void )
0394 {
0395 if( !detect_auxiliary_port() ) {
0396 printk( "PS/2 - mouse not found.\n" );
0397 return -EIO;
0398 }
0399 queue = (struct aux_queue *)malloc( sizeof(*queue) );
0400 memset(queue, 0, sizeof(*queue));
0401 queue->head = queue->tail = 0;
0402 queue->proc_list = NULL;
0403
0404 #ifdef INITIALIZE_MOUSE
0405 kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE);
0406 aux_write_ack(AUX_SET_SAMPLE);
0407 aux_write_ack(100);
0408 aux_write_ack(AUX_SET_RES);
0409 aux_write_ack(3);
0410 aux_write_ack(AUX_SET_SCALE21);
0411 #endif
0412 kbd_write_command(KBD_CCMD_MOUSE_DISABLE);
0413 kbd_write_cmd(AUX_INTS_OFF);
0414 return 0;
0415 }
0416
0417
0418
0419
0420 rtems_device_driver paux_initialize(
0421 rtems_device_major_number major,
0422 rtems_device_minor_number minor,
0423 void *arg)
0424 {
0425 rtems_status_code status;
0426
0427
0428
0429
0430 rtems_termios_initialize();
0431
0432 printk( "PS/2 mouse probe.\n" );
0433 if( psaux_init() < 0 ) {
0434 printk("Error detecting PS/2 mouse --\n");
0435
0436 }
0437 open_aux();
0438
0439
0440
0441
0442 status = rtems_io_register_name ("/dev/mouse", major, 0);
0443 if (status != RTEMS_SUCCESSFUL) {
0444 printk("Error registering paux device!\n");
0445 rtems_fatal_error_occurred (status);
0446 }
0447 return RTEMS_SUCCESSFUL;
0448 }
0449
0450 static int paux_last_close(int major, int minor, void *arg)
0451 {
0452 release_aux();
0453 return 0;
0454 }
0455
0456
0457
0458
0459
0460
0461 static ssize_t write_aux_echo( int minor, const char * buffer, size_t count )
0462 {
0463 return 0;
0464 }
0465
0466
0467
0468
0469 rtems_device_driver paux_open(
0470 rtems_device_major_number major,
0471 rtems_device_minor_number minor,
0472 void *arg)
0473 {
0474 rtems_status_code status;
0475 static rtems_termios_callbacks cb =
0476 {
0477 NULL,
0478 paux_last_close,
0479 NULL,
0480 write_aux_echo,
0481 NULL,
0482 NULL,
0483 NULL,
0484 TERMIOS_POLLED
0485 };
0486
0487 status = rtems_termios_open (major, minor, arg, &cb );
0488 termios_ttyp_paux = ( (rtems_libio_open_close_args_t *)arg)->iop->data1;
0489 return status;
0490 }
0491
0492
0493
0494
0495 rtems_device_driver paux_close(
0496 rtems_device_major_number major,
0497 rtems_device_minor_number minor,
0498 void *arg)
0499 {
0500 return (rtems_termios_close (arg));
0501 }
0502
0503
0504
0505
0506
0507 rtems_device_driver paux_read(
0508 rtems_device_major_number major,
0509 rtems_device_minor_number minor,
0510 void *arg)
0511 {
0512 return rtems_termios_read (arg);
0513 }
0514
0515
0516
0517
0518
0519 rtems_device_driver paux_write(
0520 rtems_device_major_number major,
0521 rtems_device_minor_number minor,
0522 void *arg)
0523 {
0524 rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
0525 char *buffer = rw_args->buffer;
0526 int maximum = rw_args->count;
0527 rw_args->bytes_moved = write_aux( minor, buffer, maximum );
0528 return RTEMS_SUCCESSFUL;
0529 }
0530
0531
0532
0533
0534 rtems_device_driver paux_control(
0535 rtems_device_major_number major,
0536 rtems_device_minor_number minor,
0537 void *arg
0538 )
0539 {
0540 rtems_libio_ioctl_args_t *args = arg;
0541
0542 switch( args->command ) {
0543 default:
0544 return rtems_termios_ioctl (arg);
0545 break;
0546
0547 case MW_UID_REGISTER_DEVICE:
0548 printk( "PS2 Mouse: registering\n" );
0549 mouse_parser_initialize( "ps2" );
0550 ps2_set_driver_handler( minor, mouse_parser_enqueue );
0551 break;
0552
0553 case MW_UID_UNREGISTER_DEVICE:
0554
0555
0556
0557 ps2_set_driver_handler( minor, NULL );
0558 break;
0559 }
0560 args->ioctl_return = 0;
0561 return RTEMS_SUCCESSFUL;
0562 }