xref: /plan9/sys/src/cmd/usb/serial/prolific.c (revision c8a340cd3a4d961f476a4f4f2d047cd5eedaced7)
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