1 #include <u.h> 2 #include <libc.h> 3 #include "compat.h" 4 #include "kbd.h" 5 #include "error.h" 6 7 typedef struct Queue Queue; 8 struct Queue 9 { 10 QLock qwait; 11 Rendez rwait; 12 13 Lock lock; 14 int notempty; 15 char buf[1024]; 16 char *w; 17 char *r; 18 char *e; 19 }; 20 21 Queue* kbdq; /* unprocessed console input */ 22 Queue* lineq; /* processed console input */ 23 Snarf snarf = { 24 .vers = 1 25 }; 26 27 static struct 28 { 29 QLock; 30 int raw; /* true if we shouldn't process input */ 31 int ctl; /* number of opens to the control file */ 32 int x; /* index into line */ 33 char line[1024]; /* current input line */ 34 } kbd; 35 36 /* 37 * cheapo fixed-length queues 38 */ 39 static void 40 qwrite(Queue *q, void *v, int n) 41 { 42 char *buf, *next; 43 int i; 44 45 buf = v; 46 lock(&q->lock); 47 for(i = 0; i < n; i++){ 48 next = q->w+1; 49 if(next >= q->e) 50 next = q->buf; 51 if(next == q->r) 52 break; 53 *q->w = buf[i]; 54 q->w = next; 55 } 56 q->notempty = 1; 57 unlock(&q->lock); 58 rendwakeup(&q->rwait); 59 } 60 61 static int 62 qcanread(void *vq) 63 { 64 Queue *q; 65 int ne; 66 67 q = vq; 68 lock(&q->lock); 69 ne = q->notempty; 70 unlock(&q->lock); 71 return ne; 72 } 73 74 static int 75 qread(Queue *q, void *v, int n) 76 { 77 char *a; 78 int nn, notempty; 79 80 if(n == 0) 81 return 0; 82 a = v; 83 nn = 0; 84 for(;;){ 85 lock(&q->lock); 86 87 while(nn < n && q->r != q->w){ 88 a[nn++] = *q->r++; 89 if(q->r >= q->e) 90 q->r = q->buf; 91 } 92 93 notempty = q->notempty; 94 q->notempty = q->r != q->w; 95 unlock(&q->lock); 96 if(notempty) 97 break; 98 99 /* 100 * wait for something to show up in the kbd buffer. 101 */ 102 qlock(&q->qwait); 103 if(waserror()){ 104 qunlock(&q->qwait); 105 nexterror(); 106 } 107 rendsleep(&q->rwait, qcanread, q); 108 qunlock(&q->qwait); 109 poperror(); 110 } 111 return nn; 112 } 113 114 static Queue * 115 mkqueue(void) 116 { 117 Queue *q; 118 119 q = smalloc(sizeof(Queue)); 120 q->r = q->buf; 121 q->w = q->r; 122 q->e = &q->buf[sizeof q->buf]; 123 q->notempty = 0; 124 return q; 125 } 126 127 static void 128 echoscreen(char *buf, int n) 129 { 130 char *e, *p; 131 char ebuf[128]; 132 int x; 133 134 p = ebuf; 135 e = ebuf + sizeof(ebuf) - 4; 136 while(n-- > 0){ 137 if(p >= e){ 138 screenputs(ebuf, p - ebuf); 139 p = ebuf; 140 } 141 x = *buf++; 142 if(x == 0x15){ 143 *p++ = '^'; 144 *p++ = 'U'; 145 *p++ = '\n'; 146 } else 147 *p++ = x; 148 } 149 if(p != ebuf) 150 screenputs(ebuf, p - ebuf); 151 } 152 153 /* 154 * Put character, possibly a rune, into read queue at interrupt time. 155 * Called at interrupt time to process a character. 156 */ 157 void 158 kbdputc(int ch) 159 { 160 int n; 161 char buf[3]; 162 Rune r; 163 164 r = ch; 165 n = runetochar(buf, &r); 166 qwrite(kbdq, buf, n); 167 if(!kbd.raw) 168 echoscreen(buf, n); 169 } 170 171 static void 172 kbdputcinit(void) 173 { 174 kbdq = mkqueue(); 175 lineq = mkqueue(); 176 kbd.raw = 0; 177 kbd.ctl = 0; 178 kbd.x = 0; 179 } 180 181 enum{ 182 Qdir, 183 Qcons, 184 Qconsctl, 185 Qsnarf, 186 Qwinname, 187 }; 188 189 static Dirtab consdir[]={ 190 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 191 "cons", {Qcons}, 0, 0660, 192 "consctl", {Qconsctl}, 0, 0220, 193 "snarf", {Qsnarf}, 0, 0600, 194 "winname", {Qwinname}, 0, 0000, 195 }; 196 197 static void 198 consinit(void) 199 { 200 kbdputcinit(); 201 } 202 203 static Chan* 204 consattach(char *spec) 205 { 206 return devattach('c', spec); 207 } 208 209 static Walkqid* 210 conswalk(Chan *c, Chan *nc, char **name, int nname) 211 { 212 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen); 213 } 214 215 static int 216 consstat(Chan *c, uchar *dp, int n) 217 { 218 return devstat(c, dp, n, consdir, nelem(consdir), devgen); 219 } 220 221 static Chan* 222 consopen(Chan *c, int omode) 223 { 224 c->aux = nil; 225 c = devopen(c, omode, consdir, nelem(consdir), devgen); 226 switch((ulong)c->qid.path){ 227 case Qconsctl: 228 qlock(&kbd); 229 kbd.ctl++; 230 qunlock(&kbd); 231 break; 232 case Qsnarf: 233 if(c->mode == OWRITE || c->mode == ORDWR) 234 c->aux = smalloc(sizeof(Snarf)); 235 break; 236 } 237 return c; 238 } 239 240 void 241 setsnarf(char *buf, int n, int *vers) 242 { 243 int i; 244 245 qlock(&snarf); 246 snarf.vers++; 247 if(vers) 248 *vers = snarf.vers; 249 for(i = 0; i < nelem(consdir); i++){ 250 if(consdir[i].qid.type == Qsnarf){ 251 consdir[i].qid.vers = snarf.vers; 252 break; 253 } 254 } 255 free(snarf.buf); 256 snarf.n = n; 257 snarf.buf = buf; 258 qunlock(&snarf); 259 } 260 261 static void 262 consclose(Chan *c) 263 { 264 Snarf *t; 265 266 switch((ulong)c->qid.path){ 267 /* last close of control file turns off raw */ 268 case Qconsctl: 269 if(c->flag&COPEN){ 270 qlock(&kbd); 271 if(--kbd.ctl == 0) 272 kbd.raw = 0; 273 qunlock(&kbd); 274 } 275 break; 276 /* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */ 277 case Qsnarf: 278 t = c->aux; 279 if(t == nil) 280 break; 281 setsnarf(t->buf, t->n, 0); 282 break; 283 } 284 } 285 286 static long 287 consread(Chan *c, void *buf, long n, vlong off) 288 { 289 char *cbuf; 290 int i, ch, eol; 291 292 if(n <= 0) 293 return n; 294 switch((ulong)c->qid.path){ 295 case Qsnarf: 296 qlock(&snarf); 297 if(off < snarf.n){ 298 if(off + n > snarf.n) 299 n = snarf.n - off; 300 memmove(buf, snarf.buf+off, n); 301 }else 302 n = 0; 303 qunlock(&snarf); 304 return n; 305 306 case Qdir: 307 return devdirread(c, buf, n, consdir, nelem(consdir), devgen); 308 309 case Qcons: 310 qlock(&kbd); 311 if(waserror()) { 312 qunlock(&kbd); 313 nexterror(); 314 } 315 if(kbd.raw) { 316 cbuf = buf; 317 if(qcanread(lineq)) 318 n = qread(lineq, buf, n); 319 else { 320 /* read as much as possible */ 321 do { 322 i = qread(kbdq, cbuf, n); 323 cbuf += i; 324 n -= i; 325 } while (n>0 && qcanread(kbdq)); 326 n = cbuf - (char*)buf; 327 } 328 } else { 329 while(!qcanread(lineq)) { 330 qread(kbdq, &kbd.line[kbd.x], 1); 331 ch = kbd.line[kbd.x]; 332 eol = 0; 333 switch(ch){ 334 case '\b': 335 if(kbd.x) 336 kbd.x--; 337 break; 338 case 0x15: 339 kbd.x = 0; 340 break; 341 case '\n': 342 case 0x04: 343 eol = 1; 344 default: 345 kbd.line[kbd.x++] = ch; 346 break; 347 } 348 if(kbd.x == sizeof(kbd.line) || eol){ 349 if(ch == 0x04) 350 kbd.x--; 351 qwrite(lineq, kbd.line, kbd.x); 352 kbd.x = 0; 353 } 354 } 355 n = qread(lineq, buf, n); 356 } 357 qunlock(&kbd); 358 poperror(); 359 return n; 360 361 default: 362 print("consread 0x%llux\n", c->qid.path); 363 error(Egreg); 364 } 365 return -1; /* never reached */ 366 } 367 368 static long 369 conswrite(Chan *c, void *va, long n, vlong) 370 { 371 Snarf *t; 372 char buf[256], *a; 373 374 switch((ulong)c->qid.path){ 375 case Qcons: 376 screenputs(va, n); 377 break; 378 379 case Qconsctl: 380 if(n >= sizeof(buf)) 381 n = sizeof(buf)-1; 382 strncpy(buf, va, n); 383 buf[n] = 0; 384 for(a = buf; a;){ 385 if(strncmp(a, "rawon", 5) == 0){ 386 qlock(&kbd); 387 if(kbd.x){ 388 qwrite(kbdq, kbd.line, kbd.x); 389 kbd.x = 0; 390 } 391 kbd.raw = 1; 392 qunlock(&kbd); 393 } else if(strncmp(a, "rawoff", 6) == 0){ 394 qlock(&kbd); 395 kbd.raw = 0; 396 kbd.x = 0; 397 qunlock(&kbd); 398 } 399 if(a = strchr(a, ' ')) 400 a++; 401 } 402 break; 403 404 case Qsnarf: 405 t = c->aux; 406 /* always append only */ 407 if(t->n > MAXSNARF) /* avoid thrashing when people cut huge text */ 408 error("snarf buffer too big"); 409 a = realloc(t->buf, t->n + n + 1); 410 if(a == nil) 411 error("snarf buffer too big"); 412 t->buf = a; 413 memmove(t->buf+t->n, va, n); 414 t->n += n; 415 t->buf[t->n] = '\0'; 416 break; 417 default: 418 print("conswrite: 0x%llux\n", c->qid.path); 419 error(Egreg); 420 } 421 return n; 422 } 423 424 Dev consdevtab = { 425 'c', 426 "cons", 427 428 devreset, 429 consinit, 430 consattach, 431 conswalk, 432 consstat, 433 consopen, 434 devcreate, 435 consclose, 436 consread, 437 devbread, 438 conswrite, 439 devbwrite, 440 devremove, 441 devwstat, 442 }; 443