19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "io.h"
79ef1f84bSDavid du Colombier #include "../port/error.h"
89ef1f84bSDavid du Colombier
99ef1f84bSDavid du Colombier enum {
109ef1f84bSDavid du Colombier Qdir = 0,
119ef1f84bSDavid du Colombier Qdata,
129ef1f84bSDavid du Colombier Qctl,
139ef1f84bSDavid du Colombier Qstat,
149ef1f84bSDavid du Colombier };
159ef1f84bSDavid du Colombier
169ef1f84bSDavid du Colombier #define UARTTYPE(x) (((unsigned)x)&0x1f)
179ef1f84bSDavid du Colombier #define UARTID(x) ((((unsigned)x))>>5)
189ef1f84bSDavid du Colombier #define UARTQID(i, t) ((((unsigned)i)<<5)|(t))
199ef1f84bSDavid du Colombier
209ef1f84bSDavid du Colombier enum
219ef1f84bSDavid du Colombier {
229ef1f84bSDavid du Colombier /* soft flow control chars */
239ef1f84bSDavid du Colombier CTLS= 023,
249ef1f84bSDavid du Colombier CTLQ= 021,
259ef1f84bSDavid du Colombier };
269ef1f84bSDavid du Colombier
279ef1f84bSDavid du Colombier extern Dev uartdevtab;
289ef1f84bSDavid du Colombier extern PhysUart* physuart[];
299ef1f84bSDavid du Colombier
309ef1f84bSDavid du Colombier static Uart* uartlist;
319ef1f84bSDavid du Colombier static Uart** uart;
329ef1f84bSDavid du Colombier static int uartnuart;
339ef1f84bSDavid du Colombier static Dirtab *uartdir;
349ef1f84bSDavid du Colombier static int uartndir;
359ef1f84bSDavid du Colombier static Timer *uarttimer;
369ef1f84bSDavid du Colombier
379ef1f84bSDavid du Colombier struct Uartalloc {
389ef1f84bSDavid du Colombier Lock;
399ef1f84bSDavid du Colombier Uart *elist; /* list of enabled interfaces */
409ef1f84bSDavid du Colombier } uartalloc;
419ef1f84bSDavid du Colombier
429ef1f84bSDavid du Colombier static void uartclock(void);
439ef1f84bSDavid du Colombier static void uartflow(void*);
449ef1f84bSDavid du Colombier
459ef1f84bSDavid du Colombier /*
469ef1f84bSDavid du Colombier * enable/disable uart and add/remove to list of enabled uarts
479ef1f84bSDavid du Colombier */
48406c76faSDavid du Colombier Uart*
uartenable(Uart * p)499ef1f84bSDavid du Colombier uartenable(Uart *p)
509ef1f84bSDavid du Colombier {
519ef1f84bSDavid du Colombier Uart **l;
529ef1f84bSDavid du Colombier
53406c76faSDavid du Colombier if(p->enabled)
54406c76faSDavid du Colombier return p;
559ef1f84bSDavid du Colombier if(p->iq == nil){
569ef1f84bSDavid du Colombier if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil)
579ef1f84bSDavid du Colombier return nil;
589ef1f84bSDavid du Colombier }
599ef1f84bSDavid du Colombier else
609ef1f84bSDavid du Colombier qreopen(p->iq);
619ef1f84bSDavid du Colombier if(p->oq == nil){
629ef1f84bSDavid du Colombier if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){
639ef1f84bSDavid du Colombier qfree(p->iq);
649ef1f84bSDavid du Colombier p->iq = nil;
659ef1f84bSDavid du Colombier return nil;
669ef1f84bSDavid du Colombier }
679ef1f84bSDavid du Colombier }
689ef1f84bSDavid du Colombier else
699ef1f84bSDavid du Colombier qreopen(p->oq);
709ef1f84bSDavid du Colombier
719ef1f84bSDavid du Colombier p->ir = p->istage;
729ef1f84bSDavid du Colombier p->iw = p->istage;
739ef1f84bSDavid du Colombier p->ie = &p->istage[Stagesize];
749ef1f84bSDavid du Colombier p->op = p->ostage;
759ef1f84bSDavid du Colombier p->oe = p->ostage;
769ef1f84bSDavid du Colombier
779ef1f84bSDavid du Colombier p->hup_dsr = p->hup_dcd = 0;
789ef1f84bSDavid du Colombier p->dsr = p->dcd = 0;
799ef1f84bSDavid du Colombier
809ef1f84bSDavid du Colombier /* assume we can send */
819ef1f84bSDavid du Colombier p->cts = 1;
829ef1f84bSDavid du Colombier p->ctsbackoff = 0;
839ef1f84bSDavid du Colombier
849ef1f84bSDavid du Colombier if(p->bits == 0)
859ef1f84bSDavid du Colombier uartctl(p, "l8");
869ef1f84bSDavid du Colombier if(p->stop == 0)
879ef1f84bSDavid du Colombier uartctl(p, "s1");
889ef1f84bSDavid du Colombier if(p->parity == 0)
899ef1f84bSDavid du Colombier uartctl(p, "pn");
909ef1f84bSDavid du Colombier if(p->baud == 0)
919ef1f84bSDavid du Colombier uartctl(p, "b9600");
929ef1f84bSDavid du Colombier (*p->phys->enable)(p, 1);
939ef1f84bSDavid du Colombier
94406c76faSDavid du Colombier /*
95406c76faSDavid du Colombier * use ilock because uartclock can otherwise interrupt here
96406c76faSDavid du Colombier * and would hang on an attempt to lock uartalloc.
97406c76faSDavid du Colombier */
98406c76faSDavid du Colombier ilock(&uartalloc);
999ef1f84bSDavid du Colombier for(l = &uartalloc.elist; *l; l = &(*l)->elist){
1009ef1f84bSDavid du Colombier if(*l == p)
1019ef1f84bSDavid du Colombier break;
1029ef1f84bSDavid du Colombier }
1039ef1f84bSDavid du Colombier if(*l == 0){
1049ef1f84bSDavid du Colombier p->elist = uartalloc.elist;
1059ef1f84bSDavid du Colombier uartalloc.elist = p;
1069ef1f84bSDavid du Colombier }
1079ef1f84bSDavid du Colombier p->enabled = 1;
108406c76faSDavid du Colombier iunlock(&uartalloc);
1099ef1f84bSDavid du Colombier
1109ef1f84bSDavid du Colombier return p;
1119ef1f84bSDavid du Colombier }
1129ef1f84bSDavid du Colombier
1139ef1f84bSDavid du Colombier static void
uartdisable(Uart * p)1149ef1f84bSDavid du Colombier uartdisable(Uart *p)
1159ef1f84bSDavid du Colombier {
1169ef1f84bSDavid du Colombier Uart **l;
1179ef1f84bSDavid du Colombier
118406c76faSDavid du Colombier if(!p->enabled)
119406c76faSDavid du Colombier return;
1209ef1f84bSDavid du Colombier (*p->phys->disable)(p);
1219ef1f84bSDavid du Colombier
122406c76faSDavid du Colombier ilock(&uartalloc);
1239ef1f84bSDavid du Colombier for(l = &uartalloc.elist; *l; l = &(*l)->elist){
1249ef1f84bSDavid du Colombier if(*l == p){
1259ef1f84bSDavid du Colombier *l = p->elist;
1269ef1f84bSDavid du Colombier break;
1279ef1f84bSDavid du Colombier }
1289ef1f84bSDavid du Colombier }
1299ef1f84bSDavid du Colombier p->enabled = 0;
130406c76faSDavid du Colombier iunlock(&uartalloc);
1319ef1f84bSDavid du Colombier }
1329ef1f84bSDavid du Colombier
1339ef1f84bSDavid du Colombier Uart*
uartconsole(int i,char * cmd)1349ef1f84bSDavid du Colombier uartconsole(int i, char *cmd)
1359ef1f84bSDavid du Colombier {
1369ef1f84bSDavid du Colombier Uart *p;
1379ef1f84bSDavid du Colombier
1389ef1f84bSDavid du Colombier if(i >= uartnuart || (p = uart[i]) == nil)
1399ef1f84bSDavid du Colombier return nil;
1409ef1f84bSDavid du Colombier
1419ef1f84bSDavid du Colombier qlock(p);
1429ef1f84bSDavid du Colombier if(!p->console){
1439ef1f84bSDavid du Colombier if(p->opens == 0 && uartenable(p) == nil){
1449ef1f84bSDavid du Colombier qunlock(p);
1459ef1f84bSDavid du Colombier return nil;
1469ef1f84bSDavid du Colombier }
1479ef1f84bSDavid du Colombier p->opens++;
1489ef1f84bSDavid du Colombier
1499ef1f84bSDavid du Colombier addkbdq(p->iq, -1);
1509ef1f84bSDavid du Colombier addconsdev(p->oq, uartputs, 2, 0);
1519ef1f84bSDavid du Colombier p->putc = kbdcr2nl;
1529ef1f84bSDavid du Colombier if(cmd != nil && *cmd != '\0')
1539ef1f84bSDavid du Colombier uartctl(p, cmd);
1549ef1f84bSDavid du Colombier
1559ef1f84bSDavid du Colombier p->console = 1;
1569ef1f84bSDavid du Colombier }
1579ef1f84bSDavid du Colombier qunlock(p);
1589ef1f84bSDavid du Colombier
1599ef1f84bSDavid du Colombier return p;
1609ef1f84bSDavid du Colombier }
1619ef1f84bSDavid du Colombier
162*45e6af3bSDavid du Colombier void
uartmouse(Uart * p,int (* putc)(Queue *,int),int setb1200)163*45e6af3bSDavid du Colombier uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200)
164*45e6af3bSDavid du Colombier {
165*45e6af3bSDavid du Colombier qlock(p);
166*45e6af3bSDavid du Colombier if(p->opens++ == 0 && uartenable(p) == nil){
167*45e6af3bSDavid du Colombier qunlock(p);
168*45e6af3bSDavid du Colombier error(Enodev);
169*45e6af3bSDavid du Colombier }
170*45e6af3bSDavid du Colombier if(setb1200)
171*45e6af3bSDavid du Colombier uartctl(p, "b1200");
172*45e6af3bSDavid du Colombier p->putc = putc;
173*45e6af3bSDavid du Colombier p->special = 1;
174*45e6af3bSDavid du Colombier qunlock(p);
175*45e6af3bSDavid du Colombier }
176*45e6af3bSDavid du Colombier
177*45e6af3bSDavid du Colombier void
uartsetmouseputc(Uart * p,int (* putc)(Queue *,int))178*45e6af3bSDavid du Colombier uartsetmouseputc(Uart* p, int (*putc)(Queue*, int))
179*45e6af3bSDavid du Colombier {
180*45e6af3bSDavid du Colombier qlock(p);
181*45e6af3bSDavid du Colombier if(p->opens == 0 || p->special == 0){
182*45e6af3bSDavid du Colombier qunlock(p);
183*45e6af3bSDavid du Colombier error(Enodev);
184*45e6af3bSDavid du Colombier }
185*45e6af3bSDavid du Colombier p->putc = putc;
186*45e6af3bSDavid du Colombier qunlock(p);
187*45e6af3bSDavid du Colombier }
188*45e6af3bSDavid du Colombier
1899ef1f84bSDavid du Colombier static void
uartsetlength(int i)1909ef1f84bSDavid du Colombier uartsetlength(int i)
1919ef1f84bSDavid du Colombier {
1929ef1f84bSDavid du Colombier Uart *p;
1939ef1f84bSDavid du Colombier
1949ef1f84bSDavid du Colombier if(i > 0){
1959ef1f84bSDavid du Colombier p = uart[i];
1969ef1f84bSDavid du Colombier if(p && p->opens && p->iq)
1979ef1f84bSDavid du Colombier uartdir[1+3*i].length = qlen(p->iq);
1989ef1f84bSDavid du Colombier } else for(i = 0; i < uartnuart; i++){
1999ef1f84bSDavid du Colombier p = uart[i];
2009ef1f84bSDavid du Colombier if(p && p->opens && p->iq)
2019ef1f84bSDavid du Colombier uartdir[1+3*i].length = qlen(p->iq);
2029ef1f84bSDavid du Colombier }
2039ef1f84bSDavid du Colombier }
2049ef1f84bSDavid du Colombier
2059ef1f84bSDavid du Colombier /*
2069ef1f84bSDavid du Colombier * set up the '#t' directory
2079ef1f84bSDavid du Colombier */
2089ef1f84bSDavid du Colombier static void
uartreset(void)2099ef1f84bSDavid du Colombier uartreset(void)
2109ef1f84bSDavid du Colombier {
2119ef1f84bSDavid du Colombier int i;
2129ef1f84bSDavid du Colombier Dirtab *dp;
2139ef1f84bSDavid du Colombier Uart *p, *tail;
2149ef1f84bSDavid du Colombier
2159ef1f84bSDavid du Colombier tail = nil;
2169ef1f84bSDavid du Colombier for(i = 0; physuart[i] != nil; i++){
2179ef1f84bSDavid du Colombier if(physuart[i]->pnp == nil)
2189ef1f84bSDavid du Colombier continue;
2199ef1f84bSDavid du Colombier if((p = physuart[i]->pnp()) == nil)
2209ef1f84bSDavid du Colombier continue;
2219ef1f84bSDavid du Colombier if(uartlist != nil)
2229ef1f84bSDavid du Colombier tail->next = p;
2239ef1f84bSDavid du Colombier else
2249ef1f84bSDavid du Colombier uartlist = p;
2259ef1f84bSDavid du Colombier for(tail = p; tail->next != nil; tail = tail->next)
2269ef1f84bSDavid du Colombier uartnuart++;
2279ef1f84bSDavid du Colombier uartnuart++;
2289ef1f84bSDavid du Colombier }
2299ef1f84bSDavid du Colombier
2309ef1f84bSDavid du Colombier //fix the case of uartnuart == 0, will panic below
2319ef1f84bSDavid du Colombier if(uartnuart)
2329ef1f84bSDavid du Colombier uart = malloc(uartnuart*sizeof(Uart*));
2339ef1f84bSDavid du Colombier
2349ef1f84bSDavid du Colombier uartndir = 1 + 3*uartnuart;
2359ef1f84bSDavid du Colombier uartdir = malloc(uartndir * sizeof(Dirtab));
2369ef1f84bSDavid du Colombier if(uart == nil || uartdir == nil){
2379ef1f84bSDavid du Colombier panic("uartreset: no memory %#p (%ud) %#p (%ud)",
2389ef1f84bSDavid du Colombier uart, uartnuart*sizeof(Uart*),
2399ef1f84bSDavid du Colombier uartdir, uartndir * sizeof(Dirtab));
2409ef1f84bSDavid du Colombier }
2419ef1f84bSDavid du Colombier dp = uartdir;
2429ef1f84bSDavid du Colombier strcpy(dp->name, ".");
2439ef1f84bSDavid du Colombier mkqid(&dp->qid, 0, 0, QTDIR);
2449ef1f84bSDavid du Colombier dp->length = 0;
2459ef1f84bSDavid du Colombier dp->perm = DMDIR|0555;
2469ef1f84bSDavid du Colombier dp++;
2479ef1f84bSDavid du Colombier p = uartlist;
2489ef1f84bSDavid du Colombier for(i = 0; i < uartnuart; i++){
2499ef1f84bSDavid du Colombier /* 3 directory entries per port */
250406c76faSDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%d", i);
2519ef1f84bSDavid du Colombier dp->qid.path = UARTQID(i, Qdata);
2529ef1f84bSDavid du Colombier dp->perm = 0660;
2539ef1f84bSDavid du Colombier dp++;
254406c76faSDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%dctl", i);
2559ef1f84bSDavid du Colombier dp->qid.path = UARTQID(i, Qctl);
2569ef1f84bSDavid du Colombier dp->perm = 0660;
2579ef1f84bSDavid du Colombier dp++;
258406c76faSDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%dstatus", i);
2599ef1f84bSDavid du Colombier dp->qid.path = UARTQID(i, Qstat);
2609ef1f84bSDavid du Colombier dp->perm = 0444;
2619ef1f84bSDavid du Colombier dp++;
2629ef1f84bSDavid du Colombier
2639ef1f84bSDavid du Colombier uart[i] = p;
2649ef1f84bSDavid du Colombier p->dev = i;
2659ef1f84bSDavid du Colombier if(p->console || p->special){
2669ef1f84bSDavid du Colombier /*
2679ef1f84bSDavid du Colombier * No qlock here, only called at boot time.
2689ef1f84bSDavid du Colombier */
2699ef1f84bSDavid du Colombier if(uartenable(p) != nil){
2709ef1f84bSDavid du Colombier if(p->console){
2719ef1f84bSDavid du Colombier addkbdq(p->iq, -1);
2729ef1f84bSDavid du Colombier addconsdev(p->oq, uartputs, 2, 0);
2739ef1f84bSDavid du Colombier p->putc = kbdcr2nl;
2749ef1f84bSDavid du Colombier }
2759ef1f84bSDavid du Colombier p->opens++;
2769ef1f84bSDavid du Colombier }
2779ef1f84bSDavid du Colombier }
2789ef1f84bSDavid du Colombier p = p->next;
2799ef1f84bSDavid du Colombier }
2809ef1f84bSDavid du Colombier
2819ef1f84bSDavid du Colombier if(uartnuart){
2829ef1f84bSDavid du Colombier /*
2839ef1f84bSDavid du Colombier * at 115200 baud, the 1024 char buffer takes 56 ms to process,
2849ef1f84bSDavid du Colombier * processing it every 22 ms should be fine.
2859ef1f84bSDavid du Colombier */
2869ef1f84bSDavid du Colombier uarttimer = addclock0link(uartclock, 22);
2879ef1f84bSDavid du Colombier }
2889ef1f84bSDavid du Colombier }
2899ef1f84bSDavid du Colombier
2909ef1f84bSDavid du Colombier
2919ef1f84bSDavid du Colombier static Chan*
uartattach(char * spec)2929ef1f84bSDavid du Colombier uartattach(char *spec)
2939ef1f84bSDavid du Colombier {
2949ef1f84bSDavid du Colombier return devattach('t', spec);
2959ef1f84bSDavid du Colombier }
2969ef1f84bSDavid du Colombier
2979ef1f84bSDavid du Colombier static Walkqid*
uartwalk(Chan * c,Chan * nc,char ** name,int nname)2989ef1f84bSDavid du Colombier uartwalk(Chan *c, Chan *nc, char **name, int nname)
2999ef1f84bSDavid du Colombier {
3009ef1f84bSDavid du Colombier return devwalk(c, nc, name, nname, uartdir, uartndir, devgen);
3019ef1f84bSDavid du Colombier }
3029ef1f84bSDavid du Colombier
3039ef1f84bSDavid du Colombier static long
uartstat(Chan * c,uchar * dp,long n)3049ef1f84bSDavid du Colombier uartstat(Chan *c, uchar *dp, long n)
3059ef1f84bSDavid du Colombier {
3069ef1f84bSDavid du Colombier if(UARTTYPE(c->qid.path) == Qdata)
3079ef1f84bSDavid du Colombier uartsetlength(UARTID(c->qid.path));
3089ef1f84bSDavid du Colombier return devstat(c, dp, n, uartdir, uartndir, devgen);
3099ef1f84bSDavid du Colombier }
3109ef1f84bSDavid du Colombier
3119ef1f84bSDavid du Colombier static Chan*
uartopen(Chan * c,int omode)3129ef1f84bSDavid du Colombier uartopen(Chan *c, int omode)
3139ef1f84bSDavid du Colombier {
3149ef1f84bSDavid du Colombier Uart *p;
3159ef1f84bSDavid du Colombier
3169ef1f84bSDavid du Colombier c = devopen(c, omode, uartdir, uartndir, devgen);
3179ef1f84bSDavid du Colombier
3189ef1f84bSDavid du Colombier switch(UARTTYPE(c->qid.path)){
3199ef1f84bSDavid du Colombier case Qctl:
3209ef1f84bSDavid du Colombier case Qdata:
3219ef1f84bSDavid du Colombier p = uart[UARTID(c->qid.path)];
3229ef1f84bSDavid du Colombier qlock(p);
3239ef1f84bSDavid du Colombier if(p->opens == 0 && uartenable(p) == nil){
3249ef1f84bSDavid du Colombier qunlock(p);
3259ef1f84bSDavid du Colombier c->flag &= ~COPEN;
3269ef1f84bSDavid du Colombier error(Enodev);
3279ef1f84bSDavid du Colombier }
3289ef1f84bSDavid du Colombier p->opens++;
3299ef1f84bSDavid du Colombier qunlock(p);
3309ef1f84bSDavid du Colombier break;
3319ef1f84bSDavid du Colombier }
3329ef1f84bSDavid du Colombier
3339ef1f84bSDavid du Colombier c->iounit = qiomaxatomic;
3349ef1f84bSDavid du Colombier return c;
3359ef1f84bSDavid du Colombier }
3369ef1f84bSDavid du Colombier
3379ef1f84bSDavid du Colombier static int
uartdrained(void * arg)3389ef1f84bSDavid du Colombier uartdrained(void* arg)
3399ef1f84bSDavid du Colombier {
3409ef1f84bSDavid du Colombier Uart *p;
3419ef1f84bSDavid du Colombier
3429ef1f84bSDavid du Colombier p = arg;
3439ef1f84bSDavid du Colombier return qlen(p->oq) == 0 && p->op == p->oe;
3449ef1f84bSDavid du Colombier }
3459ef1f84bSDavid du Colombier
3469ef1f84bSDavid du Colombier static void
uartdrainoutput(Uart * p)3479ef1f84bSDavid du Colombier uartdrainoutput(Uart *p)
3489ef1f84bSDavid du Colombier {
3499ef1f84bSDavid du Colombier if(!p->enabled)
3509ef1f84bSDavid du Colombier return;
3519ef1f84bSDavid du Colombier
3529ef1f84bSDavid du Colombier p->drain = 1;
3539ef1f84bSDavid du Colombier if(waserror()){
3549ef1f84bSDavid du Colombier p->drain = 0;
3559ef1f84bSDavid du Colombier nexterror();
3569ef1f84bSDavid du Colombier }
3579ef1f84bSDavid du Colombier sleep(&p->r, uartdrained, p);
3589ef1f84bSDavid du Colombier poperror();
3599ef1f84bSDavid du Colombier }
3609ef1f84bSDavid du Colombier
3619ef1f84bSDavid du Colombier static void
uartclose(Chan * c)3629ef1f84bSDavid du Colombier uartclose(Chan *c)
3639ef1f84bSDavid du Colombier {
3649ef1f84bSDavid du Colombier Uart *p;
3659ef1f84bSDavid du Colombier
3669ef1f84bSDavid du Colombier if(c->qid.type & QTDIR)
3679ef1f84bSDavid du Colombier return;
3689ef1f84bSDavid du Colombier if((c->flag & COPEN) == 0)
3699ef1f84bSDavid du Colombier return;
3709ef1f84bSDavid du Colombier switch(UARTTYPE(c->qid.path)){
3719ef1f84bSDavid du Colombier case Qdata:
3729ef1f84bSDavid du Colombier case Qctl:
3739ef1f84bSDavid du Colombier p = uart[UARTID(c->qid.path)];
3749ef1f84bSDavid du Colombier qlock(p);
3759ef1f84bSDavid du Colombier if(--(p->opens) == 0){
3769ef1f84bSDavid du Colombier qclose(p->iq);
3779ef1f84bSDavid du Colombier ilock(&p->rlock);
3789ef1f84bSDavid du Colombier p->ir = p->iw = p->istage;
3799ef1f84bSDavid du Colombier iunlock(&p->rlock);
3809ef1f84bSDavid du Colombier
3819ef1f84bSDavid du Colombier /*
3829ef1f84bSDavid du Colombier */
3839ef1f84bSDavid du Colombier qhangup(p->oq, nil);
3849ef1f84bSDavid du Colombier if(!waserror()){
3859ef1f84bSDavid du Colombier uartdrainoutput(p);
3869ef1f84bSDavid du Colombier poperror();
3879ef1f84bSDavid du Colombier }
3889ef1f84bSDavid du Colombier qclose(p->oq);
3899ef1f84bSDavid du Colombier uartdisable(p);
3909ef1f84bSDavid du Colombier p->dcd = p->dsr = p->dohup = 0;
3919ef1f84bSDavid du Colombier }
3929ef1f84bSDavid du Colombier qunlock(p);
3939ef1f84bSDavid du Colombier break;
3949ef1f84bSDavid du Colombier }
3959ef1f84bSDavid du Colombier }
3969ef1f84bSDavid du Colombier
3979ef1f84bSDavid du Colombier static long
uartread(Chan * c,void * buf,long n,vlong off)3989ef1f84bSDavid du Colombier uartread(Chan *c, void *buf, long n, vlong off)
3999ef1f84bSDavid du Colombier {
4009ef1f84bSDavid du Colombier Uart *p;
4019ef1f84bSDavid du Colombier ulong offset = off;
4029ef1f84bSDavid du Colombier
4039ef1f84bSDavid du Colombier if(c->qid.type & QTDIR){
4049ef1f84bSDavid du Colombier uartsetlength(-1);
4059ef1f84bSDavid du Colombier return devdirread(c, buf, n, uartdir, uartndir, devgen);
4069ef1f84bSDavid du Colombier }
4079ef1f84bSDavid du Colombier
4089ef1f84bSDavid du Colombier p = uart[UARTID(c->qid.path)];
4099ef1f84bSDavid du Colombier switch(UARTTYPE(c->qid.path)){
4109ef1f84bSDavid du Colombier case Qdata:
4119ef1f84bSDavid du Colombier return qread(p->iq, buf, n);
4129ef1f84bSDavid du Colombier case Qctl:
4139ef1f84bSDavid du Colombier return readnum(offset, buf, n, UARTID(c->qid.path), NUMSIZE);
4149ef1f84bSDavid du Colombier case Qstat:
4159ef1f84bSDavid du Colombier return (*p->phys->status)(p, buf, n, offset);
4169ef1f84bSDavid du Colombier }
4179ef1f84bSDavid du Colombier
4189ef1f84bSDavid du Colombier return 0;
4199ef1f84bSDavid du Colombier }
4209ef1f84bSDavid du Colombier
4219ef1f84bSDavid du Colombier int
uartctl(Uart * p,char * cmd)4229ef1f84bSDavid du Colombier uartctl(Uart *p, char *cmd)
4239ef1f84bSDavid du Colombier {
4249ef1f84bSDavid du Colombier char *f[16];
4259ef1f84bSDavid du Colombier int i, n, nf;
4269ef1f84bSDavid du Colombier
4279ef1f84bSDavid du Colombier nf = tokenize(cmd, f, nelem(f));
4289ef1f84bSDavid du Colombier for(i = 0; i < nf; i++){
4299ef1f84bSDavid du Colombier if(strncmp(f[i], "break", 5) == 0){
4309ef1f84bSDavid du Colombier (*p->phys->dobreak)(p, 0);
4319ef1f84bSDavid du Colombier continue;
4329ef1f84bSDavid du Colombier }
4339ef1f84bSDavid du Colombier
4349ef1f84bSDavid du Colombier n = atoi(f[i]+1);
4359ef1f84bSDavid du Colombier switch(*f[i]){
4369ef1f84bSDavid du Colombier case 'B':
4379ef1f84bSDavid du Colombier case 'b':
4389ef1f84bSDavid du Colombier uartdrainoutput(p);
4399ef1f84bSDavid du Colombier if((*p->phys->baud)(p, n) < 0)
4409ef1f84bSDavid du Colombier return -1;
4419ef1f84bSDavid du Colombier break;
4429ef1f84bSDavid du Colombier case 'C':
4439ef1f84bSDavid du Colombier case 'c':
4449ef1f84bSDavid du Colombier p->hup_dcd = n;
4459ef1f84bSDavid du Colombier break;
4469ef1f84bSDavid du Colombier case 'D':
4479ef1f84bSDavid du Colombier case 'd':
4489ef1f84bSDavid du Colombier uartdrainoutput(p);
4499ef1f84bSDavid du Colombier (*p->phys->dtr)(p, n);
4509ef1f84bSDavid du Colombier break;
4519ef1f84bSDavid du Colombier case 'E':
4529ef1f84bSDavid du Colombier case 'e':
4539ef1f84bSDavid du Colombier p->hup_dsr = n;
4549ef1f84bSDavid du Colombier break;
4559ef1f84bSDavid du Colombier case 'F':
4569ef1f84bSDavid du Colombier case 'f':
4579ef1f84bSDavid du Colombier if(p->oq != nil)
4589ef1f84bSDavid du Colombier qflush(p->oq);
4599ef1f84bSDavid du Colombier break;
4609ef1f84bSDavid du Colombier case 'H':
4619ef1f84bSDavid du Colombier case 'h':
4629ef1f84bSDavid du Colombier if(p->iq != nil)
4639ef1f84bSDavid du Colombier qhangup(p->iq, 0);
4649ef1f84bSDavid du Colombier if(p->oq != nil)
4659ef1f84bSDavid du Colombier qhangup(p->oq, 0);
4669ef1f84bSDavid du Colombier break;
4679ef1f84bSDavid du Colombier case 'I':
4689ef1f84bSDavid du Colombier case 'i':
4699ef1f84bSDavid du Colombier uartdrainoutput(p);
4709ef1f84bSDavid du Colombier (*p->phys->fifo)(p, n);
4719ef1f84bSDavid du Colombier break;
4729ef1f84bSDavid du Colombier case 'K':
4739ef1f84bSDavid du Colombier case 'k':
4749ef1f84bSDavid du Colombier uartdrainoutput(p);
4759ef1f84bSDavid du Colombier (*p->phys->dobreak)(p, n);
4769ef1f84bSDavid du Colombier break;
4779ef1f84bSDavid du Colombier case 'L':
4789ef1f84bSDavid du Colombier case 'l':
4799ef1f84bSDavid du Colombier uartdrainoutput(p);
4809ef1f84bSDavid du Colombier if((*p->phys->bits)(p, n) < 0)
4819ef1f84bSDavid du Colombier return -1;
4829ef1f84bSDavid du Colombier break;
4839ef1f84bSDavid du Colombier case 'M':
4849ef1f84bSDavid du Colombier case 'm':
4859ef1f84bSDavid du Colombier uartdrainoutput(p);
4869ef1f84bSDavid du Colombier (*p->phys->modemctl)(p, n);
4879ef1f84bSDavid du Colombier break;
4889ef1f84bSDavid du Colombier case 'N':
4899ef1f84bSDavid du Colombier case 'n':
4909ef1f84bSDavid du Colombier if(p->oq != nil)
4919ef1f84bSDavid du Colombier qnoblock(p->oq, n);
4929ef1f84bSDavid du Colombier break;
4939ef1f84bSDavid du Colombier case 'P':
4949ef1f84bSDavid du Colombier case 'p':
4959ef1f84bSDavid du Colombier uartdrainoutput(p);
4969ef1f84bSDavid du Colombier if((*p->phys->parity)(p, *(f[i]+1)) < 0)
4979ef1f84bSDavid du Colombier return -1;
4989ef1f84bSDavid du Colombier break;
4999ef1f84bSDavid du Colombier case 'Q':
5009ef1f84bSDavid du Colombier case 'q':
5019ef1f84bSDavid du Colombier if(p->iq != nil)
5029ef1f84bSDavid du Colombier qsetlimit(p->iq, n);
5039ef1f84bSDavid du Colombier if(p->oq != nil)
5049ef1f84bSDavid du Colombier qsetlimit(p->oq, n);
5059ef1f84bSDavid du Colombier break;
5069ef1f84bSDavid du Colombier case 'R':
5079ef1f84bSDavid du Colombier case 'r':
5089ef1f84bSDavid du Colombier uartdrainoutput(p);
5099ef1f84bSDavid du Colombier (*p->phys->rts)(p, n);
5109ef1f84bSDavid du Colombier break;
5119ef1f84bSDavid du Colombier case 'S':
5129ef1f84bSDavid du Colombier case 's':
5139ef1f84bSDavid du Colombier uartdrainoutput(p);
5149ef1f84bSDavid du Colombier if((*p->phys->stop)(p, n) < 0)
5159ef1f84bSDavid du Colombier return -1;
5169ef1f84bSDavid du Colombier break;
5179ef1f84bSDavid du Colombier case 'W':
5189ef1f84bSDavid du Colombier case 'w':
5199ef1f84bSDavid du Colombier if(uarttimer == nil || n < 1)
5209ef1f84bSDavid du Colombier return -1;
5219ef1f84bSDavid du Colombier uarttimer->tns = (vlong)n * 100000LL;
5229ef1f84bSDavid du Colombier break;
5239ef1f84bSDavid du Colombier case 'X':
5249ef1f84bSDavid du Colombier case 'x':
5259ef1f84bSDavid du Colombier if(p->enabled){
5269ef1f84bSDavid du Colombier ilock(&p->tlock);
5279ef1f84bSDavid du Colombier p->xonoff = n;
5289ef1f84bSDavid du Colombier iunlock(&p->tlock);
5299ef1f84bSDavid du Colombier }
5309ef1f84bSDavid du Colombier break;
5319ef1f84bSDavid du Colombier }
5329ef1f84bSDavid du Colombier }
5339ef1f84bSDavid du Colombier return 0;
5349ef1f84bSDavid du Colombier }
5359ef1f84bSDavid du Colombier
5369ef1f84bSDavid du Colombier static long
uartwrite(Chan * c,void * buf,long n,vlong)5379ef1f84bSDavid du Colombier uartwrite(Chan *c, void *buf, long n, vlong)
5389ef1f84bSDavid du Colombier {
5399ef1f84bSDavid du Colombier Uart *p;
5409ef1f84bSDavid du Colombier char *cmd;
5419ef1f84bSDavid du Colombier
5429ef1f84bSDavid du Colombier if(c->qid.type & QTDIR)
5439ef1f84bSDavid du Colombier error(Eperm);
5449ef1f84bSDavid du Colombier
5459ef1f84bSDavid du Colombier p = uart[UARTID(c->qid.path)];
5469ef1f84bSDavid du Colombier
5479ef1f84bSDavid du Colombier switch(UARTTYPE(c->qid.path)){
5489ef1f84bSDavid du Colombier case Qdata:
5499ef1f84bSDavid du Colombier qlock(p);
5509ef1f84bSDavid du Colombier if(waserror()){
5519ef1f84bSDavid du Colombier qunlock(p);
5529ef1f84bSDavid du Colombier nexterror();
5539ef1f84bSDavid du Colombier }
5549ef1f84bSDavid du Colombier
5559ef1f84bSDavid du Colombier n = qwrite(p->oq, buf, n);
5569ef1f84bSDavid du Colombier
5579ef1f84bSDavid du Colombier qunlock(p);
5589ef1f84bSDavid du Colombier poperror();
5599ef1f84bSDavid du Colombier break;
5609ef1f84bSDavid du Colombier case Qctl:
5619ef1f84bSDavid du Colombier cmd = malloc(n+1);
562406c76faSDavid du Colombier if(cmd == nil)
563406c76faSDavid du Colombier error(Enomem);
5649ef1f84bSDavid du Colombier memmove(cmd, buf, n);
5659ef1f84bSDavid du Colombier cmd[n] = 0;
5669ef1f84bSDavid du Colombier qlock(p);
5679ef1f84bSDavid du Colombier if(waserror()){
5689ef1f84bSDavid du Colombier qunlock(p);
5699ef1f84bSDavid du Colombier free(cmd);
5709ef1f84bSDavid du Colombier nexterror();
5719ef1f84bSDavid du Colombier }
5729ef1f84bSDavid du Colombier
5739ef1f84bSDavid du Colombier /* let output drain */
5749ef1f84bSDavid du Colombier if(uartctl(p, cmd) < 0)
5759ef1f84bSDavid du Colombier error(Ebadarg);
5769ef1f84bSDavid du Colombier
5779ef1f84bSDavid du Colombier qunlock(p);
5789ef1f84bSDavid du Colombier poperror();
5799ef1f84bSDavid du Colombier free(cmd);
5809ef1f84bSDavid du Colombier break;
5819ef1f84bSDavid du Colombier }
5829ef1f84bSDavid du Colombier
5839ef1f84bSDavid du Colombier return n;
5849ef1f84bSDavid du Colombier }
5859ef1f84bSDavid du Colombier
5869ef1f84bSDavid du Colombier static long
uartwstat(Chan * c,uchar * dp,long n)5879ef1f84bSDavid du Colombier uartwstat(Chan *c, uchar *dp, long n)
5889ef1f84bSDavid du Colombier {
5899ef1f84bSDavid du Colombier Dir d;
5909ef1f84bSDavid du Colombier Dirtab *dt;
5919ef1f84bSDavid du Colombier
5929ef1f84bSDavid du Colombier if(!iseve())
5939ef1f84bSDavid du Colombier error(Eperm);
5949ef1f84bSDavid du Colombier if(QTDIR & c->qid.type)
5959ef1f84bSDavid du Colombier error(Eperm);
5969ef1f84bSDavid du Colombier if(UARTTYPE(c->qid.path) == Qstat)
5979ef1f84bSDavid du Colombier error(Eperm);
5989ef1f84bSDavid du Colombier
5999ef1f84bSDavid du Colombier dt = &uartdir[1 + 3 * UARTID(c->qid.path)];
6009ef1f84bSDavid du Colombier n = convM2D(dp, n, &d, nil);
6019ef1f84bSDavid du Colombier if(n == 0)
6029ef1f84bSDavid du Colombier error(Eshortstat);
6039ef1f84bSDavid du Colombier if(d.mode != ~0UL)
6049ef1f84bSDavid du Colombier dt[0].perm = dt[1].perm = d.mode;
6059ef1f84bSDavid du Colombier return n;
6069ef1f84bSDavid du Colombier }
6079ef1f84bSDavid du Colombier
6089ef1f84bSDavid du Colombier void
uartpower(int on)6099ef1f84bSDavid du Colombier uartpower(int on)
6109ef1f84bSDavid du Colombier {
6119ef1f84bSDavid du Colombier Uart *p;
6129ef1f84bSDavid du Colombier
6139ef1f84bSDavid du Colombier for(p = uartlist; p != nil; p = p->next) {
6149ef1f84bSDavid du Colombier if(p->phys->power)
6159ef1f84bSDavid du Colombier (*p->phys->power)(p, on);
6169ef1f84bSDavid du Colombier }
6179ef1f84bSDavid du Colombier }
6189ef1f84bSDavid du Colombier
6199ef1f84bSDavid du Colombier Dev uartdevtab = {
6209ef1f84bSDavid du Colombier 't',
6219ef1f84bSDavid du Colombier "uart",
6229ef1f84bSDavid du Colombier
6239ef1f84bSDavid du Colombier uartreset,
6249ef1f84bSDavid du Colombier devinit,
6259ef1f84bSDavid du Colombier devshutdown,
6269ef1f84bSDavid du Colombier uartattach,
6279ef1f84bSDavid du Colombier uartwalk,
6289ef1f84bSDavid du Colombier uartstat,
6299ef1f84bSDavid du Colombier uartopen,
6309ef1f84bSDavid du Colombier devcreate,
6319ef1f84bSDavid du Colombier uartclose,
6329ef1f84bSDavid du Colombier uartread,
6339ef1f84bSDavid du Colombier devbread,
6349ef1f84bSDavid du Colombier uartwrite,
6359ef1f84bSDavid du Colombier devbwrite,
6369ef1f84bSDavid du Colombier devremove,
6379ef1f84bSDavid du Colombier uartwstat,
6389ef1f84bSDavid du Colombier uartpower,
6399ef1f84bSDavid du Colombier };
6409ef1f84bSDavid du Colombier
6419ef1f84bSDavid du Colombier /*
6429ef1f84bSDavid du Colombier * restart input if it's off
6439ef1f84bSDavid du Colombier */
6449ef1f84bSDavid du Colombier static void
uartflow(void * v)6459ef1f84bSDavid du Colombier uartflow(void *v)
6469ef1f84bSDavid du Colombier {
6479ef1f84bSDavid du Colombier Uart *p;
6489ef1f84bSDavid du Colombier
6499ef1f84bSDavid du Colombier p = v;
6509ef1f84bSDavid du Colombier if(p->modem)
6519ef1f84bSDavid du Colombier (*p->phys->rts)(p, 1);
6529ef1f84bSDavid du Colombier }
6539ef1f84bSDavid du Colombier
6549ef1f84bSDavid du Colombier /*
6559ef1f84bSDavid du Colombier * put some bytes into the local queue to avoid calling
6569ef1f84bSDavid du Colombier * qconsume for every character
6579ef1f84bSDavid du Colombier */
6589ef1f84bSDavid du Colombier int
uartstageoutput(Uart * p)6599ef1f84bSDavid du Colombier uartstageoutput(Uart *p)
6609ef1f84bSDavid du Colombier {
6619ef1f84bSDavid du Colombier int n;
6629ef1f84bSDavid du Colombier
6639ef1f84bSDavid du Colombier n = qconsume(p->oq, p->ostage, Stagesize);
6649ef1f84bSDavid du Colombier if(n <= 0)
6659ef1f84bSDavid du Colombier return 0;
6669ef1f84bSDavid du Colombier p->op = p->ostage;
6679ef1f84bSDavid du Colombier p->oe = p->ostage + n;
6689ef1f84bSDavid du Colombier return n;
6699ef1f84bSDavid du Colombier }
6709ef1f84bSDavid du Colombier
6719ef1f84bSDavid du Colombier /*
6729ef1f84bSDavid du Colombier * restart output
6739ef1f84bSDavid du Colombier */
6749ef1f84bSDavid du Colombier void
uartkick(void * v)6759ef1f84bSDavid du Colombier uartkick(void *v)
6769ef1f84bSDavid du Colombier {
6779ef1f84bSDavid du Colombier Uart *p = v;
6789ef1f84bSDavid du Colombier
6799ef1f84bSDavid du Colombier if(p->blocked)
6809ef1f84bSDavid du Colombier return;
6819ef1f84bSDavid du Colombier
6829ef1f84bSDavid du Colombier ilock(&p->tlock);
6839ef1f84bSDavid du Colombier (*p->phys->kick)(p);
6849ef1f84bSDavid du Colombier iunlock(&p->tlock);
6859ef1f84bSDavid du Colombier
6869ef1f84bSDavid du Colombier if(p->drain && uartdrained(p)){
6879ef1f84bSDavid du Colombier p->drain = 0;
6889ef1f84bSDavid du Colombier wakeup(&p->r);
6899ef1f84bSDavid du Colombier }
6909ef1f84bSDavid du Colombier }
6919ef1f84bSDavid du Colombier
6929ef1f84bSDavid du Colombier /*
6939ef1f84bSDavid du Colombier * Move data from the interrupt staging area to
6949ef1f84bSDavid du Colombier * the input Queue.
6959ef1f84bSDavid du Colombier */
6969ef1f84bSDavid du Colombier static void
uartstageinput(Uart * p)6979ef1f84bSDavid du Colombier uartstageinput(Uart *p)
6989ef1f84bSDavid du Colombier {
6999ef1f84bSDavid du Colombier int n;
7009ef1f84bSDavid du Colombier uchar *ir, *iw;
7019ef1f84bSDavid du Colombier
7029ef1f84bSDavid du Colombier while(p->ir != p->iw){
7039ef1f84bSDavid du Colombier ir = p->ir;
7049ef1f84bSDavid du Colombier if(p->ir > p->iw){
7059ef1f84bSDavid du Colombier iw = p->ie;
7069ef1f84bSDavid du Colombier p->ir = p->istage;
7079ef1f84bSDavid du Colombier }
7089ef1f84bSDavid du Colombier else{
7099ef1f84bSDavid du Colombier iw = p->iw;
7109ef1f84bSDavid du Colombier p->ir = p->iw;
7119ef1f84bSDavid du Colombier }
7129ef1f84bSDavid du Colombier if((n = qproduce(p->iq, ir, iw - ir)) < 0){
7139ef1f84bSDavid du Colombier p->serr++;
7149ef1f84bSDavid du Colombier (*p->phys->rts)(p, 0);
7159ef1f84bSDavid du Colombier }
7169ef1f84bSDavid du Colombier else if(n == 0)
7179ef1f84bSDavid du Colombier p->berr++;
7189ef1f84bSDavid du Colombier }
7199ef1f84bSDavid du Colombier }
7209ef1f84bSDavid du Colombier
7219ef1f84bSDavid du Colombier /*
7229ef1f84bSDavid du Colombier * receive a character at interrupt time
7239ef1f84bSDavid du Colombier */
7249ef1f84bSDavid du Colombier void
uartrecv(Uart * p,char ch)7259ef1f84bSDavid du Colombier uartrecv(Uart *p, char ch)
7269ef1f84bSDavid du Colombier {
7279ef1f84bSDavid du Colombier uchar *next;
7289ef1f84bSDavid du Colombier
7299ef1f84bSDavid du Colombier /* software flow control */
7309ef1f84bSDavid du Colombier if(p->xonoff){
7319ef1f84bSDavid du Colombier if(ch == CTLS){
7329ef1f84bSDavid du Colombier p->blocked = 1;
7339ef1f84bSDavid du Colombier }else if(ch == CTLQ){
7349ef1f84bSDavid du Colombier p->blocked = 0;
7359ef1f84bSDavid du Colombier p->ctsbackoff = 2; /* clock gets output going again */
7369ef1f84bSDavid du Colombier }
7379ef1f84bSDavid du Colombier }
7389ef1f84bSDavid du Colombier
7399ef1f84bSDavid du Colombier /* receive the character */
7409ef1f84bSDavid du Colombier if(p->putc)
7419ef1f84bSDavid du Colombier p->putc(p->iq, ch);
742406c76faSDavid du Colombier else if (p->iw) { /* maybe the line isn't enabled yet */
7439ef1f84bSDavid du Colombier ilock(&p->rlock);
7449ef1f84bSDavid du Colombier next = p->iw + 1;
7459ef1f84bSDavid du Colombier if(next == p->ie)
7469ef1f84bSDavid du Colombier next = p->istage;
7479ef1f84bSDavid du Colombier if(next == p->ir)
7489ef1f84bSDavid du Colombier uartstageinput(p);
7499ef1f84bSDavid du Colombier if(next != p->ir){
7509ef1f84bSDavid du Colombier *p->iw = ch;
7519ef1f84bSDavid du Colombier p->iw = next;
7529ef1f84bSDavid du Colombier }
7539ef1f84bSDavid du Colombier iunlock(&p->rlock);
7549ef1f84bSDavid du Colombier }
7559ef1f84bSDavid du Colombier }
7569ef1f84bSDavid du Colombier
7579ef1f84bSDavid du Colombier /*
7589ef1f84bSDavid du Colombier * we save up input characters till clock time to reduce
7599ef1f84bSDavid du Colombier * per character interrupt overhead.
7609ef1f84bSDavid du Colombier */
7619ef1f84bSDavid du Colombier static void
uartclock(void)7629ef1f84bSDavid du Colombier uartclock(void)
7639ef1f84bSDavid du Colombier {
7649ef1f84bSDavid du Colombier Uart *p;
7659ef1f84bSDavid du Colombier
7669ef1f84bSDavid du Colombier ilock(&uartalloc);
7679ef1f84bSDavid du Colombier for(p = uartalloc.elist; p; p = p->elist){
7689ef1f84bSDavid du Colombier
7699ef1f84bSDavid du Colombier if(p->phys->poll != nil)
7709ef1f84bSDavid du Colombier (*p->phys->poll)(p);
7719ef1f84bSDavid du Colombier
7729ef1f84bSDavid du Colombier /* this hopefully amortizes cost of qproduce to many chars */
7739ef1f84bSDavid du Colombier if(p->iw != p->ir){
7749ef1f84bSDavid du Colombier ilock(&p->rlock);
7759ef1f84bSDavid du Colombier uartstageinput(p);
7769ef1f84bSDavid du Colombier iunlock(&p->rlock);
7779ef1f84bSDavid du Colombier }
7789ef1f84bSDavid du Colombier
7799ef1f84bSDavid du Colombier /* hang up if requested */
7809ef1f84bSDavid du Colombier if(p->dohup){
7819ef1f84bSDavid du Colombier qhangup(p->iq, 0);
7829ef1f84bSDavid du Colombier qhangup(p->oq, 0);
7839ef1f84bSDavid du Colombier p->dohup = 0;
7849ef1f84bSDavid du Colombier }
7859ef1f84bSDavid du Colombier
7869ef1f84bSDavid du Colombier /* this adds hysteresis to hardware/software flow control */
7879ef1f84bSDavid du Colombier if(p->ctsbackoff){
7889ef1f84bSDavid du Colombier ilock(&p->tlock);
7899ef1f84bSDavid du Colombier if(p->ctsbackoff){
7909ef1f84bSDavid du Colombier if(--(p->ctsbackoff) == 0)
7919ef1f84bSDavid du Colombier (*p->phys->kick)(p);
7929ef1f84bSDavid du Colombier }
7939ef1f84bSDavid du Colombier iunlock(&p->tlock);
7949ef1f84bSDavid du Colombier }
7959ef1f84bSDavid du Colombier }
7969ef1f84bSDavid du Colombier iunlock(&uartalloc);
7979ef1f84bSDavid du Colombier }
7989ef1f84bSDavid du Colombier
7999ef1f84bSDavid du Colombier /*
8009ef1f84bSDavid du Colombier * polling console input, output
8019ef1f84bSDavid du Colombier */
8029ef1f84bSDavid du Colombier
8039ef1f84bSDavid du Colombier Uart* consuart;
8049ef1f84bSDavid du Colombier
8059ef1f84bSDavid du Colombier int
uartgetc(void)8069ef1f84bSDavid du Colombier uartgetc(void)
8079ef1f84bSDavid du Colombier {
8089ef1f84bSDavid du Colombier if(consuart == nil || consuart->phys->getc == nil)
8099ef1f84bSDavid du Colombier return -1;
8109ef1f84bSDavid du Colombier return consuart->phys->getc(consuart);
8119ef1f84bSDavid du Colombier }
8129ef1f84bSDavid du Colombier
8139ef1f84bSDavid du Colombier void
uartputc(int c)8149ef1f84bSDavid du Colombier uartputc(int c)
8159ef1f84bSDavid du Colombier {
816406c76faSDavid du Colombier char c2;
817406c76faSDavid du Colombier
818406c76faSDavid du Colombier if(consuart == nil || consuart->phys->putc == nil) {
819406c76faSDavid du Colombier c2 = c;
820406c76faSDavid du Colombier if (lprint)
821406c76faSDavid du Colombier (*lprint)(&c2, 1);
8229ef1f84bSDavid du Colombier return;
823406c76faSDavid du Colombier }
8249ef1f84bSDavid du Colombier consuart->phys->putc(consuart, c);
8259ef1f84bSDavid du Colombier }
8269ef1f84bSDavid du Colombier
8279ef1f84bSDavid du Colombier void
uartputs(char * s,int n)8289ef1f84bSDavid du Colombier uartputs(char *s, int n)
8299ef1f84bSDavid du Colombier {
8309ef1f84bSDavid du Colombier char *e;
8319ef1f84bSDavid du Colombier
832406c76faSDavid du Colombier if(consuart == nil || consuart->phys->putc == nil) {
833406c76faSDavid du Colombier if (lprint)
834406c76faSDavid du Colombier (*lprint)(s, n);
8359ef1f84bSDavid du Colombier return;
836406c76faSDavid du Colombier }
8379ef1f84bSDavid du Colombier e = s+n;
8389ef1f84bSDavid du Colombier for(; s<e; s++){
8399ef1f84bSDavid du Colombier if(*s == '\n')
8409ef1f84bSDavid du Colombier consuart->phys->putc(consuart, '\r');
8419ef1f84bSDavid du Colombier consuart->phys->putc(consuart, *s);
8429ef1f84bSDavid du Colombier }
8439ef1f84bSDavid du Colombier }
844