119370Spst/* 219370Spst * Copyright 2001-2014 Haiku, Inc. All rights reserved. 3130803Smarcel * Distributed under the terms of the MIT License. 4130803Smarcel * 5130803Smarcel * Authors (in chronological order): 6130803Smarcel * Elad Lahav, elad@eldarshany.com 798944Sobrien * Stefano Ceccherini, burton666@libero.it 819370Spst * Axel D��rfler, axeld@pinc-software.de 998944Sobrien * Marcus Overhagen, marcus@overhagen.de 1098944Sobrien * Clemens Zeidler, czeidler@gmx.de 1198944Sobrien * John Scipione, jscipione@gmail.com 1298944Sobrien */ 1319370Spst 1498944Sobrien 1598944Sobrien/*! PS/2 mouse device driver 1698944Sobrien 1798944Sobrien A PS/2 mouse is connected to the IBM 8042 controller, and gets its 1819370Spst name from the IBM PS/2 personal computer, which was the first to 1998944Sobrien use this device. All resources are shared between the keyboard, and 2098944Sobrien the mouse, referred to as the "Auxiliary Device". 2198944Sobrien 2298944Sobrien I/O: 2319370Spst ~~~ 2419370Spst The controller has 3 I/O registers: 2519370Spst 1. Status (input), mapped to port 64h 2619370Spst 2. Control (output), mapped to port 64h 2719370Spst 3. Data (input/output), mapped to port 60h 2819370Spst 2919370Spst Data: 3019370Spst ~~~~ 3119370Spst A packet read from the mouse data port is composed of 3219370Spst three bytes: 3319370Spst byte 0: status byte, where 3446283Sdfr - bit 7: Y overflow (1 = true) 3598944Sobrien - bit 6: X overflow (1 = true) 3698944Sobrien - bit 5: MSB of Y offset 3719370Spst - bit 4: MSB of X offset 3819370Spst - bit 3: Syncronization bit (always 1) 3919370Spst - bit 2: Middle button (1 = down) 4019370Spst - bit 1: Right button (1 = down) 4119370Spst - bit 0: Left button (1 = down) 4298944Sobrien byte 1: X position change, since last probed (-127 to +127) 4398944Sobrien byte 2: Y position change, since last probed (-127 to +127) 4419370Spst 4598944Sobrien Intellimouse mice send a four byte packet, where the first three 4619370Spst bytes are the same as standard mice, and the last one reports the 4798944Sobrien Z position, which is, usually, the wheel movement. 4819370Spst 4998944Sobrien Interrupts: 5019370Spst ~~~~~~~~~~ 5198944Sobrien The PS/2 mouse device is connected to interrupt 12. 5219370Spst The controller uses 3 consecutive interrupts to inform the computer 5398944Sobrien that it has new data. On the first the data register holds the status 5419370Spst byte, on the second the X offset, and on the 3rd the Y offset. 5598944Sobrien*/ 5619370Spst 5798944Sobrien 5819370Spst#include <stdlib.h> 5998944Sobrien#include <string.h> 6046283Sdfr 6198944Sobrien#include <keyboard_mouse_driver.h> 6298944Sobrien 6319370Spst#include "ps2_service.h" 6419370Spst#include "ps2_standard_mouse.h" 6519370Spst 6619370Spst 6719370Spst//#define TRACE_PS2_MOUSE 6819370Spst#ifdef TRACE_PS2_MOUSE 6919370Spst# define TRACE(x...) dprintf(x) 7019370Spst#else 7119370Spst# define TRACE(x...) 7219370Spst#endif 7319370Spst 7419370Spst 7519370Spstconst char* kStandardMousePath[4] = { 7619370Spst "input/mouse/ps2/standard_0", 7719370Spst "input/mouse/ps2/standard_1", 7819370Spst "input/mouse/ps2/standard_2", 7919370Spst "input/mouse/ps2/standard_3" 8019370Spst}; 8119370Spst 8219370Spstconst char* kIntelliMousePath[4] = { 8319370Spst "input/mouse/ps2/intelli_0", 8419370Spst "input/mouse/ps2/intelli_1", 8519370Spst "input/mouse/ps2/intelli_2", 8619370Spst "input/mouse/ps2/intelli_3" 8719370Spst}; 8819370Spst 8919370Spst 9019370Spst//! Set sampling rate of the ps2 port. 9119370Spststatic inline status_t 9219370Spstps2_set_sample_rate(ps2_dev* dev, uint8 rate) 9319370Spst{ 9419370Spst return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &rate, 1, NULL, 0); 9519370Spst} 9619370Spst 9719370Spst 9819370Spst//! Converts a packet received by the mouse to a "movement". 9919370Spststatic void 10019370Spstps2_packet_to_movement(standard_mouse_cookie* cookie, uint8 packet[], 10119370Spst mouse_movement* pos) 10219370Spst{ 10398944Sobrien int buttons = packet[0] & 7; 10419370Spst int xDelta = ((packet[0] & 0x10) ? ~0xff : 0) | packet[1]; 10519370Spst int yDelta = ((packet[0] & 0x20) ? ~0xff : 0) | packet[2]; 10619370Spst int xDeltaWheel = 0; 10719370Spst int yDeltaWheel = 0; 10819370Spst bigtime_t currentTime = system_time(); 10919370Spst 11019370Spst if (buttons != 0 && cookie->buttons_state == 0) { 11119370Spst if (cookie->click_last_time + cookie->click_speed > currentTime) 11219370Spst cookie->click_count++; 11319370Spst else 11419370Spst cookie->click_count = 1; 11519370Spst 11619370Spst cookie->click_last_time = currentTime; 11719370Spst } 11819370Spst 11919370Spst cookie->buttons_state = buttons; 12019370Spst 12119370Spst if (cookie->flags & F_MOUSE_TYPE_INTELLIMOUSE) { 12219370Spst yDeltaWheel = packet[3] & 0x07; 12319370Spst if (packet[3] & 0x08) 12419370Spst yDeltaWheel |= ~0x07; 12519370Spst } 12698944Sobrien#if 0 12798944Sobrien if (cookie->flags & F_MOUSE_TYPE_2WHEELS) { 12898944Sobrien switch (packet[3] & 0x0F) { 12919370Spst case 0x01: yDeltaWheel = +1; break; // wheel 1 down 13019370Spst case 0x0F: yDeltaWheel = -1; break; // wheel 1 up 13119370Spst case 0x02: xDeltaWheel = +1; break; // wheel 2 down 13219370Spst case 0x0E: xDeltaWheel = -1; break; // wheel 2 up 13319370Spst } 13419370Spst } 13598944Sobrien#endif 13619370Spst 13719370Spst#if 0 13819370Spst TRACE("packet: %02x %02x %02x %02x: xd %d, yd %d, 0x%x (%d), w-xd %d, " 13919370Spst "w-yd %d\n", packet[0], packet[1], packet[2], packet[3], 14019370Spst xDelta, yDelta, buttons, cookie->click_count, xDeltaWheel, 14119370Spst yDeltaWheel); 14298944Sobrien#endif 14319370Spst 14419370Spst if (pos != NULL) { 14519370Spst pos->xdelta = xDelta; 14619370Spst pos->ydelta = yDelta; 14719370Spst pos->buttons = buttons; 14898944Sobrien pos->clicks = cookie->click_count; 14946283Sdfr pos->modifiers = 0; 15098944Sobrien pos->timestamp = currentTime; 15119370Spst pos->wheel_ydelta = yDeltaWheel; 15219370Spst pos->wheel_xdelta = xDeltaWheel; 153242936Semaste 154242936Semaste TRACE("ps2: ps2_packet_to_movement xdelta: %d, ydelta: %d, buttons %x, " 155242936Semaste "clicks: %d, timestamp %" B_PRIdBIGTIME "\n", 15619370Spst xDelta, yDelta, buttons, cookie->click_count, currentTime); 157242936Semaste } 158242936Semaste} 15919370Spst 16019370Spst 16119370Spst//! Read a mouse event from the mouse events chain buffer. 162242936Semastestatic status_t 16319370Spststandard_mouse_read_event(standard_mouse_cookie* cookie, 16419370Spst mouse_movement* movement) 165242936Semaste{ 16619370Spst uint8 packet[PS2_MAX_PACKET_SIZE]; 16719370Spst status_t status; 168242936Semaste 16919370Spst TRACE("ps2: standard_mouse_read_event\n"); 17019370Spst 171242936Semaste status = acquire_sem_etc(cookie->standard_mouse_sem, 1, B_CAN_INTERRUPT, 0); 172242936Semaste TRACE("ps2: standard_mouse_read_event acquired\n"); 173242936Semaste if (status < B_OK) 174242936Semaste return status; 175242936Semaste 176242936Semaste if (!cookie->dev->active) { 177242936Semaste TRACE("ps2: standard_mouse_read_event: Error device no longer " 178242936Semaste "active\n"); 179242936Semaste return B_ERROR; 180242936Semaste } 181242936Semaste 182242936Semaste if (packet_buffer_read(cookie->standard_mouse_buffer, packet, 183242936Semaste cookie->dev->packet_size) != cookie->dev->packet_size) { 184242936Semaste TRACE("ps2: error copying buffer\n"); 185242936Semaste return B_ERROR; 186242936Semaste } 187242936Semaste 188242936Semaste if (!(packet[0] & 8)) 189242936Semaste panic("ps2: got broken data from packet_buffer_read\n"); 190242936Semaste 191242936Semaste ps2_packet_to_movement(cookie, packet, movement); 192242936Semaste return B_OK; 193242936Semaste} 194242936Semaste 195242936Semaste 196242936Semaste// #pragma mark - Interrupt handler functions 197242936Semaste 198242936Semaste 199242936Semastevoid 200242936Semastestandard_mouse_disconnect(ps2_dev* dev) 201242936Semaste{ 202242936Semaste // the mouse device might not be opened at this point 203242936Semaste INFO("ps2: ps2_standard_mouse_disconnect %s\n", dev->name); 204242936Semaste if (dev->flags & PS2_FLAG_OPEN) 205242936Semaste release_sem(((standard_mouse_cookie*)dev->cookie)->standard_mouse_sem); 206242936Semaste} 207242936Semaste 208242936Semaste 209242936Semaste/*! Interrupt handler for the mouse device. Called whenever the I/O 210242936Semaste controller generates an interrupt for the PS/2 mouse. Reads mouse 211242936Semaste information from the data port, and stores it, so it can be accessed 212242936Semaste by read() operations. The full data is obtained using 3 consecutive 21319370Spst calls to the handler, each holds a different byte on the data port. 21419370Spst*/ 21519370Spstint32 21619370Spststandard_mouse_handle_int(ps2_dev* dev) 21719370Spst{ 21819370Spst standard_mouse_cookie* cookie = (standard_mouse_cookie*)dev->cookie; 21919370Spst const uint8 data = dev->history[0].data; 22019370Spst 22198944Sobrien TRACE("ps2: standard mouse: %1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\n", 22298944Sobrien data >> 7 & 1, data >> 6 & 1, data >> 5 & 1, 22319370Spst data >> 4 & 1, data >> 3 & 1, data >> 2 & 1, 22419370Spst data >> 1 & 1, data >> 0 & 1); 22519370Spst 22619370Spst if (cookie->packet_index == 0 && (data & 8) == 0) { 22719370Spst INFO("ps2: bad mouse data, trying resync\n"); 22819370Spst return B_HANDLED_INTERRUPT; 22919370Spst } 23019370Spst 23119370Spst // Workarounds for active multiplexing keyboard controllers 23219370Spst // that lose data or send them to the wrong port. 23319370Spst if (cookie->packet_index == 0 && (data & 0xc0) != 0) { 23419370Spst INFO("ps2: strange mouse data, x/y overflow, trying resync\n"); 23519370Spst return B_HANDLED_INTERRUPT; 23619370Spst } 23719370Spst 23819370Spst cookie->buffer[cookie->packet_index++] = data; 23919370Spst 24019370Spst if (cookie->packet_index != dev->packet_size) { 24119370Spst // packet not yet complete 24219370Spst return B_HANDLED_INTERRUPT; 24319370Spst } 24419370Spst 24519370Spst // complete packet is assembled 24619370Spst 24719370Spst cookie->packet_index = 0; 24819370Spst if (packet_buffer_write(cookie->standard_mouse_buffer, 24919370Spst cookie->buffer, dev->packet_size) != dev->packet_size) { 25019370Spst // buffer is full, drop new data 25119370Spst return B_HANDLED_INTERRUPT; 25246283Sdfr } 25346283Sdfr 25446283Sdfr release_sem_etc(cookie->standard_mouse_sem, 1, B_DO_NOT_RESCHEDULE); 25546283Sdfr 25646283Sdfr return B_INVOKE_SCHEDULER; 25746283Sdfr} 25819370Spst 25946283Sdfr 26046283Sdfr// #pragma mark - probe_standard_mouse() 26146283Sdfr 26246283Sdfr 26398944Sobrienstatus_t 26446283Sdfrprobe_standard_mouse(ps2_dev* dev) 26546283Sdfr{ 26698944Sobrien status_t status; 26798944Sobrien uint8 deviceId = 0; 26846283Sdfr 26998944Sobrien // get device id 27098944Sobrien status = ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, 27146283Sdfr &deviceId, 1); 27246283Sdfr if (status != B_OK) { 27346283Sdfr INFO("ps2: probe_mouse get device id failed\n"); 27446283Sdfr return B_ERROR; 27546283Sdfr } 27646283Sdfr 27746283Sdfr TRACE("ps2: probe_mouse device id: %2x\n", deviceId); 27846283Sdfr 27946283Sdfr // check for MS Intellimouse 28046283Sdfr if (deviceId == 0) { 28146283Sdfr uint8 alternate_device_id; 28246283Sdfr status = ps2_set_sample_rate(dev, 200); 28346283Sdfr status |= ps2_set_sample_rate(dev, 100); 28446283Sdfr status |= ps2_set_sample_rate(dev, 80); 28546283Sdfr status |= ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, 28646283Sdfr &alternate_device_id, 1); 28746283Sdfr if (status == 0) { 28846283Sdfr TRACE("ps2: probe_mouse alternate device id: %2x\n", 28946283Sdfr alternate_device_id); 29046283Sdfr deviceId = alternate_device_id; 29146283Sdfr } 29246283Sdfr } 29346283Sdfr 29446283Sdfr if (deviceId == PS2_DEV_ID_STANDARD 29546283Sdfr || deviceId == PS2_DEV_ID_TOUCHPAD_RICATECH) { 29698944Sobrien INFO("ps2: probe_mouse Standard PS/2 mouse found\n"); 29746283Sdfr dev->name = kStandardMousePath[dev->idx]; 29846283Sdfr dev->packet_size = PS2_PACKET_STANDARD; 29946283Sdfr } else if (deviceId == PS2_DEV_ID_INTELLIMOUSE) { 30046283Sdfr dev->name = kIntelliMousePath[dev->idx]; 30146283Sdfr dev->packet_size = PS2_PACKET_INTELLIMOUSE; 30219370Spst INFO("ps2: probe_mouse Extended PS/2 mouse found\n"); 30398944Sobrien } else { 30498944Sobrien INFO("ps2: probe_mouse Error unknown device id.\n"); 30519370Spst return B_ERROR; 30619370Spst } 30746283Sdfr 30819370Spst return B_OK; 30946283Sdfr} 31046283Sdfr 31146283Sdfr 31246283Sdfr// #pragma mark - Device functions 31346283Sdfr 31446283Sdfr 31546283Sdfrstatus_t 31646283Sdfrstandard_mouse_open(const char* name, uint32 flags, void** _cookie) 31746283Sdfr{ 31846283Sdfr standard_mouse_cookie* cookie; 31946283Sdfr status_t status; 32046283Sdfr ps2_dev* dev = NULL; 32146283Sdfr int i; 32246283Sdfr 32346283Sdfr TRACE("ps2: standard_mouse_open %s\n", name); 32446283Sdfr 32546283Sdfr for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) { 32646283Sdfr if (0 == strcmp(ps2_device[i].name, name)) { 32746283Sdfr dev = &ps2_device[i]; 32846283Sdfr break; 32946283Sdfr } 33046283Sdfr#if 0 33146283Sdfr if (0 == strcmp(g_passthrough_dev.name, name)) { 33246283Sdfr dev = &g_passthrough_dev; 33346283Sdfr isSynapticsPTDevice = true; 33446283Sdfr break; 33546283Sdfr } 33646283Sdfr#endif 33746283Sdfr } 33846283Sdfr 33946283Sdfr if (dev == NULL) { 34046283Sdfr TRACE("ps2: dev = NULL\n"); 34146283Sdfr return B_ERROR; 34246283Sdfr } 34346283Sdfr 34446283Sdfr if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN) 34546283Sdfr return B_BUSY; 34646283Sdfr 34746283Sdfr cookie = (standard_mouse_cookie*)malloc(sizeof(standard_mouse_cookie)); 34846283Sdfr if (cookie == NULL) 34946283Sdfr goto err1; 35046283Sdfr 35146283Sdfr *_cookie = cookie; 35246283Sdfr memset(cookie, 0, sizeof(*cookie)); 35346283Sdfr 35446283Sdfr cookie->dev = dev; 35546283Sdfr dev->cookie = cookie; 35646283Sdfr dev->disconnect = &standard_mouse_disconnect; 35746283Sdfr dev->handle_int = &standard_mouse_handle_int; 35846283Sdfr 35919370Spst if (strstr(dev->name, "standard") != NULL) 36019370Spst cookie->flags = F_MOUSE_TYPE_STANDARD; 36119370Spst 36246283Sdfr if (strstr(dev->name, "intelli") != NULL) 36319370Spst cookie->flags = F_MOUSE_TYPE_INTELLIMOUSE; 36419370Spst 36519370Spst cookie->standard_mouse_buffer 36619370Spst = create_packet_buffer(MOUSE_HISTORY_SIZE * dev->packet_size); 36719370Spst if (cookie->standard_mouse_buffer == NULL) { 36898944Sobrien TRACE("ps2: can't allocate mouse actions buffer\n"); 369130803Smarcel goto err2; 37019370Spst } 37119370Spst 372130803Smarcel // create the mouse semaphore, used for synchronization between 37319370Spst // the interrupt handler and the read operation 37419370Spst cookie->standard_mouse_sem = create_sem(0, "ps2_standard_mouse_sem"); 37519370Spst if (cookie->standard_mouse_sem < 0) { 37619370Spst TRACE("ps2: failed creating PS/2 mouse semaphore!\n"); 37798944Sobrien goto err3; 378130803Smarcel } 37919370Spst 38019370Spst status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); 38119370Spst if (status < B_OK) { 38219370Spst INFO("ps2: cannot enable mouse %s\n", name); 38398944Sobrien goto err4; 384130803Smarcel } 38519370Spst 38619370Spst atomic_or(&dev->flags, PS2_FLAG_ENABLED); 38719370Spst 38819370Spst 38919370Spst TRACE("ps2: standard_mouse_open %s success\n", name); 39019370Spst return B_OK; 39119370Spst 39219370Spsterr4: 39319370Spst delete_sem(cookie->standard_mouse_sem); 39419370Spsterr3: 39519370Spst delete_packet_buffer(cookie->standard_mouse_buffer); 39619370Spsterr2: 39719370Spst free(cookie); 39819370Spsterr1: 39998944Sobrien atomic_and(&dev->flags, ~PS2_FLAG_OPEN); 40019370Spst 40198944Sobrien TRACE("ps2: standard_mouse_open %s failed\n", name); 40219370Spst return B_ERROR; 40319370Spst} 40419370Spst 40519370Spst 40619370Spststatus_t 40719370Spststandard_mouse_close(void* _cookie) 40819370Spst{ 40919370Spst standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie; 41019370Spst 41198944Sobrien TRACE("ps2: standard_mouse_close %s enter\n", cookie->dev->name); 41219370Spst 41319370Spst ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0, 41419370Spst 150000); 41519370Spst 41619370Spst delete_packet_buffer(cookie->standard_mouse_buffer); 41719370Spst delete_sem(cookie->standard_mouse_sem); 41819370Spst 41919370Spst atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN); 42098944Sobrien atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED); 42146283Sdfr 42219370Spst TRACE("ps2: standard_mouse_close %s done\n", cookie->dev->name); 42319370Spst return B_OK; 42419370Spst} 42519370Spst 42698944Sobrien 42746283Sdfrstatus_t 42819370Spststandard_mouse_freecookie(void* _cookie) 42919370Spst{ 43019370Spst standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie; 43146283Sdfr free(cookie); 43219370Spst return B_OK; 43319370Spst} 43419370Spst 43546283Sdfr 43619370Spststatic status_t 43719370Spststandard_mouse_read(void* cookie, off_t pos, void* buffer, size_t* _length) 43819370Spst{ 43946283Sdfr *_length = 0; 44019370Spst return B_NOT_ALLOWED; 44119370Spst} 44219370Spst 44346283Sdfr 44419370Spststatic status_t 44519370Spststandard_mouse_write(void* cookie, off_t pos, const void* buffer, 44698944Sobrien size_t* _length) 44719370Spst{ 44846283Sdfr *_length = 0; 44946283Sdfr return B_NOT_ALLOWED; 45046283Sdfr} 45119370Spst 45219370Spst 45319370Spststatus_t 45419370Spststandard_mouse_ioctl(void* _cookie, uint32 op, void* buffer, size_t length) 45519370Spst{ 45619370Spst standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie; 45719370Spst 45898944Sobrien switch (op) { 45919370Spst case MS_NUM_EVENTS: 46046283Sdfr { 46146283Sdfr int32 count; 46219370Spst TRACE("ps2: ioctl MS_NUM_EVENTS\n"); 46346283Sdfr get_sem_count(cookie->standard_mouse_sem, &count); 46446283Sdfr return count; 46546283Sdfr } 46646283Sdfr 46746283Sdfr case MS_READ: 46846283Sdfr { 46946283Sdfr mouse_movement movement; 47046283Sdfr status_t status; 47146283Sdfr TRACE("ps2: ioctl MS_READ\n"); 47219370Spst if ((status = standard_mouse_read_event(cookie, &movement)) < B_OK) 47319370Spst return status; 47498944Sobrien// TRACE("%s %d %d %d %d\n", cookie->dev->name, 47598944Sobrien// movement.xdelta, movement.ydelta, movement.buttons, 47619370Spst// movement.clicks); 47719370Spst return user_memcpy(buffer, &movement, sizeof(movement)); 47898944Sobrien } 47919370Spst 48019370Spst case MS_SET_TYPE: 48119370Spst TRACE("ps2: ioctl MS_SET_TYPE not implemented\n"); 48298944Sobrien return B_BAD_VALUE; 48319370Spst 48419370Spst case MS_SET_MAP: 48598944Sobrien TRACE("ps2: ioctl MS_SET_MAP (set mouse mapping) not " 48698944Sobrien "implemented\n"); 48798944Sobrien return B_BAD_VALUE; 48898944Sobrien 48998944Sobrien case MS_GET_ACCEL: 49098944Sobrien TRACE("ps2: ioctl MS_GET_ACCEL (get mouse acceleration) not " 49198944Sobrien "implemented\n"); 49298944Sobrien return B_BAD_VALUE; 493130803Smarcel 494130803Smarcel case MS_SET_ACCEL: 495130803Smarcel TRACE("ps2: ioctl MS_SET_ACCEL (set mouse acceleration) not " 49698944Sobrien "implemented\n"); 49798944Sobrien return B_BAD_VALUE; 49898944Sobrien 49919370Spst case MS_SET_CLICKSPEED: 50098944Sobrien TRACE("ps2: ioctl MS_SETCLICK (set click speed)\n"); 50198944Sobrien return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t)); 50298944Sobrien 50398944Sobrien default: 50498944Sobrien TRACE("ps2: ioctl unknown mouse opcode: %" B_PRIu32 "\n", op); 50598944Sobrien return B_DEV_INVALID_IOCTL; 50698944Sobrien } 50798944Sobrien} 50819370Spst 50919370Spst 51019370Spstdevice_hooks gStandardMouseDeviceHooks = { 51119370Spst standard_mouse_open, 51219370Spst standard_mouse_close, 51319370Spst standard_mouse_freecookie, 51419370Spst standard_mouse_ioctl, 51519370Spst standard_mouse_read, 51698944Sobrien standard_mouse_write, 51798944Sobrien}; 51898944Sobrien