/* * Generic serial driver interface. * * The operating system dependent code must * provide the four functions detailed below. * All functions should error() rather than returning * an error condition. * * eiaopenport(n, omode): * open port #n for omode. * return a pointer to an Eiaport p. * eiacloseport(p): * close the device returned by eiaopenport. * note that there may be multiple connections * to a given port at any time, so some * reference counting may be needed here. * eiacloseport must not error. * eiardwr(p, a, n, iswrite): * read or write n bytes of data at a on port p. * if iswrite!=0, the call is a write. * eiactl(p, ctl): * process the control message ctl. * messages are typically a single letter * immediate followed by a number, e.g. b9600. * messages are case-insensitive, so B9600 and b9600 * mean the same thing. * the following are messages supported by native Plan 9: * b# - set baud rate to #. * l# - set byte size to # bits/byte (5, 6, 7, or 8). * d# - set dtr if # is non-zero; else clear it. * k# - send a # millisecond break. * r# - set rts if # is non-zero; else clear it. * m# - obey cts signal if # is non-zero; else don't. * i# - enable input fifo if # is non-zero; else disable. * pc - set parity odd if c is 'o', even if c is 'e', * else no parity. * s# - set stop bits to # (1 or 2). * the b and l messages are the most important. the others * can safely go unimplemented for most uses. */ #include <9pm/u.h> #include <9pm/libc.h> #include "dat.h" #include "fns.h" enum { Qdir, Qeia0, Qeia0ctl, Qeia1, Qeia1ctl, Qeia2, Qeia2ctl, Qeia3, Qeia3ctl, Neia = 4 }; #define PORT(qp) (((qp)-Qeia0)/2) Dirtab eiatab[]= { ".", {Qdir, 0, QTDIR}, 0, 0555, "eia0", {Qeia0}, 0, 0600, "eia1", {Qeia1}, 0, 0600, "eia2", {Qeia2}, 0, 0600, "eia3", {Qeia3}, 0, 0600, "eia0ctl", {Qeia0ctl}, 0, 0600, "eia1ctl", {Qeia1ctl}, 0, 0600, "eia2ctl", {Qeia2ctl}, 0, 0600, "eia3ctl", {Qeia3ctl}, 0, 0600, }; #define Neiatab (sizeof(eiatab)/sizeof(Dirtab)) void eiareset(void) { } Chan* eiaattach(char *spec) { return devattach('t', spec); } Walkqid* eiawalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, eiatab, Neiatab, devgen); } int eiastat(Chan *c, uchar *db, int n) { return devstat(c, db, n, eiatab, Neiatab, devgen); } Chan* eiaopen(Chan *c, int omode) { c = devopen(c, omode, eiatab, Neiatab, devgen); if(waserror()){ c->flag &= ~COPEN; nexterror(); } switch(c->qid.path) { case Qeia0: case Qeia0ctl: case Qeia1: case Qeia1ctl: case Qeia2: case Qeia2ctl: case Qeia3: case Qeia3ctl: c->aux = eiaopenport(PORT(c->qid.path), omode); break; } poperror(); return c; } void eiaclose(Chan *c) { switch(c->qid.path) { case Qeia0: case Qeia1: case Qeia2: case Qeia3: case Qeia0ctl: case Qeia1ctl: case Qeia2ctl: case Qeia3ctl: if(c->aux){ eiacloseport(c->aux); c->aux = nil; } break; } } long eiaread(Chan *c, void *a, long n, vlong offset) { switch(c->qid.path){ case Qdir: return devdirread(c, a, n, eiatab, Neiatab, devgen); case Qeia0: case Qeia1: case Qeia2: case Qeia3: n = eiardwr(c->aux, a, n, 0); break; case Qeia0ctl: case Qeia1ctl: case Qeia2ctl: case Qeia3ctl: default: error(Ebadusefd); } return n; } long eiawrite(Chan *c, char *a, long n, vlong offset) { char buf[128]; switch(c->qid.path){ case Qeia0: case Qeia1: case Qeia2: case Qeia3: n = eiardwr(c->aux, a, n, 1); break; case Qeia0ctl: case Qeia1ctl: case Qeia2ctl: case Qeia3ctl: if(n >= sizeof buf || n < 0) error(Ebadarg); memmove(buf, a, n); buf[n] = '\0'; eiactl(c->aux, buf); break; default: error(Ebadusefd); } return n; } Dev eiadevtab = { 't', "eia", devreset, eiaattach, eiawalk, eiastat, eiaopen, devcreate, eiaclose, eiaread, devbread, eiawrite, devbwrite, devremove, devwstat };