]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/uartaxp.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / pc / uartaxp.c
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 = smalloc(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         if(ctlr == nil){
767                 print("uartaxp: can't allocate memory\n");
768                 return nil;
769         }
770         seprint(name, name+sizeof(name), "uartaxp%d", ctlrno);
771         kstrdup(&ctlr->name, name);
772         ctlr->pcidev = pcidev;
773         ctlr->ctlrno = ctlrno;
774
775         /*
776          * Access to runtime registers.
777          */
778         bar = pcidev->mem[0].bar;
779         if((addr = vmap(bar & ~0x0F, pcidev->mem[0].size)) == 0){
780                 print("%s: can't map registers at %#ux\n", ctlr->name, bar);
781                 return axpdealloc(ctlr);
782         }
783         ctlr->reg = addr;
784         print("%s: port 0x%ux irq %d ", ctlr->name, bar, pcidev->intl);
785
786         /*
787          * Local address space 0.
788          */
789         bar = pcidev->mem[2].bar;
790         if((addr = vmap(bar & ~0x0F, pcidev->mem[2].size)) == 0){
791                 print("%s: can't map memory at %#ux\n", ctlr->name, bar);
792                 return axpdealloc(ctlr);
793         }
794         ctlr->mem = addr;
795         ctlr->gcb = (Gcb*)(ctlr->mem+0x10000);
796         print("mem 0x%ux size %d: ", bar, pcidev->mem[2].size);
797
798         pcienable(pcidev);
799
800         /*
801          * Toggle the software reset and wait for
802          * the adapter local init status to indicate done.
803          *
804          * The two 'delay(100)'s below are important,
805          * without them the board seems to become confused
806          * (perhaps it needs some 'quiet time' because the
807          * timeout loops are not sufficient in themselves).
808          */
809         r = csr32r(ctlr, Mcc);
810         csr32w(ctlr, Mcc, r|Asr);
811         microdelay(1);
812         csr32w(ctlr, Mcc, r&~Asr);
813         delay(100);
814
815         for(timeo = 0; timeo < 100000; timeo++){
816                 if(csr32r(ctlr, Mcc) & Lis)
817                         break;
818                 microdelay(1);
819         }
820         if(!(csr32r(ctlr, Mcc) & Lis)){
821                 print("%s: couldn't reset\n", ctlr->name);
822                 return axpdealloc(ctlr);
823         }
824         print("downloading...");
825         /*
826          * Copy the control programme to the card memory.
827          * The card's i960 control structures live at 0xD000.
828          */
829         if(sizeof(uartaxpcp) > 0xD000){
830                 print("%s: control programme too big\n", ctlr->name);
831                 return axpdealloc(ctlr);
832         }
833         /* TODO: is this right for more than 1 card? devastar does the same */
834         csr32w(ctlr, Remap, 0xA0000001);
835         for(i = 0; i < sizeof(uartaxpcp); i++)
836                 ctlr->mem[i] = uartaxpcp[i];
837         /*
838          * Execute downloaded code and wait for it
839          * to signal ready.
840          */
841         csr32w(ctlr, Mb0, Edcc);
842         delay(100);
843         /* the manual says to wait for Cpr for 1 second */
844         for(timeo = 0; timeo < 10000; timeo++){
845                 if(csr32r(ctlr, Mb0) & Cpr)
846                         break;
847                 microdelay(100);
848         }
849         if(!(csr32r(ctlr, Mb0) & Cpr)){
850                 print("control programme not ready; Mb0 %#ux\n",
851                         csr32r(ctlr, Mb0));
852                 print("%s: distribution panel not connected or card not fully seated?\n",
853                         ctlr->name);
854
855                 return axpdealloc(ctlr);
856         }
857         print("\n");
858
859         n = ctlr->gcb->ccbn;
860         if(ctlr->gcb->bt != 0x12 || n > 16){
861                 print("%s: wrong board type %#ux, %d channels\n",
862                         ctlr->name, ctlr->gcb->bt, ctlr->gcb->ccbn);
863                 return axpdealloc(ctlr);
864         }
865
866         p = ((uchar*)ctlr->gcb) + ctlr->gcb->ccboff;
867         for(i = 0; i < n; i++){
868                 cc = &ctlr->cc[i];
869                 cc->ccb = (Ccb*)p;
870                 p += ctlr->gcb->ccbsz;
871                 cc->uartno = i;
872                 cc->ctlr = ctlr;
873
874                 cc->regs = cc;          /* actually Uart->regs */
875                 seprint(name, name+sizeof(name), "uartaxp%d%2.2d", ctlrno, i);
876                 kstrdup(&cc->name, name);
877                 cc->freq = 0;
878                 cc->bits = 8;
879                 cc->stop = 1;
880                 cc->parity = 'n';
881                 cc->baud = 9600;
882                 cc->phys = &axpphysuart;
883                 cc->console = 0;
884                 cc->special = 0;
885
886                 cc->next = &ctlr->cc[i+1];
887         }
888         ctlr->cc[n-1].next = nil;
889
890         ctlr->next = nil;
891         if(axpctlrhead != nil)
892                 axpctlrtail->next = ctlr;
893         else
894                 axpctlrhead = ctlr;
895         axpctlrtail = ctlr;
896
897         return ctlr->cc;
898 }
899
900 static Uart*
901 axppnp(void)
902 {
903         Pcidev *p;
904         int ctlrno;
905         Uart *head, *tail, *uart;
906
907         /*
908          * Loop through all PCI devices looking for simple serial
909          * controllers (ccrb == 0x07) and configure the ones which
910          * are familiar.
911          */
912         head = tail = nil;
913         ctlrno = 0;
914         for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){
915                 if(p->ccrb != 0x07)
916                         continue;
917
918                 switch((p->did<<16)|p->vid){
919                 default:
920                         continue;
921                 case (0x6001<<16)|0x114F:       /* AvanstarXp */
922                         if((uart = axpalloc(ctlrno, p)) == nil)
923                                 continue;
924                         break;
925                 }
926
927                 if(head != nil)
928                         tail->next = uart;
929                 else
930                         head = uart;
931                 for(tail = uart; tail->next != nil; tail = tail->next)
932                         ;
933                 ctlrno++;
934         }
935
936         return head;
937 }
938
939 PhysUart axpphysuart = {
940         .name           = "AvanstarXp",
941         .pnp            = axppnp,
942         .enable         = axpenable,
943         .disable        = axpdisable,
944         .kick           = axpkick,
945         .dobreak        = axpbreak,
946         .baud           = axpbaud,
947         .bits           = axpbits,
948         .stop           = axpstop,
949         .parity         = axpparity,
950         .modemctl       = axpmodemctl,
951         .rts            = axprts,
952         .dtr            = axpdtr,
953         .status         = axpstatus,
954         .fifo           = axpfifo,
955         .getc           = nil,
956         .putc           = nil,
957 };