pndevmapperd: support multiple charge devices
[pandora-libraries.git] / lib / pnd_io_evdev.c
1
2 #include <string.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <stdio.h>
6 #include <stdlib.h> /* abs() */
7 #include <linux/input.h> /* struct input_event */
8 #include <sys/select.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11
12 #include "pnd_device.h"
13 #include "pnd_io_evdev.h"
14
15 typedef struct {
16   int fd;
17   // state info
18   union {
19     pnd_nubstate_t nub;
20     unsigned int buttons;
21   } state;
22 } pnd_evmap_t;
23 static pnd_evmap_t evmap [ pnd_evdev_max ];
24 static unsigned char evmap_first = 1;
25 static pnd_evdev_e evmapback [ 10 ]; // map fd back to which device
26
27 unsigned char pnd_evdev_open ( pnd_evdev_e device ) {
28
29   // if first, reset global struct
30   if ( evmap_first ) {
31     evmap_first = 0; // don't repeat
32     unsigned char i;
33     for ( i = 0; i < pnd_evdev_max; i++ ) {
34       evmap [ i ].fd = -1; // not opened
35     }
36   } // if first
37
38   // do it
39   switch ( device ) {
40
41   case pnd_evdev_dpads:
42     if ( ( evmap [ pnd_evdev_dpads ].fd = pnd_evdev_open_by_name ( PND_EVDEV_GPIO ) ) >= 0 ) {
43       evmapback [ evmap [ pnd_evdev_dpads ].fd ] = pnd_evdev_dpads;
44       return ( 1 );
45     }
46     break;
47
48   case pnd_evdev_nub1:
49     if ( ( evmap [ pnd_evdev_nub1 ].fd = pnd_evdev_open_by_name ( PND_EVDEV_NUB1 ) ) >= 0 ) {
50       evmapback [ evmap [ pnd_evdev_nub1 ].fd ] = pnd_evdev_nub1;
51       return ( 1 );
52     }
53     break;
54
55   case pnd_evdev_nub2:
56     if ( ( evmap [ pnd_evdev_nub2 ].fd = pnd_evdev_open_by_name ( PND_EVDEV_NUB2 ) ) >= 0 ) {
57       evmapback [ evmap [ pnd_evdev_nub2 ].fd ] = pnd_evdev_nub2;
58       return ( 1 );
59     }
60     break;
61
62   case pnd_evdev_power:
63     if ( ( evmap [ pnd_evdev_power ].fd = pnd_evdev_open_by_name ( PND_EVDEV_POWER ) ) >= 0 ) {
64       evmapback [ evmap [ pnd_evdev_power ].fd ] = pnd_evdev_power;
65       return ( 1 );
66     }
67     break;
68
69   case pnd_evdev_max:
70     return ( 0 ); // shutup gcc
71   } // switch
72
73   // error opening, or not supported in this bit of code, or wtf
74   return ( 0 );
75 }
76
77 void pnd_evdev_close ( pnd_evdev_e device ) {
78   // if open
79   if ( evmap [ device ].fd >= 0 ) {
80     close ( evmap [ device ].fd ); // close it
81     evmap [ device ].fd = -1; // flag as closed
82   }
83   return;
84 }
85
86 void pnd_evdev_closeall ( void ) {
87   unsigned char i;
88
89   for ( i = 0; i < pnd_evdev_max; i++ ) {
90     pnd_evdev_close ( i );
91   } // for
92
93   return;
94 }
95
96 int pnd_evdev_get_fd ( unsigned char device ) {
97   return ( evmap [ device ].fd );
98 }
99
100 int pnd_evdev_open_by_name ( char *devname ) {
101   int fd;
102   char fname [ 64 ];
103   char name[256] = { 0, };
104   unsigned char id;
105
106   // keep opening event# devices until we run out
107   for ( id = 0; ; id++ ) {
108
109     // set temp filename
110     snprintf ( fname, sizeof ( fname ), "/dev/input/event%i", id );
111
112     // try open, or bail out if no more
113     if ( ( fd = open ( fname, O_RDONLY | O_NDELAY ) ) < 0 ) {
114       return ( -1 );
115     }
116
117     // fetch the devices name
118     if ( ioctl (fd, EVIOCGNAME(sizeof(name)), name ) < 0 ) {
119       close ( fd ); // couldn't get the name?!
120       continue; // pretty odd to not have a name, but maybe the next device does..
121     }
122
123     // are we done?
124     if ( strcmp ( name, devname ) == 0 ) {
125       return ( fd );
126     }
127
128     // next!
129     close ( fd );
130   }
131
132   return ( -1 ); // couldn't find it
133 }
134
135 unsigned char pnd_evdev_catchup ( unsigned char blockp ) {
136   fd_set fdset;
137   int maxfd = -99;
138   int i;
139
140   // if not blocking, we want a zero duration timeout
141   struct timeval tv;
142   struct timeval *ptv;
143   bzero ( &tv, sizeof(struct timeval) ); // set to 0s, ie: return immediately
144
145   if ( blockp ) {
146     ptv = NULL;
147   } else {
148     ptv = &tv;
149   }
150
151   // clear watch fd's
152   FD_ZERO ( &fdset );
153
154   // for all our open evdev's, flag them in the watch fd list
155   for ( i = 0; i < pnd_evdev_max; i++ ) {
156     if ( evmap [ i ].fd >= 0 ) {
157       // set the fd into the select set
158       FD_SET( evmap [ i ].fd, &fdset );
159       // select(2) needs to know the highest fd
160       if ( evmap [ i ].fd > maxfd ) {
161         maxfd = evmap [ i ].fd;
162       } // if
163     } // if
164   } // for
165
166   if ( maxfd < 0 ) {
167     return ( 0 ); // nothing to do
168   }
169
170   int ret;
171
172   ret = select ( maxfd + 1, &fdset, NULL, NULL, ptv );
173
174   if ( ret < 0 ) {
175     return ( 0 ); // something bad
176   } else if ( ret == 0 ) {
177     return ( 1 ); // all good, nothing here
178   }
179
180   // all good, and something in the queue..
181   for ( i = 0; i < pnd_evdev_max; i++ ) {
182     // if open..
183     if ( evmap [ i ].fd >= 0 ) {
184       // if pending in the queue
185       if ( FD_ISSET ( evmap [ i ].fd, &fdset ) ) {
186
187         int rd, fd;
188         int j;
189         struct input_event ev[64];
190
191         fd = evmap [ i ].fd;
192
193         // pull events from the queue; max 64 events
194         rd = read ( fd, ev, sizeof(struct input_event) * 64 );
195         if ( rd < (int) sizeof(struct input_event) ) {
196           // less than a whole event-struct? bad!
197           break;
198         }
199
200         // for each event in the pulled events, parse it
201         for (j = 0; j < rd / sizeof(struct input_event); j++ ) {
202
203           // SYN, ignore
204           if ( ev[j].type == EV_SYN ) {
205             continue;
206
207           } else if ( ev[j].type == EV_KEY ) {
208             // KEY event -- including dpads
209
210             // store val for key
211             // keycode: ev[j].code -> keycode, see linux/input.h
212             // state val: ev[j].value -> 0keyup, 1keydown
213
214 #if 0 // as of mid-March; notaz did a recent keycode change so had to refigure it out
215             printf ( "evdev\tkey %d\tvalue %d\n", ev[j].code, ev[j].value );
216             // a 102    b 107    x 109     y 104
217             // ltrigger 54           rtrigger 97
218             // start  56      select 29    pandora 139
219 #endif
220
221             unsigned int state = evmap [ pnd_evdev_dpads ].state.buttons;
222
223             switch ( ev[j].code ) {
224
225             case KEY_UP:     state &= ~pnd_evdev_up; if ( ev[j].value ) state |= pnd_evdev_up; break;
226             case KEY_DOWN:   state &= ~pnd_evdev_down; if ( ev[j].value ) state |= pnd_evdev_down; break;
227             case KEY_LEFT:   state &= ~pnd_evdev_left; if ( ev[j].value ) state |= pnd_evdev_left; break;
228             case KEY_RIGHT:  state &= ~pnd_evdev_right; if ( ev[j].value ) state |= pnd_evdev_right; break;
229             case KEY_PAGEDOWN: /*KEY_X*/     state &= ~pnd_evdev_x; if ( ev[j].value ) state |= pnd_evdev_x; break;
230             case KEY_PAGEUP: /*KEY_Y*/       state &= ~pnd_evdev_y; if ( ev[j].value ) state |= pnd_evdev_y; break;
231             case KEY_HOME: /*KEY_A*/         state &= ~pnd_evdev_a; if ( ev[j].value ) state |= pnd_evdev_a; break;
232             case KEY_END: /*KEY_B*/          state &= ~pnd_evdev_b; if ( ev[j].value ) state |= pnd_evdev_b; break;
233
234             case KEY_RIGHTSHIFT: // ltrigger
235               state &= ~pnd_evdev_ltrigger; if ( ev[j].value ) state |= pnd_evdev_ltrigger; break;
236             case KEY_RIGHTCTRL: // rtrigger
237               state &= ~pnd_evdev_rtrigger; if ( ev[j].value ) state |= pnd_evdev_rtrigger; break;
238
239               // start
240               // select
241               // pandora
242             case KEY_LEFTALT:     state &= ~pnd_evdev_start; if ( ev[j].value ) state |= pnd_evdev_start; break;
243             case KEY_LEFTCTRL:     state &= ~pnd_evdev_select; if ( ev[j].value ) state |= pnd_evdev_select; break;
244             case KEY_MENU:     state &= ~pnd_evdev_pandora; if ( ev[j].value ) state |= pnd_evdev_pandora; break;
245
246             } // switch
247
248             evmap [ pnd_evdev_dpads ].state.buttons = state;
249
250           } else if ( ev[j].type == EV_SW ) {
251             // SWITCH event
252
253           } else if ( ev[j].type == EV_ABS ) {
254             // ABS .. ie: nub
255
256             // vsense66 -> nub1 (left)
257             // vsense67 -> nub2 (right)
258             pnd_nubstate_t *pn = NULL;
259             if ( evmapback [ fd ] == pnd_evdev_nub1 ) {
260               pn = &( evmap [ pnd_evdev_nub1 ].state.nub );
261             } else {
262               pn = &( evmap [ pnd_evdev_nub2 ].state.nub );
263             }
264
265             if ( ev[j].code == ABS_X ) {
266               pn -> x = ev[j].value;
267             } else if ( ev[j].code == ABS_Y ) {
268               pn -> y = ev[j].value;
269             } else {
270               //printf("unexpected EV_ABS code: %i\n", ev[i].code);
271             }
272
273           } else {
274             // unknown?
275             continue;
276           } // event type?
277
278         } // for each pulled event
279
280       } // if pending
281     } // if open
282   } // for all device..
283
284   return ( 1 );
285 }
286
287 unsigned int pnd_evdev_dpad_state ( pnd_evdev_e device ) {
288   if ( evmap [ device ].fd < 0 ) {
289     return ( -1 );
290   }
291   return ( evmap [ device ].state.buttons );
292 }
293
294 int pnd_evdev_nub_state ( pnd_evdev_e nubdevice, pnd_nubstate_t *r_nubstate ) {
295   if ( evmap [ nubdevice ].fd < 0 ) {
296     return ( -1 );
297   }
298   memcpy ( r_nubstate, &(evmap [ nubdevice ].state.nub), sizeof(pnd_nubstate_t) );
299   return ( 1 );
300 }