PageRenderTime 74ms CodeModel.GetById 30ms app.highlight 26ms RepoModel.GetById 14ms app.codeStats 0ms

/src/backend/native/ftk_source_ps2mouse.c

http://ftk.googlecode.com/
C | 452 lines | 323 code | 90 blank | 39 comment | 61 complexity | 5bdcbd2cb78ffb05d3badafd94814f23 MD5 | raw file
  1/*
  2   (c) Copyright 2001-2008  The world wide DirectFB Open Source Community (directfb.org)
  3   (c) Copyright 2000-2004  Convergence (integrated media) GmbH
  4   (c) Copyright 2011 Li XianJing 
  5
  6   All rights reserved.
  7
  8   Written by Denis Oliver Kropp <dok@directfb.org>,
  9              Andreas Hundt <andi@fischlustig.de>,
 10              Sven Neumann <neo@directfb.org>,
 11              Ville Syrj?l? <syrjala@sci.fi> and
 12              Claudio Ciccani <klan@users.sf.net>.
 13
 14   This library is free software; you can redistribute it and/or
 15   modify it under the terms of the GNU Lesser General Public
 16   License as published by the Free Software Foundation; either
 17   version 2 of the License, or (at your option) any later version.
 18
 19   This library is distributed in the hope that it will be useful,
 20   but WITHOUT ANY WARRANTY; without even the implied warranty of
 21   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 22   Lesser General Public License for more details.
 23
 24   You should have received a copy of the GNU Lesser General Public
 25   License along with this library; if not, write to the
 26   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 27   Boston, MA 02111-1307, USA.
 28*/
 29
 30#include <stdlib.h>
 31#include <stdio.h>
 32#include <string.h>
 33#include <unistd.h>
 34#include <errno.h>
 35#include <fcntl.h>
 36#include <termios.h>
 37#include <ctype.h>
 38#include <sys/utsname.h>
 39
 40#include "ftk_log.h"
 41#include "ftk_source_ps2mouse.h"
 42
 43#define s8 char
 44
 45typedef enum 
 46{
 47	false,
 48	true
 49}bool;
 50
 51#define PS2_SET_RES		 0xE8	/* Set resolution	 */
 52#define PS2_SET_SCALE11  0xE6	 /* Set 1:1 scaling    */
 53#define PS2_SET_SAMPLE	 0xF3	 /* Set sample rate    */
 54#define PS2_ENABLE_DEV	 0xF4	 /* Enable aux device  */
 55#define PS2_ACK		     0xFA    /* Command byte ACK	 */
 56
 57#define PS2_SEND_ID		0xF2
 58#define PS2_Iprintf    -1
 59#define PS2_ID_PS2		0
 60#define PS2_ID_IMPS2	3
 61
 62typedef struct _PrivInfo
 63{
 64	int	fd;
 65	int x;
 66	int y;
 67	int	dx;
 68	int	dy;
 69	int max_x;
 70	int max_y;
 71	int	mouseId;
 72	int	packetLength;
 73	FtkEvent event;
 74	FtkOnEvent on_event;
 75	void* user_data;
 76	char filename[64];
 77
 78	int pressed;
 79	int last_x;
 80	int last_y;
 81	int is_first_move;
 82} PrivInfo;
 83
 84static void flush_event(PrivInfo *priv, int button, int press)
 85{
 86	if (priv->dx) 
 87	{
 88		priv->x += priv->dx;
 89	}
 90
 91	if (priv->dy) 
 92	{
 93		priv->y += priv->dy;
 94	}
 95	
 96	priv->dy = 0;
 97	priv->dx = 0;
 98	if(priv->x < 0) priv->x = 0;
 99	if(priv->y < 0) priv->y = 0;
100	if(priv->x > priv->max_x) priv->x = priv->max_x;
101	if(priv->y > priv->max_y) priv->y = priv->max_y;
102
103	if(button < 0)
104	{
105		if(!priv->is_first_move)
106		{
107			if(priv->last_x == priv->x && priv->last_y == priv->y)
108			{
109				/*skip duplicated move*/
110				return;
111			}
112
113			priv->last_x = priv->x;
114			priv->last_y = priv->y;
115		}
116
117		priv->is_first_move = false;
118	
119		priv->event.type = FTK_EVT_MOUSE_MOVE;
120	}
121	else
122	{
123		if(priv->pressed == press)
124		{
125			return;
126		}
127
128		priv->pressed = press;
129		priv->event.type = press ? FTK_EVT_MOUSE_DOWN : FTK_EVT_MOUSE_UP;
130	}
131	
132	priv->event.u.mouse.x = priv->x;
133	priv->event.u.mouse.y = priv->y;
134	priv->on_event(priv->user_data, &priv->event);
135	priv->event.type = FTK_EVT_NOP;
136
137	return;
138}
139
140void dispatch_event(PrivInfo* priv)
141{
142	int readlen = 0;
143	unsigned char pos = 0;
144	unsigned char packet[4] = {0};
145	unsigned char last_buttons = 0;
146	unsigned char buf[256] = {0};
147
148	if( (readlen = read(priv->fd, buf, 256)) > 0 ) 
149	{
150		int i = 0;
151		for ( i = 0; i < readlen; i++ ) 
152		{
153			if ( pos == 0  &&  (buf[i] & 0xc0) ) 
154			{
155				continue;
156			}
157			packet[pos++] = buf[i];
158			if ( pos == priv->packetLength ) 
159			{
160				int dx, dy, dz;
161				int buttons;
162
163				pos = 0;
164				if ( !(packet[0] & 0x08) ) 
165				{
166					/* We've lost sync! */
167					i--;	/* does this make sense? oh well,
168							 it will resync eventually (will it ?)*/
169					continue;
170				}
171
172				buttons = packet[0] & 0x07;
173				dx = (packet[0] & 0x10) ?	packet[1]-256  :  packet[1];
174				dy = (packet[0] & 0x20) ? -(packet[2]-256) : -packet[2];
175				if (priv->mouseId == PS2_ID_IMPS2) 
176				{
177					/* Just strip off the extra buttons if present
178					   and sign extend the 4 bit value */
179					dz = (s8)((packet[3] & 0x80) ?
180							   packet[3] | 0xf0 : packet[3] & 0x0F);
181					if (dz) {
182						flush_event( priv , -1, -1);
183					}
184				}
185				else 
186				{
187					dz = 0;
188				}
189
190				priv->dx += dx;
191				priv->dy += dy;
192
193				flush_event( priv, -1, -1);
194
195				if ( last_buttons != buttons ) {
196					unsigned char changed_buttons;
197
198					changed_buttons = last_buttons ^ buttons;
199
200					/* make sure the compressed motion event is dispatched
201					   before any button change */
202					flush_event(priv, -1, -1);
203					
204					if ( changed_buttons & 0x01 ) {
205						flush_event(priv, 1, buttons & 0x01);
206					}
207					
208					if ( changed_buttons & 0x02 ) {
209						flush_event(priv, 2, buttons & 0x02);
210					}
211					
212					if ( changed_buttons & 0x04 ) {
213						flush_event(priv, 3, buttons & 0x04);
214					}
215
216					//FIXME
217					flush_event(priv, 1, 0);
218
219					last_buttons = buttons;
220				}
221			}
222		}
223		flush_event( priv , -1, -1);
224	}
225
226	return ;
227}
228
229
230static int
231ps2WriteChar( int fd, unsigned char c, bool verbose )
232{
233	struct timeval tv;
234	fd_set fds;
235
236	tv.tv_sec = 0;
237	tv.tv_usec = 200000;	  /*  timeout 200 ms  */
238
239	FD_ZERO( &fds );
240	FD_SET( fd, &fds );
241
242	write( fd, &c, 1 );
243
244	if ( select(fd+1, &fds, NULL, NULL, &tv) == 0 ) {
245		return -1;
246	}
247
248	read( fd, &c, 1 );
249
250	if ( c != PS2_ACK )
251		return -2;
252
253	return 0;
254}
255
256
257static int
258ps2GetId( int fd, bool verbose )
259{
260	unsigned char c;
261
262	if ( ps2WriteChar(fd, PS2_SEND_ID, verbose) < 0 )
263		return PS2_Iprintf;
264
265	read( fd, &c, 1 );
266
267	return( c );
268}
269
270
271static int
272ps2Write( int fd, const unsigned char *priv, size_t len, bool verbose)
273{
274	size_t i;
275	int    error = 0;
276
277	for ( i = 0; i < len; i++ ) {
278		if ( ps2WriteChar(fd, priv[i], verbose) < 0 ) {
279			if ( verbose )
280			error++;
281		}
282	}
283
284	if ( error && verbose )
285		printf( "DirectFB/PS2Mouse: missed %i ack's!\n", error);
286
287	return( error );
288}
289
290
291static int
292init_ps2( int fd, bool verbose )
293{
294	static const unsigned char basic_init[] =
295	{ PS2_ENABLE_DEV, PS2_SET_SAMPLE, 100 };
296	static const unsigned char imps2_init[] =
297	{ PS2_SET_SAMPLE, 200, PS2_SET_SAMPLE, 100, PS2_SET_SAMPLE, 80 };
298	static const unsigned char ps2_init[] =
299	{ PS2_SET_SCALE11, PS2_ENABLE_DEV, PS2_SET_SAMPLE, 100, PS2_SET_RES, 3 };
300	int mouseId;
301
302	struct timeval tv;
303	fd_set fds;
304	int count = 100;
305
306	/* read all data from the file descriptor before initializing the mouse */
307	while (true) {
308		unsigned char buf[64];
309
310		tv.tv_sec  = 0;
311		tv.tv_usec = 50000;		 /*  timeout 1/50 sec  */
312
313		FD_ZERO( &fds );
314		FD_SET( fd, &fds );
315
316		if (select( fd+1, &fds, NULL, NULL, &tv ))
317			read( fd, buf, sizeof(buf) );
318		else
319			break;
320
321		if (! --count) {
322			printf( "DirectFB/PS2Mouse: "
323					"PS/2 mouse keeps sending data, "
324					"initialization failed\n" );
325			return -1;
326		}
327	}
328
329	ps2Write( fd, basic_init, sizeof (basic_init), verbose );
330	/* Do a basic init in case the mouse is confused */
331	if (ps2Write( fd, basic_init, sizeof (basic_init), verbose ) != 0) {
332		if (verbose)
333			printf( "DirectFB/PS2Mouse: PS/2 mouse failed init\n" );
334		return -1;
335	}
336
337	ps2Write( fd, ps2_init, sizeof (ps2_init), verbose );
338
339	if (ps2Write(fd, imps2_init, sizeof (imps2_init), verbose) != 0) {
340		if (verbose)
341			printf ("DirectFB/PS2Mouse: mouse failed IMPS/2 init\n");
342		return -2;
343	}
344
345	if ((mouseId = ps2GetId( fd, verbose )) < 0)
346		return mouseId;
347
348	if ( mouseId != PS2_ID_IMPS2 )	 /*  unknown id, assume PS/2  */
349		mouseId = PS2_ID_PS2;
350
351	return mouseId;
352}
353
354/**************************************************************************************************/
355
356static Ret open_device(PrivInfo* priv, int max_x, int max_y)
357{
358	int			fd = 0;
359	int			mouseId = -1;
360	int			flags = O_RDWR | O_SYNC | O_EXCL;;
361
362	fd = open( "/dev/input/mice", flags );
363	if (fd < 0) 
364	{
365		return RET_OK;
366	}
367
368	fcntl( fd, F_SETFL, fcntl ( fd, F_GETFL ) & ~O_NONBLOCK );
369	mouseId = init_ps2( fd, true );
370		
371	if (mouseId  < 0) {
372		close( fd );
373		return RET_OK;
374	}
375
376	priv->max_x = max_x;
377	priv->max_y = max_y;
378	priv->fd		   = fd;
379	priv->mouseId	   = mouseId;
380	priv->packetLength = (mouseId == PS2_ID_IMPS2) ? 4 : 3;
381
382	return RET_OK;
383}
384
385static int ftk_source_ps2mouse_get_fd(FtkSource* thiz)
386{
387	DECL_PRIV(thiz, priv);
388
389	return priv->fd;
390}
391
392static int ftk_source_ps2mouse_check(FtkSource* thiz)
393{
394	return -1;
395}
396
397static Ret ftk_source_ps2mouse_dispatch(FtkSource* thiz)
398{
399	int ret = 0;
400	DECL_PRIV(thiz, priv);
401
402	dispatch_event(priv);
403
404	return RET_OK;
405}
406
407static void ftk_source_ps2mouse_destroy(FtkSource* thiz)
408{
409	if(thiz != NULL)
410	{
411		DECL_PRIV(thiz, priv);
412
413		close(priv->fd);
414		FTK_ZFREE(thiz, sizeof(thiz) + sizeof(PrivInfo));
415	}
416
417	return;
418}
419
420FtkSource* ftk_source_ps2mouse_create(const char* filename, FtkOnEvent on_event, void* user_data, int max_x, int max_y)
421{
422	FtkSource* thiz = (FtkSource*)FTK_ZALLOC(sizeof(FtkSource) + sizeof(PrivInfo));
423
424	if(thiz != NULL)
425	{
426		DECL_PRIV(thiz, priv);
427
428		thiz->get_fd   = ftk_source_ps2mouse_get_fd;
429		thiz->check    = ftk_source_ps2mouse_check;
430		thiz->dispatch = ftk_source_ps2mouse_dispatch;
431		thiz->destroy  = ftk_source_ps2mouse_destroy;
432
433		thiz->ref = 1;
434		priv->fd = open(filename, O_RDONLY);
435		ftk_strncpy(priv->filename, filename, sizeof(priv->filename));
436
437		open_device(priv, max_x, max_y);
438		if(priv->fd < 0)
439		{
440			FTK_ZFREE(thiz, sizeof(thiz) + sizeof(PrivInfo));
441			return NULL;
442		}
443
444		priv->on_event = on_event;
445		priv->user_data = user_data;
446		priv->is_first_move = true;
447		ftk_logd("%s: %d=%s priv->user_data=%p\n", __func__, priv->fd, filename, priv->user_data);
448	}
449
450	return thiz;
451}
452