chiark / gitweb /
hostside: hidrawconv: cope with difference between 2.6.26 and 2.6.33, guessing the...
[trains.git] / hostside / hidrawconv.c
1 /*
2  * usage:
3  *   .../hidrawconv-<controller> -d
4  *   .../hidrawconv-<controller> -e </dev/hidrawN
5  * where -a means all, and the other letters are:
6  *   -d   print expected descriptor (as for hidraw-ioctl -d)
7  *   -e   pretend to be evdev-manip
8  *   -E   pretend to be evdev-manip, print to stderr about the device at start
9  * exit status:
10  *   0      all ok
11  *   other  some other problem
12  *
13  * joystick values are always doubles from -1 to 0 to +1
14  */
15
16 #include "hidrawconv.h"
17
18 void die_vprintf_hook(const char *fmt, va_list al) { }
19 void die_hook(void) { }
20
21 static LastReports lasts;
22
23 void reportbits(const uint8_t msg[], const uint8_t last[],
24                 int len, const KeyBit *bit) {
25   for (; bit->str; bit++) {
26     if (bit->pos >= len) continue;
27     uint8_t m= msg[bit->pos] & bit->mask;
28     uint8_t l= last[bit->pos] & bit->mask;
29     if (m==l) continue;
30     printf("%s %d\n", bit->str, !!m);
31   }
32 }
33
34 void reportlocs(const uint8_t msg[], const uint8_t last[],
35                 int len, const ValLoc *loc) {
36   for (; loc->str; loc++) {
37     if (loc->pos >= len) continue;
38     uint8_t mb= msg[loc->pos] & loc->mask;
39     uint8_t lb= last[loc->pos] & loc->mask;
40     if (mb==lb) continue;
41     mb >>= loc->rshift;
42     mb -= loc->zero;
43     double val= (int8_t)mb;
44     val /= (val >= 0 ? 127 : 128);
45     printf("%s %.5f\n", loc->str, loc->sign * val);
46   }
47 }
48
49 void dispatch(LastReports *lasts, const char *message_prefix,
50               ProcessReport *const report_processors[MAXREPORTS],
51               const uint8_t *msg, int l) {
52   if (!l) {
53     fprintf(stderr,"%s:%s report too short\n", progname, message_prefix);
54     return;
55   }
56
57   ProcessReport *pr= report_processors[msg[0]];
58   Last *last= &lasts->lasts[msg[0]];
59   if (!pr) {
60     if (!last->len)
61       fprintf(stderr,"%s:%s unexpected report 0x%02x\n",
62               progname, message_prefix, msg[0]);
63     last->len= l;
64     return;
65   }
66   if (last->len < l) {
67     last->msg= mrealloc(last->msg, l);
68     memset(last->msg + last->len, 0, l - last->len);
69     last->len= l;
70   }
71   pr(msg, l, last->msg);
72   memcpy(last->msg, msg, l);
73 }  
74
75 static void events(int verbose) {
76   uint8_t msg[MAXREPORTLEN+1];
77   char phys[PATH_MAX], name[PATH_MAX];
78   int rphys, errnophys=0, rname, errnoname=0;
79   int reportnumbug;
80
81   rphys= ioctl(0, HIDIOCGRAWPHYS(PATH_MAX), phys);  errnophys=errno;
82   rname= ioctl(0, HIDIOCGRAWNAME(PATH_MAX), name);  errnoname=errno;
83   if (rphys>=0 && rname>=0) {
84     reportnumbug= 0;
85     if (verbose)
86       fprintf(stderr,"%s: %.*s %.*s\n",progname,rphys,phys,rname,name);
87   } else if (rphys<0 && errnophys==EINVAL &&
88              rname<0 && errnoname==EINVAL) {
89     fprintf(stderr,"%s: warning, HIDIOCGRAWPHYS/NAME gave EINVAL,"
90             " assuming kernel eats report number, assuming reports are 00\n",
91             progname);
92     reportnumbug= 1;
93   } else {
94     die("HIDIOCGRAWPHYS %s / HIDIOCGRAWNAME %s",
95         rphys<0 ? strerror(errnophys) : "ok",
96         rname<0 ? strerror(errnoname) : "ok");
97   }
98
99   if (reportnumbug) msg[0]=0;
100
101   for (;;) {
102     int l= read(0, msg+reportnumbug, sizeof(msg)-reportnumbug);
103     if (!l) break;
104     if (l<0) { perror("hidrawconv: read"); exit(-1); }
105     l += reportnumbug;
106     dispatch(&lasts,"",report_processors, msg,l);
107     if (ferror(stdout) || fflush(stdout))
108       diee("failed flushing event to stdout");
109   }
110 }
111
112 int main(int argc, char **argv) {
113   const char *how;
114
115   if (!*argv || !(how=*++argv) || *how++!='-' || !*how || how[1] || *++argv)
116     badusage("need exactly one argument, -d, -e or -E");
117
118   switch (how[0]) {
119   case 'd':
120     puts(descriptor);
121     break;
122
123   case 'E':
124     events(1);
125     break;
126
127   case 'e':
128     events(0);
129     break;
130
131   default:
132     badusage("unknown option/mode");
133   }
134
135   if (ferror(stdout) || fflush(stdout))
136     diee("write/flush stdout");
137
138   return 0;
139 }