/*
* 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
};
syntax highlighted by Code2HTML, v. 0.9.1