The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bitsy/devµc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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, nelemcdir), devgen);
  279 }
  280 
  281 static int       
  282 µcstat(Chan *c, uchar *dp, int n)
  283 {
  284         return devstat(c, dp, n, µcdir, nelemcdir), 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, nelemcdir), 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, nelemcdir), 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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.