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 58 if(m->icount == 0) 59 m->iptr = m->ibuf; 60 61 if(m->icount){ 62 *p = *m->iptr++; 63 m->icount--; 64 return Eok; 65 } 66 67 m->iptr = m->ibuf; 68 69 if(dirfstat(m->fd, &d) < 0){ 70 verbose("rawmchar: dirfstat: %r"); 71 return seterror(m, Esys); 72 } 73 if(d.length == 0) 74 return Enoresponse; 75 76 if(d.length > sizeof(m->ibuf)) 77 d.length = sizeof(m->ibuf); 78 if((m->icount = read(m->fd, m->ibuf, d.length)) <= 0){ 79 verbose("rawmchar: read: %r"); 80 m->icount = 0; 81 return seterror(m, Esys); 82 } 83 *p = *m->iptr++; 84 m->icount--; 85 86 return Eok; 87 } 88 89 int 90 getmchar(Modem *m, char *buf, long timeout) 91 { 92 int r; 93 94 timeout += time(0); 95 while(time(0) <= timeout){ 96 switch(r = rawmchar(m, buf)){ 97 98 case Eok: 99 return Eok; 100 101 case Enoresponse: 102 sleep(100); 103 continue; 104 105 default: 106 return r; 107 } 108 } 109 110 return seterror(m, Enoresponse); 111 } 112 113 int 114 putmchar(Modem *m, char *p) 115 { 116 if(write(m->fd, p, 1) < 0) 117 return seterror(m, Esys); 118 return Eok; 119 } 120 121 static int 122 getmline(Modem *m, char *buf, int len, long timeout) 123 { 124 int r; 125 char *e = buf+len-1; 126 127 timeout += time(0); 128 while(time(0) <= timeout){ 129 switch(r = rawmchar(m, buf)){ 130 131 case Eok: 132 if(*buf == '\n') 133 continue; 134 if(*buf == '\r'){ 135 *buf = 0; 136 return Eok; 137 } 138 buf++; 139 if(buf == e){ 140 *buf = 0; 141 return Eok; 142 } 143 continue; 144 145 case Enoresponse: 146 sleep(100); 147 continue; 148 149 default: 150 return r; 151 } 152 } 153 154 return seterror(m, Enoresponse); 155 } 156 157 int 158 command(Modem *m, char *s) 159 { 160 verbose("m->: %s", s); 161 if(fprint(m->fd, "%s\r", s) < 0) 162 return seterror(m, Esys); 163 return Eok; 164 } 165 166 /* 167 * Read till we see a message or we time out. 168 * BUG: line lengths not checked; 169 * newlines 170 */ 171 int 172 response(Modem *m, int timeout) 173 { 174 int r; 175 ResultCode *rp; 176 177 while(getmline(m, m->response, sizeof(m->response), timeout) == Eok){ 178 if(m->response[0] == 0) 179 continue; 180 verbose("<-m: %s", m->response); 181 for(rp = results; rp->terse; rp++){ 182 if(strncmp(rp->verbose, m->response, strlen(rp->verbose))) 183 continue; 184 r = rp->result; 185 if(rp->f && (r = (*rp->f)(m)) == Rcontinue) 186 break; 187 return r; 188 } 189 } 190 191 m->response[0] = 0; 192 return Rnoise; 193 } 194 195 void 196 xonoff(Modem *m, int i) 197 { 198 char buf[8]; 199 200 sprint(buf, "x%d", i); 201 i = strlen(buf); 202 write(m->cfd, buf, i); 203 } 204