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 };