9os

Experimental kernel using plan9 ideas for embedded device
git clone git://git.simple-cc.org/9os
Log | Files | Refs | README | LICENSE

devuart.c (5252B)


      1 #include <os9/os9.h>
      2 
      3 #include <ctype.h>
      4 #include <errno.h>
      5 #include <libk.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 
      9 #include "dev.h"
     10 #include "uart.h"
     11 
     12 #define UARTSTATUS   128
     13 #define NR_UARTS     2
     14 
     15 enum Ouartqid {
     16 	Quartfs,
     17 	Qraw,
     18 	Qctl,
     19 };
     20 
     21 static Dirtab dirtab[] = {
     22 	{"raw", QID(CHFILE, 0, Qraw), 0, O_READ | O_WRITE},
     23 	{"ctl", QID(CHFILE, 0, Qctl), 0, O_READ | O_WRITE}
     24 };
     25 
     26 static Uart *uarts[NR_UARTS];
     27 static int nuarts;
     28 
     29 static int
     30 uartwalk(Chan *c, char *name)
     31 {
     32 	return devwalk(c, name, dirtab, NELEM(dirtab), devgen);
     33 }
     34 
     35 static int
     36 uartstat(Chan *c, char *file, unsigned char *buf, int n)
     37 {
     38 	return devstat(c, file, buf, n, dirtab, NELEM(dirtab), devgen);
     39 }
     40 
     41 static Uart *
     42 getuart(Chan *c)
     43 {
     44 	if (c->dev >= NR_UARTS)
     45 		panic("getuart");
     46 	return uarts[c->dev];
     47 }
     48 
     49 static int
     50 uartstatus(Uart *up, void *buf, Chan *c, int n)
     51 {
     52 	int len;
     53 	struct uartstat st;
     54 	char tmp[UARTSTATUS];
     55 
     56 	(*up->phy->status)(up, &st);
     57 
     58 	len = ksnprint(tmp, sizeof(tmp),
     59 	               "b%ld c%d d%d e%d l%d m%d p%c r%d s%d i%d\n",
     60 	               up->rate,
     61 	               (up->hang & SIG_DCD) != 0,
     62 	               up->dtr,
     63 	               (up->hang & SIG_DSR) != 0,
     64 	               up->nbits,
     65 	               up->ctsflow,
     66 	               up->parity,
     67 	               up->rts,
     68 	               up->nstop,
     69 	               up->fifo);
     70 
     71 	if (len == sizeof(tmp))
     72 		panic("uartstatus");
     73 
     74 	return buf2chan(c, buf, tmp, n, len);
     75 }
     76 
     77 static void
     78 uartdrain(Uart *up)
     79 {
     80 	/* TODO */
     81 }
     82 
     83 /*
     84  * bn   Set the baud rate to n.
     85  * cn   Set hangup on DCD if n is non-zero; else clear it.
     86  * dn   Set DTR if n is non-zero; else clear it.
     87  * f    Flush output queue.
     88  * in   Enable/disable the FIFOs.  If n is zero the FIFOs are
     89  *      disabled; otherwise n is taken as a trigger level for
     90  *      the FIFOs.  The trigger levels supported are device
     91  *      dependant, but usually include 1, 4 and 8.  An unrecog-
     92  *      nised, but non-zero, value of n causes the maximum-
     93  *      supported trigger level to be set.
     94  * en   Set hangup on DSR if n is non-zero; else clear it.
     95  * ln   Set number of bits per byte to n. Legal values are 5,
     96  *      6, 7, or 8.
     97  * mn   Obey modem CTS signal if n is non-zero; else clear it.
     98  * pc   Set parity to odd if c is o, to even if c is e; else
     99  *      set no parity.
    100  * rn   Set RTS if n is non-zero; else clear it.
    101  * sn   Set number of stop bits to n. Legal values are 1 or 2.
    102 */
    103 static int
    104 uartctl(Uart *up, char *cfg, int n)
    105 {
    106 	int cnt, r, i;
    107 	Uartphy *phy = up->phy;
    108 	unsigned char *s = (unsigned char *) cfg;
    109 
    110 	for (cnt = i = 0; i < n; cnt = ++i) {
    111 		int sig, par, c = s[i];
    112 
    113 		if (isspace(c))
    114 			continue;
    115 
    116 		par = 0;
    117 		while (i+1 < n && isdigit(s[i+1]))
    118 			par = par*10 + s[++i] - '0';
    119 
    120 		switch (c) {
    121 		case 'b':
    122 			uartdrain(up);	
    123 			r = (*phy->setbauds)(up, par);
    124 			break;
    125 		case 'e':
    126 			up->hang &= ~ (1 << SIG_DSR);
    127 			up->hang |= (par != 0) << SIG_DSR;
    128 			r = 0;
    129 			break;
    130 		case 'c':
    131 			up->hang &= ~ (1 << SIG_DCD);
    132 			up->hang |= (par != 0) << SIG_DCD;
    133 			r = 0;
    134 			break;
    135 		case 'r':
    136 			par = (par != 0) << SIG_RTS;
    137 			sig = SIG_RTS;
    138 			goto signal;
    139 		case 'd':
    140 			par = (par != 0) << SIG_DCD;
    141 			sig = SIG_DCD;
    142 		signal:
    143 			r = (*phy->signal)(up, sig, par);
    144 			break;
    145 		case 'f':
    146 			 r = (*phy->flush)(up);
    147 			break;
    148 		case 'i':
    149 			r = (*phy->setfifo)(up, par);
    150 			break;
    151 		case 'l':
    152 			 r = (*phy->numbits)(up, par);
    153 			break;
    154 		case 'm':
    155 			r = (*phy->obey)(up, SIG_CTS, par != 0);
    156 			break;
    157 		case 'p':
    158 			if (par != OPARITY && par != EPARITY)
    159 				par = NPARITY;
    160 			r = (*phy->parity)(up, par);
    161 			break;
    162 		case 's':
    163 			if (par != 1 && par != 2)
    164 				return -1;
    165 			r = (*phy->bitstop)(up, par);
    166 			break;
    167 		default:
    168 			r = -1;
    169 		}
    170 
    171 		if (r < 0)
    172 			return cnt;
    173 	}
    174 
    175 	return cnt;
    176 }
    177 
    178 static int
    179 uartread(Chan *c, void *buf, int n)
    180 {
    181 	Uart *up;
    182 
    183 	switch (c->qid.path) {
    184 	case Quartfs:
    185 		return dirread(c, buf, n, dirtab, NELEM(dirtab), devgen);
    186 	case Qraw:
    187 		up = getuart(c);
    188 		return (*up->phy->read)(up, buf, n);
    189 	case Qctl:
    190 		up = getuart(c);
    191 		return uartstatus(up, buf, c, n);
    192 	default:
    193 		panic("uartread");
    194 	}
    195 }
    196 
    197 static int
    198 uartwrite(Chan *c, void *buf, int n)
    199 {
    200 	Uart *up;
    201 
    202 	switch (c->qid.path) {
    203 	case Qraw:
    204 		up = getuart(c);
    205 		return (*up->phy->write)(up, buf, n);
    206 	case Qctl:
    207 		up = getuart(c);
    208 		return uartctl(up, buf, n);
    209 	default:
    210 		panic("uartwrite");
    211 	}
    212 }
    213 
    214 void
    215 uartlink(Uartphy *phy, Attr *attr)
    216 {
    217 	size_t siz;
    218 	Uart *up;
    219 	Attr *a;
    220 	char *cfg = NULL;
    221 
    222 	kprint("uart: Linking uart%d %s", nuarts, phy->name);
    223 	if (nuarts == NR_UARTS)
    224 		panic("uartlink1");
    225 
    226 	siz = sizeof(Uart);
    227 	up = alloc(siz);
    228 	up->phy = phy;
    229 	uarts[nuarts++] = up;
    230 
    231 	for (a = attr; a->key; a++) {
    232 		kprint(" %s=%s", a->key, a->value);
    233 		if (!strcmp(a->key, "base"))
    234 			up->base = (void *) strtoull(a->value, NULL, 0);
    235 		else if (!strcmp(a->key, "clk"))
    236 			up->clk = strtoull(a->value, NULL, 0);
    237 		else if (!strcmp(a->key, "cfg"))
    238 			cfg = a->value;
    239 	}
    240 	kprint("\n");
    241 	(*phy->init)(up, attr);
    242 
    243 	if (!cfg)
    244 		cfg = "b19200 l8";
    245 	siz = strlen(cfg);
    246 
    247 	if (uartctl(up, cfg, siz) != siz)
    248 		panic("uartlink2");
    249 }
    250 
    251 Dev uartdevtab = {
    252 	.id = 't',
    253 	.stat = uartstat,
    254 	.clone = devclone,
    255 	.attach = devattach,
    256 	.walk = uartwalk,
    257 	.read = uartread,
    258 	.write = uartwrite,
    259 	.mount = deverrmount,
    260 	.seek = deverrseek,
    261 	.sync = devsync,
    262 	.close = devclose,
    263 };