1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 5 #include "modem.h" 6 7 typedef struct { 8 char *terse; 9 char *verbose; 10 int result; 11 int (*f)(Modem*); 12 } ResultCode; 13 14 static ResultCode results[] = { 15 { "0", "OK", Rok, 0, }, 16 { "1", "CONNECT", Rconnect, 0, }, 17 { "2", "RING", Rring, 0, }, 18 { "3", "NO CARRIER", Rfailure, 0, }, 19 { "4", "ERROR", Rrerror, 0, }, 20 { "5", "CONNECT 1200", Rconnect, 0, }, 21 { "6", "NO DIALTONE", Rfailure, 0, }, 22 { "7", "BUSY", Rfailure, 0, }, 23 { "8", "NO ANSWER", Rfailure, 0, }, 24 { "9", "CONNECT 2400", Rconnect, 0, }, /* MT1432BA */ 25 { "10", "CONNECT 2400", Rconnect, 0, }, /* Hayes */ 26 { "11", "CONNECT 4800", Rconnect, 0, }, 27 { "12", "CONNECT 9600", Rconnect, 0, }, 28 { "13", "CONNECT 14400",Rconnect, 0, }, 29 { "23", "CONNECT 1275", Rconnect, 0, }, /* MT1432BA */ 30 31 { "-1", "+FCON", Rcontinue, fcon, }, 32 { "-1", "+FTSI", Rcontinue, ftsi, }, 33 { "-1", "+FDCS", Rcontinue, fdcs, }, 34 { "-1", "+FCFR", Rcontinue, fcfr, }, 35 { "-1", "+FPTS", Rcontinue, fpts, }, 36 { "-1", "+FET", Rcontinue, fet, }, 37 { "-1", "+FHNG", Rcontinue, fhng, }, 38 39 { 0 }, 40 }; 41 42 void 43 initmodem(Modem *m, int fd, int cfd, char *type, char *id) 44 { 45 m->fd = fd; 46 m->cfd = cfd; 47 if(id == 0) 48 id = "Plan 9"; 49 m->id = id; 50 m->t = type; 51 } 52 53 int 54 rawmchar(Modem *m, char *p) 55 { 56 Dir *d; 57 int n; 58 59 if(m->icount == 0) 60 m->iptr = m->ibuf; 61 62 if(m->icount){ 63 *p = *m->iptr++; 64 m->icount--; 65 return Eok; 66 } 67 68 m->iptr = m->ibuf; 69 70 if((d = dirfstat(m->fd)) == nil){ 71 verbose("rawmchar: dirfstat: %r"); 72 return seterror(m, Esys); 73 } 74 n = d->length; 75 free(d); 76 if(n == 0) 77 return Enoresponse; 78 79 if(n > sizeof(m->ibuf)-1) 80 n = sizeof(m->ibuf)-1; 81 if((m->icount = read(m->fd, m->ibuf, n)) <= 0){ 82 verbose("rawmchar: read: %r"); 83 m->icount = 0; 84 return seterror(m, Esys); 85 } 86 *p = *m->iptr++; 87 m->icount--; 88 89 return Eok; 90 } 91 92 int 93 getmchar(Modem *m, char *buf, long timeout) 94 { 95 int r, t; 96 97 timeout += time(0); 98 while((t = time(0)) <= timeout){ 99 switch(r = rawmchar(m, buf)){ 100 101 case Eok: 102 return Eok; 103 104 case Enoresponse: 105 sleep(100); 106 continue; 107 108 default: 109 return r; 110 } 111 } 112 verbose("getmchar: time %ud, timeout %ud", t, timeout); 113 114 return seterror(m, Enoresponse); 115 } 116 117 int 118 putmchar(Modem *m, char *p) 119 { 120 if(write(m->fd, p, 1) < 0) 121 return seterror(m, Esys); 122 return Eok; 123 } 124 125 /* 126 * lines terminate with cr-lf 127 */ 128 static int 129 getmline(Modem *m, char *buf, int len, long timeout) 130 { 131 int r, t; 132 char *e = buf+len-1; 133 char last = 0; 134 135 timeout += time(0); 136 while((t = time(0)) <= timeout){ 137 switch(r = rawmchar(m, buf)){ 138 139 case Eok: 140 /* ignore ^s ^q which are used for flow */ 141 if(*buf == '\021' || *buf == '\023') 142 continue; 143 if(*buf == '\n'){ 144 /* ignore nl if its not with a cr */ 145 if(last == '\r'){ 146 *buf = 0; 147 return Eok; 148 } 149 continue; 150 } 151 last = *buf; 152 if(*buf == '\r') 153 continue; 154 buf++; 155 if(buf == e){ 156 *buf = 0; 157 return Eok; 158 } 159 continue; 160 161 case Enoresponse: 162 sleep(100); 163 continue; 164 165 default: 166 return r; 167 } 168 } 169 verbose("getmline: time %ud, timeout %ud", t, timeout); 170 171 return seterror(m, Enoresponse); 172 } 173 174 int 175 command(Modem *m, char *s) 176 { 177 verbose("m->: %s", s); 178 if(fprint(m->fd, "%s\r", s) < 0) 179 return seterror(m, Esys); 180 return Eok; 181 } 182 183 /* 184 * Read till we see a message or we time out. 185 * BUG: line lengths not checked; 186 * newlines 187 */ 188 int 189 response(Modem *m, int timeout) 190 { 191 int r; 192 ResultCode *rp; 193 194 while(getmline(m, m->response, sizeof(m->response), timeout) == Eok){ 195 if(m->response[0] == 0) 196 continue; 197 verbose("<-m: %s", m->response); 198 for(rp = results; rp->terse; rp++){ 199 if(strncmp(rp->verbose, m->response, strlen(rp->verbose))) 200 continue; 201 r = rp->result; 202 if(rp->f && (r = (*rp->f)(m)) == Rcontinue) 203 break; 204 return r; 205 } 206 } 207 208 m->response[0] = 0; 209 return Rnoise; 210 } 211 212 void 213 xonoff(Modem *m, int i) 214 { 215 char buf[8]; 216 217 sprint(buf, "x%d", i); 218 i = strlen(buf); 219 write(m->cfd, buf, i); 220 } 221