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