]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bitsy/devµc.c
merge
[plan9front.git] / sys / src / 9 / bitsy / devµc.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "io.h"
7 #include        "../port/error.h"
8
9 enum{
10         Qdir,
11         Qbacklight,
12         Qbattery,
13         Qbuttons,
14         Qcruft,
15         Qled,
16         Qversion,
17         Qpower,
18
19         /* command types */
20         BLversion=      0,
21         BLbuttons=      2,      /* button events */
22         BLtouch=                3,      /* read touch screen events */
23         BLled=          8,      /* turn LED on/off */
24         BLbattery=      9,      /* read battery status */
25         BLbacklight=    0xd,    /* backlight control */
26
27         SOF=    0x2,            /* start of frame */
28 };
29
30 Dirtab µcdir[]={
31         ".",                    { Qdir, 0, QTDIR },     0,      DMDIR|0755,
32         "backlight",            { Qbacklight, 0 },      0,      0664,
33         "battery",              { Qbattery, 0 },                0,      0664,
34         "buttons",              { Qbuttons, 0 },                0,      0664,
35         "cruft",                { Qcruft, 0 },          0,      0664,
36         "led",                  { Qled, 0 },                    0,      0664,
37         "version",              { Qversion, 0 },                0,      0664,
38         "power",                { Qpower, 0 },          0,      0600,
39 };
40
41 static struct µcontroller
42 {
43         /* message being rcvd */
44         int             state;
45         uchar   buf[16+4];
46         uchar   n;
47
48         /* for messages that require acks */
49         QLock;
50         Rendez  r;
51
52         /* battery */
53         uchar   acstatus;
54         uchar   voltage;
55         ushort  batstatus;
56         uchar   batchem;
57
58         /* version string */
59         char    version[16+2];
60 } ctlr;
61
62 extern int landscape;
63
64 int
65 µcputc(Queue*, int ch)
66 {
67         int i, len, b, up;
68         uchar cksum;
69         uchar *p;
70         static int samseq;
71         static int touching;    /* guard against something we call going spllo() */
72         static int buttoning;   /* guard against something we call going spllo() */
73
74         if(ctlr.n > sizeof(ctlr.buf))
75                 panic("µcputc");
76
77         ctlr.buf[ctlr.n++] = (uchar)ch;
78
79         for(;;){
80                 /* message hasn't started yet? */
81                 if(ctlr.buf[0] != SOF){
82                         p = memchr(ctlr.buf, SOF, ctlr.n);
83                         if(p == nil){
84                                 ctlr.n = 0;
85                                 break;
86                         } else {
87                                 ctlr.n -= p-ctlr.buf;
88                                 memmove(ctlr.buf, p, ctlr.n);
89                         }
90                 }
91         
92                 /* whole msg? */
93                 len = ctlr.buf[1] & 0xf;
94                 if(ctlr.n < 3 || ctlr.n < len+3)
95                         break;
96         
97                 /* check the sum */
98                 ctlr.buf[0] = ~SOF;     /* make sure we process this msg exactly once */
99                 cksum = 0;
100                 for(i = 1; i < len+2; i++)
101                         cksum += ctlr.buf[i];
102                 if(ctlr.buf[len+2] != cksum)
103                         continue;
104         
105                 /* parse resulting message */
106                 p = ctlr.buf+2;
107                 switch(ctlr.buf[1] >> 4){
108                 case BLversion:
109                         strncpy(ctlr.version, (char*)p, len);
110                         ctlr.version[len] = '0';
111                         strcat(ctlr.version, "\n");
112                         wakeup(&ctlr.r);
113                         break;
114                 case BLbuttons:
115                         if(len < 1 || buttoning)
116                                 break;
117                         buttoning = 1;
118                         b = p[0] & 0x7f;
119                         up = p[0] & 0x80;
120
121                         if(b <= 5){
122                                 /* like mouse buttons */
123                                 if(--b == 0)
124                                         b = 5;
125                                 penbutton(up, 1<<b);
126                         }
127                         buttoning = 0;
128                         break;
129                 case BLtouch:
130                         if(touching)
131                                 break;
132                         touching = 1;
133                         if(len == 4) {
134                                 if (samseq++ > 10){
135                                         if (landscape)
136                                                 pentrackxy((p[0]<<8)|p[1], (p[2]<<8)|p[3]);
137                                         else
138                                                 pentrackxy((p[2]<<8)|p[3], (p[0]<<8)|p[1]);
139                                 }
140                         } else {
141                                 samseq = 0;
142                                 pentrackxy(-1, -1);
143                         }
144                         touching = 0;
145                         break;
146                 case BLled:
147                         wakeup(&ctlr.r);
148                         break;
149                 case BLbattery:
150                         if(len >= 5){
151                                 ctlr.acstatus = p[0];
152                                 ctlr.voltage = (p[3]<<8)|p[2];
153                                 ctlr.batstatus = p[4];
154                                 ctlr.batchem = p[1];
155                         }
156                         wakeup(&ctlr.r);
157                         break;
158                 case BLbacklight:
159                         wakeup(&ctlr.r);
160                         break;
161                 default:
162                         print("unknown µc message: %ux", ctlr.buf[1] >> 4);
163                         for(i = 0; i < len; i++)
164                                 print(" %ux", p[i]);
165                         print("\n");
166                         break;
167                 }
168         
169                 /* remove the message */
170                 ctlr.n -= len+3;
171                 memmove(ctlr.buf, &ctlr.buf[len+3], ctlr.n);
172         }
173         return 0;
174 }
175
176 static void
177 _sendmsg(uchar id, uchar *data, int len)
178 {
179         uchar buf[20];
180         uchar cksum;
181         uchar c;
182         uchar *p = buf;
183         int i;
184
185         /* create the message */
186         if(sizeof(buf) < len+4)
187                 return;
188         cksum = (id<<4) | len;
189         *p++ = SOF;
190         *p++ = cksum;
191         for(i = 0; i < len; i++){
192                 c = data[i];
193                 cksum += c;
194                 *p++ = c;
195         }
196         *p++ = cksum;
197
198         /* send the message - there should be a more generic way to do this */
199         serialµcputs(buf, p-buf);
200 }
201
202 /* the tsleep takes care of lost acks */
203 static void
204 sendmsgwithack(uchar id, uchar *data, int len)
205 {
206         if(waserror()){
207                 qunlock(&ctlr);
208                 nexterror();
209         }
210         qlock(&ctlr);
211         _sendmsg(id, data, len);
212         tsleep(&ctlr.r, return0, 0, 100);
213         qunlock(&ctlr);
214         poperror();
215 }
216
217 static void
218 sendmsg(uchar id, uchar *data, int len)
219 {
220         if(waserror()){
221                 qunlock(&ctlr);
222                 nexterror();
223         }
224         qlock(&ctlr);
225         _sendmsg(id, data, len);
226         qunlock(&ctlr);
227         poperror();
228 }
229
230 void
231 µcinit(void)
232 {
233 }
234
235 static Chan*
236 µcattach(char* spec)
237 {
238         return devattach('r', spec);
239 }
240
241 static Walkqid*
242 µcwalk(Chan *c, Chan *nc, char **name, int nname)
243 {
244         return devwalk(c, nc, name, nname, µcdir, nelem(µcdir), devgen);
245 }
246
247 static int       
248 µcstat(Chan *c, uchar *dp, int n)
249 {
250         return devstat(c, dp, n, µcdir, nelem(µcdir), devgen);
251 }
252
253 static Chan*
254 µcopen(Chan* c, int omode)
255 {
256         omode = openmode(omode);
257         if(!iseve())
258                 error(Eperm);
259         return devopen(c, omode, µcdir, nelem(µcdir), devgen);
260 }
261
262 static void      
263 µcclose(Chan*)
264 {
265 }
266
267 char*
268 acstatus(int x)
269 {
270         if(x)
271                 return "attached";
272         else
273                 return "detached";
274 }
275
276 char*
277 batstatus(int x)
278 {
279         switch(x){
280         case 1:         return "high";
281         case 2:         return "low";
282         case 4:         return "critical";
283         case 8:         return "charging";
284         case 0x80:      return "none";
285         }
286         return "ok";
287 }
288
289 static long      
290 µcread(Chan* c, void* a, long n, vlong off)
291 {
292         char buf[64];
293
294         if(c->qid.path == Qdir)
295                 return devdirread(c, a, n, µcdir, nelem(µcdir), devgen);
296
297         switch((ulong)c->qid.path){
298         case Qbattery:
299                 sendmsgwithack(BLbattery, nil, 0);              /* send a battery request */
300                 sprint(buf, "voltage: %d\nac: %s\nstatus: %s\n", ctlr.voltage,
301                         acstatus(ctlr.acstatus),
302                         batstatus(ctlr.batstatus));
303                 return readstr(off, a, n, buf);
304         case Qversion:
305                 sendmsgwithack(BLversion, nil, 0);              /* send a battery request */
306                 return readstr(off, a, n, ctlr.version);
307         }
308         error(Ebadarg);
309         return 0;
310 }
311
312 #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
313
314 static uchar lightdata[16];
315
316 static long      
317 µcwrite(Chan* c, void* a, long n, vlong)
318 {
319         Cmdbuf *cmd;
320         uchar data[16];
321         char str[64];
322         int i, j;
323         ulong l;
324         Rune r;
325         extern ulong resumeaddr[];
326         extern void power_resume(void);
327
328         if(c->qid.path == Qpower){
329                 if(!iseve())
330                         error(Eperm);
331                 if(strncmp(a, "suspend", 7) == 0)
332                         *resumeaddr = (ulong)power_resume;
333                 else if(strncmp(a, "halt", 4) == 0)
334                         *resumeaddr = 0;
335                 else if(strncmp(a, "wakeup", 6) == 0){
336                         cmd = parsecmd(a, n);
337                         if (cmd->nf != 2)
338                                 error(Ebadarg);
339                         l = strtoul(cmd->f[1], 0, 0);
340                         rtcalarm(l);
341                         return n;
342                 } else
343                         error(Ebadarg);
344                 deepsleep();
345                 return n;
346         }
347
348         cmd = parsecmd(a, n);
349         if(cmd->nf > 15)
350                 error(Ebadarg);
351         for(i = 0; i < cmd->nf; i++)
352                 data[i] = atoi(cmd->f[i]);
353
354         switch((ulong)c->qid.path){
355         case Qled:
356                 sendmsgwithack(BLled, data, cmd->nf);
357                 break;
358         case Qbacklight:
359                 memmove(lightdata, data, 16);
360                 sendmsgwithack(BLbacklight, data, cmd->nf);
361                 break;
362         case Qcruft:
363 //              lcdtweak(cmd);
364                 break;
365         default:
366                 error(Ebadarg);
367         }
368         return n;
369 }
370
371 void 
372 µcpower(int on)
373 {
374         uchar data[16];
375         if (on == 0)
376                 return;
377         /* maybe dangerous, not holding the lock */
378         if (lightdata[0] == 0){
379                 data[0]= 2;
380                 data[1]= 1;
381                 data[2]= 0;
382         } else
383                 memmove(data, lightdata, 16);
384         _sendmsg(0xd, data, 3);
385         wakeup(&ctlr.r);
386 }
387
388 Dev µcdevtab = {
389         'r',
390         "µc",
391
392         devreset,
393         µcinit,
394         devshutdown,
395         µcattach,
396         µcwalk,
397         µcstat,
398         µcopen,
399         devcreate,
400         µcclose,
401         µcread,
402         devbread,
403         µcwrite,
404         devbwrite,
405         devremove,
406         devwstat,
407 };