1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "usb.h"
5 #include "usbfs.h"
6 #include "serial.h"
7 #include "prolific.h"
8
9 Cinfo plinfo[] = {
10 { PL2303Vid, PL2303Did },
11 { PL2303Vid, PL2303DidRSAQ2 },
12 { PL2303Vid, PL2303DidDCU11 },
13 { PL2303Vid, PL2303DidRSAQ3 },
14 { PL2303Vid, PL2303DidPHAROS },
15 { PL2303Vid, PL2303DidALDIGA },
16 { PL2303Vid, PL2303DidMMX },
17 { PL2303Vid, PL2303DidGPRS },
18 { IODATAVid, IODATADid },
19 { IODATAVid, IODATADidRSAQ5 },
20 { ATENVid, ATENDid },
21 { ATENVid2, ATENDid },
22 { ELCOMVid, ELCOMDid },
23 { ELCOMVid, ELCOMDidUCSGT },
24 { ITEGNOVid, ITEGNODid },
25 { ITEGNOVid, ITEGNODid2080 },
26 { MA620Vid, MA620Did },
27 { RATOCVid, RATOCDid },
28 { TRIPPVid, TRIPPDid },
29 { RADIOSHACKVid,RADIOSHACKDid },
30 { DCU10Vid, DCU10Did },
31 { SITECOMVid, SITECOMDid },
32 { ALCATELVid, ALCATELDid },
33 { SAMSUNGVid, SAMSUNGDid },
34 { SIEMENSVid, SIEMENSDidSX1 },
35 { SIEMENSVid, SIEMENSDidX65 },
36 { SIEMENSVid, SIEMENSDidX75 },
37 { SIEMENSVid, SIEMENSDidEF81 },
38 { SYNTECHVid, SYNTECHDid },
39 { NOKIACA42Vid, NOKIACA42Did },
40 { CA42CA42Vid, CA42CA42Did },
41 { SAGEMVid, SAGEMDid },
42 { LEADTEKVid, LEADTEK9531Did },
43 { SPEEDDRAGONVid,SPEEDDRAGONDid },
44 { DATAPILOTU2Vid,DATAPILOTU2Did },
45 { BELKINVid, BELKINDid },
46 { ALCORVid, ALCORDid },
47 { WS002INVid, WS002INDid },
48 { COREGAVid, COREGADid },
49 { YCCABLEVid, YCCABLEDid },
50 { SUPERIALVid, SUPERIALDid },
51 { HPVid, HPLD220Did },
52 { 0, 0 },
53 };
54
55 int
plmatch(char * info)56 plmatch(char *info)
57 {
58 Cinfo *ip;
59 char buf[50];
60
61 for(ip = plinfo; ip->vid != 0; ip++){
62 snprint(buf, sizeof buf, "vid %#06x did %#06x",
63 ip->vid, ip->did);
64 dsprint(2, "serial: %s %s\n", buf, info);
65 if(strstr(info, buf) != nil)
66 return 0;
67 }
68 return -1;
69 }
70
71 static void statusreader(void *u);
72
73 static void
dumpbuf(uchar * buf,int bufsz)74 dumpbuf(uchar *buf, int bufsz)
75 {
76 int i;
77
78 for(i=0; i<bufsz; i++)
79 print("buf[%d]=%#ux ", i, buf[i]);
80 print("\n");
81 }
82
83 static int
vendorread(Serialport * p,int val,int index,uchar * buf)84 vendorread(Serialport *p, int val, int index, uchar *buf)
85 {
86 int res;
87 Serial *ser;
88
89 ser = p->s;
90
91 dsprint(2, "serial: vendorread val: 0x%x idx:%d buf:%p\n",
92 val, index, buf);
93 res = usbcmd(ser->dev, Rd2h | Rvendor | Rdev, VendorReadReq,
94 val, index, buf, 1);
95 dsprint(2, "serial: vendorread res:%d\n", res);
96 return res;
97 }
98
99 static int
vendorwrite(Serialport * p,int val,int index)100 vendorwrite(Serialport *p, int val, int index)
101 {
102 int res;
103 Serial *ser;
104
105 ser = p->s;
106
107 dsprint(2, "serial: vendorwrite val: 0x%x idx:%d\n", val, index);
108 res = usbcmd(ser->dev, Rh2d | Rvendor | Rdev, VendorWriteReq,
109 val, index, nil, 0);
110 dsprint(2, "serial: vendorwrite res:%d\n", res);
111 return res;
112 }
113
114 /* BUG: I could probably read Dcr0 and set only the bits */
115 static int
plmodemctl(Serialport * p,int set)116 plmodemctl(Serialport *p, int set)
117 {
118 Serial *ser;
119
120 ser = p->s;
121
122 if(set == 0){
123 p->mctl = 0;
124 vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init);
125 return 0;
126 }
127
128 p->mctl = 1;
129 if(ser->type == TypeHX)
130 vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init|Dcr0HwFcX);
131 else
132 vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init|Dcr0HwFcH);
133 return 0;
134 }
135
136 static int
plgetparam(Serialport * p)137 plgetparam(Serialport *p)
138 {
139 uchar buf[ParamReqSz];
140 int res;
141 Serial *ser;
142
143 ser = p->s;
144
145
146 res = usbcmd(ser->dev, Rd2h | Rclass | Riface, GetLineReq,
147 0, 0, buf, sizeof buf);
148 p->baud = GET4(buf);
149
150 /*
151 * with the Pl9 interface it is not possible to set `1.5' as stop bits
152 * for the prologic:
153 * 0 is 1 stop bit
154 * 1 is 1.5 stop bits
155 * 2 is 2 stop bits
156 */
157 if(buf[4] == 1)
158 fprint(2, "warning, stop bit set to 1.5 unsupported");
159 else if(buf[4] == 0)
160 p->stop = 1;
161 else if(buf[4] == 2)
162 p->stop = 2;
163 p->parity = buf[5];
164 p->bits = buf[6];
165
166 dsprint(2, "serial: getparam: ");
167 if(serialdebug)
168 dumpbuf(buf, sizeof buf);
169 dsprint(2, "serial: getparam res: %d\n", res);
170 return res;
171 }
172
173 static int
plsetparam(Serialport * p)174 plsetparam(Serialport *p)
175 {
176 uchar buf[ParamReqSz];
177 int res;
178 Serial *ser;
179
180 ser = p->s;
181
182 PUT4(buf, p->baud);
183
184 if(p->stop == 1)
185 buf[4] = 0;
186 else if(p->stop == 2)
187 buf[4] = 2; /* see comment in getparam */
188 buf[5] = p->parity;
189 buf[6] = p->bits;
190
191 dsprint(2, "serial: setparam: ");
192 if(serialdebug)
193 dumpbuf(buf, sizeof buf);
194 res = usbcmd(ser->dev, Rh2d | Rclass | Riface, SetLineReq,
195 0, 0, buf, sizeof buf);
196 plmodemctl(p, p->mctl);
197 plgetparam(p); /* make sure our state corresponds */
198
199 dsprint(2, "serial: setparam res: %d\n", res);
200 return res;
201 }
202
203 static int
revid(ulong devno)204 revid(ulong devno)
205 {
206 switch(devno){
207 case RevH:
208 return TypeH;
209 case RevX:
210 case RevHX:
211 case Rev1:
212 return TypeHX;
213 default:
214 return TypeUnk;
215 }
216 }
217
218 /* linux driver says the release id is not always right */
219 static int
heuristicid(ulong csp,ulong maxpkt)220 heuristicid(ulong csp, ulong maxpkt)
221 {
222 if(Class(csp) == 0x02)
223 return TypeH;
224 else if(maxpkt == 0x40)
225 return TypeHX;
226 else if(Class(csp) == 0x00 || Class(csp) == 0xFF)
227 return TypeH;
228 else{
229 fprint(2, "serial: chip unknown, setting to HX version\n");
230 return TypeHX;
231 }
232 }
233
234 static int
plinit(Serialport * p)235 plinit(Serialport *p)
236 {
237 char *st;
238 uchar *buf;
239 ulong csp, maxpkt, dno;
240 Serial *ser;
241
242 ser = p->s;
243 buf = emallocz(VendorReqSz, 1);
244 dsprint(2, "plinit\n");
245
246 csp = ser->dev->usb->csp;
247 maxpkt = ser->dev->maxpkt;
248 dno = ser->dev->usb->dno;
249
250 if((ser->type = revid(dno)) == TypeUnk)
251 ser->type = heuristicid(csp, maxpkt);
252
253 dsprint(2, "serial: type %d\n", ser->type);
254
255 vendorread(p, 0x8484, 0, buf);
256 vendorwrite(p, 0x0404, 0);
257 vendorread(p, 0x8484, 0, buf);
258 vendorread(p, 0x8383, 0, buf);
259 vendorread(p, 0x8484, 0, buf);
260 vendorwrite(p, 0x0404, 1);
261 vendorread(p, 0x8484, 0, buf);
262 vendorread(p, 0x8383, 0, buf);
263
264 vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init);
265 vendorwrite(p, Dcr1Idx|DcrSet, Dcr1Init);
266
267 if(ser->type == TypeHX)
268 vendorwrite(p, Dcr2Idx|DcrSet, Dcr2InitX);
269 else
270 vendorwrite(p, Dcr2Idx|DcrSet, Dcr2InitH);
271
272 plgetparam(p);
273 qunlock(ser);
274 free(buf);
275 st = emallocz(255, 1);
276 qlock(ser);
277 if(serialdebug)
278 serdumpst(p, st, 255);
279 dsprint(2, st);
280 free(st);
281 /* p gets freed by closedev, the process has a reference */
282 incref(ser->dev);
283 proccreate(statusreader, p, 8*1024);
284 return 0;
285 }
286
287 static int
plsetbreak(Serialport * p,int val)288 plsetbreak(Serialport *p, int val)
289 {
290 Serial *ser;
291
292 ser = p->s;
293 return usbcmd(ser->dev, Rh2d | Rclass | Riface,
294 (val != 0? BreakOn: BreakOff), val, 0, nil, 0);
295 }
296
297 static int
plclearpipes(Serialport * p)298 plclearpipes(Serialport *p)
299 {
300 Serial *ser;
301
302 ser = p->s;
303
304 if(ser->type == TypeHX){
305 vendorwrite(p, PipeDSRst, 0);
306 vendorwrite(p, PipeUSRst, 0);
307 }else{
308 if(unstall(ser->dev, p->epout, Eout) < 0)
309 dprint(2, "disk: unstall epout: %r\n");
310 if(unstall(ser->dev, p->epin, Ein) < 0)
311 dprint(2, "disk: unstall epin: %r\n");
312 if(unstall(ser->dev, p->epintr, Ein) < 0)
313 dprint(2, "disk: unstall epintr: %r\n");
314 }
315 return 0;
316 }
317
318 static int
setctlline(Serialport * p,uchar val)319 setctlline(Serialport *p, uchar val)
320 {
321 Serial *ser;
322
323 ser = p->s;
324 return usbcmd(ser->dev, Rh2d | Rclass | Riface, SetCtlReq,
325 val, 0, nil, 0);
326 }
327
328 static void
composectl(Serialport * p)329 composectl(Serialport *p)
330 {
331 if(p->rts)
332 p->ctlstate |= CtlRTS;
333 else
334 p->ctlstate &= ~CtlRTS;
335 if(p->dtr)
336 p->ctlstate |= CtlDTR;
337 else
338 p->ctlstate &= ~CtlDTR;
339 }
340
341 static int
plsendlines(Serialport * p)342 plsendlines(Serialport *p)
343 {
344 int res;
345
346 dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate);
347 composectl(p);
348 res = setctlline(p, p->ctlstate);
349 dsprint(2, "serial: sendlines res: %d\n", res);
350 return 0;
351 }
352
353 static int
plreadstatus(Serialport * p)354 plreadstatus(Serialport *p)
355 {
356 int nr, dfd;
357 char err[40];
358 uchar buf[VendorReqSz];
359 Serial *ser;
360
361 ser = p->s;
362
363 qlock(ser);
364 dsprint(2, "serial: reading from interrupt\n");
365 dfd = p->epintr->dfd;
366
367 qunlock(ser);
368 nr = read(dfd, buf, sizeof buf);
369 qlock(ser);
370 snprint(err, sizeof err, "%r");
371 dsprint(2, "serial: interrupt read %d %r\n", nr);
372
373 if(nr < 0 && strstr(err, "timed out") == nil){
374 dsprint(2, "serial: need to recover, status read %d %r\n", nr);
375 if(serialrecover(ser, nil, nil, err) < 0){
376 qunlock(ser);
377 return -1;
378 }
379 }
380 if(nr < 0)
381 dsprint(2, "serial: reading status: %r");
382 else if(nr >= sizeof buf - 1){
383 p->dcd = buf[8] & DcdStatus;
384 p->dsr = buf[8] & DsrStatus;
385 p->cts = buf[8] & BreakerrStatus;
386 p->ring = buf[8] & RingStatus;
387 p->cts = buf[8] & CtsStatus;
388 if(buf[8] & FrerrStatus)
389 p->nframeerr++;
390 if(buf[8] & ParerrStatus)
391 p->nparityerr++;
392 if(buf[8] & OvererrStatus)
393 p->novererr++;
394 } else
395 dsprint(2, "serial: bad status read %d\n", nr);
396 dsprint(2, "serial: finished read from interrupt %d\n", nr);
397 qunlock(ser);
398 return 0;
399 }
400
401 static void
statusreader(void * u)402 statusreader(void *u)
403 {
404 Serialport *p;
405 Serial *ser;
406
407 p = u;
408 ser = p->s;
409 threadsetname("statusreaderproc");
410 while(plreadstatus(p) >= 0)
411 ;
412 fprint(2, "serial: statusreader exiting\n");
413 closedev(ser->dev);
414 }
415
416 /*
417 * Maximum number of bytes transferred per frame
418 * The output buffer size cannot be increased due to the size encoding
419 */
420
421 static int
plseteps(Serialport * p)422 plseteps(Serialport *p)
423 {
424 devctl(p->epin, "maxpkt 256");
425 devctl(p->epout, "maxpkt 256");
426 return 0;
427 }
428
429 Serialops plops = {
430 .init = plinit,
431 .getparam = plgetparam,
432 .setparam = plsetparam,
433 .clearpipes = plclearpipes,
434 .sendlines = plsendlines,
435 .modemctl = plmodemctl,
436 .setbreak = plsetbreak,
437 .seteps = plseteps,
438 };
439