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/uartaxp.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 /*
    2  * Avanstar Xp pci uart driver
    3  */
    4 #include "u.h"
    5 #include "../port/lib.h"
    6 #include "mem.h"
    7 #include "dat.h"
    8 #include "fns.h"
    9 #include "io.h"
   10 #include "../port/error.h"
   11 
   12 #include "uartaxp.i"
   13 
   14 typedef struct Cc Cc;
   15 typedef struct Ccb Ccb;
   16 typedef struct Ctlr Ctlr;
   17 typedef struct Gcb Gcb;
   18 
   19 /*
   20  * Global Control Block.
   21  * Service Request fields must be accessed using XCHG.
   22  */
   23 struct Gcb {
   24         u16int  gcw;                            /* Global Command Word */
   25         u16int  gsw;                            /* Global Status Word */
   26         u16int  gsr;                            /* Global Service Request */
   27         u16int  abs;                            /* Available Buffer Space */
   28         u16int  bt;                             /* Board Type */
   29         u16int  cpv;                            /* Control Program Version */
   30         u16int  ccbn;                           /* Ccb count */
   31         u16int  ccboff;                         /* Ccb offset */
   32         u16int  ccbsz;                          /* Ccb size */
   33         u16int  gcw2;                           /* Global Command Word 2 */
   34         u16int  gsw2;                           /* Global Status Word 2 */
   35         u16int  esr;                            /* Error Service Request */
   36         u16int  isr;                            /* Input Service Request */
   37         u16int  osr;                            /* Output Service Request */
   38         u16int  msr;                            /* Modem Service Request */
   39         u16int  csr;                            /* Command Service Request */
   40 };
   41 
   42 /*
   43  * Channel Control Block.
   44  */
   45 struct Ccb {
   46         u16int  br;                             /* Baud Rate */
   47         u16int  df;                             /* Data Format */
   48         u16int  lp;                             /* Line Protocol */
   49         u16int  ibs;                            /* Input Buffer Size */
   50         u16int  obs;                            /* Output Buffer Size */
   51         u16int  ibtr;                           /* Ib Trigger Rate */
   52         u16int  oblw;                           /* Ob Low Watermark */
   53         u8int   ixon[2];                        /* IXON characters */
   54         u16int  ibhw;                           /* Ib High Watermark */
   55         u16int  iblw;                           /* Ib Low Watermark */
   56         u16int  cc;                             /* Channel Command */
   57         u16int  cs;                             /* Channel Status */
   58         u16int  ibsa;                           /* Ib Start Addr */
   59         u16int  ibea;                           /* Ib Ending Addr */
   60         u16int  obsa;                           /* Ob Start Addr */
   61         u16int  obea;                           /* Ob Ending Addr */
   62         u16int  ibwp;                           /* Ib write pointer (RO) */
   63         u16int  ibrp;                           /* Ib read pointer (R/W) */
   64         u16int  obwp;                           /* Ob write pointer (R/W) */
   65         u16int  obrp;                           /* Ob read pointer (RO) */
   66         u16int  ces;                            /* Communication Error Status */
   67         u16int  bcp;                            /* Bad Character Pointer */
   68         u16int  mc;                             /* Modem Control */
   69         u16int  ms;                             /* Modem Status */
   70         u16int  bs;                             /* Blocking Status */
   71         u16int  crf;                            /* Character Received Flag */
   72         u8int   ixoff[2];                       /* IXOFF characters */
   73         u16int  cs2;                            /* Channel Status 2 */
   74         u8int   sec[2];                         /* Strip/Error Characters */
   75 };
   76 
   77 enum {                                          /* br */
   78         Br76800         = 0xFF00,
   79         Br115200        = 0xFF01,
   80 };
   81 
   82 enum {                                          /* df */
   83         Db5             = 0x0000,               /* Data Bits - 5 bits/byte */
   84         Db6             = 0x0001,               /*      6 bits/byte */
   85         Db7             = 0x0002,               /*      7 bits/byte */
   86         Db8             = 0x0003,               /*      8 bits/byte */
   87         DbMASK          = 0x0003,
   88         Sb1             = 0x0000,               /* 1 Stop Bit */
   89         Sb2             = 0x0004,               /* 2 Stop Bit */
   90         SbMASK          = 0x0004,
   91         Np              = 0x0000,               /* No Parity */
   92         Op              = 0x0008,               /* Odd Parity */
   93         Ep              = 0x0010,               /* Even Parity */
   94         Mp              = 0x0020,               /* Mark Parity */
   95         Sp              = 0x0030,               /* Space Parity */
   96         PMASK           = 0x0038,
   97         Cmn             = 0x0000,               /* Channel Mode Normal */
   98         Cme             = 0x0040,               /* CM Echo */
   99         Cmll            = 0x0080,               /* CM Local Loopback */
  100         Cmrl            = 0x00C0,               /* CM Remote Loopback */
  101 };
  102 
  103 enum {                                          /* lp */
  104         Ixon            = 0x0001,               /* Obey IXON/IXOFF */
  105         Ixany           = 0x0002,               /* Any character retarts Tx */
  106         Ixgen           = 0x0004,               /* Generate IXON/IXOFF  */
  107         Cts             = 0x0008,               /* CTS controls Tx */
  108         Dtr             = 0x0010,               /* Rx controls DTR */
  109         ½d             = 0x0020,               /* RTS off during Tx */
  110         Rts             = 0x0040,               /* generate RTS */
  111         Emcs            = 0x0080,               /* Enable Modem Control */
  112         Ecs             = 0x1000,               /* Enable Character Stripping */
  113         Eia422          = 0x2000,               /* EIA422 */
  114 };
  115 
  116 enum {                                          /* cc */
  117         Ccu             = 0x0001,               /* Configure Channel and UART */
  118         Cco             = 0x0002,               /* Configure Channel Only */
  119         Fib             = 0x0004,               /* Flush Input Buffer */
  120         Fob             = 0x0008,               /* Flush Output Buffer */
  121         Er              = 0x0010,               /* Enable Receiver */
  122         Dr              = 0x0020,               /* Disable Receiver */
  123         Et              = 0x0040,               /* Enable Transmitter */
  124         Dt              = 0x0080,               /* Disable Transmitter */
  125 };
  126 
  127 enum {                                          /* ces */
  128         Oe              = 0x0001,               /* Overrun Error */
  129         Pe              = 0x0002,               /* Parity Error */
  130         Fe              = 0x0004,               /* Framing Error */
  131         Br              = 0x0008,               /* Break Received */
  132 };
  133 
  134 enum {                                          /* mc */
  135         Adtr            = 0x0001,               /* Assert DTR */
  136         Arts            = 0x0002,               /* Assert RTS */
  137         Ab              = 0x0010,               /* Assert BREAK */
  138 };
  139 
  140 enum {                                          /* ms */
  141         Scts            = 0x0001,               /* Status od CTS */
  142         Sdsr            = 0x0002,               /* Status of DSR */
  143         Sri             = 0x0004,               /* Status of RI */
  144         Sdcd            = 0x0008,               /* Status of DCD */
  145 };
  146 
  147 enum {                                          /* bs */
  148         Rd              = 0x0001,               /* Receiver Disabled */
  149         Td              = 0x0002,               /* Transmitter Disabled */
  150         Tbxoff          = 0x0004,               /* Tx Blocked by XOFF */
  151         Tbcts           = 0x0008,               /* Tx Blocked by CTS */
  152         Rbxoff          = 0x0010,               /* Rx Blocked by XOFF */
  153         Rbrts           = 0x0020,               /* Rx Blocked by RTS */
  154 };
  155 
  156 enum {                                          /* Local Configuration */
  157         Range           = 0x00,
  158         Remap           = 0x04,
  159         Region          = 0x18,
  160         Mb0             = 0x40,                 /* Mailbox 0 */
  161         Ldb             = 0x60,                 /* PCI to Local Doorbell */
  162         Pdb             = 0x64,                 /* Local to PCI Doorbell */
  163         Ics             = 0x68,                 /* Interrupt Control/Status */
  164         Mcc             = 0x6C,                 /* Misc. Command and Control */
  165 };
  166 
  167 enum {                                          /* Mb0 */
  168         Edcc            = 1,                    /* exec. downloaded code cmd */
  169         Aic             = 0x10,                 /* adapter init'zed correctly */
  170         Cpr             = 1ul << 31,            /* control program ready */
  171 };
  172 
  173 enum {                                          /* Mcc */
  174         Rcr             = 1ul << 29,            /* reload config. reg.s */
  175         Asr             = 1ul << 30,            /* pci adapter sw reset */
  176         Lis             = 1ul << 31,            /* local init status */
  177 };
  178 
  179 typedef struct Cc Cc;
  180 typedef struct Ccb Ccb;
  181 typedef struct Ctlr Ctlr;
  182 
  183 /*
  184  * Channel Control, one per uart.
  185  * Devuart communicates via the PhysUart functions with
  186  * a Uart* argument. Uart.regs is filled in by this driver
  187  * to point to a Cc, and Cc.ctlr points to the Axp board
  188  * controller.
  189  */
  190 struct Cc {
  191         int     uartno;
  192         Ccb*    ccb;
  193         Ctlr*   ctlr;
  194 
  195         Rendez;
  196 
  197         Uart;
  198 };
  199 
  200 typedef struct Ctlr {
  201         char*   name;
  202         Pcidev* pcidev;
  203         int     ctlrno;
  204         Ctlr*   next;
  205 
  206         u32int* reg;
  207         uchar*  mem;
  208         Gcb*    gcb;
  209 
  210         int     im;             /* interrupt mask */
  211         Cc      cc[16];
  212 } Ctlr;
  213 
  214 #define csr32r(c, r)    (*((c)->reg+((r)/4)))
  215 #define csr32w(c, r, v) (*((c)->reg+((r)/4)) = (v))
  216 
  217 static Ctlr* axpctlrhead;
  218 static Ctlr* axpctlrtail;
  219 
  220 extern PhysUart axpphysuart;
  221 
  222 static int
  223 axpccdone(void* ccb)
  224 {
  225         return !((Ccb*)ccb)->cc;        /* hw sets ccb->cc to zero */
  226 }
  227 
  228 static void
  229 axpcc(Cc* cc, int cmd)
  230 {
  231         Ccb *ccb;
  232         int timeo;
  233         u16int cs;
  234 
  235         ccb = cc->ccb;
  236         ccb->cc = cmd;
  237 
  238         if(!cc->ctlr->im)
  239                 for(timeo = 0; timeo < 1000000; timeo++){
  240                         if(!ccb->cc)
  241                                 break;
  242                         microdelay(1);
  243                 }
  244         else
  245                 tsleep(cc, axpccdone, ccb, 1000);
  246 
  247         cs = ccb->cs;
  248         if(ccb->cc || cs){
  249                 print("%s: cmd %#ux didn't terminate: %#ux %#ux\n",
  250                         cc->name, cmd, ccb->cc, cs);
  251                 if(cc->ctlr->im)
  252                         error(Eio);
  253         }
  254 }
  255 
  256 static long
  257 axpstatus(Uart* uart, void* buf, long n, long offset)
  258 {
  259         char *p;
  260         Ccb *ccb;
  261         u16int bs, fstat, ms;
  262 
  263         ccb = ((Cc*)(uart->regs))->ccb;
  264 
  265         p = malloc(READSTR);
  266         bs = ccb->bs;
  267         fstat = ccb->df;
  268         ms = ccb->ms;
  269 
  270         snprint(p, READSTR,
  271                 "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
  272                 "dev(%d) type(%d) framing(%d) overruns(%d) "
  273                 "berr(%d) serr(%d)%s%s%s%s\n",
  274 
  275                 uart->baud,
  276                 uart->hup_dcd,
  277                 ms & Sdsr,
  278                 uart->hup_dsr,
  279                 (fstat & DbMASK) + 5,
  280                 0,
  281                 (fstat & PMASK) ? ((fstat & Ep) == Ep? 'e': 'o'): 'n',
  282                 (bs & Rbrts) ? 1 : 0,
  283                 (fstat & Sb2) ? 2 : 1,
  284                 0,
  285 
  286                 uart->dev,
  287                 uart->type,
  288                 uart->ferr,
  289                 uart->oerr,
  290                 uart->berr,
  291                 uart->serr,
  292                 (ms & Scts) ? " cts"  : "",
  293                 (ms & Sdsr) ? " dsr"  : "",
  294                 (ms & Sdcd) ? " dcd"  : "",
  295                 (ms & Sri) ? " ring" : ""
  296         );
  297         n = readstr(offset, buf, n, p);
  298         free(p);
  299 
  300         return n;
  301 }
  302 
  303 static void
  304 axpfifo(Uart*, int)
  305 {
  306 }
  307 
  308 static void
  309 axpdtr(Uart* uart, int on)
  310 {
  311         Ccb *ccb;
  312         u16int mc;
  313 
  314         ccb = ((Cc*)(uart->regs))->ccb;
  315 
  316         mc = ccb->mc;
  317         if(on)
  318                 mc |= Adtr;
  319         else
  320                 mc &= ~Adtr;
  321         ccb->mc = mc;
  322 }
  323 
  324 /*
  325  * can be called from uartstageinput() during an input interrupt,
  326  * with uart->rlock ilocked or the uart qlocked, sometimes both.
  327  */
  328 static void
  329 axprts(Uart* uart, int on)
  330 {
  331         Ccb *ccb;
  332         u16int mc;
  333 
  334         ccb = ((Cc*)(uart->regs))->ccb;
  335 
  336         mc = ccb->mc;
  337         if(on)
  338                 mc |= Arts;
  339         else
  340                 mc &= ~Arts;
  341         ccb->mc = mc;
  342 }
  343 
  344 static void
  345 axpmodemctl(Uart* uart, int on)
  346 {
  347         Ccb *ccb;
  348         u16int lp;
  349 
  350         ccb = ((Cc*)(uart->regs))->ccb;
  351 
  352         ilock(&uart->tlock);
  353         lp = ccb->lp;
  354         if(on){
  355                 lp |= Cts|Rts;
  356                 lp &= ~Emcs;
  357                 uart->cts = ccb->ms & Scts;
  358         }
  359         else{
  360                 lp &= ~(Cts|Rts);
  361                 lp |= Emcs;
  362                 uart->cts = 1;
  363         }
  364         uart->modem = on;
  365         iunlock(&uart->tlock);
  366 
  367         ccb->lp = lp;
  368         axpcc(uart->regs, Ccu);
  369 }
  370 
  371 static int
  372 axpparity(Uart* uart, int parity)
  373 {
  374         Ccb *ccb;
  375         u16int df;
  376 
  377         switch(parity){
  378         default:
  379                 return -1;
  380         case 'e':
  381                 parity = Ep;
  382                 break;
  383         case 'o':
  384                 parity = Op;
  385                 break;
  386         case 'n':
  387                 parity = Np;
  388                 break;
  389         }
  390 
  391         ccb = ((Cc*)(uart->regs))->ccb;
  392 
  393         df = ccb->df & ~PMASK;
  394         ccb->df = df|parity;
  395         axpcc(uart->regs, Ccu);
  396 
  397         return 0;
  398 }
  399 
  400 static int
  401 axpstop(Uart* uart, int stop)
  402 {
  403         Ccb *ccb;
  404         u16int df;
  405 
  406         switch(stop){
  407         default:
  408                 return -1;
  409         case 1:
  410                 stop = Sb1;
  411                 break;
  412         case 2:
  413                 stop = Sb2;
  414                 break;
  415         }
  416 
  417         ccb = ((Cc*)(uart->regs))->ccb;
  418 
  419         df = ccb->df & ~SbMASK;
  420         ccb->df = df|stop;
  421         axpcc(uart->regs, Ccu);
  422 
  423         return 0;
  424 }
  425 
  426 static int
  427 axpbits(Uart* uart, int bits)
  428 {
  429         Ccb *ccb;
  430         u16int df;
  431 
  432         bits -= 5;
  433         if(bits < 0 || bits > 3)
  434                 return -1;
  435 
  436         ccb = ((Cc*)(uart->regs))->ccb;
  437 
  438         df = ccb->df & ~DbMASK;
  439         ccb->df = df|bits;
  440         axpcc(uart->regs, Ccu);
  441 
  442         return 0;
  443 }
  444 
  445 static int
  446 axpbaud(Uart* uart, int baud)
  447 {
  448         Ccb *ccb;
  449         int i, ibtr;
  450 
  451         /*
  452          * Set baud rate (high rates are special - only 16 bits).
  453          */
  454         if(baud <= 0)
  455                 return -1;
  456         uart->baud = baud;
  457 
  458         ccb = ((Cc*)(uart->regs))->ccb;
  459 
  460         switch(baud){
  461         default:
  462                 ccb->br = baud;
  463                 break;
  464         case 76800:
  465                 ccb->br = Br76800;
  466                 break;
  467         case 115200:
  468                 ccb->br = Br115200;
  469                 break;
  470         }
  471 
  472         /*
  473          * Set trigger level to about 50 per second.
  474          */
  475         ibtr = baud/500;
  476         i = (ccb->ibea - ccb->ibsa)/2;
  477         if(ibtr > i)
  478                 ibtr = i;
  479         ccb->ibtr = ibtr;
  480         axpcc(uart->regs, Ccu);
  481 
  482         return 0;
  483 }
  484 
  485 static void
  486 axpbreak(Uart* uart, int ms)
  487 {
  488         Ccb *ccb;
  489         u16int mc;
  490 
  491         /*
  492          * Send a break.
  493          */
  494         if(ms <= 0)
  495                 ms = 200;
  496 
  497         ccb = ((Cc*)(uart->regs))->ccb;
  498 
  499         mc = ccb->mc;
  500         ccb->mc = Ab|mc;
  501         tsleep(&up->sleep, return0, 0, ms);
  502         ccb->mc = mc & ~Ab;
  503 }
  504 
  505 /* only called from interrupt service */
  506 static void
  507 axpmc(Cc* cc)
  508 {
  509         int old;
  510         Ccb *ccb;
  511         u16int ms;
  512 
  513         ccb = cc->ccb;
  514 
  515         ms = ccb->ms;
  516 
  517         if(ms & Scts){
  518                 ilock(&cc->tlock);
  519                 old = cc->cts;
  520                 cc->cts = ms & Scts;
  521                 if(old == 0 && cc->cts)
  522                         cc->ctsbackoff = 2;
  523                 iunlock(&cc->tlock);
  524         }
  525         if(ms & Sdsr){
  526                 old = ms & Sdsr;
  527                 if(cc->hup_dsr && cc->dsr && !old)
  528                         cc->dohup = 1;
  529                 cc->dsr = old;
  530         }
  531         if(ms & Sdcd){
  532                 old = ms & Sdcd;
  533                 if(cc->hup_dcd && cc->dcd && !old)
  534                         cc->dohup = 1;
  535                 cc->dcd = old;
  536         }
  537 }
  538 
  539 /* called from uartkick() with uart->tlock ilocked */
  540 static void
  541 axpkick(Uart* uart)
  542 {
  543         Cc *cc;
  544         Ccb *ccb;
  545         uchar *ep, *mem, *rp, *wp, *bp;
  546 
  547         if(uart->cts == 0 || uart->blocked)
  548                 return;
  549 
  550         cc = uart->regs;
  551         ccb = cc->ccb;
  552 
  553         mem = (uchar*)cc->ctlr->gcb;
  554         bp = mem + ccb->obsa;
  555         rp = mem + ccb->obrp;
  556         wp = mem + ccb->obwp;
  557         ep = mem + ccb->obea;
  558         while(wp != rp-1 && (rp != bp || wp != ep)){
  559                 /*
  560                  * if we've exhausted the uart's output buffer,
  561                  * ask for more from the output queue, and quit if there
  562                  * isn't any.
  563                  */
  564                 if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
  565                         break;
  566                 *wp++ = *(uart->op++);
  567                 if(wp > ep)
  568                         wp = bp;
  569                 ccb->obwp = wp - mem;
  570         }
  571 }
  572 
  573 /* only called from interrupt service */
  574 static void
  575 axprecv(Cc* cc)
  576 {
  577         Ccb *ccb;
  578         uchar *ep, *mem, *rp, *wp;
  579 
  580         ccb = cc->ccb;
  581 
  582         mem = (uchar*)cc->ctlr->gcb;
  583         rp = mem + ccb->ibrp;
  584         wp = mem + ccb->ibwp;
  585         ep = mem + ccb->ibea;
  586 
  587         while(rp != wp){
  588                 uartrecv(cc, *rp++);            /* ilocks cc->tlock */
  589                 if(rp > ep)
  590                         rp = mem + ccb->ibsa;
  591                 ccb->ibrp = rp - mem;
  592         }
  593 }
  594 
  595 static void
  596 axpinterrupt(Ureg*, void* arg)
  597 {
  598         int work;
  599         Cc *cc;
  600         Ctlr *ctlr;
  601         u32int ics;
  602         u16int r, sr;
  603 
  604         work = 0;
  605         ctlr = arg;
  606         ics = csr32r(ctlr, Ics);
  607         if(ics & 0x0810C000)
  608                 print("%s: unexpected interrupt %#ux\n", ctlr->name, ics);
  609         if(!(ics & 0x00002000)) {
  610                 /* we get a steady stream of these on consoles */
  611                 // print("%s: non-doorbell interrupt\n", ctlr->name);
  612                 ctlr->gcb->gcw2 = 0x0001;       /* set Gintack */
  613                 return;
  614         }
  615 
  616 //      while(work to do){
  617                 cc = ctlr->cc;
  618                 for(sr = xchgw(&ctlr->gcb->isr, 0); sr != 0; sr >>= 1){
  619                         if(sr & 0x0001)
  620                                 work++, axprecv(cc);
  621                         cc++;
  622                 }
  623                 cc = ctlr->cc;
  624                 for(sr = xchgw(&ctlr->gcb->osr, 0); sr != 0; sr >>= 1){
  625                         if(sr & 0x0001)
  626                                 work++, uartkick(&cc->Uart);
  627                         cc++;
  628                 }
  629                 cc = ctlr->cc;
  630                 for(sr = xchgw(&ctlr->gcb->csr, 0); sr != 0; sr >>= 1){
  631                         if(sr & 0x0001)
  632                                 work++, wakeup(cc);
  633                         cc++;
  634                 }
  635                 cc = ctlr->cc;
  636                 for(sr = xchgw(&ctlr->gcb->msr, 0); sr != 0; sr >>= 1){
  637                         if(sr & 0x0001)
  638                                 work++, axpmc(cc);
  639                         cc++;
  640                 }
  641                 cc = ctlr->cc;
  642                 for(sr = xchgw(&ctlr->gcb->esr, 0); sr != 0; sr >>= 1){
  643                         if(sr & 0x0001){
  644                                 r = cc->ccb->ms;
  645                                 if(r & Oe)
  646                                         cc->oerr++;
  647                                 if(r & Pe)
  648                                         cc->perr++;
  649                                 if(r & Fe)
  650                                         cc->ferr++;
  651                                 if (r & (Oe|Pe|Fe))
  652                                         work++;
  653                         }
  654                         cc++;
  655                 }
  656 //      }
  657         /* only meaningful if we don't share the irq */
  658         if (0 && !work)
  659                 print("%s: interrupt with no work\n", ctlr->name);
  660         csr32w(ctlr, Pdb, 1);           /* clear doorbell interrupt */
  661         ctlr->gcb->gcw2 = 0x0001;       /* set Gintack */
  662 }
  663 
  664 static void
  665 axpdisable(Uart* uart)
  666 {
  667         Cc *cc;
  668         u16int lp;
  669         Ctlr *ctlr;
  670 
  671         /*
  672          * Turn off DTR and RTS, disable interrupts.
  673          */
  674         (*uart->phys->dtr)(uart, 0);
  675         (*uart->phys->rts)(uart, 0);
  676 
  677         cc = uart->regs;
  678         lp = cc->ccb->lp;
  679         cc->ccb->lp = Emcs|lp;
  680         axpcc(cc, Dt|Dr|Fob|Fib|Ccu);
  681 
  682         /*
  683          * The Uart is qlocked.
  684          */
  685         ctlr = cc->ctlr;
  686         ctlr->im &= ~(1<<cc->uartno);
  687         if(ctlr->im == 0)
  688                 intrdisable(ctlr->pcidev->intl, axpinterrupt, ctlr,
  689                         ctlr->pcidev->tbdf, ctlr->name);
  690 }
  691 
  692 static void
  693 axpenable(Uart* uart, int ie)
  694 {
  695         Cc *cc;
  696         Ctlr *ctlr;
  697         u16int lp;
  698 
  699         cc = uart->regs;
  700         ctlr = cc->ctlr;
  701 
  702         /*
  703          * Enable interrupts and turn on DTR and RTS.
  704          * Be careful if this is called to set up a polled serial line
  705          * early on not to try to enable interrupts as interrupt-
  706          * -enabling mechanisms might not be set up yet.
  707          */
  708         if(ie){
  709                 /*
  710                  * The Uart is qlocked.
  711                  */
  712                 if(ctlr->im == 0){
  713                         intrenable(ctlr->pcidev->intl, axpinterrupt, ctlr,
  714                                 ctlr->pcidev->tbdf, ctlr->name);
  715                         csr32w(ctlr, Ics, 0x00031F00);
  716                         csr32w(ctlr, Pdb, 1);
  717                         ctlr->gcb->gcw2 = 1;
  718                 }
  719                 ctlr->im |= 1<<cc->uartno;
  720         }
  721 
  722         (*uart->phys->dtr)(uart, 1);
  723         (*uart->phys->rts)(uart, 1);
  724 
  725         /*
  726          * Make sure we control RTS, DTR and break.
  727          */
  728         lp = cc->ccb->lp;
  729         cc->ccb->lp = Emcs|lp;
  730         cc->ccb->oblw = 64;
  731         axpcc(cc, Et|Er|Ccu);
  732 }
  733 
  734 static void*
  735 axpdealloc(Ctlr* ctlr)
  736 {
  737         int i;
  738 
  739         for(i = 0; i < 16; i++){
  740                 if(ctlr->cc[i].name != nil)
  741                         free(ctlr->cc[i].name);
  742         }
  743         if(ctlr->reg != nil)
  744                 vunmap(ctlr->reg, ctlr->pcidev->mem[0].size);
  745         if(ctlr->mem != nil)
  746                 vunmap(ctlr->mem, ctlr->pcidev->mem[2].size);
  747         if(ctlr->name != nil)
  748                 free(ctlr->name);
  749         free(ctlr);
  750 
  751         return nil;
  752 }
  753 
  754 static Uart*
  755 axpalloc(int ctlrno, Pcidev* pcidev)
  756 {
  757         Cc *cc;
  758         uchar *p;
  759         Ctlr *ctlr;
  760         void *addr;
  761         char name[64];
  762         u32int bar, r;
  763         int i, n, timeo;
  764 
  765         ctlr = malloc(sizeof(Ctlr));
  766         seprint(name, name+sizeof(name), "uartaxp%d", ctlrno);
  767         kstrdup(&ctlr->name, name);
  768         ctlr->pcidev = pcidev;
  769         ctlr->ctlrno = ctlrno;
  770 
  771         /*
  772          * Access to runtime registers.
  773          */
  774         bar = pcidev->mem[0].bar;
  775         if((addr = vmap(bar & ~0x0F, pcidev->mem[0].size)) == 0){
  776                 print("%s: can't map registers at %#ux\n", ctlr->name, bar);
  777                 return axpdealloc(ctlr);
  778         }
  779         ctlr->reg = addr;
  780         print("%s: port 0x%ux irq %d ", ctlr->name, bar, pcidev->intl);
  781 
  782         /*
  783          * Local address space 0.
  784          */
  785         bar = pcidev->mem[2].bar;
  786         if((addr = vmap(bar & ~0x0F, pcidev->mem[2].size)) == 0){
  787                 print("%s: can't map memory at %#ux\n", ctlr->name, bar);
  788                 return axpdealloc(ctlr);
  789         }
  790         ctlr->mem = addr;
  791         ctlr->gcb = (Gcb*)(ctlr->mem+0x10000);
  792         print("mem 0x%ux size %d: ", bar, pcidev->mem[2].size);
  793 
  794         /*
  795          * Toggle the software reset and wait for
  796          * the adapter local init status to indicate done.
  797          *
  798          * The two 'delay(100)'s below are important,
  799          * without them the board seems to become confused
  800          * (perhaps it needs some 'quiet time' because the
  801          * timeout loops are not sufficient in themselves).
  802          */
  803         r = csr32r(ctlr, Mcc);
  804         csr32w(ctlr, Mcc, r|Asr);
  805         microdelay(1);
  806         csr32w(ctlr, Mcc, r&~Asr);
  807         delay(100);
  808 
  809         for(timeo = 0; timeo < 100000; timeo++){
  810                 if(csr32r(ctlr, Mcc) & Lis)
  811                         break;
  812                 microdelay(1);
  813         }
  814         if(!(csr32r(ctlr, Mcc) & Lis)){
  815                 print("%s: couldn't reset\n", ctlr->name);
  816                 return axpdealloc(ctlr);
  817         }
  818         print("downloading...");
  819         /*
  820          * Copy the control programme to the card memory.
  821          * The card's i960 control structures live at 0xD000.
  822          */
  823         if(sizeof(uartaxpcp) > 0xD000){
  824                 print("%s: control programme too big\n", ctlr->name);
  825                 return axpdealloc(ctlr);
  826         }
  827         /* TODO: is this right for more than 1 card? devastar does the same */
  828         csr32w(ctlr, Remap, 0xA0000001);
  829         for(i = 0; i < sizeof(uartaxpcp); i++)
  830                 ctlr->mem[i] = uartaxpcp[i];
  831         /*
  832          * Execute downloaded code and wait for it
  833          * to signal ready.
  834          */
  835         csr32w(ctlr, Mb0, Edcc);
  836         delay(100);
  837         /* the manual says to wait for Cpr for 1 second */
  838         for(timeo = 0; timeo < 10000; timeo++){
  839                 if(csr32r(ctlr, Mb0) & Cpr)
  840                         break;
  841                 microdelay(100);
  842         }
  843         if(!(csr32r(ctlr, Mb0) & Cpr)){
  844                 print("control programme not ready; Mb0 %#ux\n",
  845                         csr32r(ctlr, Mb0));
  846                 print("%s: distribution panel not connected or card not fully seated?\n",
  847                         ctlr->name);
  848 
  849                 return axpdealloc(ctlr);
  850         }
  851         print("\n");
  852 
  853         n = ctlr->gcb->ccbn;
  854         if(ctlr->gcb->bt != 0x12 || n > 16){
  855                 print("%s: wrong board type %#ux, %d channels\n",
  856                         ctlr->name, ctlr->gcb->bt, ctlr->gcb->ccbn);
  857                 return axpdealloc(ctlr);
  858         }
  859 
  860         p = ((uchar*)ctlr->gcb) + ctlr->gcb->ccboff;
  861         for(i = 0; i < n; i++){
  862                 cc = &ctlr->cc[i];
  863                 cc->ccb = (Ccb*)p;
  864                 p += ctlr->gcb->ccbsz;
  865                 cc->uartno = i;
  866                 cc->ctlr = ctlr;
  867 
  868                 cc->regs = cc;          /* actually Uart->regs */
  869                 seprint(name, name+sizeof(name), "uartaxp%d%2.2d", ctlrno, i);
  870                 kstrdup(&cc->name, name);
  871                 cc->freq = 0;
  872                 cc->bits = 8;
  873                 cc->stop = 1;
  874                 cc->parity = 'n';
  875                 cc->baud = 9600;
  876                 cc->phys = &axpphysuart;
  877                 cc->console = 0;
  878                 cc->special = 0;
  879 
  880                 cc->next = &ctlr->cc[i+1];
  881         }
  882         ctlr->cc[n-1].next = nil;
  883 
  884         ctlr->next = nil;
  885         if(axpctlrhead != nil)
  886                 axpctlrtail->next = ctlr;
  887         else
  888                 axpctlrhead = ctlr;
  889         axpctlrtail = ctlr;
  890 
  891         return ctlr->cc;
  892 }
  893 
  894 static Uart*
  895 axppnp(void)
  896 {
  897         Pcidev *p;
  898         int ctlrno;
  899         Uart *head, *tail, *uart;
  900 
  901         /*
  902          * Loop through all PCI devices looking for simple serial
  903          * controllers (ccrb == 0x07) and configure the ones which
  904          * are familiar.
  905          */
  906         head = tail = nil;
  907         ctlrno = 0;
  908         for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){
  909                 if(p->ccrb != 0x07)
  910                         continue;
  911 
  912                 switch((p->did<<16)|p->vid){
  913                 default:
  914                         continue;
  915                 case (0x6001<<16)|0x114F:       /* AvanstarXp */
  916                         if((uart = axpalloc(ctlrno, p)) == nil)
  917                                 continue;
  918                         break;
  919                 }
  920 
  921                 if(head != nil)
  922                         tail->next = uart;
  923                 else
  924                         head = uart;
  925                 for(tail = uart; tail->next != nil; tail = tail->next)
  926                         ;
  927                 ctlrno++;
  928         }
  929 
  930         return head;
  931 }
  932 
  933 PhysUart axpphysuart = {
  934         .name           = "AvanstarXp",
  935         .pnp            = axppnp,
  936         .enable         = axpenable,
  937         .disable        = axpdisable,
  938         .kick           = axpkick,
  939         .dobreak        = axpbreak,
  940         .baud           = axpbaud,
  941         .bits           = axpbits,
  942         .stop           = axpstop,
  943         .parity         = axpparity,
  944         .modemctl       = axpmodemctl,
  945         .rts            = axprts,
  946         .dtr            = axpdtr,
  947         .status         = axpstatus,
  948         .fifo           = axpfifo,
  949         .getc           = nil,
  950         .putc           = nil,
  951 };

Cache object: fb892c42633101eaf67f5bb161d60253


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