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/devpcmcia.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 "../port/error.h"
    7 #include "io.h"
    8 
    9 /*
   10  * BUG: insertion events are detected by polling.
   11  *      Should look into the compaq docs to see if
   12  *      there's an interrupt for card insertion
   13  *      there's probably one.
   14  */
   15 
   16 static PCMslot  slot[2];
   17 int nslot = 2;
   18 
   19 struct {
   20         Ref;
   21         Rendez  event;          // where to wait for card events
   22         int     evreader;       // there's a reader for events
   23 } pcmcia;
   24 
   25 enum
   26 {
   27         Qdir,
   28         Qmem,
   29         Qattr,
   30         Qctl,
   31         Qevs,
   32 
   33         Nents = 3,
   34 };
   35 
   36 enum
   37 {
   38         /*
   39          *  configuration registers - they start at an offset in attribute
   40          *  memory found in the CIS.
   41          */
   42         Rconfig=        0,
   43          Creset=         (1<<7),        /*  reset device */
   44          Clevel=         (1<<6),        /*  level sensitive interrupt line */
   45 };
   46 
   47 static void increfp(PCMslot*);
   48 static void decrefp(PCMslot*);
   49 static void slotmap(int, ulong, ulong, ulong);
   50 static void slottiming(int, int, int, int, int);
   51 static void slotinfo(Ureg*, void*);
   52 
   53 #define TYPE(c)         (((ulong)c->qid.path)&0xff)
   54 #define PATH(s,t)       (((s)<<8)|(t))
   55 
   56 static PCMslot*
   57 slotof(Chan *c)
   58 {
   59         ulong x;
   60 
   61         x = c->qid.path;
   62         return slot + ((x>>8)&0xff);
   63 }
   64 
   65 static int
   66 pcmgen(Chan *c, char *, Dirtab * , int, int i, Dir *dp)
   67 {
   68         int slotno;
   69         Qid qid;
   70         long len;
   71         PCMslot *sp;
   72 
   73         if(i == DEVDOTDOT){
   74                 mkqid(&qid, Qdir, 0, QTDIR);
   75                 devdir(c, qid, "#y", 0, eve, 0555, dp);
   76                 return 1;
   77         }
   78 
   79         if(i >= Nents*nslot + 1)
   80                 return -1;
   81         if(i == Nents*nslot){
   82                 len = 0;
   83                 qid.path = PATH(0, Qevs);
   84                 snprint(up->genbuf, sizeof up->genbuf, "pcmevs");
   85                 goto found;
   86         }
   87 
   88         slotno = i/Nents;
   89         sp = slot + slotno;
   90         len = 0;
   91         switch(i%Nents){
   92         case 0:
   93                 qid.path = PATH(slotno, Qmem);
   94                 snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);
   95                 len = sp->memlen;
   96                 break;
   97         case 1:
   98                 qid.path = PATH(slotno, Qattr);
   99                 snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);
  100                 len = sp->memlen;
  101                 break;
  102         case 2:
  103                 qid.path = PATH(slotno, Qctl);
  104                 snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);
  105                 break;
  106         }
  107 found:
  108         qid.vers = 0;
  109         qid.type = QTFILE;
  110         devdir(c, qid, up->genbuf, len, eve, 0660, dp);
  111         return 1;
  112 }
  113 
  114 static int
  115 bitno(ulong x)
  116 {
  117         int i;
  118 
  119         for(i = 0; i < 8*sizeof(x); i++)
  120                 if((1<<i) & x)
  121                         break;
  122         return i;
  123 }
  124 
  125 /*
  126  *  set up the cards, default timing is 300 ns
  127  */
  128 static void
  129 pcmciareset(void)
  130 {
  131         /* staticly map the whole area */
  132         slotmap(0, PHYSPCM0REGS, PYHSPCM0ATTR, PYHSPCM0MEM);
  133         slotmap(1, PHYSPCM1REGS, PYHSPCM1ATTR, PYHSPCM1MEM);
  134 
  135         /* set timing to the default, 300 */
  136         slottiming(0, 300, 300, 300, 0);
  137         slottiming(1, 300, 300, 300, 0);
  138 
  139         /* if there's no pcmcia sleave, no interrupts */
  140         if(gpioregs->level & GPIO_OPT_IND_i)
  141                 return;
  142 
  143         /* sleave there, interrupt on card removal */
  144         intrenable(GPIOrising, bitno(GPIO_CARD_IND1_i), slotinfo, nil, "pcmcia slot1 status");
  145         intrenable(GPIOrising, bitno(GPIO_CARD_IND0_i), slotinfo, nil, "pcmcia slot0 status");
  146 }
  147 
  148 static Chan*
  149 pcmciaattach(char *spec)
  150 {
  151         return devattach('y', spec);
  152 }
  153 
  154 static Walkqid*
  155 pcmciawalk(Chan *c, Chan *nc, char **name, int nname)
  156 {
  157         return devwalk(c, nc, name, nname, 0, 0, pcmgen);
  158 }
  159 
  160 static int
  161 pcmciastat(Chan *c, uchar *db, int n)
  162 {
  163         return devstat(c, db, n, 0, 0, pcmgen);
  164 }
  165 
  166 static Chan*
  167 pcmciaopen(Chan *c, int omode)
  168 {
  169         PCMslot *slotp;
  170 
  171         if(c->qid.type & QTDIR){
  172                 if(omode != OREAD)
  173                         error(Eperm);
  174         } else {
  175                 slotp = slotof(c);
  176                 increfp(slotp);
  177         }
  178         c->mode = openmode(omode);
  179         c->flag |= COPEN;
  180         c->offset = 0;
  181         return c;
  182 }
  183 
  184 static void
  185 pcmciaclose(Chan *c)
  186 {
  187         if(c->flag & COPEN)
  188                 if((c->qid.type & QTDIR) == 0)
  189                         decrefp(slotof(c));
  190 }
  191 
  192 /* a memmove using only bytes */
  193 static void
  194 memmoveb(uchar *to, uchar *from, int n)
  195 {
  196         while(n-- > 0)
  197                 *to++ = *from++;
  198 }
  199 
  200 /* a memmove using only shorts & bytes */
  201 static void
  202 memmoves(uchar *to, uchar *from, int n)
  203 {
  204         ushort *t, *f;
  205 
  206         if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
  207                 while(n-- > 0)
  208                         *to++ = *from++;
  209         } else {
  210                 n = n/2;
  211                 t = (ushort*)to;
  212                 f = (ushort*)from;
  213                 while(n-- > 0)
  214                         *t++ = *f++;
  215         }
  216 }
  217 
  218 static long
  219 pcmread(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
  220 {
  221         rlock(sp);
  222         if(waserror()){
  223                 runlock(sp);
  224                 nexterror();
  225         }
  226         if(off > len)
  227                 return 0;
  228         if(off + n > len)
  229                 n = len - off;
  230         memmoveb(a, start+off, n);
  231         runlock(sp);
  232         poperror();
  233         return n;
  234 }
  235 
  236 static long
  237 pcmctlread(void *a, long n, ulong off, PCMslot *sp)
  238 {
  239         char *p, *buf, *e;
  240 
  241         buf = p = malloc(READSTR);
  242         if(waserror()){
  243                 free(buf);
  244                 nexterror();
  245         }
  246         e = p + READSTR;
  247 
  248         buf[0] = 0;
  249         if(sp->occupied){
  250                 p = seprint(p, e, "occupied\n");
  251                 if(sp->verstr[0])
  252                         p = seprint(p, e, "version %s\n", sp->verstr);
  253         }
  254         USED(p);
  255 
  256         n = readstr(off, a, n, buf);
  257         free(buf);
  258         poperror();
  259         return n;
  260 }
  261 
  262 static int
  263 inserted(void *)
  264 {
  265         if (slot[0].inserted)
  266                 return 1;
  267         if (slot[1].inserted)
  268                 return 2;
  269         return 0;
  270 }
  271 
  272 static long
  273 pcmevsread(void *a, long n, ulong off)
  274 {
  275         int i;
  276         char *buf = nil;
  277         char *e;
  278 
  279         if (pcmcia.evreader)
  280                 error("At most one reader");
  281         off = 0;
  282         pcmcia.evreader++;
  283         if (waserror()){
  284                 free(buf);
  285                 pcmcia.evreader--;
  286                 nexterror();
  287         }
  288         while((i = inserted(nil)) == 0){
  289                 slotinfo(nil, nil);
  290                 tsleep(&pcmcia.event, inserted, nil, 500);
  291         }
  292         pcmcia.evreader--;
  293         slot[i-1].inserted = 0;
  294         buf = malloc(READSTR);
  295         e = buf + READSTR;
  296         buf[0] = 0;
  297         seprint(buf, e, "#y/pcm%dctl\n", i-1);
  298         n = readstr(off, a, n, buf);
  299         free(buf);
  300         poperror();
  301         return n;
  302 }
  303 
  304 static long
  305 pcmciaread(Chan *c, void *a, long n, vlong off)
  306 {
  307         PCMslot *sp;
  308         ulong offset = off;
  309 
  310         sp = slotof(c);
  311 
  312         switch(TYPE(c)){
  313         case Qdir:
  314                 return devdirread(c, a, n, 0, 0, pcmgen);
  315         case Qmem:
  316                 if(!sp->occupied)
  317                         error(Eio);
  318                 return pcmread(a, n, offset, sp, sp->mem, 64*OneMeg);
  319         case Qattr:
  320                 if(!sp->occupied)
  321                         error(Eio);
  322                 return pcmread(a, n, offset, sp, sp->attr, OneMeg);
  323         case Qevs:
  324                 return pcmevsread(a, n, offset);
  325         case Qctl:
  326                 return pcmctlread(a, n, offset, sp);
  327         }
  328         error(Ebadarg);
  329         return -1;      /* not reached */
  330 }
  331 
  332 static long
  333 pcmwrite(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
  334 {
  335         rlock(sp);
  336         if(waserror()){
  337                 runlock(sp);
  338                 nexterror();
  339         }
  340         if(off > len)
  341                 error(Eio);
  342         if(off + n > len)
  343                 error(Eio);
  344         memmoveb(start+off, a, n);
  345         poperror();
  346         runlock(sp);
  347         return n;
  348 }
  349 
  350 static long
  351 pcmctlwrite(char *p, long n, ulong, PCMslot *sp)
  352 {
  353         Cmdbuf *cmd;
  354         uchar *cp;
  355         int index, i, dtx;
  356         Rune r;
  357         DevConf cf;
  358         Devport port;
  359 
  360         cmd = parsecmd(p, n);
  361         if(strcmp(cmd->f[0], "configure") == 0){
  362                 wlock(sp);
  363                 if(waserror()){
  364                         wunlock(sp);
  365                         nexterror();
  366                 }
  367 
  368                 /* see if driver exists and is configurable */
  369                 if(cmd->nf < 3)
  370                         error(Ebadarg);
  371                 p = cmd->f[1];
  372                 if(*p++ != '#')
  373                         error(Ebadarg);
  374                 p += chartorune(&r, p);
  375                 dtx = devno(r, 1);
  376                 if(dtx < 0)
  377                         error("no such device type");
  378                 if(devtab[dtx]->config == nil)
  379                         error("not a dynamicly configurable device");
  380 
  381                 /* set pcmcia card configuration */
  382                 index = 0;
  383                 if(sp->def != nil)
  384                         index = sp->def->index;
  385                 if(cmd->nf > 3){
  386                         i = atoi(cmd->f[3]);
  387                         if(i < 0 || i >= sp->nctab)
  388                                 error("bad configuration index");
  389                         index = i;
  390                 }
  391                 if(sp->cfg[0].cpresent & (1<<Rconfig)){
  392                         cp = sp->attr;
  393                         cp += sp->cfg[0].caddr + Rconfig;
  394                         *cp = index;
  395                 }
  396 
  397                 /* configure device */
  398                 memset(&cf, 0, sizeof cf);
  399                 kstrdup(&cf.type, cmd->f[2]);
  400                 cf.mem = (ulong)sp->mem;
  401                 cf.ports = &port;
  402                 cf.ports[0].port = (ulong)sp->regs;
  403                 cf.ports[0].size = 0;
  404                 cf.nports = 1;
  405                 cf.itype = GPIOfalling;
  406                 cf.intnum = bitno(sp == slot ? GPIO_CARD_IRQ0_i : GPIO_CARD_IRQ1_i);
  407                 if(devtab[dtx]->config(1, p, &cf) < 0)
  408                         error("couldn't configure device");
  409                 sp->dev = devtab[dtx];
  410                 free(cf.type);
  411                 wunlock(sp);
  412                 poperror();
  413 
  414                 /* don't let the power turn off */
  415                 increfp(sp);
  416         }else if(strcmp(cmd->f[0], "remove") == 0){
  417                 /* see if driver exists and is configurable */
  418                 if(cmd->nf != 2)
  419                         error(Ebadarg);
  420                 p = cmd->f[1];
  421                 if(*p++ != '#')
  422                         error(Ebadarg);
  423                 p += chartorune(&r, p);
  424                 dtx = devno(r, 1);
  425                 if(dtx < 0)
  426                         error("no such device type");
  427                 if(devtab[dtx]->config == nil)
  428                         error("not a dynamicly configurable device");
  429                 if(devtab[dtx]->config(0, p, nil) < 0)
  430                         error("couldn't unconfigure device");
  431 
  432                 /* let the power turn off */
  433                 decrefp(sp);
  434         }
  435         free(cmd);
  436 
  437         return 0;
  438 }
  439 
  440 static long
  441 pcmciawrite(Chan *c, void *a, long n, vlong off)
  442 {
  443         PCMslot *sp;
  444         ulong offset = off;
  445 
  446         sp = slotof(c);
  447 
  448         switch(TYPE(c)){
  449         case Qmem:
  450                 if(!sp->occupied)
  451                         error(Eio);
  452                 return pcmwrite(a, n, offset, sp, sp->mem, 64*OneMeg);
  453         case Qattr:
  454                 if(!sp->occupied)
  455                         error(Eio);
  456                 return pcmwrite(a, n, offset, sp, sp->attr, OneMeg);
  457         case Qevs:
  458                 break;
  459         case Qctl:
  460                 if(!sp->occupied)
  461                         error(Eio);
  462                 return pcmctlwrite(a, n, offset, sp);
  463         }
  464         error(Ebadarg);
  465         return -1;      /* not reached */
  466 }
  467 
  468 /*
  469  * power up/down pcmcia
  470  */
  471 void
  472 pcmciapower(int on)
  473 {
  474         PCMslot *sp;
  475 
  476         /* if there's no pcmcia sleave, no interrupts */
  477 iprint("pcmciapower %d\n", on);
  478 
  479         if (on){
  480                 /* set timing to the default, 300 */
  481                 slottiming(0, 300, 300, 300, 0);
  482                 slottiming(1, 300, 300, 300, 0);
  483 
  484                 /* if there's no pcmcia sleave, no interrupts */
  485                 if(gpioregs->level & GPIO_OPT_IND_i){
  486                         iprint("pcmciapower: no sleeve\n");
  487                         return;
  488                 }
  489 
  490                 for (sp = slot; sp < slot + nslot; sp++){
  491                         if (sp->dev){
  492                                 increfp(sp);
  493                                 iprint("pcmciapower: %s\n", sp->verstr);
  494                                 delay(10000);
  495                                 if (sp->dev->power)
  496                                         sp->dev->power(on);
  497                         }
  498                 }
  499         }else{
  500                 if(gpioregs->level & GPIO_OPT_IND_i){
  501                         iprint("pcmciapower: no sleeve\n");
  502                         return;
  503                 }
  504 
  505                 for (sp = slot; sp < slot + nslot; sp++){
  506                         if (sp->dev){
  507                                 if (sp->dev->power)
  508                                         sp->dev->power(on);
  509                                 decrefp(sp);
  510                         }
  511                         sp->occupied = 0;
  512                         sp->cisread = 0;
  513                 }
  514                 egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
  515         }
  516 }
  517 
  518 Dev pcmciadevtab = {
  519         'y',
  520         "pcmcia",
  521 
  522         pcmciareset,
  523         devinit,
  524         devshutdown,
  525         pcmciaattach,
  526         pcmciawalk,
  527         pcmciastat,
  528         pcmciaopen,
  529         devcreate,
  530         pcmciaclose,
  531         pcmciaread,
  532         devbread,
  533         pcmciawrite,
  534         devbwrite,
  535         devremove,
  536         devwstat,
  537         pcmciapower,
  538 };
  539 
  540 /* see what's there */
  541 static void
  542 slotinfo(Ureg*, void*)
  543 {
  544         ulong x = gpioregs->level;
  545 
  546         if(x & GPIO_OPT_IND_i){
  547                 /* no expansion pack */
  548                 slot[0].occupied = slot[0].inserted = 0;
  549                 slot[1].occupied = slot[1].inserted = 0;
  550         } else {
  551                 if(x & GPIO_CARD_IND0_i){
  552                         slot[0].occupied = slot[0].inserted = 0;
  553                         slot[0].cisread = 0;
  554                 } else {
  555                         if(slot[0].occupied == 0){
  556                                 slot[0].inserted = 1;
  557                                 slot[0].cisread = 0;
  558                         }
  559                         slot[0].occupied = 1;
  560                 }
  561                 if(x & GPIO_CARD_IND1_i){
  562                         slot[1].occupied = slot[1].inserted = 0;
  563                         slot[1].cisread = 0;
  564                 } else {
  565                         if(slot[1].occupied == 0){
  566                                 slot[1].inserted = 1;
  567                                 slot[1].cisread = 0;
  568                         }
  569                         slot[1].occupied = 1;
  570                 }
  571                 if (inserted(nil))
  572                         wakeup(&pcmcia.event);
  573         }
  574 }
  575 
  576 /* use reference card to turn cards on and off */
  577 static void
  578 increfp(PCMslot *sp)
  579 {
  580         wlock(sp);
  581         if(waserror()){
  582                 wunlock(sp);
  583                 nexterror();
  584         }
  585 
  586 iprint("increfp %ld\n", sp - slot);
  587         if(incref(&pcmcia) == 1){
  588 iprint("increfp full power\n");
  589                 egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 1);
  590                 delay(200);
  591                 egpiobits(EGPIO_pcmcia_reset, 1);
  592                 delay(100);
  593                 egpiobits(EGPIO_pcmcia_reset, 0);
  594                 delay(500);
  595         }
  596         incref(&sp->ref);
  597         slotinfo(nil, nil);
  598         if(sp->occupied && sp->cisread == 0) {
  599                 pcmcisread(sp);
  600         }
  601 
  602         wunlock(sp);
  603         poperror();
  604 }
  605 
  606 static void
  607 decrefp(PCMslot *sp)
  608 {
  609 iprint("decrefp %ld\n", sp - slot);
  610         decref(&sp->ref);
  611         if(decref(&pcmcia) == 0){
  612 iprint("increfp power down\n");
  613                 egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
  614         }
  615 }
  616 
  617 /*
  618  *  the regions are staticly mapped
  619  */
  620 static void
  621 slotmap(int slotno, ulong regs, ulong attr, ulong mem)
  622 {
  623         PCMslot *sp;
  624 
  625         sp = &slot[slotno];
  626         sp->slotno = slotno;
  627         sp->memlen = 64*OneMeg;
  628         sp->verstr[0] = 0;
  629 
  630         sp->mem = mapmem(mem, 64*OneMeg, 0);
  631         sp->memmap.ca = 0;
  632         sp->memmap.cea = 64*MB;
  633         sp->memmap.isa = (ulong)mem;
  634         sp->memmap.len = 64*OneMeg;
  635         sp->memmap.attr = 0;
  636 
  637         sp->attr = mapmem(attr, OneMeg, 0);
  638         sp->attrmap.ca = 0;
  639         sp->attrmap.cea = MB;
  640         sp->attrmap.isa = (ulong)attr;
  641         sp->attrmap.len = OneMeg;
  642         sp->attrmap.attr = 1;
  643 
  644         sp->regs = mapspecial(regs, 32*1024);
  645 }
  646 
  647 PCMmap*
  648 pcmmap(int slotno, ulong, int, int attr)
  649 {
  650         if(slotno > nslot)
  651                 panic("pcmmap");
  652         if(attr)
  653                 return &slot[slotno].attrmap;
  654         else
  655                 return &slot[slotno].memmap;
  656 }
  657 
  658 void
  659 pcmunmap(int, PCMmap*)
  660 {
  661 }
  662 
  663 /*
  664  *  setup card timings
  665  *    times are in ns
  666  *    count = ceiling[access-time/(2*3*T)] - 1, where T is a processor cycle
  667  *
  668  */
  669 static int
  670 ns2count(int ns)
  671 {
  672         ulong y;
  673 
  674         /* get 100 times cycle time */
  675         y = 100000000/(conf.hz/1000);
  676 
  677         /* get 10 times ns/(cycle*6) */
  678         y = (1000*ns)/(6*y);
  679 
  680         /* round up */
  681         y += 9;
  682         y /= 10;
  683 
  684         /* subtract 1 */
  685         return y-1;
  686 }
  687 static void
  688 slottiming(int slotno, int tio, int tattr, int tmem, int fast)
  689 {
  690         ulong x;
  691 
  692         x = 0;
  693         if(fast)
  694                 x |= 1<<MECR_fast0;
  695         x |= ns2count(tio) << MECR_io0;
  696         x |= ns2count(tattr) << MECR_attr0;
  697         x |= ns2count(tmem) << MECR_mem0;
  698         if(slotno == 0){
  699                 x |= memconfregs->mecr & 0xffff0000;
  700         } else {
  701                 x <<= 16;
  702                 x |= memconfregs->mecr & 0xffff;
  703         }
  704         memconfregs->mecr = x;
  705 }
  706 
  707 /* For compat with ../pc devices. Don't use it for the bitsy 
  708  */
  709 int
  710 pcmspecial(char*, ISAConf*)
  711 {
  712         return -1;
  713 }

Cache object: b950b82e3e4ed42dd0a38c6c04e76fc1


[ 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.