1 /* 2 * Copyright 2001-2014 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors (in chronological order): 6 * Elad Lahav, elad@eldarshany.com 7 * Stefano Ceccherini, burton666@libero.it 8 * Axel Dörfler, axeld@pinc-software.de 9 * Marcus Overhagen, marcus@overhagen.de 10 * Clemens Zeidler, czeidler@gmx.de 11 * John Scipione, jscipione@gmail.com 12 */ 13 14 15 /*! PS/2 mouse device driver 16 17 A PS/2 mouse is connected to the IBM 8042 controller, and gets its 18 name from the IBM PS/2 personal computer, which was the first to 19 use this device. All resources are shared between the keyboard, and 20 the mouse, referred to as the "Auxiliary Device". 21 22 I/O: 23 ~~~ 24 The controller has 3 I/O registers: 25 1. Status (input), mapped to port 64h 26 2. Control (output), mapped to port 64h 27 3. Data (input/output), mapped to port 60h 28 29 Data: 30 ~~~~ 31 A packet read from the mouse data port is composed of 32 three bytes: 33 byte 0: status byte, where 34 - bit 7: Y overflow (1 = true) 35 - bit 6: X overflow (1 = true) 36 - bit 5: MSB of Y offset 37 - bit 4: MSB of X offset 38 - bit 3: Syncronization bit (always 1) 39 - bit 2: Middle button (1 = down) 40 - bit 1: Right button (1 = down) 41 - bit 0: Left button (1 = down) 42 byte 1: X position change, since last probed (-127 to +127) 43 byte 2: Y position change, since last probed (-127 to +127) 44 45 Intellimouse mice send a four byte packet, where the first three 46 bytes are the same as standard mice, and the last one reports the 47 Z position, which is, usually, the wheel movement. 48 49 Interrupts: 50 ~~~~~~~~~~ 51 The PS/2 mouse device is connected to interrupt 12. 52 The controller uses 3 consecutive interrupts to inform the computer 53 that it has new data. On the first the data register holds the status 54 byte, on the second the X offset, and on the 3rd the Y offset. 55 */ 56 57 58 #include <stdlib.h> 59 #include <string.h> 60 61 #include <keyboard_mouse_driver.h> 62 63 #include "ps2_service.h" 64 #include "ps2_standard_mouse.h" 65 66 67 const char* kStandardMousePath[4] = { 68 "input/mouse/ps2/standard_0", 69 "input/mouse/ps2/standard_1", 70 "input/mouse/ps2/standard_2", 71 "input/mouse/ps2/standard_3" 72 }; 73 74 const char* kIntelliMousePath[4] = { 75 "input/mouse/ps2/intelli_0", 76 "input/mouse/ps2/intelli_1", 77 "input/mouse/ps2/intelli_2", 78 "input/mouse/ps2/intelli_3" 79 }; 80 81 82 //! Set sampling rate of the ps2 port. 83 static inline status_t 84 ps2_set_sample_rate(ps2_dev* dev, uint8 rate) 85 { 86 return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &rate, 1, NULL, 0); 87 } 88 89 90 //! Converts a packet received by the mouse to a "movement". 91 static void 92 ps2_packet_to_movement(standard_mouse_cookie* cookie, uint8 packet[], 93 mouse_movement* pos) 94 { 95 int buttons = packet[0] & 7; 96 int xDelta = ((packet[0] & 0x10) ? ~0xff : 0) | packet[1]; 97 int yDelta = ((packet[0] & 0x20) ? ~0xff : 0) | packet[2]; 98 int xDeltaWheel = 0; 99 int yDeltaWheel = 0; 100 bigtime_t currentTime = system_time(); 101 102 if (buttons != 0 && cookie->buttons_state == 0) { 103 if (cookie->click_last_time + cookie->click_speed > currentTime) 104 cookie->click_count++; 105 else 106 cookie->click_count = 1; 107 108 cookie->click_last_time = currentTime; 109 } 110 111 cookie->buttons_state = buttons; 112 113 if (cookie->flags & F_MOUSE_TYPE_INTELLIMOUSE) { 114 yDeltaWheel = packet[3] & 0x07; 115 if (packet[3] & 0x08) 116 yDeltaWheel |= ~0x07; 117 } 118 #if 0 119 if (cookie->flags & F_MOUSE_TYPE_2WHEELS) { 120 switch (packet[3] & 0x0F) { 121 case 0x01: yDeltaWheel = +1; break; // wheel 1 down 122 case 0x0F: yDeltaWheel = -1; break; // wheel 1 up 123 case 0x02: xDeltaWheel = +1; break; // wheel 2 down 124 case 0x0E: xDeltaWheel = -1; break; // wheel 2 up 125 } 126 } 127 #endif 128 129 #if 0 130 TRACE("packet: %02x %02x %02x %02x: xd %d, yd %d, 0x%x (%d), w-xd %d, " 131 "w-yd %d\n", packet[0], packet[1], packet[2], packet[3], 132 xDelta, yDelta, buttons, cookie->click_count, xDeltaWheel, 133 yDeltaWheel); 134 #endif 135 136 if (pos != NULL) { 137 pos->xdelta = xDelta; 138 pos->ydelta = yDelta; 139 pos->buttons = buttons; 140 pos->clicks = cookie->click_count; 141 pos->modifiers = 0; 142 pos->timestamp = currentTime; 143 pos->wheel_ydelta = yDeltaWheel; 144 pos->wheel_xdelta = xDeltaWheel; 145 146 TRACE("ps2: ps2_packet_to_movement xdelta: %d, ydelta: %d, buttons %x, " 147 "clicks: %d, timestamp %Ld\n", 148 xDelta, yDelta, buttons, cookie->click_count, currentTime); 149 } 150 } 151 152 153 //! Read a mouse event from the mouse events chain buffer. 154 static status_t 155 standard_mouse_read_event(standard_mouse_cookie* cookie, 156 mouse_movement* movement) 157 { 158 uint8 packet[PS2_MAX_PACKET_SIZE]; 159 status_t status; 160 161 TRACE("ps2: standard_mouse_read_event\n"); 162 163 status = acquire_sem_etc(cookie->standard_mouse_sem, 1, B_CAN_INTERRUPT, 0); 164 TRACE("ps2: standard_mouse_read_event acquired\n"); 165 if (status < B_OK) 166 return status; 167 168 if (!cookie->dev->active) { 169 TRACE("ps2: standard_mouse_read_event: Error device no longer " 170 "active\n"); 171 return B_ERROR; 172 } 173 174 if (packet_buffer_read(cookie->standard_mouse_buffer, packet, 175 cookie->dev->packet_size) != cookie->dev->packet_size) { 176 TRACE("ps2: error copying buffer\n"); 177 return B_ERROR; 178 } 179 180 if (!(packet[0] & 8)) 181 panic("ps2: got broken data from packet_buffer_read\n"); 182 183 ps2_packet_to_movement(cookie, packet, movement); 184 return B_OK; 185 } 186 187 188 // #pragma mark - Interrupt handler functions 189 190 191 void 192 standard_mouse_disconnect(ps2_dev* dev) 193 { 194 // the mouse device might not be opened at this point 195 INFO("ps2: ps2_standard_mouse_disconnect %s\n", dev->name); 196 if (dev->flags & PS2_FLAG_OPEN) 197 release_sem(((standard_mouse_cookie*)dev->cookie)->standard_mouse_sem); 198 } 199 200 201 /*! Interrupt handler for the mouse device. Called whenever the I/O 202 controller generates an interrupt for the PS/2 mouse. Reads mouse 203 information from the data port, and stores it, so it can be accessed 204 by read() operations. The full data is obtained using 3 consecutive 205 calls to the handler, each holds a different byte on the data port. 206 */ 207 int32 208 standard_mouse_handle_int(ps2_dev* dev) 209 { 210 standard_mouse_cookie* cookie = (standard_mouse_cookie*)dev->cookie; 211 const uint8 data = dev->history[0].data; 212 213 TRACE("ps2: standard mouse: %1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\n", 214 data >> 7 & 1, data >> 6 & 1, data >> 5 & 1, 215 data >> 4 & 1, data >> 3 & 1, data >> 2 & 1, 216 data >> 1 & 1, data >> 0 & 1); 217 218 if (cookie->packet_index == 0 && (data & 8) == 0) { 219 INFO("ps2: bad mouse data, trying resync\n"); 220 return B_HANDLED_INTERRUPT; 221 } 222 223 // Workarounds for active multiplexing keyboard controllers 224 // that lose data or send them to the wrong port. 225 if (cookie->packet_index == 0 && (data & 0xc0) != 0) { 226 INFO("ps2: strange mouse data, x/y overflow, trying resync\n"); 227 return B_HANDLED_INTERRUPT; 228 } 229 230 if (cookie->packet_index == 1) { 231 int xDelta 232 = ((cookie->buffer[0] & 0x10) ? 0xFFFFFF00 : 0) | data; 233 if (xDelta < -100 || xDelta > 100) { 234 INFO("ps2: strange mouse data, x-delta %d, trying resync\n", 235 xDelta); 236 cookie->packet_index = 0; 237 return B_HANDLED_INTERRUPT; 238 } 239 } 240 if (cookie->packet_index == 2) { 241 int yDelta 242 = ((cookie->buffer[0] & 0x20) ? 0xFFFFFF00 : 0) | data; 243 if (yDelta < -100 || yDelta > 100) { 244 INFO("ps2: strange mouse data, y-delta %d, trying resync\n", 245 yDelta); 246 cookie->packet_index = 0; 247 return B_HANDLED_INTERRUPT; 248 } 249 } 250 251 cookie->buffer[cookie->packet_index++] = data; 252 253 if (cookie->packet_index != dev->packet_size) { 254 // packet not yet complete 255 return B_HANDLED_INTERRUPT; 256 } 257 258 // complete packet is assembled 259 260 cookie->packet_index = 0; 261 if (packet_buffer_write(cookie->standard_mouse_buffer, 262 cookie->buffer, dev->packet_size) != dev->packet_size) { 263 // buffer is full, drop new data 264 return B_HANDLED_INTERRUPT; 265 } 266 267 release_sem_etc(cookie->standard_mouse_sem, 1, B_DO_NOT_RESCHEDULE); 268 269 return B_INVOKE_SCHEDULER; 270 } 271 272 273 // #pragma mark - probe_standard_mouse() 274 275 276 status_t 277 probe_standard_mouse(ps2_dev* dev) 278 { 279 status_t status; 280 uint8 deviceId = 0; 281 282 // get device id 283 status = ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, 284 &deviceId, 1); 285 if (status != B_OK) { 286 INFO("ps2: probe_mouse get device id failed\n"); 287 return B_ERROR; 288 } 289 290 TRACE("ps2: probe_mouse device id: %2x\n", deviceId); 291 292 // check for MS Intellimouse 293 if (deviceId == 0) { 294 uint8 alternate_device_id; 295 status = ps2_set_sample_rate(dev, 200); 296 status |= ps2_set_sample_rate(dev, 100); 297 status |= ps2_set_sample_rate(dev, 80); 298 status |= ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, 299 &alternate_device_id, 1); 300 if (status == 0) { 301 TRACE("ps2: probe_mouse alternate device id: %2x\n", 302 alternate_device_id); 303 deviceId = alternate_device_id; 304 } 305 } 306 307 if (deviceId == PS2_DEV_ID_STANDARD 308 || deviceId == PS2_DEV_ID_TOUCHPAD_RICATECH) { 309 INFO("ps2: probe_mouse Standard PS/2 mouse found\n"); 310 dev->name = kStandardMousePath[dev->idx]; 311 dev->packet_size = PS2_PACKET_STANDARD; 312 } else if (deviceId == PS2_DEV_ID_INTELLIMOUSE) { 313 dev->name = kIntelliMousePath[dev->idx]; 314 dev->packet_size = PS2_PACKET_INTELLIMOUSE; 315 INFO("ps2: probe_mouse Extended PS/2 mouse found\n"); 316 } else { 317 INFO("ps2: probe_mouse Error unknown device id.\n"); 318 return B_ERROR; 319 } 320 321 return B_OK; 322 } 323 324 325 // #pragma mark - Device functions 326 327 328 status_t 329 standard_mouse_open(const char* name, uint32 flags, void** _cookie) 330 { 331 standard_mouse_cookie* cookie; 332 status_t status; 333 ps2_dev* dev = NULL; 334 int i; 335 336 TRACE("ps2: standard_mouse_open %s\n", name); 337 338 for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) { 339 if (0 == strcmp(ps2_device[i].name, name)) { 340 dev = &ps2_device[i]; 341 break; 342 } 343 #if 0 344 if (0 == strcmp(g_passthrough_dev.name, name)) { 345 dev = &g_passthrough_dev; 346 isSynapticsPTDevice = true; 347 break; 348 } 349 #endif 350 } 351 352 if (dev == NULL) { 353 TRACE("ps2: dev = NULL\n"); 354 return B_ERROR; 355 } 356 357 if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN) 358 return B_BUSY; 359 360 cookie = (standard_mouse_cookie*)malloc(sizeof(standard_mouse_cookie)); 361 if (cookie == NULL) 362 goto err1; 363 364 *_cookie = cookie; 365 memset(cookie, 0, sizeof(*cookie)); 366 367 cookie->dev = dev; 368 dev->cookie = cookie; 369 dev->disconnect = &standard_mouse_disconnect; 370 dev->handle_int = &standard_mouse_handle_int; 371 372 if (strstr(dev->name, "standard") != NULL) 373 cookie->flags = F_MOUSE_TYPE_STANDARD; 374 375 if (strstr(dev->name, "intelli") != NULL) 376 cookie->flags = F_MOUSE_TYPE_INTELLIMOUSE; 377 378 cookie->standard_mouse_buffer 379 = create_packet_buffer(MOUSE_HISTORY_SIZE * dev->packet_size); 380 if (cookie->standard_mouse_buffer == NULL) { 381 TRACE("ps2: can't allocate mouse actions buffer\n"); 382 goto err2; 383 } 384 385 // create the mouse semaphore, used for synchronization between 386 // the interrupt handler and the read operation 387 cookie->standard_mouse_sem = create_sem(0, "ps2_standard_mouse_sem"); 388 if (cookie->standard_mouse_sem < 0) { 389 TRACE("ps2: failed creating PS/2 mouse semaphore!\n"); 390 goto err3; 391 } 392 393 status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); 394 if (status < B_OK) { 395 INFO("ps2: cannot enable mouse %s\n", name); 396 goto err4; 397 } 398 399 atomic_or(&dev->flags, PS2_FLAG_ENABLED); 400 401 402 TRACE("ps2: standard_mouse_open %s success\n", name); 403 return B_OK; 404 405 err4: 406 delete_sem(cookie->standard_mouse_sem); 407 err3: 408 delete_packet_buffer(cookie->standard_mouse_buffer); 409 err2: 410 free(cookie); 411 err1: 412 atomic_and(&dev->flags, ~PS2_FLAG_OPEN); 413 414 TRACE("ps2: standard_mouse_open %s failed\n", name); 415 return B_ERROR; 416 } 417 418 419 status_t 420 standard_mouse_close(void* _cookie) 421 { 422 standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie; 423 424 TRACE("ps2: standard_mouse_close %s enter\n", cookie->dev->name); 425 426 ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0, 427 150000); 428 429 delete_packet_buffer(cookie->standard_mouse_buffer); 430 delete_sem(cookie->standard_mouse_sem); 431 432 atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN); 433 atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED); 434 435 TRACE("ps2: standard_mouse_close %s done\n", cookie->dev->name); 436 return B_OK; 437 } 438 439 440 status_t 441 standard_mouse_freecookie(void* _cookie) 442 { 443 standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie; 444 free(cookie); 445 return B_OK; 446 } 447 448 449 static status_t 450 standard_mouse_read(void* cookie, off_t pos, void* buffer, size_t* _length) 451 { 452 *_length = 0; 453 return B_NOT_ALLOWED; 454 } 455 456 457 static status_t 458 standard_mouse_write(void* cookie, off_t pos, const void* buffer, 459 size_t* _length) 460 { 461 *_length = 0; 462 return B_NOT_ALLOWED; 463 } 464 465 466 status_t 467 standard_mouse_ioctl(void* _cookie, uint32 op, void* buffer, size_t length) 468 { 469 standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie; 470 471 switch (op) { 472 case MS_NUM_EVENTS: 473 { 474 int32 count; 475 TRACE("ps2: ioctl MS_NUM_EVENTS\n"); 476 get_sem_count(cookie->standard_mouse_sem, &count); 477 return count; 478 } 479 480 case MS_READ: 481 { 482 mouse_movement movement; 483 status_t status; 484 TRACE("ps2: ioctl MS_READ\n"); 485 if ((status = standard_mouse_read_event(cookie, &movement)) < B_OK) 486 return status; 487 // TRACE("%s %d %d %d %d\n", cookie->dev->name, 488 // movement.xdelta, movement.ydelta, movement.buttons, 489 // movement.clicks); 490 return user_memcpy(buffer, &movement, sizeof(movement)); 491 } 492 493 case MS_SET_TYPE: 494 TRACE("ps2: ioctl MS_SET_TYPE not implemented\n"); 495 return B_BAD_VALUE; 496 497 case MS_SET_MAP: 498 TRACE("ps2: ioctl MS_SET_MAP (set mouse mapping) not " 499 "implemented\n"); 500 return B_BAD_VALUE; 501 502 case MS_GET_ACCEL: 503 TRACE("ps2: ioctl MS_GET_ACCEL (get mouse acceleration) not " 504 "implemented\n"); 505 return B_BAD_VALUE; 506 507 case MS_SET_ACCEL: 508 TRACE("ps2: ioctl MS_SET_ACCEL (set mouse acceleration) not " 509 "implemented\n"); 510 return B_BAD_VALUE; 511 512 case MS_SET_CLICKSPEED: 513 TRACE("ps2: ioctl MS_SETCLICK (set click speed)\n"); 514 return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t)); 515 516 default: 517 TRACE("ps2: ioctl unknown mouse opcode: %ld\n", op); 518 return B_DEV_INVALID_IOCTL; 519 } 520 } 521 522 523 device_hooks gStandardMouseDeviceHooks = { 524 standard_mouse_open, 525 standard_mouse_close, 526 standard_mouse_freecookie, 527 standard_mouse_ioctl, 528 standard_mouse_read, 529 standard_mouse_write, 530 }; 531