From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- .../inputdrivers/serialmouse/serialmouse.c | 572 +++++++++++++++++++++ 1 file changed, 572 insertions(+) create mode 100755 Source/DirectFB/inputdrivers/serialmouse/serialmouse.c (limited to 'Source/DirectFB/inputdrivers/serialmouse/serialmouse.c') diff --git a/Source/DirectFB/inputdrivers/serialmouse/serialmouse.c b/Source/DirectFB/inputdrivers/serialmouse/serialmouse.c new file mode 100755 index 0000000..3aba563 --- /dev/null +++ b/Source/DirectFB/inputdrivers/serialmouse/serialmouse.c @@ -0,0 +1,572 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include + + +DFB_INPUT_DRIVER( serialmouse ) + +#define MIDDLE 0x08 + +typedef enum +{ + PROTOCOL_MS, /* two buttons MS protocol */ + PROTOCOL_MS3, /* MS with ugly 3-button extension */ + PROTOCOL_MOUSEMAN, /* referred to as MS + Logitech extension in mouse(4) */ + PROTOCOL_MOUSESYSTEMS, /* most commonly used serial mouse protocol nowadays */ + LAST_PROTOCOL +} MouseProtocol; + +static const char *protocol_names[LAST_PROTOCOL] = +{ + "MS", + "MS3", + "MouseMan", + "MouseSystems" +}; + +typedef struct { + CoreInputDevice *device; + DirectThread *thread; + + int fd; + + MouseProtocol protocol; + + DFBInputEvent x_motion; + DFBInputEvent y_motion; +} SerialMouseData; + +static inline void +mouse_motion_initialize( SerialMouseData *data ) +{ + data->x_motion.type = data->y_motion.type = DIET_AXISMOTION; + data->x_motion.axisrel = data->y_motion.axisrel = 0; + + data->x_motion.axis = DIAI_X; + data->y_motion.axis = DIAI_Y; +} + +static inline void +mouse_motion_compress( SerialMouseData *data, int dx, int dy ) +{ + data->x_motion.axisrel += dx; + data->y_motion.axisrel += dy; +} + +static inline void +mouse_motion_realize( SerialMouseData *data ) +{ + if (data->x_motion.axisrel) { + data->x_motion.flags = DIEF_AXISREL; + dfb_input_dispatch( data->device, &data->x_motion ); + data->x_motion.axisrel = 0; + } + + if (data->y_motion.axisrel) { + data->y_motion.flags = DIEF_AXISREL; + dfb_input_dispatch( data->device, &data->y_motion ); + data->y_motion.axisrel = 0; + } +} + + +static void +mouse_setspeed( SerialMouseData *data ) +{ + struct termios tty; + + tcgetattr (data->fd, &tty); + + tty.c_iflag = IGNBRK | IGNPAR; + tty.c_oflag = 0; + tty.c_lflag = 0; + tty.c_line = 0; + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 1; + tty.c_cflag = CREAD|CLOCAL|HUPCL|B1200; + tty.c_cflag |= ((data->protocol == PROTOCOL_MOUSESYSTEMS) ? + CS8|CSTOPB : CS7); + + tcsetattr (data->fd, TCSAFLUSH, &tty); + + write (data->fd, "*n", 2); +} + +/* the main routine for MS mice (plus extensions) */ +static void* +mouseEventThread_ms( DirectThread *thread, void *driver_data ) +{ + SerialMouseData *data = (SerialMouseData*) driver_data; + DFBInputEvent evt; + + unsigned char buf[256]; + unsigned char packet[4]; + unsigned char pos = 0; + unsigned char last_buttons = 0; + int dx, dy; + int buttons; + int readlen; + int i; + + mouse_motion_initialize( data ); + + /* Read data */ + while ((readlen = read( data->fd, buf, 256 )) >= 0 || errno == EINTR) { + + direct_thread_testcancel( thread ); + + for (i = 0; i < readlen; i++) { + + if (pos == 0 && !(buf[i] & 0x40)) + continue; + + /* We did not reset the position in the mouse event handler + since a forth byte may follow. We check for it now and + reset the position if this is a start byte. */ + if (pos == 3 && buf[i] & 0x40) + pos = 0; + + packet[pos++] = buf[i]; + + switch (pos) { + case 3: + if (data->protocol != PROTOCOL_MOUSEMAN) + pos = 0; + + buttons = packet[0] & 0x30; + dx = (signed char) + (((packet[0] & 0x03) << 6) | (packet[1] & 0x3f)); + dy = (signed char) + (((packet[0] & 0x0C) << 4) | (packet[2] & 0x3f)); + + mouse_motion_compress( data, dx, dy ); + + if (data->protocol == PROTOCOL_MS3) { + if (!dx && !dy && buttons == (last_buttons & ~MIDDLE)) + buttons = last_buttons ^ MIDDLE; /* toggle */ + else + buttons |= last_buttons & MIDDLE; /* preserve */ + } + + if (!dfb_config->mouse_motion_compression) + mouse_motion_realize( data ); + + if (last_buttons != buttons) { + unsigned char changed_buttons = last_buttons ^ buttons; + + /* make sure the compressed motion event is dispatched + before any button change */ + mouse_motion_realize( data ); + + if (changed_buttons & 0x20) { + evt.type = (buttons & 0x20) ? + DIET_BUTTONPRESS : DIET_BUTTONRELEASE; + evt.flags = DIEF_NONE; + evt.button = DIBI_LEFT; + dfb_input_dispatch( data->device, &evt ); + } + if (changed_buttons & 0x10) { + evt.type = (buttons & 0x10) ? + DIET_BUTTONPRESS : DIET_BUTTONRELEASE; + evt.flags = DIEF_NONE; + evt.button = DIBI_RIGHT; + dfb_input_dispatch( data->device, &evt ); + } + if (changed_buttons & MIDDLE) { + evt.type = (buttons & MIDDLE) ? + DIET_BUTTONPRESS : DIET_BUTTONRELEASE; + evt.flags = DIEF_NONE; + evt.button = DIBI_MIDDLE; + dfb_input_dispatch( data->device, &evt ); + } + + last_buttons = buttons; + } + break; + + case 4: + pos = 0; + + evt.type = (packet[3] & 0x20) ? + DIET_BUTTONPRESS : DIET_BUTTONRELEASE; + evt.flags = DIEF_NONE; /* button is always valid */ + evt.button = DIBI_MIDDLE; + dfb_input_dispatch( data->device, &evt ); + break; + + default: + break; + } + } + + /* make sure the compressed motion event is dispatched, + necessary if the last packet was a motion event */ + if (readlen > 0) + mouse_motion_realize( data ); + + direct_thread_testcancel( thread ); + } + + D_PERROR ("serial mouse thread died\n"); + + return NULL; +} + +/* the main routine for MouseSystems */ +static void* +mouseEventThread_mousesystems( DirectThread *thread, void *driver_data ) +{ + SerialMouseData *data = (SerialMouseData*) driver_data; + + unsigned char buf[256]; + unsigned char packet[5]; + unsigned char pos = 0; + unsigned char last_buttons = 0; + int i; + int readlen; + + mouse_motion_initialize( data ); + + /* Read data */ + while ((readlen = read( data->fd, buf, 256 )) >= 0 || errno == EINTR) { + + direct_thread_testcancel( thread ); + + for (i = 0; i < readlen; i++) { + + if (pos == 0 && (buf[i] & 0xf8) != 0x80) + continue; + + packet[pos++] = buf[i]; + + if (pos == 5) { + int dx, dy; + int buttons; + + pos = 0; + + buttons= (~packet[0]) & 0x07; + dx = (signed char) (packet[1]) + (signed char)(packet[3]); + dy = - ((signed char) (packet[2]) + (signed char)(packet[4])); + + mouse_motion_compress( data, dx, dy ); + + if (!dfb_config->mouse_motion_compression) + mouse_motion_realize( data ); + + if (last_buttons != buttons) { + DFBInputEvent evt; + unsigned char changed_buttons = last_buttons ^ buttons; + + /* make sure the compressed motion event is dispatched + before any button change */ + mouse_motion_realize( data ); + + if (changed_buttons & 0x04) { + evt.type = (buttons & 0x04) ? + DIET_BUTTONPRESS : DIET_BUTTONRELEASE; + evt.flags = DIEF_NONE; /* button is always valid */ + evt.button = DIBI_LEFT; + dfb_input_dispatch( data->device, &evt ); + } + if (changed_buttons & 0x01) { + evt.type = (buttons & 0x01) ? + DIET_BUTTONPRESS : DIET_BUTTONRELEASE; + evt.flags = DIEF_NONE; /* button is always valid */ + evt.button = DIBI_MIDDLE; + dfb_input_dispatch( data->device, &evt ); + } + if (changed_buttons & 0x02) { + evt.type = (buttons & 0x02) ? + DIET_BUTTONPRESS : DIET_BUTTONRELEASE; + evt.flags = DIEF_NONE; /* button is always valid */ + evt.button = DIBI_RIGHT; + dfb_input_dispatch( data->device, &evt ); + } + + last_buttons = buttons; + } + } + } + + /* make sure the compressed motion event is dispatched, + necessary if the last packet was a motion event */ + if (readlen > 0) + mouse_motion_realize( data ); + + direct_thread_testcancel( thread ); + } + + D_PERROR ("serial mouse thread died\n"); + + return NULL; +} + +static MouseProtocol mouse_get_protocol( void ) +{ + MouseProtocol protocol; + + if (!dfb_config->mouse_protocol) + return LAST_PROTOCOL; + + for (protocol = 0; protocol < LAST_PROTOCOL; protocol++) { + if (strcasecmp (dfb_config->mouse_protocol, + protocol_names[protocol]) == 0) + break; + } + + return protocol; +} + +/* exported symbols */ + +static int +driver_get_available( void ) +{ + struct serial_struct serial_info; + struct timeval timeout; + MouseProtocol protocol; + fd_set set; + int fd; + char buf[8]; + int readlen; + int lines; + int flags; + + if (dfb_system_type() != CORE_FBDEV) + return 0; + + protocol = mouse_get_protocol(); + if (protocol == LAST_PROTOCOL) + return 0; + + /* initialize source device name to read from */ + /* initialize flags to open device with */ + flags = O_NONBLOCK; + D_INFO( "DirectFB/SerialMouse: mouse detection on device '%s'...", dfb_config->mouse_source ); + + /* open device to read from */ + fd = open( dfb_config->mouse_source, flags ); + if (fd < 0) { + D_INFO( "DirectFB/SerialMouse: could not open device '%s'!\n", dfb_config->mouse_source ); + return 0; + } + + /* test if this is a serial device */ + if (dfb_config->mouse_gpm_source) { + + /* test whether a there is really a GPM driver active */ + /* availibity of device name is enough */ + + goto success; + + } + else { + if (ioctl( fd, TIOCGSERIAL, &serial_info )) + goto error; + + /* test if there's a mouse connected by lowering and raising RTS */ + if (ioctl( fd, TIOCMGET, &lines )) + goto error; + + lines ^= TIOCM_RTS; + if (ioctl( fd, TIOCMSET, &lines )) + goto error; + usleep (1000); + lines |= TIOCM_RTS; + if (ioctl( fd, TIOCMSET, &lines )) + goto error; + + /* wait for the mouse to send 0x4D */ + FD_ZERO (&set); + FD_SET (fd, &set); + timeout.tv_sec = 0; + timeout.tv_usec = 50000; + + while (select (fd+1, &set, NULL, NULL, &timeout) < 0 && errno == EINTR); + + if (FD_ISSET (fd, &set) && (readlen = read (fd, buf, 8) > 0)) { + int i; + + for (i=0; iname, + DFB_INPUT_DRIVER_INFO_NAME_LENGTH, "Serial Mouse Driver" ); + + snprintf( info->vendor, + DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH, "directfb.org" ); + + info->version.major = 0; + info->version.minor = 2; +} + +static DFBResult +driver_open_device( CoreInputDevice *device, + unsigned int number, + InputDeviceInfo *info, + void **driver_data ) +{ + int fd; + int flags; + MouseProtocol protocol; + SerialMouseData *data; + + protocol = mouse_get_protocol(); + if (protocol == LAST_PROTOCOL) /* shouldn't happen */ + return DFB_BUG; + + /* open device */ + flags = O_NONBLOCK | (dfb_config->mouse_gpm_source ? O_RDONLY : O_RDWR); + fd = open( dfb_config->mouse_source, flags ); + if (fd < 0) { + D_PERROR( "DirectFB/SerialMouse: Error opening '%s'!\n", dfb_config->mouse_source ); + return DFB_INIT; + } + + /* reset the O_NONBLOCK flag */ + fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) & ~O_NONBLOCK); + + /* allocate and fill private data */ + data = D_CALLOC( 1, sizeof(SerialMouseData) ); + if (!data) { + close( fd ); + return D_OOM(); + } + + data->fd = fd; + data->device = device; + data->protocol = protocol; + + mouse_setspeed( data ); + + /* fill device info structure */ + snprintf( info->desc.name, DFB_INPUT_DEVICE_DESC_NAME_LENGTH, + "Serial Mouse (%s)", protocol_names[protocol] ); + + snprintf( info->desc.vendor, DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH, "Unknown" ); + + info->prefered_id = DIDID_MOUSE; + + info->desc.type = DIDTF_MOUSE; + info->desc.caps = DICAPS_AXES | DICAPS_BUTTONS; + info->desc.max_axis = DIAI_Y; + info->desc.max_button = (protocol > PROTOCOL_MS) ? DIBI_MIDDLE : DIBI_RIGHT; + + /* start input thread */ + data->thread = direct_thread_create( DTT_INPUT, protocol == PROTOCOL_MOUSESYSTEMS ? + mouseEventThread_mousesystems : mouseEventThread_ms, + data, "SerMouse Input" ); + + /* set private data pointer */ + *driver_data = data; + + return DFB_OK; +} + +/* + * Fetch one entry from the device's keymap if supported. + */ +static DFBResult +driver_get_keymap_entry( CoreInputDevice *device, + void *driver_data, + DFBInputDeviceKeymapEntry *entry ) +{ + return DFB_UNSUPPORTED; +} + +static void +driver_close_device( void *driver_data ) +{ + SerialMouseData *data = (SerialMouseData*) driver_data; + + /* stop input thread */ + direct_thread_cancel( data->thread ); + direct_thread_join( data->thread ); + direct_thread_destroy( data->thread ); + + /* close device */ + close( data->fd ); + + /* free private data */ + D_FREE( data ); +} + -- cgit