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