1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier
5219b2ee8SDavid du Colombier #include "modem.h"
6219b2ee8SDavid du Colombier
7219b2ee8SDavid du Colombier typedef struct {
8219b2ee8SDavid du Colombier char *terse;
9219b2ee8SDavid du Colombier char *verbose;
10219b2ee8SDavid du Colombier int result;
11219b2ee8SDavid du Colombier int (*f)(Modem*);
12219b2ee8SDavid du Colombier } ResultCode;
13219b2ee8SDavid du Colombier
14219b2ee8SDavid du Colombier static ResultCode results[] = {
15219b2ee8SDavid du Colombier { "0", "OK", Rok, 0, },
16219b2ee8SDavid du Colombier { "1", "CONNECT", Rconnect, 0, },
17219b2ee8SDavid du Colombier { "2", "RING", Rring, 0, },
18219b2ee8SDavid du Colombier { "3", "NO CARRIER", Rfailure, 0, },
19219b2ee8SDavid du Colombier { "4", "ERROR", Rrerror, 0, },
20219b2ee8SDavid du Colombier { "5", "CONNECT 1200", Rconnect, 0, },
21219b2ee8SDavid du Colombier { "6", "NO DIALTONE", Rfailure, 0, },
22219b2ee8SDavid du Colombier { "7", "BUSY", Rfailure, 0, },
23219b2ee8SDavid du Colombier { "8", "NO ANSWER", Rfailure, 0, },
24219b2ee8SDavid du Colombier { "9", "CONNECT 2400", Rconnect, 0, }, /* MT1432BA */
25219b2ee8SDavid du Colombier { "10", "CONNECT 2400", Rconnect, 0, }, /* Hayes */
26219b2ee8SDavid du Colombier { "11", "CONNECT 4800", Rconnect, 0, },
27219b2ee8SDavid du Colombier { "12", "CONNECT 9600", Rconnect, 0, },
28219b2ee8SDavid du Colombier { "13", "CONNECT 14400",Rconnect, 0, },
29219b2ee8SDavid du Colombier { "23", "CONNECT 1275", Rconnect, 0, }, /* MT1432BA */
30219b2ee8SDavid du Colombier
31219b2ee8SDavid du Colombier { "-1", "+FCON", Rcontinue, fcon, },
32219b2ee8SDavid du Colombier { "-1", "+FTSI", Rcontinue, ftsi, },
33219b2ee8SDavid du Colombier { "-1", "+FDCS", Rcontinue, fdcs, },
34219b2ee8SDavid du Colombier { "-1", "+FCFR", Rcontinue, fcfr, },
35219b2ee8SDavid du Colombier { "-1", "+FPTS", Rcontinue, fpts, },
36219b2ee8SDavid du Colombier { "-1", "+FET", Rcontinue, fet, },
37219b2ee8SDavid du Colombier { "-1", "+FHNG", Rcontinue, fhng, },
38219b2ee8SDavid du Colombier
39219b2ee8SDavid du Colombier { 0 },
40219b2ee8SDavid du Colombier };
41219b2ee8SDavid du Colombier
42219b2ee8SDavid du Colombier void
initmodem(Modem * m,int fd,int cfd,char * type,char * id)43219b2ee8SDavid du Colombier initmodem(Modem *m, int fd, int cfd, char *type, char *id)
44219b2ee8SDavid du Colombier {
45219b2ee8SDavid du Colombier m->fd = fd;
46219b2ee8SDavid du Colombier m->cfd = cfd;
47219b2ee8SDavid du Colombier if(id == 0)
48219b2ee8SDavid du Colombier id = "Plan 9";
49219b2ee8SDavid du Colombier m->id = id;
50219b2ee8SDavid du Colombier m->t = type;
51219b2ee8SDavid du Colombier }
52219b2ee8SDavid du Colombier
53219b2ee8SDavid du Colombier int
rawmchar(Modem * m,char * p)54219b2ee8SDavid du Colombier rawmchar(Modem *m, char *p)
55219b2ee8SDavid du Colombier {
56*9a747e4fSDavid du Colombier Dir *d;
577dd7cddfSDavid du Colombier int n;
58219b2ee8SDavid du Colombier
59219b2ee8SDavid du Colombier if(m->icount == 0)
60219b2ee8SDavid du Colombier m->iptr = m->ibuf;
61219b2ee8SDavid du Colombier
62219b2ee8SDavid du Colombier if(m->icount){
63219b2ee8SDavid du Colombier *p = *m->iptr++;
64219b2ee8SDavid du Colombier m->icount--;
65219b2ee8SDavid du Colombier return Eok;
66219b2ee8SDavid du Colombier }
67219b2ee8SDavid du Colombier
68219b2ee8SDavid du Colombier m->iptr = m->ibuf;
69219b2ee8SDavid du Colombier
70*9a747e4fSDavid du Colombier if((d = dirfstat(m->fd)) == nil){
71219b2ee8SDavid du Colombier verbose("rawmchar: dirfstat: %r");
72219b2ee8SDavid du Colombier return seterror(m, Esys);
73219b2ee8SDavid du Colombier }
74*9a747e4fSDavid du Colombier n = d->length;
75*9a747e4fSDavid du Colombier free(d);
767dd7cddfSDavid du Colombier if(n == 0)
77219b2ee8SDavid du Colombier return Enoresponse;
78219b2ee8SDavid du Colombier
797dd7cddfSDavid du Colombier if(n > sizeof(m->ibuf)-1)
807dd7cddfSDavid du Colombier n = sizeof(m->ibuf)-1;
817dd7cddfSDavid du Colombier if((m->icount = read(m->fd, m->ibuf, n)) <= 0){
82219b2ee8SDavid du Colombier verbose("rawmchar: read: %r");
83219b2ee8SDavid du Colombier m->icount = 0;
84219b2ee8SDavid du Colombier return seterror(m, Esys);
85219b2ee8SDavid du Colombier }
86219b2ee8SDavid du Colombier *p = *m->iptr++;
87219b2ee8SDavid du Colombier m->icount--;
88219b2ee8SDavid du Colombier
89219b2ee8SDavid du Colombier return Eok;
90219b2ee8SDavid du Colombier }
91219b2ee8SDavid du Colombier
92219b2ee8SDavid du Colombier int
getmchar(Modem * m,char * buf,long timeout)93219b2ee8SDavid du Colombier getmchar(Modem *m, char *buf, long timeout)
94219b2ee8SDavid du Colombier {
957dd7cddfSDavid du Colombier int r, t;
96219b2ee8SDavid du Colombier
97219b2ee8SDavid du Colombier timeout += time(0);
987dd7cddfSDavid du Colombier while((t = time(0)) <= timeout){
99219b2ee8SDavid du Colombier switch(r = rawmchar(m, buf)){
100219b2ee8SDavid du Colombier
101219b2ee8SDavid du Colombier case Eok:
102219b2ee8SDavid du Colombier return Eok;
103219b2ee8SDavid du Colombier
104219b2ee8SDavid du Colombier case Enoresponse:
105219b2ee8SDavid du Colombier sleep(100);
106219b2ee8SDavid du Colombier continue;
107219b2ee8SDavid du Colombier
108219b2ee8SDavid du Colombier default:
109219b2ee8SDavid du Colombier return r;
110219b2ee8SDavid du Colombier }
111219b2ee8SDavid du Colombier }
1127dd7cddfSDavid du Colombier verbose("getmchar: time %ud, timeout %ud", t, timeout);
113219b2ee8SDavid du Colombier
114219b2ee8SDavid du Colombier return seterror(m, Enoresponse);
115219b2ee8SDavid du Colombier }
116219b2ee8SDavid du Colombier
117219b2ee8SDavid du Colombier int
putmchar(Modem * m,char * p)118219b2ee8SDavid du Colombier putmchar(Modem *m, char *p)
119219b2ee8SDavid du Colombier {
120219b2ee8SDavid du Colombier if(write(m->fd, p, 1) < 0)
121219b2ee8SDavid du Colombier return seterror(m, Esys);
122219b2ee8SDavid du Colombier return Eok;
123219b2ee8SDavid du Colombier }
124219b2ee8SDavid du Colombier
1257dd7cddfSDavid du Colombier /*
1267dd7cddfSDavid du Colombier * lines terminate with cr-lf
1277dd7cddfSDavid du Colombier */
128219b2ee8SDavid du Colombier static int
getmline(Modem * m,char * buf,int len,long timeout)129219b2ee8SDavid du Colombier getmline(Modem *m, char *buf, int len, long timeout)
130219b2ee8SDavid du Colombier {
1317dd7cddfSDavid du Colombier int r, t;
132219b2ee8SDavid du Colombier char *e = buf+len-1;
1337dd7cddfSDavid du Colombier char last = 0;
134219b2ee8SDavid du Colombier
135219b2ee8SDavid du Colombier timeout += time(0);
1367dd7cddfSDavid du Colombier while((t = time(0)) <= timeout){
137219b2ee8SDavid du Colombier switch(r = rawmchar(m, buf)){
138219b2ee8SDavid du Colombier
139219b2ee8SDavid du Colombier case Eok:
1407dd7cddfSDavid du Colombier /* ignore ^s ^q which are used for flow */
1417dd7cddfSDavid du Colombier if(*buf == '\021' || *buf == '\023')
142219b2ee8SDavid du Colombier continue;
1437dd7cddfSDavid du Colombier if(*buf == '\n'){
1447dd7cddfSDavid du Colombier /* ignore nl if its not with a cr */
1457dd7cddfSDavid du Colombier if(last == '\r'){
146219b2ee8SDavid du Colombier *buf = 0;
147219b2ee8SDavid du Colombier return Eok;
148219b2ee8SDavid du Colombier }
1497dd7cddfSDavid du Colombier continue;
1507dd7cddfSDavid du Colombier }
1517dd7cddfSDavid du Colombier last = *buf;
1527dd7cddfSDavid du Colombier if(*buf == '\r')
1537dd7cddfSDavid du Colombier continue;
154219b2ee8SDavid du Colombier buf++;
155219b2ee8SDavid du Colombier if(buf == e){
156219b2ee8SDavid du Colombier *buf = 0;
157219b2ee8SDavid du Colombier return Eok;
158219b2ee8SDavid du Colombier }
159219b2ee8SDavid du Colombier continue;
160219b2ee8SDavid du Colombier
161219b2ee8SDavid du Colombier case Enoresponse:
162219b2ee8SDavid du Colombier sleep(100);
163219b2ee8SDavid du Colombier continue;
164219b2ee8SDavid du Colombier
165219b2ee8SDavid du Colombier default:
166219b2ee8SDavid du Colombier return r;
167219b2ee8SDavid du Colombier }
168219b2ee8SDavid du Colombier }
1697dd7cddfSDavid du Colombier verbose("getmline: time %ud, timeout %ud", t, timeout);
170219b2ee8SDavid du Colombier
171219b2ee8SDavid du Colombier return seterror(m, Enoresponse);
172219b2ee8SDavid du Colombier }
173219b2ee8SDavid du Colombier
174219b2ee8SDavid du Colombier int
command(Modem * m,char * s)175219b2ee8SDavid du Colombier command(Modem *m, char *s)
176219b2ee8SDavid du Colombier {
177219b2ee8SDavid du Colombier verbose("m->: %s", s);
178219b2ee8SDavid du Colombier if(fprint(m->fd, "%s\r", s) < 0)
179219b2ee8SDavid du Colombier return seterror(m, Esys);
180219b2ee8SDavid du Colombier return Eok;
181219b2ee8SDavid du Colombier }
182219b2ee8SDavid du Colombier
183219b2ee8SDavid du Colombier /*
184219b2ee8SDavid du Colombier * Read till we see a message or we time out.
185219b2ee8SDavid du Colombier * BUG: line lengths not checked;
186219b2ee8SDavid du Colombier * newlines
187219b2ee8SDavid du Colombier */
188219b2ee8SDavid du Colombier int
response(Modem * m,int timeout)189219b2ee8SDavid du Colombier response(Modem *m, int timeout)
190219b2ee8SDavid du Colombier {
191219b2ee8SDavid du Colombier int r;
192219b2ee8SDavid du Colombier ResultCode *rp;
193219b2ee8SDavid du Colombier
194219b2ee8SDavid du Colombier while(getmline(m, m->response, sizeof(m->response), timeout) == Eok){
195219b2ee8SDavid du Colombier if(m->response[0] == 0)
196219b2ee8SDavid du Colombier continue;
197219b2ee8SDavid du Colombier verbose("<-m: %s", m->response);
198219b2ee8SDavid du Colombier for(rp = results; rp->terse; rp++){
199219b2ee8SDavid du Colombier if(strncmp(rp->verbose, m->response, strlen(rp->verbose)))
200219b2ee8SDavid du Colombier continue;
201219b2ee8SDavid du Colombier r = rp->result;
202219b2ee8SDavid du Colombier if(rp->f && (r = (*rp->f)(m)) == Rcontinue)
203219b2ee8SDavid du Colombier break;
204219b2ee8SDavid du Colombier return r;
205219b2ee8SDavid du Colombier }
206219b2ee8SDavid du Colombier }
207219b2ee8SDavid du Colombier
208219b2ee8SDavid du Colombier m->response[0] = 0;
209219b2ee8SDavid du Colombier return Rnoise;
210219b2ee8SDavid du Colombier }
211219b2ee8SDavid du Colombier
212219b2ee8SDavid du Colombier void
xonoff(Modem * m,int i)213219b2ee8SDavid du Colombier xonoff(Modem *m, int i)
214219b2ee8SDavid du Colombier {
215219b2ee8SDavid du Colombier char buf[8];
216219b2ee8SDavid du Colombier
217219b2ee8SDavid du Colombier sprint(buf, "x%d", i);
218219b2ee8SDavid du Colombier i = strlen(buf);
219219b2ee8SDavid du Colombier write(m->cfd, buf, i);
220219b2ee8SDavid du Colombier }
221