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/pc/devi82365.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  *  Intel 82365SL PCIC controller and compatibles.
   11  */
   12 enum
   13 {
   14         /*
   15          *  registers indices
   16          */
   17         Rid=            0x0,            /* identification and revision */
   18         Ris=            0x1,            /* interface status */
   19         Rpc=            0x2,            /* power control */
   20          Foutena=        (1<<7),        /*  output enable */
   21          Fautopower=     (1<<5),        /*  automatic power switching */
   22          Fcardena=       (1<<4),        /*  PC card enable */
   23         Rigc=           0x3,            /* interrupt and general control */
   24          Fiocard=        (1<<5),        /*  I/O card (vs memory) */
   25          Fnotreset=      (1<<6),        /*  reset if not set */ 
   26          FSMIena=        (1<<4),        /*  enable change interrupt on SMI */ 
   27         Rcsc=           0x4,            /* card status change */
   28         Rcscic=         0x5,            /* card status change interrupt config */
   29          Fchangeena=     (1<<3),        /*  card changed */
   30          Fbwarnena=      (1<<1),        /*  card battery warning */
   31          Fbdeadena=      (1<<0),        /*  card battery dead */
   32         Rwe=            0x6,            /* address window enable */
   33          Fmem16=         (1<<5),        /*  use A23-A12 to decode address */
   34         Rio=            0x7,            /* I/O control */
   35          Fwidth16=       (1<<0),        /*  16 bit data width */
   36          Fiocs16=        (1<<1),        /*  IOCS16 determines data width */
   37          Fzerows=        (1<<2),        /*  zero wait state */
   38          Ftiming=        (1<<3),        /*  timing register to use */
   39         Riobtm0lo=      0x8,            /* I/O address 0 start low byte */
   40         Riobtm0hi=      0x9,            /* I/O address 0 start high byte */
   41         Riotop0lo=      0xa,            /* I/O address 0 stop low byte */
   42         Riotop0hi=      0xb,            /* I/O address 0 stop high byte */
   43         Riobtm1lo=      0xc,            /* I/O address 1 start low byte */
   44         Riobtm1hi=      0xd,            /* I/O address 1 start high byte */
   45         Riotop1lo=      0xe,            /* I/O address 1 stop low byte */
   46         Riotop1hi=      0xf,            /* I/O address 1 stop high byte */
   47         Rmap=           0x10,           /* map 0 */
   48 
   49         /*
   50          *  CL-PD67xx extension registers
   51          */
   52         Rmisc1=         0x16,           /* misc control 1 */
   53          F5Vdetect=      (1<<0),
   54          Fvcc3V=         (1<<1),
   55          Fpmint=         (1<<2),
   56          Fpsirq=         (1<<3),
   57          Fspeaker=       (1<<4),
   58          Finpack=        (1<<7),
   59         Rfifo=          0x17,           /* fifo control */
   60          Fflush=         (1<<7),        /*  flush fifo */
   61         Rmisc2=         0x1E,           /* misc control 2 */
   62          Flowpow=        (1<<1),        /*  low power mode */
   63         Rchipinfo=      0x1F,           /* chip information */
   64         Ratactl=        0x26,           /* ATA control */
   65 
   66         /*
   67          *  offsets into the system memory address maps
   68          */
   69         Mbtmlo=         0x0,            /* System mem addr mapping start low byte */
   70         Mbtmhi=         0x1,            /* System mem addr mapping start high byte */
   71          F16bit=         (1<<7),        /*  16-bit wide data path */
   72         Mtoplo=         0x2,            /* System mem addr mapping stop low byte */
   73         Mtophi=         0x3,            /* System mem addr mapping stop high byte */
   74          Ftimer1=        (1<<6),        /*  timer set 1 */
   75         Mofflo=         0x4,            /* Card memory offset address low byte */
   76         Moffhi=         0x5,            /* Card memory offset address high byte */
   77          Fregactive=     (1<<6),        /*  attribute memory */
   78 
   79         /*
   80          *  configuration registers - they start at an offset in attribute
   81          *  memory found in the CIS.
   82          */
   83         Rconfig=        0,
   84          Creset=         (1<<7),        /*  reset device */
   85          Clevel=         (1<<6),        /*  level sensitive interrupt line */
   86          Cirq=           (1<<2),        /*  IRQ enable */
   87          Cdecode=        (1<<1),        /*  address decode */
   88          Cfunc=          (1<<0),        /*  function enable */
   89         Riobase0=       5,
   90         Riobase1=       6,
   91         Riosize=        9,
   92 };
   93 
   94 #define MAP(x,o)        (Rmap + (x)*0x8 + o)
   95 
   96 typedef struct I82365   I82365;
   97 
   98 /* a controller */
   99 enum
  100 {
  101         Ti82365,
  102         Tpd6710,
  103         Tpd6720,
  104         Tvg46x,
  105 };
  106 struct I82365
  107 {
  108         int     type;
  109         int     dev;
  110         int     nslot;
  111         int     xreg;           /* index register address */
  112         int     dreg;           /* data register address */
  113         int     irq;
  114 };
  115 static I82365 *controller[4];
  116 static int ncontroller;
  117 static PCMslot  *slot;
  118 static PCMslot  *lastslot;
  119 static nslot;
  120 
  121 static void     i82365intr(Ureg*, void*);
  122 static int      pcmio(int, ISAConf*);
  123 static long     pcmread(int, int, void*, long, vlong);
  124 static long     pcmwrite(int, int, void*, long, vlong);
  125 
  126 static void i82365dump(PCMslot*);
  127 
  128 /*
  129  *  reading and writing card registers
  130  */
  131 static uchar
  132 rdreg(PCMslot *pp, int index)
  133 {
  134         outb(((I82365*)pp->cp)->xreg, pp->base + index);
  135         return inb(((I82365*)pp->cp)->dreg);
  136 }
  137 static void
  138 wrreg(PCMslot *pp, int index, uchar val)
  139 {
  140         outb(((I82365*)pp->cp)->xreg, pp->base + index);
  141         outb(((I82365*)pp->cp)->dreg, val);
  142 }
  143 
  144 /*
  145  *  get info about card
  146  */
  147 static void
  148 slotinfo(PCMslot *pp)
  149 {
  150         uchar isr;
  151 
  152         isr = rdreg(pp, Ris);
  153         pp->occupied = (isr & (3<<2)) == (3<<2);
  154         pp->powered = isr & (1<<6);
  155         pp->battery = (isr & 3) == 3;
  156         pp->wrprot = isr & (1<<4);
  157         pp->busy = isr & (1<<5);
  158         pp->msec = TK2MS(MACHP(0)->ticks);
  159 }
  160 
  161 static int
  162 vcode(int volt)
  163 {
  164         switch(volt){
  165         case 5:
  166                 return 1;
  167         case 12:
  168                 return 2;
  169         default:
  170                 return 0;
  171         }
  172 }
  173 
  174 /*
  175  *  enable the slot card
  176  */
  177 static void
  178 slotena(PCMslot *pp)
  179 {
  180         if(pp->enabled)
  181                 return;
  182 
  183         /* power up and unreset, wait's are empirical (???) */
  184         wrreg(pp, Rpc, Fautopower|Foutena|Fcardena);
  185         delay(300);
  186         wrreg(pp, Rigc, 0);
  187         delay(100);
  188         wrreg(pp, Rigc, Fnotreset);
  189         delay(500);
  190 
  191         /* get configuration */
  192         slotinfo(pp);
  193         if(pp->occupied){
  194                 pcmcisread(pp);
  195                 pp->enabled = 1;
  196         } else
  197                 wrreg(pp, Rpc, Fautopower);
  198 }
  199 
  200 /*
  201  *  disable the slot card
  202  */
  203 static void
  204 slotdis(PCMslot *pp)
  205 {
  206         wrreg(pp, Rpc, 0);      /* turn off card power */
  207         wrreg(pp, Rwe, 0);      /* no windows */
  208         pp->enabled = 0;
  209 }
  210 
  211 /*
  212  *  status change interrupt
  213  */
  214 static void
  215 i82365intr(Ureg *, void *)
  216 {
  217         uchar csc, was;
  218         PCMslot *pp;
  219 
  220         if(slot == 0)
  221                 return;
  222 
  223         for(pp = slot; pp < lastslot; pp++){
  224                 csc = rdreg(pp, Rcsc);
  225                 was = pp->occupied;
  226                 slotinfo(pp);
  227                 if(csc & (1<<3) && was != pp->occupied){
  228                         if(!pp->occupied)
  229                                 slotdis(pp);
  230                 }
  231         }
  232 }
  233 
  234 enum
  235 {
  236         Mshift= 12,
  237         Mgran=  (1<<Mshift),    /* granularity of maps */
  238         Mmask=  ~(Mgran-1),     /* mask for address bits important to the chip */
  239 };
  240 
  241 /*
  242  *  get a map for pc card region, return corrected len
  243  */
  244 PCMmap*
  245 pcmmap(int slotno, ulong offset, int len, int attr)
  246 {
  247         PCMslot *pp;
  248         uchar we, bit;
  249         PCMmap *m, *nm;
  250         int i;
  251         ulong e;
  252 
  253         pp = slot + slotno;
  254         lock(&pp->mlock);
  255 
  256         /* convert offset to granularity */
  257         if(len <= 0)
  258                 len = 1;
  259         e = ROUND(offset+len, Mgran);
  260         offset &= Mmask;
  261         len = e - offset;
  262 
  263         /* look for a map that covers the right area */
  264         we = rdreg(pp, Rwe);
  265         bit = 1;
  266         nm = 0;
  267         for(m = pp->mmap; m < &pp->mmap[nelem(pp->mmap)]; m++){
  268                 if((we & bit))
  269                 if(m->attr == attr)
  270                 if(offset >= m->ca && e <= m->cea){
  271 
  272                         m->ref++;
  273                         unlock(&pp->mlock);
  274                         return m;
  275                 }
  276                 bit <<= 1;
  277                 if(nm == 0 && m->ref == 0)
  278                         nm = m;
  279         }
  280         m = nm;
  281         if(m == 0){
  282                 unlock(&pp->mlock);
  283                 return 0;
  284         }
  285 
  286         /* if isa space isn't big enough, free it and get more */
  287         if(m->len < len){
  288                 if(m->isa){
  289                         umbfree(m->isa, m->len);
  290                         m->len = 0;
  291                 }
  292                 m->isa = PADDR(umbmalloc(0, len, Mgran));
  293                 if(m->isa == 0){
  294                         print("pcmmap: out of isa space\n");
  295                         unlock(&pp->mlock);
  296                         return 0;
  297                 }
  298                 m->len = len;
  299         }
  300 
  301         /* set up new map */
  302         m->ca = offset;
  303         m->cea = m->ca + m->len;
  304         m->attr = attr;
  305         i = m-pp->mmap;
  306         bit = 1<<i;
  307         wrreg(pp, Rwe, we & ~bit);              /* disable map before changing it */
  308         wrreg(pp, MAP(i, Mbtmlo), m->isa>>Mshift);
  309         wrreg(pp, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit);
  310         wrreg(pp, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift);
  311         wrreg(pp, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8)));
  312         offset -= m->isa;
  313         offset &= (1<<25)-1;
  314         offset >>= Mshift;
  315         wrreg(pp, MAP(i, Mofflo), offset);
  316         wrreg(pp, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0));
  317         wrreg(pp, Rwe, we | bit);               /* enable map */
  318         m->ref = 1;
  319 
  320         unlock(&pp->mlock);
  321         return m;
  322 }
  323 
  324 void
  325 pcmunmap(int slotno, PCMmap* m)
  326 {
  327         PCMslot *pp;
  328 
  329         pp = slot + slotno;
  330         lock(&pp->mlock);
  331         m->ref--;
  332         unlock(&pp->mlock);
  333 }
  334 
  335 static void
  336 increfp(PCMslot *pp)
  337 {
  338         lock(pp);
  339         if(pp->ref++ == 0)
  340                 slotena(pp);
  341         unlock(pp);
  342 }
  343 
  344 static void
  345 decrefp(PCMslot *pp)
  346 {
  347         lock(pp);
  348         if(pp->ref-- == 1)
  349                 slotdis(pp);
  350         unlock(pp);
  351 }
  352 
  353 /*
  354  *  look for a card whose version contains 'idstr'
  355  */
  356 static int
  357 pcmcia_pcmspecial(char *idstr, ISAConf *isa)
  358 {
  359         PCMslot *pp;
  360         extern char *strstr(char*, char*);
  361         int enabled;
  362 
  363         for(pp = slot; pp < lastslot; pp++){
  364                 if(pp->special)
  365                         continue;       /* already taken */
  366 
  367                 /*
  368                  *  make sure we don't power on cards when we already know what's
  369                  *  in them.  We'll reread every two minutes if necessary
  370                  */
  371                 enabled = 0;
  372                 if (pp->msec == ~0 || TK2MS(MACHP(0)->ticks) - pp->msec > 120000){
  373                         increfp(pp);
  374                         enabled++;
  375                 }
  376 
  377                 if(pp->occupied) {
  378                         if(strstr(pp->verstr, idstr)){
  379                                 if (!enabled){
  380                                         enabled = 1;
  381                                         increfp(pp);
  382                                 }
  383                                 if(isa == 0 || pcmio(pp->slotno, isa) == 0){
  384                                         pp->special = 1;
  385                                         return pp->slotno;
  386                                 }
  387                         }
  388                 } else
  389                         pp->special = 1;
  390                 if (enabled)
  391                         decrefp(pp);
  392         }
  393         return -1;
  394 }
  395 
  396 static void
  397 pcmcia_pcmspecialclose(int slotno)
  398 {
  399         PCMslot *pp;
  400 
  401         if(slotno >= nslot)
  402                 panic("pcmspecialclose");
  403         pp = slot + slotno;
  404         pp->special = 0;
  405         decrefp(pp);
  406 }
  407 
  408 enum
  409 {
  410         Qdir,
  411         Qmem,
  412         Qattr,
  413         Qctl,
  414 
  415         Nents = 3,
  416 };
  417 
  418 #define SLOTNO(c)       ((ulong)((c->qid.path>>8)&0xff))
  419 #define TYPE(c) ((ulong)(c->qid.path&0xff))
  420 #define QID(s,t)        (((s)<<8)|(t))
  421 
  422 static int
  423 pcmgen(Chan *c, char*, Dirtab *, int , int i, Dir *dp)
  424 {
  425         int slotno;
  426         Qid qid;
  427         long len;
  428         PCMslot *pp;
  429 
  430         if(i == DEVDOTDOT){
  431                 mkqid(&qid, Qdir, 0, QTDIR);
  432                 devdir(c, qid, "#y", 0, eve, 0555, dp);
  433                 return 1;
  434         }
  435 
  436         if(i >= Nents*nslot)
  437                 return -1;
  438         slotno = i/Nents;
  439         pp = slot + slotno;
  440         len = 0;
  441         switch(i%Nents){
  442         case 0:
  443                 qid.path = QID(slotno, Qmem);
  444                 snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);
  445                 len = pp->memlen;
  446                 break;
  447         case 1:
  448                 qid.path = QID(slotno, Qattr);
  449                 snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);
  450                 len = pp->memlen;
  451                 break;
  452         case 2:
  453                 qid.path = QID(slotno, Qctl);
  454                 snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);
  455                 break;
  456         }
  457         qid.vers = 0;
  458         qid.type = QTFILE;
  459         devdir(c, qid, up->genbuf, len, eve, 0660, dp);
  460         return 1;
  461 }
  462 
  463 static char *chipname[] =
  464 {
  465 [Ti82365]       "Intel 82365SL",
  466 [Tpd6710]       "Cirrus Logic CL-PD6710",
  467 [Tpd6720]       "Cirrus Logic CL-PD6720",
  468 [Tvg46x]        "Vadem VG-46x",
  469 };
  470 
  471 static I82365*
  472 i82365probe(int x, int d, int dev)
  473 {
  474         uchar c, id;
  475         I82365 *cp;
  476         ISAConf isa;
  477         int i, nslot;
  478 
  479         outb(x, Rid + (dev<<7));
  480         id = inb(d);
  481         if((id & 0xf0) != 0x80)
  482                 return 0;               /* not a memory & I/O card */
  483         if((id & 0x0f) == 0x00)
  484                 return 0;               /* no revision number, not possible */
  485 
  486         cp = xalloc(sizeof(I82365));
  487         cp->xreg = x;
  488         cp->dreg = d;
  489         cp->dev = dev;
  490         cp->type = Ti82365;
  491         cp->nslot = 2;
  492 
  493         switch(id){
  494         case 0x82:
  495         case 0x83:
  496         case 0x84:
  497                 /* could be a cirrus */
  498                 outb(x, Rchipinfo + (dev<<7));
  499                 outb(d, 0);
  500                 c = inb(d);
  501                 if((c & 0xc0) != 0xc0)
  502                         break;
  503                 c = inb(d);
  504                 if((c & 0xc0) != 0x00)
  505                         break;
  506                 if(c & 0x20){
  507                         cp->type = Tpd6720;
  508                 } else {
  509                         cp->type = Tpd6710;
  510                         cp->nslot = 1;
  511                 }
  512 
  513                 /* low power mode */
  514                 outb(x, Rmisc2 + (dev<<7));
  515                 c = inb(d);
  516                 outb(d, c & ~Flowpow);
  517                 break;
  518         }
  519 
  520         /* if it's not a Cirrus, it could be a Vadem... */
  521         if(cp->type == Ti82365){
  522                 /* unlock the Vadem extended regs */
  523                 outb(x, 0x0E + (dev<<7));
  524                 outb(x, 0x37 + (dev<<7));
  525 
  526                 /* make the id register show the Vadem id */
  527                 outb(x, 0x3A + (dev<<7));
  528                 c = inb(d);
  529                 outb(d, c|0xC0);
  530                 outb(x, Rid + (dev<<7));
  531                 c = inb(d);
  532                 if(c & 0x08)
  533                         cp->type = Tvg46x;
  534 
  535                 /* go back to Intel compatible id */
  536                 outb(x, 0x3A + (dev<<7));
  537                 c = inb(d);
  538                 outb(d, c & ~0xC0);
  539         }
  540 
  541         memset(&isa, 0, sizeof(ISAConf));
  542         if(isaconfig("pcmcia", ncontroller, &isa) && isa.irq)
  543                 cp->irq = isa.irq;
  544         else
  545                 cp->irq = IrqPCMCIA;
  546 
  547         for(i = 0; i < isa.nopt; i++){
  548                 if(cistrncmp(isa.opt[i], "nslot=", 6))
  549                         continue;
  550                 nslot = strtol(&isa.opt[i][6], nil, 0);
  551                 if(nslot > 0 && nslot <= 2)
  552                         cp->nslot = nslot;
  553         }
  554 
  555         controller[ncontroller++] = cp;
  556         return cp;
  557 }
  558 
  559 static void
  560 i82365dump(PCMslot *pp)
  561 {
  562         int i;
  563 
  564         for(i = 0; i < 0x40; i++){
  565                 if((i&0x0F) == 0)
  566                         print("\n%2.2uX:        ", i);
  567                 print("%2.2uX ", rdreg(pp, i));
  568                 if(((i+1) & 0x0F) == 0x08)
  569                         print(" - ");
  570         }
  571         print("\n");
  572 }
  573 
  574 /*
  575  *  set up for slot cards
  576  */
  577 void
  578 devi82365link(void)
  579 {
  580         static int already;
  581         int i, j;
  582         I82365 *cp;
  583         PCMslot *pp;
  584         char buf[32], *p;
  585 
  586         if(already)
  587                 return;
  588         already = 1;
  589 
  590         if((p=getconf("pcmcia0")) && strncmp(p, "disabled", 8)==0)
  591                 return;
  592 
  593         if(_pcmspecial)
  594                 return;
  595         
  596         /* look for controllers if the ports aren't already taken */
  597         if(ioalloc(0x3E0, 2, 0, "i82365.0") >= 0){
  598                 i82365probe(0x3E0, 0x3E1, 0);
  599                 i82365probe(0x3E0, 0x3E1, 1);
  600                 if(ncontroller == 0)
  601                         iofree(0x3E0);
  602         }
  603         if(ioalloc(0x3E2, 2, 0, "i82365.1") >= 0){
  604                 i = ncontroller;
  605                 i82365probe(0x3E2, 0x3E3, 0);
  606                 i82365probe(0x3E2, 0x3E3, 1);
  607                 if(ncontroller == i)
  608                         iofree(0x3E2);
  609         }
  610 
  611         if(ncontroller == 0)
  612                 return;
  613 
  614         _pcmspecial = pcmcia_pcmspecial;
  615         _pcmspecialclose = pcmcia_pcmspecialclose;
  616 
  617         for(i = 0; i < ncontroller; i++)
  618                 nslot += controller[i]->nslot;
  619         slot = xalloc(nslot * sizeof(PCMslot));
  620 
  621         lastslot = slot;
  622         for(i = 0; i < ncontroller; i++){
  623                 cp = controller[i];
  624                 print("#y%d: %d slot %s: port 0x%uX irq %d\n",
  625                         i, cp->nslot, chipname[cp->type], cp->xreg, cp->irq);
  626                 for(j = 0; j < cp->nslot; j++){
  627                         pp = lastslot++;
  628                         pp->slotno = pp - slot;
  629                         pp->memlen = 64*MB;
  630                         pp->base = (cp->dev<<7) | (j<<6);
  631                         pp->cp = cp;
  632                         pp->msec = ~0;
  633                         pp->verstr[0] = 0;
  634                         slotdis(pp);
  635 
  636                         /* interrupt on status change */
  637                         wrreg(pp, Rcscic, (cp->irq<<4) | Fchangeena);
  638                         rdreg(pp, Rcsc);
  639                 }
  640 
  641                 /* for card management interrupts */
  642                 snprint(buf, sizeof buf, "i82365.%d", i);
  643                 intrenable(cp->irq, i82365intr, 0, BUSUNKNOWN, buf);
  644         }
  645 }
  646 
  647 static Chan*
  648 i82365attach(char *spec)
  649 {
  650         return devattach('y', spec);
  651 }
  652 
  653 static Walkqid*
  654 i82365walk(Chan *c, Chan *nc, char **name, int nname)
  655 {
  656         return devwalk(c, nc, name, nname, 0, 0, pcmgen);
  657 }
  658 
  659 static int
  660 i82365stat(Chan *c, uchar *db, int n)
  661 {
  662         return devstat(c, db, n, 0, 0, pcmgen);
  663 }
  664 
  665 static Chan*
  666 i82365open(Chan *c, int omode)
  667 {
  668         if(c->qid.type & QTDIR){
  669                 if(omode != OREAD)
  670                         error(Eperm);
  671         } else
  672                 increfp(slot + SLOTNO(c));
  673         c->mode = openmode(omode);
  674         c->flag |= COPEN;
  675         c->offset = 0;
  676         return c;
  677 }
  678 
  679 static void
  680 i82365close(Chan *c)
  681 {
  682         if(c->flag & COPEN)
  683                 if((c->qid.type & QTDIR) == 0)
  684                         decrefp(slot+SLOTNO(c));
  685 }
  686 
  687 /* a memmove using only bytes */
  688 static void
  689 memmoveb(uchar *to, uchar *from, int n)
  690 {
  691         while(n-- > 0)
  692                 *to++ = *from++;
  693 }
  694 
  695 /* a memmove using only shorts & bytes */
  696 static void
  697 memmoves(uchar *to, uchar *from, int n)
  698 {
  699         ushort *t, *f;
  700 
  701         if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
  702                 while(n-- > 0)
  703                         *to++ = *from++;
  704         } else {
  705                 n = n/2;
  706                 t = (ushort*)to;
  707                 f = (ushort*)from;
  708                 while(n-- > 0)
  709                         *t++ = *f++;
  710         }
  711 }
  712 
  713 static long
  714 pcmread(int slotno, int attr, void *a, long n, vlong off)
  715 {
  716         int i, len;
  717         PCMmap *m;
  718         uchar *ac;
  719         PCMslot *pp;
  720         ulong offset = off;
  721 
  722         pp = slot + slotno;
  723         if(pp->memlen < offset)
  724                 return 0;
  725         if(pp->memlen < offset + n)
  726                 n = pp->memlen - offset;
  727 
  728         m = 0;
  729         if(waserror()){
  730                 if(m)
  731                         pcmunmap(pp->slotno, m);
  732                 nexterror();
  733         }
  734 
  735         ac = a;
  736         for(len = n; len > 0; len -= i){
  737                 m = pcmmap(pp->slotno, offset, 0, attr);
  738                 if(m == 0)
  739                         error("cannot map PCMCIA card");
  740                 if(offset + len > m->cea)
  741                         i = m->cea - offset;
  742                 else
  743                         i = len;
  744                 memmoveb(ac, KADDR(m->isa + offset - m->ca), i);
  745                 pcmunmap(pp->slotno, m);
  746                 offset += i;
  747                 ac += i;
  748         }
  749 
  750         poperror();
  751         return n;
  752 }
  753 
  754 static long
  755 i82365read(Chan *c, void *a, long n, vlong off)
  756 {
  757         char *p, *buf, *e;
  758         PCMslot *pp;
  759         ulong offset = off;
  760 
  761         switch(TYPE(c)){
  762         case Qdir:
  763                 return devdirread(c, a, n, 0, 0, pcmgen);
  764         case Qmem:
  765         case Qattr:
  766                 return pcmread(SLOTNO(c), TYPE(c) == Qattr, a, n, off);
  767         case Qctl:
  768                 buf = p = malloc(READSTR);
  769                 e = p + READSTR;
  770                 pp = slot + SLOTNO(c);
  771 
  772                 buf[0] = 0;
  773                 if(pp->occupied){
  774                         p = seprint(p, e, "occupied\n");
  775                         if(pp->verstr[0])
  776                                 p = seprint(p, e, "version %s\n", pp->verstr);
  777                 }
  778                 if(pp->enabled)
  779                         p = seprint(p, e, "enabled\n");
  780                 if(pp->powered)
  781                         p = seprint(p, e, "powered\n");
  782                 if(pp->configed)
  783                         p = seprint(p, e, "configed\n");
  784                 if(pp->wrprot)
  785                         p = seprint(p, e, "write protected\n");
  786                 if(pp->busy)
  787                         p = seprint(p, e, "busy\n");
  788                 seprint(p, e, "battery lvl %d\n", pp->battery);
  789 
  790                 n = readstr(offset, a, n, buf);
  791                 free(buf);
  792 
  793                 return n;
  794         }
  795         error(Ebadarg);
  796         return -1;      /* not reached */
  797 }
  798 
  799 static long
  800 pcmwrite(int dev, int attr, void *a, long n, vlong off)
  801 {
  802         int i, len;
  803         PCMmap *m;
  804         uchar *ac;
  805         PCMslot *pp;
  806         ulong offset = off;
  807 
  808         pp = slot + dev;
  809         if(pp->memlen < offset)
  810                 return 0;
  811         if(pp->memlen < offset + n)
  812                 n = pp->memlen - offset;
  813 
  814         m = 0;
  815         if(waserror()){
  816                 if(m)
  817                         pcmunmap(pp->slotno, m);
  818                 nexterror();
  819         }
  820 
  821         ac = a;
  822         for(len = n; len > 0; len -= i){
  823                 m = pcmmap(pp->slotno, offset, 0, attr);
  824                 if(m == 0)
  825                         error("cannot map PCMCIA card");
  826                 if(offset + len > m->cea)
  827                         i = m->cea - offset;
  828                 else
  829                         i = len;
  830                 memmoveb(KADDR(m->isa + offset - m->ca), ac, i);
  831                 pcmunmap(pp->slotno, m);
  832                 offset += i;
  833                 ac += i;
  834         }
  835 
  836         poperror();
  837         return n;
  838 }
  839 
  840 static long
  841 i82365write(Chan *c, void *a, long n, vlong off)
  842 {
  843         PCMslot *pp;
  844         char buf[32];
  845 
  846         switch(TYPE(c)){
  847         case Qctl:
  848                 if(n >= sizeof(buf))
  849                         n = sizeof(buf) - 1;
  850                 strncpy(buf, a, n);
  851                 buf[n] = 0;
  852                 pp = slot + SLOTNO(c);
  853                 if(!pp->occupied)
  854                         error(Eio);
  855 
  856                 /* set vpp on card */
  857                 if(strncmp(buf, "vpp", 3) == 0)
  858                         wrreg(pp, Rpc, vcode(atoi(buf+3))|Fautopower|Foutena|Fcardena);
  859                 return n;
  860         case Qmem:
  861         case Qattr:
  862                 pp = slot + SLOTNO(c);
  863                 if(pp->occupied == 0 || pp->enabled == 0)
  864                         error(Eio);
  865                 n = pcmwrite(pp->slotno, TYPE(c) == Qattr, a, n, off);
  866                 if(n < 0)
  867                         error(Eio);
  868                 return n;
  869         }
  870         error(Ebadarg);
  871         return -1;      /* not reached */
  872 }
  873 
  874 Dev i82365devtab = {
  875         'y',
  876         "i82365",
  877 
  878         devreset,
  879         devinit,
  880         devshutdown,
  881         i82365attach,
  882         i82365walk,
  883         i82365stat,
  884         i82365open,
  885         devcreate,
  886         i82365close,
  887         i82365read,
  888         devbread,
  889         i82365write,
  890         devbwrite,
  891         devremove,
  892         devwstat,
  893 };
  894 
  895 /*
  896  *  configure the PCMslot for IO.  We assume very heavily that we can read
  897  *  configuration info from the CIS.  If not, we won't set up correctly.
  898  */
  899 static int
  900 pcmio(int slotno, ISAConf *isa)
  901 {
  902         uchar we, x, *p;
  903         PCMslot *pp;
  904         PCMconftab *ct, *et, *t;
  905         PCMmap *m;
  906         int i, index, irq;
  907         char *cp;
  908 
  909         irq = isa->irq;
  910         if(irq == 2)
  911                 irq = 9;
  912 
  913         if(slotno > nslot)
  914                 return -1;
  915         pp = slot + slotno;
  916 
  917         if(!pp->occupied)
  918                 return -1;
  919 
  920         et = &pp->ctab[pp->nctab];
  921 
  922         ct = 0;
  923         for(i = 0; i < isa->nopt; i++){
  924                 if(strncmp(isa->opt[i], "index=", 6))
  925                         continue;
  926                 index = strtol(&isa->opt[i][6], &cp, 0);
  927                 if(cp == &isa->opt[i][6] || index >= pp->nctab)
  928                         return -1;
  929                 ct = &pp->ctab[index];
  930         }
  931 
  932         if(ct == 0){
  933                 /* assume default is right */
  934                 if(pp->def)
  935                         ct = pp->def;
  936                 else
  937                         ct = pp->ctab;
  938         
  939                 /* try for best match */
  940                 if(ct->nio == 0
  941                 || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){
  942                         for(t = pp->ctab; t < et; t++)
  943                                 if(t->nio
  944                                 && t->io[0].start == isa->port
  945                                 && ((1<<irq) & t->irqs)){
  946                                         ct = t;
  947                                         break;
  948                                 }
  949                 }
  950                 if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){
  951                         for(t = pp->ctab; t < et; t++)
  952                                 if(t->nio && ((1<<irq) & t->irqs)){
  953                                         ct = t;
  954                                         break;
  955                                 }
  956                 }
  957                 if(ct->nio == 0){
  958                         for(t = pp->ctab; t < et; t++)
  959                                 if(t->nio){
  960                                         ct = t;
  961                                         break;
  962                                 }
  963                 }
  964         }
  965 
  966         if(ct == et || ct->nio == 0)
  967                 return -1;
  968         if(isa->port == 0 && ct->io[0].start == 0)
  969                 return -1;
  970 
  971         /* route interrupts */
  972         isa->irq = irq;
  973         wrreg(pp, Rigc, irq | Fnotreset | Fiocard);
  974 
  975         /* set power and enable device */
  976         x = vcode(ct->vpp1);
  977         wrreg(pp, Rpc, x|Fautopower|Foutena|Fcardena);
  978 
  979         /* 16-bit data path */
  980         if(ct->bit16)
  981                 x = Ftiming|Fiocs16|Fwidth16;
  982         else
  983                 x = Ftiming;
  984         if(ct->nio == 2 && ct->io[1].start)
  985                 x |= x<<4;
  986         wrreg(pp, Rio, x);
  987 
  988         /*
  989          * enable io port map 0
  990          * the 'top' register value includes the last valid address
  991          */
  992         if(isa->port == 0)
  993                 isa->port = ct->io[0].start;
  994         we = rdreg(pp, Rwe);
  995         wrreg(pp, Riobtm0lo, isa->port);
  996         wrreg(pp, Riobtm0hi, isa->port>>8);
  997         i = isa->port+ct->io[0].len-1;
  998         wrreg(pp, Riotop0lo, i);
  999         wrreg(pp, Riotop0hi, i>>8);
 1000         we |= 1<<6;
 1001         if(ct->nio >= 2 && ct->io[1].start){
 1002                 wrreg(pp, Riobtm1lo, ct->io[1].start);
 1003                 wrreg(pp, Riobtm1hi, ct->io[1].start>>8);
 1004                 i = ct->io[1].start+ct->io[1].len-1;
 1005                 wrreg(pp, Riotop1lo, i);
 1006                 wrreg(pp, Riotop1hi, i>>8);
 1007                 we |= 1<<7;
 1008         }
 1009         wrreg(pp, Rwe, we);
 1010 
 1011         /* only touch Rconfig if it is present */
 1012         m = pcmmap(slotno, pp->cfg[0].caddr + Rconfig, 0x20, 1);
 1013         p = KADDR(m->isa + pp->cfg[0].caddr - m->ca);
 1014         if(pp->cfg[0].cpresent & (1<<Rconfig)){
 1015                 /*  Reset adapter */
 1016 
 1017                 /*  set configuration and interrupt type.
 1018                  *  if level is possible on the card, use it.
 1019                  */
 1020                 x = ct->index;
 1021                 if(ct->irqtype & 0x20)
 1022                         x |= Clevel;
 1023 
 1024                 /*  enable the device, enable address decode and
 1025                  *  irq enable.
 1026                  */
 1027                 x |= Cfunc|Cdecode|Cirq;
 1028 
 1029                 p[0] = x;
 1030                 //delay(5);
 1031                 microdelay(40);
 1032         }
 1033 
 1034         if(pp->cfg[0].cpresent & (1<<Riobase0)){
 1035                 /* set up the iobase 0 */
 1036                 p[Riobase0 << 1] = isa->port;
 1037                 p[Riobase1 << 1] = isa->port >> 8;
 1038         }
 1039 
 1040         if(pp->cfg[0].cpresent & (1<<Riosize))
 1041                 p[Riosize << 1] = ct->io[0].len;
 1042         pcmunmap(slotno, m);
 1043         return 0;
 1044 }

Cache object: 6bcd9182ea4349ef6d2abb3709e9bdbc


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