Ticket #38: main.c

File main.c, 19.2 kB (added by xkill, 1 year ago)

wminput main.c

Line 
1 /* Copyright (C) 2007 L. Donnie Smith <wiimote@abstrakraft.org>
2  *
3  *  This program is free software; you can redistribute it and/or modify
4  *  it under the terms of the GNU General Public License as published by
5  *  the Free Software Foundation; either version 2 of the License, or
6  *  (at your option) any later version.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  *
17  *  ChangeLog:
18  *
19  *  2007-07-24 Pablo Catalina <xkill@ciberhell.ath.cx>
20  *  * Signaling support to trap SIGINT, SIGTERM and SIGUSR1 that exit the program.
21  *  * Syslog support
22  *  * Daemon support
23  *
24  *  2007-07-19 Pablo Catalina <xkill@ciberhell.ath.cx>
25  *  * always listen in wiimote standby mode, with wait time support
26  *
27  *  2007-06-18 L. Donnie Smith <cwiid@abstrakraft.org>
28  *  * revised error messages
29  *
30  *  2007-06-05 L. Donnie Smith <cwiid@abstrakraft.org>
31  *  * refactored to isolate plugin logic
32  *
33  *  2007-06-01 Nick <nickishappy@gmail.com>
34  *  * reworked command-line options (added standard options, long options)
35  *
36  *  2007-06-01 L. Donnie Smith <cwiid@abstrakraft.org>
37  *  * added python plugin support
38  *  * pass mesg instead of &mesg to wmplugin_exec
39  *
40  *  2007-05-16 L. Donnie Smith <cwiid@abstrakraft.org>
41  *  * changed cwiid_{connect,disconnect,command} to
42  *    cwiid_{open,close,request_status|set_led|set_rumble|set_rpt_mode}
43  *
44  *  2007-05-14 L. Donnie Smith <cwiid@abstrakraft.org>
45  *  * added timestamp to message callback
46  *
47  *  2007-04-24 L. Donnie Smith <cwiid@abstrakraft.org>
48  *  * update for API overhaul
49  *
50  *  2007-04-09 L. Donnie Smith <cwiid@abstrakraft.org>
51  *  * updated for libcwiid rename
52  *
53  *  2007-04-04 L. Donnie Smith <cwiid@abstrakraft.org>
54  *  * exit on cwiid_error
55  *
56  *  2007-03-03 L. Donnie Smith <cwiid@abstrakraft.org>
57  *  * Initial ChangeLog
58  *  * type audit (stdint, const, char booleans)
59  */
60
61 #include <stdint.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <getopt.h>
65
66 #include <pthread.h>
67 #include <signal.h>
68 #include <sys/types.h>
69 #include <unistd.h>
70
71 #include <cwiid.h>
72
73 #include "conf.h"
74 #include "util.h"
75 #include "wmplugin.h"
76 #include "c_plugin.h"
77 #include "py_plugin.h"
78 #include "syslog.h"
79
80
81 struct conf conf;
82
83 /* Prototypes */
84 cwiid_mesg_callback_t cwiid_callback;
85 int wminput_set_report_mode();
86 void process_btn_mesg(struct cwiid_btn_mesg *mesg);
87 void process_nunchuk_mesg(struct cwiid_nunchuk_mesg *mesg);
88 void process_classic_mesg(struct cwiid_classic_mesg *mesg);
89 void process_plugin(struct plugin *, int, union cwiid_mesg []);
90
91 /* Globals */
92 cwiid_wiimote_t *wiimote;
93 char init;
94 int always=0, wait_time=0, daemon_mode=0, wiimote_connected=0;
95
96 #define DEFAULT_CONFIG_FILE     "default"
97
98 #define HOME_DIR_LEN    128
99
100 void print_usage(void)
101 {
102         printf("wminput is a program that allows you to use a wiimote as a standard input device\n");
103         printf("Usage: %s [OPTIONS]...\n\n", "wminput");
104         printf("Options:\n");
105         printf("\t-h, --help\t\tPrints this output.\n");
106         printf("\t-v, --version\t\toutput version information and exit.\n");
107         printf("\t-c, --config [file]\tChoose config file to use.\n");
108         printf("\t-w, --wait\t\tWait indefinitely for wiimote to connect.\n");
109         printf("\t-a, --always <s>\tWait always but wait N seconds before discover.\n\t\t\t\tDon't kill when wiimote disconnect.\n");
110         printf("\t-d, --daemon \tPut wminput into daemon mode\n");
111 }
112
113 void handle_exit(int sig){
114         signal (sig,handle_exit);
115         syslog(LOG_INFO,"wminput user exit. CTRL+C or KILL");
116         if (daemon_mode==0) {
117                 printf ("User exit. CTRL+C or KILL \n");
118         }
119         closelog();
120         always=0;
121 }
122
123
124 int main(int argc, char *argv[])
125 {
126         char wait_forever = 0;
127         char *config_search_dirs[3], *plugin_search_dirs[3];
128         char *config_filename = DEFAULT_CONFIG_FILE;
129         char home_config_dir[HOME_DIR_LEN];
130         char home_plugin_dir[HOME_DIR_LEN];
131         char *tmp;
132         int c, i;
133         char *str_addr;
134         bdaddr_t bdaddr;
135         struct uinput_listen_data uinput_listen_data;
136         pthread_t uinput_listen_thread;
137         int ret=0;
138
139 //      openlog("cwiid-wminput",LOG_PID,LOG_DAEMON);
140
141         init = 1;
142
143         /* Parse Options */
144         while (1) {
145                 int option_index = 0;
146
147                 static struct option long_options[] = {
148                         {"help", 0, 0, 'h'},
149                         {"wait", 0, 0, 'w'},
150                         {"config", 1, 0, 'c'},
151                         {"version", 0, 0, 'v'},
152                         {"always", 1, 0, 'a'},
153                         {"daemon", 0, 0, 'd'},
154                         {0, 0, 0, 0}
155                 };
156
157                 c = getopt_long (argc, argv, "hwa:c:vd", long_options, &option_index);
158
159                 if (c == -1) {
160                         break;
161                 }
162
163                 switch (c) {
164                 case 'h':
165                         print_usage();
166                         return 0;
167                         break;
168                 case 'a':
169                         always=1;
170                         if (optarg) {
171                                 wait_time = atoi(optarg);
172                         }
173                         break;
174                 case 'w':
175                         wait_forever = 1;
176                         break;
177                 case 'c':
178                         config_filename = optarg;
179                         break;
180                 case 'v':
181                         printf("CWiid Version %s\n", CWIID_VERSION);
182                         return 0;
183                         break;
184                 case '?':
185                         printf("Try `wminput --help` for more information\n");
186                         return 1;
187                         break;
188                 case 'd':
189                         printf("Entering daemon mode\n");
190                         daemon ( 1, 0);
191                         daemon_mode=1;
192                         break;
193                 default:
194                         return -1;
195                         break;
196                 }
197         }
198
199         if (c_init()) {
200                 return -1;
201         }
202         if (py_init()) {
203                 return -1;
204         }
205
206         /* Load Config */
207         /* Setup search directory arrays */
208         if ((tmp = getenv("HOME")) == NULL) {
209                 wminput_err("Unable to find home directory");
210                 config_search_dirs[0] = WMINPUT_CONFIG_DIR;
211                 plugin_search_dirs[0] = CWIID_PLUGINS_DIR;
212                 config_search_dirs[1] = plugin_search_dirs[1] = NULL;
213         }
214         else {
215                 snprintf(home_config_dir, HOME_DIR_LEN, "%s/.cwiid/wminput", tmp);
216                 snprintf(home_plugin_dir, HOME_DIR_LEN, "%s/.cwiid/plugins", tmp);
217                 config_search_dirs[0] = home_config_dir;
218                 plugin_search_dirs[0] = home_plugin_dir;
219                 config_search_dirs[1] = WMINPUT_CONFIG_DIR;
220                 plugin_search_dirs[1] = CWIID_PLUGINS_DIR;
221                 config_search_dirs[2] = plugin_search_dirs[2] = NULL;
222         }
223
224         if (conf_load(&conf, config_filename, config_search_dirs,
225           plugin_search_dirs)) {
226                 return -1;
227         }
228         /* Determine BDADDR */
229         /* priority: command-line option, environment variable, BDADDR_ANY */
230         if (optind < argc) {
231                 if (str2ba(argv[optind], &bdaddr)) {
232                         wminput_err("invalid bdaddr");
233                         bdaddr = *BDADDR_ANY;
234                 }
235                 optind++;
236                 if (optind < argc) {
237                         wminput_err("invalid command-line");
238                         print_usage();
239                         conf_unload(&conf);
240                         return -1;
241                 }
242         }
243         else if ((str_addr = getenv(WIIMOTE_BDADDR)) != NULL) {
244                 if (str2ba(str_addr, &bdaddr)) {
245                         wminput_err("invalid address in %s", WIIMOTE_BDADDR);
246                         bdaddr = *BDADDR_ANY;
247                 }
248         }
249         else {
250                 bdaddr = *BDADDR_ANY;
251         }
252
253         signal (SIGINT,handle_exit);
254         signal (SIGTERM,handle_exit);
255         signal (SIGUSR1,handle_exit);
256         syslog(LOG_INFO,"CWiid Version %s. wminput started", CWIID_VERSION);
257
258         do {
259         /* TODO: fix wait_forever logic - currently assumes bdaddr is unspecified */
260         /* Wiimote Connect */
261
262                 syslog (LOG_INFO,"Catching wiimote");
263                 if (daemon_mode==0) {
264                         printf("Put Wiimote in discoverable mode now (press 1+2)...\n");
265                 }
266                 if (wait_forever) {
267                         if (cwiid_find_wiimote(&bdaddr, -1)) {
268                                 wminput_err("error finding wiimote");
269                                 conf_unload(&conf);
270                                 return -1;
271                         }
272                 }
273                 if ((wiimote = cwiid_open(&bdaddr, CWIID_FLAG_MESG_IFC)) == NULL) {
274                         wminput_err("unable to connect");
275                         conf_unload(&conf);
276                         return -1;
277                 } else {
278                         wiimote_connected = 1;
279                 }
280                 if (cwiid_set_mesg_callback(wiimote, &cwiid_callback)) {
281                         wminput_err("error setting callback");
282                         conf_unload(&conf);
283                         return -1;
284                 }
285        
286                 if (c_wiimote(wiimote)) {
287                         conf_unload(&conf);
288                         return -1;
289                 }
290                 if (py_wiimote(wiimote)) {
291                         conf_unload(&conf);
292                         return -1;
293                 }
294        
295                 /* init plugins */
296                 for (i=0; (i < CONF_MAX_PLUGINS) && conf.plugins[i].name; i++) {
297                         switch (conf.plugins[i].type) {
298                         case PLUGIN_C:
299                                 if (c_plugin_init(&conf.plugins[i], i)) {
300                                         wminput_err("error on %s init", conf.plugins[i].name);
301                                         conf_unload(&conf);
302                                         cwiid_close(wiimote);
303                                         return -1;
304                                 }
305                                 break;
306                         case PLUGIN_PYTHON:
307                                 if (py_plugin_init(&conf.plugins[i], i)) {
308                                         wminput_err("error %s init", conf.plugins[i].name);
309                                         conf_unload(&conf);
310                                         cwiid_close(wiimote);
311                                         return -1;
312                                 }
313                                 break;
314                         }
315                 }
316        
317                 if (wminput_set_report_mode()) {
318                         conf_unload(&conf);
319                         cwiid_close(wiimote);
320                         return -1;
321                 }
322        
323                 uinput_listen_data.wiimote = wiimote;
324                 uinput_listen_data.conf = &conf;
325                 if (pthread_create(&uinput_listen_thread, NULL,
326                                    (void *(*)(void *))uinput_listen,
327                                    &uinput_listen_data)) {
328                         wminput_err("error starting uinput listen thread");
329                         conf_unload(&conf);
330                         cwiid_close(wiimote);
331                         return -1;
332                 }
333
334                
335        
336                 syslog(LOG_INFO,"Wiimote Cached");
337
338                 if (daemon_mode==0) {
339                         printf("Ready.\n");
340                 }
341                
342                 init = 0;
343        
344
345                 do {
346                         sleep (2);
347                 }
348                 while (wiimote_connected == 1) ;
349
350                 if ( wait_time > 0 ) {
351                         if (daemon_mode==0) {
352                                 printf ("Waiting %ds\n",wait_time);     
353                         }
354                         syslog (LOG_INFO,"Waiting %ds for retry.",wait_time);
355                         sleep ( wait_time );
356                 }
357
358                        
359         } while (always==1);
360
361         syslog(LOG_INFO,"WMInput exit");       
362         if (daemon_mode==0) {
363                 printf("Exiting.\n");
364         }
365
366         if (pthread_cancel(uinput_listen_thread)) {
367                 wminput_err("Error canceling uinput listen thread");
368                 ret = -1;
369         }
370         else if (pthread_join(uinput_listen_thread, NULL)) {
371                 wminput_err("Error joining uinput listen thread");
372                 ret = -1;
373         }
374
375         /* disconnect */
376         if (cwiid_close(wiimote)) {
377                 wminput_err("Error on wiimote disconnect");
378                 ret = -1;
379         }
380
381         if (conf_unload(&conf)) {
382                 ret = -1;
383         }
384
385         py_deinit();
386
387         return ret;
388 }
389
390 int wminput_set_report_mode()
391 {
392         unsigned char rpt_mode_flags;
393         int i;
394
395         rpt_mode_flags = conf.rpt_mode_flags;
396
397         for (i=0; (i < CONF_MAX_PLUGINS) && conf.plugins[i].name; i++) {
398                 rpt_mode_flags |= conf.plugins[i].rpt_mode_flags;
399         }
400
401         if (cwiid_set_rpt_mode(wiimote, rpt_mode_flags)) {
402                 wminput_err("Error setting report mode");
403                 return -1;
404         }
405
406         return 0;
407 }
408
409 int wmplugin_set_rpt_mode(int id, uint8_t flags)
410 {
411         conf.plugins[id].rpt_mode_flags = flags;
412
413         if (!init) {
414                 wminput_set_report_mode();
415         }
416
417         return 0;
418 }
419
420 void cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count,
421                     union cwiid_mesg mesg[], struct timespec *timestamp)
422 {
423         int i;
424
425         for (i=0; i < mesg_count; i++) {
426                 switch (mesg[i].type) {
427                 case CWIID_MESG_BTN:
428                         process_btn_mesg((struct cwiid_btn_mesg *) &mesg[i]);
429                         break;
430                 case CWIID_MESG_NUNCHUK:
431                         process_nunchuk_mesg((struct cwiid_nunchuk_mesg *) &mesg[i]);
432                         break;
433                 case CWIID_MESG_CLASSIC:
434                         process_classic_mesg((struct cwiid_classic_mesg *) &mesg[i]);
435                         break;
436                 case CWIID_MESG_ERROR:
437                         syslog (LOG_INFO,"Wiimote disappears");
438                         wminput_err("Wiimote disappears");
439                         wiimote_connected = 0;
440                         break;
441                 default:
442                         break;
443                 }
444         }
445         for (i=0; (i < CONF_MAX_PLUGINS) && conf.plugins[i].name; i++) {
446                 process_plugin(&conf.plugins[i], mesg_count, mesg);
447         }
448         send_event(&conf, EV_SYN, SYN_REPORT, 0);
449 }
450
451 void process_btn_mesg(struct cwiid_btn_mesg *mesg)
452 {
453         static uint16_t prev_buttons = 0;
454         uint16_t pressed, released;
455         __s32 axis_value;
456         int i;
457
458         /* Wiimote Button/Key Events */
459         pressed = mesg->buttons & ~prev_buttons;
460         released = ~mesg->buttons & prev_buttons;
461         for (i=0; i < CONF_WM_BTN_COUNT; i++) {
462                 if (conf.wiimote_bmap[i].active) {
463                         if (pressed & conf.wiimote_bmap[i].mask) {
464                                 send_event(&conf, EV_KEY, conf.wiimote_bmap[i].action, 1);
465                         }
466                         else if (released & conf.wiimote_bmap[i].mask) {
467                                 send_event(&conf, EV_KEY, conf.wiimote_bmap[i].action, 0);
468                         }
469                 }
470         }
471         prev_buttons = mesg->buttons;
472
473         /* Wiimote.Dpad.X */
474         if (conf.amap[CONF_WM_AXIS_DPAD_X].active) {
475                 axis_value = 0;
476                 if (mesg->buttons & CWIID_BTN_LEFT) {
477                         axis_value = -1;
478                 }
479                 else if (mesg->buttons & CWIID_BTN_RIGHT) {
480                         axis_value = 1;
481                 }
482                 if (conf.amap[CONF_WM_AXIS_DPAD_X].flags & CONF_INVERT) {
483                         axis_value *= -1;
484                 }
485                 send_event(&conf, conf.amap[CONF_WM_AXIS_DPAD_X].axis_type,
486                            conf.amap[CONF_WM_AXIS_DPAD_X].action, axis_value);
487         }
488
489         /* Wiimote.Dpad.Y */
490         if (conf.amap[CONF_WM_AXIS_DPAD_Y].active) {
491                 axis_value = 0;
492                 if (mesg->buttons & CWIID_BTN_DOWN) {
493                         axis_value = -1;
494                 }
495                 else if (mesg->buttons & CWIID_BTN_UP) {
496                         axis_value = 1;
497                 }
498                 if (conf.amap[CONF_WM_AXIS_DPAD_Y].flags & CONF_INVERT) {
499                         axis_value *= -1;
500                 }
501                 send_event(&conf, conf.amap[CONF_WM_AXIS_DPAD_Y].axis_type,
502                            conf.amap[CONF_WM_AXIS_DPAD_Y].action, axis_value);
503         }
504 }
505
506 void process_nunchuk_mesg(struct cwiid_nunchuk_mesg *mesg)
507 {
508         static uint8_t prev_buttons = 0;
509         uint8_t pressed, released;
510         __s32 axis_value;
511         int i;
512
513         /* Nunchuk Button/Key Events */
514         pressed = mesg->buttons & ~prev_buttons;
515         released = ~mesg->buttons & prev_buttons;
516         for (i=0; i < CONF_NC_BTN_COUNT; i++) {
517                 if (conf.nunchuk_bmap[i].active) {
518                         if (pressed & conf.nunchuk_bmap[i].mask) {
519                                 send_event(&conf, EV_KEY, conf.nunchuk_bmap[i].action, 1);
520                         }
521                         else if (released & conf.nunchuk_bmap[i].mask) {
522                                 send_event(&conf, EV_KEY, conf.nunchuk_bmap[i].action, 0);
523                         }
524                 }
525         }
526         prev_buttons = mesg->buttons;
527
528         /* Nunchuk.Stick.X */
529         if (conf.amap[CONF_NC_AXIS_STICK_X].active) {
530                 axis_value = mesg->stick[CWIID_X];
531                 if (conf.amap[CONF_NC_AXIS_STICK_X].flags & CONF_INVERT) {
532                         axis_value = 0xFF - axis_value;
533                 }
534                 send_event(&conf, conf.amap[CONF_NC_AXIS_STICK_X].axis_type,
535                            conf.amap[CONF_NC_AXIS_STICK_X].action, axis_value);
536         }
537
538         /* Nunchuk.Stick.Y */
539         if (conf.amap[CONF_NC_AXIS_STICK_Y].active) {
540                 axis_value = mesg->stick[CWIID_Y];
541                 if (conf.amap[CONF_NC_AXIS_STICK_Y].flags & CONF_INVERT) {
542                         axis_value = 0xFF - axis_value;
543                 }
544                 send_event(&conf, conf.amap[CONF_NC_AXIS_STICK_Y].axis_type,
545                            conf.amap[CONF_NC_AXIS_STICK_Y].action, axis_value);
546         }
547 }
548
549 void process_classic_mesg(struct cwiid_classic_mesg *mesg)
550 {
551         static uint16_t prev_buttons = 0;
552         uint16_t pressed, released;
553         __s32 axis_value;
554         int i;
555
556         /* Classic Button/Key Events */
557         pressed = mesg->buttons & ~prev_buttons;
558         released = ~mesg->buttons & prev_buttons;
559         for (i=0; i < CONF_CC_BTN_COUNT; i++) {
560                 if (conf.classic_bmap[i].active) {
561                         if (pressed & conf.classic_bmap[i].mask) {
562                                 send_event(&conf, EV_KEY, conf.classic_bmap[i].action, 1);
563                         }
564                         else if (released & conf.classic_bmap[i].mask) {
565                                 send_event(&conf, EV_KEY, conf.classic_bmap[i].action, 0);
566                         }
567                 }
568         }
569         prev_buttons = mesg->buttons;
570
571         /* Classic.Dpad.X */
572         if (conf.amap[CONF_CC_AXIS_DPAD_X].active) {
573                 axis_value = 0;
574                 if (mesg->buttons & CWIID_CLASSIC_BTN_LEFT) {
575                         axis_value = -1;
576                 }
577                 else if (mesg->buttons & CWIID_CLASSIC_BTN_RIGHT) {
578                         axis_value = 1;
579                 }
580                 if (conf.amap[CONF_CC_AXIS_DPAD_X].flags & CONF_INVERT) {
581                         axis_value *= -1;
582                 }
583                 send_event(&conf, conf.amap[CONF_CC_AXIS_DPAD_X].axis_type,
584                            conf.amap[CONF_CC_AXIS_DPAD_X].action, axis_value);
585         }
586
587         /* Classic.Dpad.Y */
588         if (conf.amap[CONF_CC_AXIS_DPAD_Y].active) {
589                 axis_value = 0;
590                 if (mesg->buttons & CWIID_CLASSIC_BTN_DOWN) {
591                         axis_value = -1;
592                 }
593                 else if (mesg->buttons & CWIID_CLASSIC_BTN_UP) {
594                         axis_value = 1;
595                 }
596                 if (conf.amap[CONF_CC_AXIS_DPAD_Y].flags & CONF_INVERT) {
597                         axis_value *= -1;
598                 }
599                 send_event(&conf, conf.amap[CONF_CC_AXIS_DPAD_Y].axis_type,
600                            conf.amap[CONF_CC_AXIS_DPAD_Y].action, axis_value);
601         }
602
603         /* Classic.LStick.X */
604         if (conf.amap[CONF_CC_AXIS_L_STICK_X].active) {
605                 axis_value = mesg->l_stick[CWIID_X];
606                 if (conf.amap[CONF_CC_AXIS_L_STICK_X].flags & CONF_INVERT) {
607                         axis_value = CWIID_CLASSIC_L_STICK_MAX - axis_value;
608                 }
609                 send_event(&conf, conf.amap[CONF_CC_AXIS_L_STICK_X].axis_type,
610                            conf.amap[CONF_CC_AXIS_L_STICK_X].action, axis_value);
611         }
612
613         /* Classic.LStick.Y */
614         if (conf.amap[CONF_CC_AXIS_L_STICK_Y].active) {
615                 axis_value = mesg->l_stick[CWIID_Y];
616                 if (conf.amap[CONF_CC_AXIS_L_STICK_Y].flags & CONF_INVERT) {
617                         axis_value = CWIID_CLASSIC_L_STICK_MAX - axis_value;
618                 }
619                 send_event(&conf, conf.amap[CONF_CC_AXIS_L_STICK_Y].axis_type,
620                            conf.amap[CONF_CC_AXIS_L_STICK_Y].action, axis_value);
621         }
622
623         /* Classic.RStick.X */
624         if (conf.amap[CONF_CC_AXIS_R_STICK_X].active) {
625                 axis_value = mesg->r_stick[CWIID_X];
626                 if (conf.amap[CONF_CC_AXIS_R_STICK_X].flags & CONF_INVERT) {
627                         axis_value = CWIID_CLASSIC_R_STICK_MAX - axis_value;
628                 }
629                 send_event(&conf, conf.amap[CONF_CC_AXIS_R_STICK_X].axis_type,
630                            conf.amap[CONF_CC_AXIS_R_STICK_X].action, axis_value);
631         }
632
633         /* Classic.RStick.Y */
634         if (conf.amap[CONF_CC_AXIS_R_STICK_Y].active) {
635                 axis_value = mesg->r_stick[CWIID_Y];
636                 if (conf.amap[CONF_CC_AXIS_R_STICK_Y].flags & CONF_INVERT) {
637                         axis_value = CWIID_CLASSIC_R_STICK_MAX - axis_value;
638                 }
639                 send_event(&conf, conf.amap[CONF_CC_AXIS_R_STICK_Y].axis_type,
640                            conf.amap[CONF_CC_AXIS_R_STICK_Y].action, axis_value);
641         }
642
643         /* Classic.LAnalog */
644         if (conf.amap[CONF_CC_AXIS_L].active) {
645                 axis_value = mesg->l;
646                 if (conf.amap[CONF_CC_AXIS_L].flags & CONF_INVERT) {
647                         axis_value = CWIID_CLASSIC_LR_MAX - axis_value;
648                 }
649                 send_event(&conf, conf.amap[CONF_CC_AXIS_L].axis_type,
650                            conf.amap[CONF_CC_AXIS_L].action, axis_value);
651         }
652
653         /* Classic.RAnalog */
654         if (conf.amap[CONF_CC_AXIS_R].active) {
655                 axis_value = mesg->r;
656                 if (conf.amap[CONF_CC_AXIS_R].flags & CONF_INVERT) {
657                         axis_value = CWIID_CLASSIC_LR_MAX - axis_value;
658                 }
659                 send_event(&conf, conf.amap[CONF_CC_AXIS_R].axis_type,
660                            conf.amap[CONF_CC_AXIS_R].action, axis_value);
661         }
662 }
663
664 void process_plugin(struct plugin *plugin, int mesg_count,
665                     union cwiid_mesg mesg[])
666 {
667         static union cwiid_mesg plugin_mesg[CWIID_MAX_MESG_COUNT];
668         int plugin_mesg_count = 0;
669         int i;
670         uint8_t flag;
671         uint16_t pressed, released;
672         __s32 axis_value;
673
674         for (i=0; i < mesg_count; i++) {
675                 switch (mesg[i].type) {
676                 case CWIID_MESG_STATUS:
677                         flag = CWIID_RPT_STATUS;
678                         break;
679                 case CWIID_MESG_BTN:
680                         flag = CWIID_RPT_BTN;
681                         break;
682                 case CWIID_MESG_ACC:
683                         flag = CWIID_RPT_ACC;
684                         break;
685                 case CWIID_MESG_IR:
686                         flag = CWIID_RPT_IR;
687                         break;
688                 case CWIID_MESG_NUNCHUK:
689                         flag = CWIID_RPT_NUNCHUK;
690                         break;
691                 case CWIID_MESG_CLASSIC:
692                         flag = CWIID_RPT_CLASSIC;
693                         break;
694                 default:
695                         break;
696                 }
697                 if (plugin->rpt_mode_flags & flag) {
698                         /* TODO: copy correct (smaller) message size */
699                         memcpy(&plugin_mesg[plugin_mesg_count++], &mesg[i], sizeof mesg[i]);
700                 }
701         }
702
703         if (plugin_mesg_count > 0) {
704                 switch (plugin->type) {
705                 case PLUGIN_C:
706                         if (c_plugin_exec(plugin, plugin_mesg_count, plugin_mesg)) {
707                                 return;
708                         }
709                         break;
710                 case PLUGIN_PYTHON:
711                         if (py_plugin_exec(plugin, plugin_mesg_count, plugin_mesg)) {
712                                 return;
713                         }
714                         break;
715                 }
716
717                 /* Plugin Button/Key Events */
718                 pressed = plugin->data->buttons & ~plugin->prev_buttons;
719                 released = ~plugin->data->buttons & plugin->prev_buttons;
720                 for (i=0; i < plugin->info->button_count; i++) {
721                         if (plugin->bmap[i].active) {
722                                 if (pressed & 1<<i) {
723                                         send_event(&conf, EV_KEY, plugin->bmap[i].action, 1);
724                                 }
725                                 else if (released & 1<<i) {
726                                         send_event(&conf, EV_KEY, plugin->bmap[i].action, 0);
727                                 }
728                         }
729                 }
730                 plugin->prev_buttons = plugin->data->buttons;
731
732                 /* Plugin Axis Events */
733                 for (i=0; i < plugin->info->axis_count; i++) {
734                         if (plugin->amap[i].active && plugin->data->axes &&
735                           plugin->data->axes[i].valid) {
736                                 axis_value = plugin->data->axes[i].value;
737                                 if (plugin->amap[i].flags & CONF_INVERT) {
738                                         axis_value = plugin->info->axis_info[i].max +
739                                                      plugin->info->axis_info[i].min - axis_value;
740                                 }
741                                 send_event(&conf, plugin->amap[i].axis_type,
742                                            plugin->amap[i].action, axis_value);
743                         }
744                 }
745         }
746 }