xref: /plan9/sys/src/cmd/usb/serial/prolific.c (revision c8a340cd3a4d961f476a4f4f2d047cd5eedaced7)
15e4f5c78SDavid du Colombier #include <u.h>
25e4f5c78SDavid du Colombier #include <libc.h>
35e4f5c78SDavid du Colombier #include <thread.h>
45e4f5c78SDavid du Colombier #include "usb.h"
55e4f5c78SDavid du Colombier #include "usbfs.h"
65e4f5c78SDavid du Colombier #include "serial.h"
75e4f5c78SDavid du Colombier #include "prolific.h"
85e4f5c78SDavid du Colombier 
94d52e0f0SDavid du Colombier Cinfo plinfo[] = {
104d52e0f0SDavid du Colombier 	{ PL2303Vid,	PL2303Did },
114d52e0f0SDavid du Colombier 	{ PL2303Vid,	PL2303DidRSAQ2 },
124d52e0f0SDavid du Colombier 	{ PL2303Vid,	PL2303DidDCU11 },
134d52e0f0SDavid du Colombier 	{ PL2303Vid,	PL2303DidRSAQ3 },
144d52e0f0SDavid du Colombier 	{ PL2303Vid,	PL2303DidPHAROS },
154d52e0f0SDavid du Colombier 	{ PL2303Vid,	PL2303DidALDIGA },
164d52e0f0SDavid du Colombier 	{ PL2303Vid,	PL2303DidMMX },
174d52e0f0SDavid du Colombier 	{ PL2303Vid,	PL2303DidGPRS },
184d52e0f0SDavid du Colombier 	{ IODATAVid,	IODATADid },
194d52e0f0SDavid du Colombier 	{ IODATAVid,	IODATADidRSAQ5 },
204d52e0f0SDavid du Colombier 	{ ATENVid,	ATENDid },
214d52e0f0SDavid du Colombier 	{ ATENVid2,	ATENDid },
224d52e0f0SDavid du Colombier 	{ ELCOMVid,	ELCOMDid },
234d52e0f0SDavid du Colombier 	{ ELCOMVid,	ELCOMDidUCSGT },
244d52e0f0SDavid du Colombier 	{ ITEGNOVid,	ITEGNODid },
254d52e0f0SDavid du Colombier 	{ ITEGNOVid,	ITEGNODid2080 },
264d52e0f0SDavid du Colombier 	{ MA620Vid,	MA620Did },
274d52e0f0SDavid du Colombier 	{ RATOCVid,	RATOCDid },
284d52e0f0SDavid du Colombier 	{ TRIPPVid,	TRIPPDid },
294d52e0f0SDavid du Colombier 	{ RADIOSHACKVid,RADIOSHACKDid },
304d52e0f0SDavid du Colombier 	{ DCU10Vid,	DCU10Did },
314d52e0f0SDavid du Colombier 	{ SITECOMVid,	SITECOMDid },
324d52e0f0SDavid du Colombier 	{ ALCATELVid,	ALCATELDid },
334d52e0f0SDavid du Colombier 	{ SAMSUNGVid,	SAMSUNGDid },
344d52e0f0SDavid du Colombier 	{ SIEMENSVid,	SIEMENSDidSX1 },
354d52e0f0SDavid du Colombier 	{ SIEMENSVid,	SIEMENSDidX65 },
364d52e0f0SDavid du Colombier 	{ SIEMENSVid,	SIEMENSDidX75 },
374d52e0f0SDavid du Colombier 	{ SIEMENSVid,	SIEMENSDidEF81 },
384d52e0f0SDavid du Colombier 	{ SYNTECHVid,	SYNTECHDid },
394d52e0f0SDavid du Colombier 	{ NOKIACA42Vid,	NOKIACA42Did },
404d52e0f0SDavid du Colombier 	{ CA42CA42Vid,	CA42CA42Did },
414d52e0f0SDavid du Colombier 	{ SAGEMVid,	SAGEMDid },
424d52e0f0SDavid du Colombier 	{ LEADTEKVid,	LEADTEK9531Did },
434d52e0f0SDavid du Colombier 	{ SPEEDDRAGONVid,SPEEDDRAGONDid },
444d52e0f0SDavid du Colombier 	{ DATAPILOTU2Vid,DATAPILOTU2Did },
454d52e0f0SDavid du Colombier 	{ BELKINVid,	BELKINDid },
464d52e0f0SDavid du Colombier 	{ ALCORVid,	ALCORDid },
474d52e0f0SDavid du Colombier 	{ WS002INVid,	WS002INDid },
484d52e0f0SDavid du Colombier 	{ COREGAVid,	COREGADid },
494d52e0f0SDavid du Colombier 	{ YCCABLEVid,	YCCABLEDid },
504d52e0f0SDavid du Colombier 	{ SUPERIALVid,	SUPERIALDid },
514d52e0f0SDavid du Colombier 	{ HPVid,	HPLD220Did },
524d52e0f0SDavid du Colombier 	{ 0,		0 },
534d52e0f0SDavid du Colombier };
544d52e0f0SDavid du Colombier 
554d52e0f0SDavid du Colombier int
plmatch(char * info)564d52e0f0SDavid du Colombier plmatch(char *info)
574d52e0f0SDavid du Colombier {
584d52e0f0SDavid du Colombier 	Cinfo *ip;
594d52e0f0SDavid du Colombier 	char buf[50];
604d52e0f0SDavid du Colombier 
614d52e0f0SDavid du Colombier 	for(ip = plinfo; ip->vid != 0; ip++){
624d52e0f0SDavid du Colombier 		snprint(buf, sizeof buf, "vid %#06x did %#06x",
634d52e0f0SDavid du Colombier 			ip->vid, ip->did);
6480e9508eSDavid du Colombier 		dsprint(2, "serial: %s %s\n", buf, info);
654d52e0f0SDavid du Colombier 		if(strstr(info, buf) != nil)
664d52e0f0SDavid du Colombier 			return 0;
674d52e0f0SDavid du Colombier 	}
684d52e0f0SDavid du Colombier 	return -1;
694d52e0f0SDavid du Colombier }
704d52e0f0SDavid du Colombier 
715e4f5c78SDavid du Colombier static void	statusreader(void *u);
725e4f5c78SDavid du Colombier 
735e4f5c78SDavid du Colombier static void
dumpbuf(uchar * buf,int bufsz)745e4f5c78SDavid du Colombier dumpbuf(uchar *buf, int bufsz)
755e4f5c78SDavid du Colombier {
765e4f5c78SDavid du Colombier 	int i;
775e4f5c78SDavid du Colombier 
785e4f5c78SDavid du Colombier 	for(i=0; i<bufsz; i++)
795e4f5c78SDavid du Colombier 		print("buf[%d]=%#ux ", i, buf[i]);
805e4f5c78SDavid du Colombier 	print("\n");
815e4f5c78SDavid du Colombier }
825e4f5c78SDavid du Colombier 
835e4f5c78SDavid du Colombier static int
vendorread(Serialport * p,int val,int index,uchar * buf)84d5789509SDavid du Colombier vendorread(Serialport *p, int val, int index, uchar *buf)
855e4f5c78SDavid du Colombier {
865e4f5c78SDavid du Colombier 	int res;
87d5789509SDavid du Colombier 	Serial *ser;
88d5789509SDavid du Colombier 
89d5789509SDavid du Colombier 	ser = p->s;
905e4f5c78SDavid du Colombier 
915e4f5c78SDavid du Colombier 	dsprint(2, "serial: vendorread val: 0x%x idx:%d buf:%p\n",
925e4f5c78SDavid du Colombier 		val, index, buf);
935e4f5c78SDavid du Colombier 	res = usbcmd(ser->dev,  Rd2h | Rvendor | Rdev, VendorReadReq,
945e4f5c78SDavid du Colombier 		val, index, buf, 1);
955e4f5c78SDavid du Colombier 	dsprint(2, "serial: vendorread res:%d\n", res);
965e4f5c78SDavid du Colombier 	return res;
975e4f5c78SDavid du Colombier }
985e4f5c78SDavid du Colombier 
995e4f5c78SDavid du Colombier static int
vendorwrite(Serialport * p,int val,int index)100d5789509SDavid du Colombier vendorwrite(Serialport *p, int val, int index)
1015e4f5c78SDavid du Colombier {
1025e4f5c78SDavid du Colombier 	int res;
103d5789509SDavid du Colombier 	Serial *ser;
104d5789509SDavid du Colombier 
105d5789509SDavid du Colombier 	ser = p->s;
1065e4f5c78SDavid du Colombier 
1075e4f5c78SDavid du Colombier 	dsprint(2, "serial: vendorwrite val: 0x%x idx:%d\n", val, index);
1085e4f5c78SDavid du Colombier 	res = usbcmd(ser->dev, Rh2d | Rvendor | Rdev, VendorWriteReq,
1095e4f5c78SDavid du Colombier 		val, index, nil, 0);
1105e4f5c78SDavid du Colombier 	dsprint(2, "serial: vendorwrite res:%d\n", res);
1115e4f5c78SDavid du Colombier 	return res;
1125e4f5c78SDavid du Colombier }
1135e4f5c78SDavid du Colombier 
11480e9508eSDavid du Colombier /* BUG: I could probably read Dcr0 and set only the bits */
11580e9508eSDavid du Colombier static int
plmodemctl(Serialport * p,int set)116d5789509SDavid du Colombier plmodemctl(Serialport *p, int set)
11780e9508eSDavid du Colombier {
118d5789509SDavid du Colombier 	Serial *ser;
119d5789509SDavid du Colombier 
120d5789509SDavid du Colombier 	ser = p->s;
121d5789509SDavid du Colombier 
12280e9508eSDavid du Colombier 	if(set == 0){
123d5789509SDavid du Colombier 		p->mctl = 0;
124d5789509SDavid du Colombier 		vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init);
12580e9508eSDavid du Colombier 		return 0;
12680e9508eSDavid du Colombier 	}
12780e9508eSDavid du Colombier 
128d5789509SDavid du Colombier 	p->mctl = 1;
12980e9508eSDavid du Colombier 	if(ser->type == TypeHX)
130d5789509SDavid du Colombier 		vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init|Dcr0HwFcX);
13180e9508eSDavid du Colombier 	else
132d5789509SDavid du Colombier 		vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init|Dcr0HwFcH);
13380e9508eSDavid du Colombier 	return 0;
13480e9508eSDavid du Colombier }
13580e9508eSDavid du Colombier 
1365e4f5c78SDavid du Colombier static int
plgetparam(Serialport * p)137d5789509SDavid du Colombier plgetparam(Serialport *p)
1385e4f5c78SDavid du Colombier {
13980e9508eSDavid du Colombier 	uchar buf[ParamReqSz];
1405e4f5c78SDavid du Colombier 	int res;
141d5789509SDavid du Colombier 	Serial *ser;
142d5789509SDavid du Colombier 
143d5789509SDavid du Colombier 	ser = p->s;
144d5789509SDavid du Colombier 
1455e4f5c78SDavid du Colombier 
1465e4f5c78SDavid du Colombier 	res = usbcmd(ser->dev, Rd2h | Rclass | Riface, GetLineReq,
1475e4f5c78SDavid du Colombier 		0, 0, buf, sizeof buf);
148d5789509SDavid du Colombier 	p->baud = GET4(buf);
1495e4f5c78SDavid du Colombier 
1505e4f5c78SDavid du Colombier 	/*
1515e4f5c78SDavid du Colombier 	 * with the Pl9 interface it is not possible to set `1.5' as stop bits
1525e4f5c78SDavid du Colombier 	 * for the prologic:
1535e4f5c78SDavid du Colombier 	 *	0 is 1 stop bit
1545e4f5c78SDavid du Colombier 	 *	1 is 1.5 stop bits
1555e4f5c78SDavid du Colombier 	 *	2 is 2 stop bits
1565e4f5c78SDavid du Colombier 	 */
1575e4f5c78SDavid du Colombier 	if(buf[4] == 1)
1585e4f5c78SDavid du Colombier 		fprint(2, "warning, stop bit set to 1.5 unsupported");
1595e4f5c78SDavid du Colombier 	else if(buf[4] == 0)
160d5789509SDavid du Colombier 		p->stop = 1;
1615e4f5c78SDavid du Colombier 	else if(buf[4] == 2)
162d5789509SDavid du Colombier 		p->stop = 2;
163d5789509SDavid du Colombier 	p->parity = buf[5];
164d5789509SDavid du Colombier 	p->bits = buf[6];
1655e4f5c78SDavid du Colombier 
1665e4f5c78SDavid du Colombier 	dsprint(2, "serial: getparam: ");
1675e4f5c78SDavid du Colombier 	if(serialdebug)
1685e4f5c78SDavid du Colombier 		dumpbuf(buf, sizeof buf);
1695e4f5c78SDavid du Colombier 	dsprint(2, "serial: getparam res: %d\n", res);
1705e4f5c78SDavid du Colombier 	return res;
1715e4f5c78SDavid du Colombier }
1725e4f5c78SDavid du Colombier 
1734d52e0f0SDavid du Colombier static int
plsetparam(Serialport * p)174d5789509SDavid du Colombier plsetparam(Serialport *p)
1755e4f5c78SDavid du Colombier {
17680e9508eSDavid du Colombier 	uchar buf[ParamReqSz];
1775e4f5c78SDavid du Colombier 	int res;
178d5789509SDavid du Colombier 	Serial *ser;
1795e4f5c78SDavid du Colombier 
180d5789509SDavid du Colombier 	ser = p->s;
1815e4f5c78SDavid du Colombier 
182d5789509SDavid du Colombier 	PUT4(buf, p->baud);
183d5789509SDavid du Colombier 
184d5789509SDavid du Colombier 	if(p->stop == 1)
1855e4f5c78SDavid du Colombier 		buf[4] = 0;
186d5789509SDavid du Colombier 	else if(p->stop == 2)
1875e4f5c78SDavid du Colombier 		buf[4] = 2; 			/* see comment in getparam */
188d5789509SDavid du Colombier 	buf[5] = p->parity;
189d5789509SDavid du Colombier 	buf[6] = p->bits;
1905e4f5c78SDavid du Colombier 
1915e4f5c78SDavid du Colombier 	dsprint(2, "serial: setparam: ");
1925e4f5c78SDavid du Colombier 	if(serialdebug)
1935e4f5c78SDavid du Colombier 		dumpbuf(buf, sizeof buf);
1945e4f5c78SDavid du Colombier 	res = usbcmd(ser->dev, Rh2d | Rclass | Riface, SetLineReq,
1955e4f5c78SDavid du Colombier 		0, 0, buf, sizeof buf);
196d5789509SDavid du Colombier 	plmodemctl(p, p->mctl);
197d5789509SDavid du Colombier 	plgetparam(p);		/* make sure our state corresponds */
1985e4f5c78SDavid du Colombier 
1995e4f5c78SDavid du Colombier 	dsprint(2, "serial: setparam res: %d\n", res);
2005e4f5c78SDavid du Colombier 	return res;
2015e4f5c78SDavid du Colombier }
2025e4f5c78SDavid du Colombier 
2035e4f5c78SDavid du Colombier static int
revid(ulong devno)20480e9508eSDavid du Colombier revid(ulong devno)
20580e9508eSDavid du Colombier {
20680e9508eSDavid du Colombier 	switch(devno){
20780e9508eSDavid du Colombier 	case RevH:
20880e9508eSDavid du Colombier 		return TypeH;
20980e9508eSDavid du Colombier 	case RevX:
21080e9508eSDavid du Colombier 	case RevHX:
21180e9508eSDavid du Colombier 	case Rev1:
21280e9508eSDavid du Colombier 		return TypeHX;
21380e9508eSDavid du Colombier 	default:
21480e9508eSDavid du Colombier 		return TypeUnk;
21580e9508eSDavid du Colombier 	}
21680e9508eSDavid du Colombier }
21780e9508eSDavid du Colombier 
21880e9508eSDavid du Colombier /* linux driver says the release id is not always right */
21980e9508eSDavid du Colombier static int
heuristicid(ulong csp,ulong maxpkt)22080e9508eSDavid du Colombier heuristicid(ulong csp, ulong maxpkt)
22180e9508eSDavid du Colombier {
22280e9508eSDavid du Colombier 	if(Class(csp) == 0x02)
22380e9508eSDavid du Colombier 		return TypeH;
22480e9508eSDavid du Colombier 	else if(maxpkt == 0x40)
22580e9508eSDavid du Colombier 		return TypeHX;
22680e9508eSDavid du Colombier 	else if(Class(csp) == 0x00 || Class(csp) == 0xFF)
22780e9508eSDavid du Colombier 		return TypeH;
22880e9508eSDavid du Colombier 	else{
22980e9508eSDavid du Colombier 		fprint(2, "serial: chip unknown, setting to HX version\n");
23080e9508eSDavid du Colombier 		return TypeHX;
23180e9508eSDavid du Colombier 	}
23280e9508eSDavid du Colombier }
23380e9508eSDavid du Colombier 
23480e9508eSDavid du Colombier static int
plinit(Serialport * p)235d5789509SDavid du Colombier plinit(Serialport *p)
2365e4f5c78SDavid du Colombier {
2375e4f5c78SDavid du Colombier 	char *st;
2385e4f5c78SDavid du Colombier 	uchar *buf;
23980e9508eSDavid du Colombier 	ulong csp, maxpkt, dno;
240d5789509SDavid du Colombier 	Serial *ser;
2415e4f5c78SDavid du Colombier 
242d5789509SDavid du Colombier 	ser = p->s;
24380e9508eSDavid du Colombier 	buf = emallocz(VendorReqSz, 1);
244d5789509SDavid du Colombier 	dsprint(2, "plinit\n");
24580e9508eSDavid du Colombier 
2465e4f5c78SDavid du Colombier 	csp = ser->dev->usb->csp;
24780e9508eSDavid du Colombier 	maxpkt = ser->dev->maxpkt;
24880e9508eSDavid du Colombier 	dno = ser->dev->usb->dno;
2495e4f5c78SDavid du Colombier 
25080e9508eSDavid du Colombier 	if((ser->type = revid(dno)) == TypeUnk)
25180e9508eSDavid du Colombier 		ser->type = heuristicid(csp, maxpkt);
2525e4f5c78SDavid du Colombier 
2535e4f5c78SDavid du Colombier 	dsprint(2, "serial: type %d\n", ser->type);
2545e4f5c78SDavid du Colombier 
255d5789509SDavid du Colombier 	vendorread(p, 0x8484, 0, buf);
256d5789509SDavid du Colombier 	vendorwrite(p, 0x0404, 0);
257d5789509SDavid du Colombier 	vendorread(p, 0x8484, 0, buf);
258d5789509SDavid du Colombier 	vendorread(p, 0x8383, 0, buf);
259d5789509SDavid du Colombier 	vendorread(p, 0x8484, 0, buf);
260d5789509SDavid du Colombier 	vendorwrite(p, 0x0404, 1);
261d5789509SDavid du Colombier 	vendorread(p, 0x8484, 0, buf);
262d5789509SDavid du Colombier 	vendorread(p, 0x8383, 0, buf);
26380e9508eSDavid du Colombier 
264d5789509SDavid du Colombier 	vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init);
265d5789509SDavid du Colombier 	vendorwrite(p, Dcr1Idx|DcrSet, Dcr1Init);
2665e4f5c78SDavid du Colombier 
2675e4f5c78SDavid du Colombier 	if(ser->type == TypeHX)
268d5789509SDavid du Colombier 		vendorwrite(p, Dcr2Idx|DcrSet, Dcr2InitX);
2695e4f5c78SDavid du Colombier 	else
270d5789509SDavid du Colombier 		vendorwrite(p, Dcr2Idx|DcrSet, Dcr2InitH);
2715e4f5c78SDavid du Colombier 
272d5789509SDavid du Colombier 	plgetparam(p);
2735e4f5c78SDavid du Colombier 	qunlock(ser);
2745e4f5c78SDavid du Colombier 	free(buf);
2755e4f5c78SDavid du Colombier 	st = emallocz(255, 1);
2765e4f5c78SDavid du Colombier 	qlock(ser);
2775e4f5c78SDavid du Colombier 	if(serialdebug)
278d5789509SDavid du Colombier 		serdumpst(p, st, 255);
2795e4f5c78SDavid du Colombier 	dsprint(2, st);
2805e4f5c78SDavid du Colombier 	free(st);
281d5789509SDavid du Colombier 	/* p gets freed by closedev, the process has a reference */
2825e4f5c78SDavid du Colombier 	incref(ser->dev);
283d5789509SDavid du Colombier 	proccreate(statusreader, p, 8*1024);
2845e4f5c78SDavid du Colombier 	return 0;
2855e4f5c78SDavid du Colombier }
2865e4f5c78SDavid du Colombier 
2875e4f5c78SDavid du Colombier static int
plsetbreak(Serialport * p,int val)288d5789509SDavid du Colombier plsetbreak(Serialport *p, int val)
2895e4f5c78SDavid du Colombier {
290d5789509SDavid du Colombier 	Serial *ser;
291d5789509SDavid du Colombier 
292d5789509SDavid du Colombier 	ser = p->s;
2935e4f5c78SDavid du Colombier 	return usbcmd(ser->dev, Rh2d | Rclass | Riface,
2945e4f5c78SDavid du Colombier 		(val != 0? BreakOn: BreakOff), val, 0, nil, 0);
2955e4f5c78SDavid du Colombier }
2965e4f5c78SDavid du Colombier 
2974d52e0f0SDavid du Colombier static int
plclearpipes(Serialport * p)298d5789509SDavid du Colombier plclearpipes(Serialport *p)
2995e4f5c78SDavid du Colombier {
300d5789509SDavid du Colombier 	Serial *ser;
301d5789509SDavid du Colombier 
302d5789509SDavid du Colombier 	ser = p->s;
303d5789509SDavid du Colombier 
3045e4f5c78SDavid du Colombier 	if(ser->type == TypeHX){
305d5789509SDavid du Colombier 		vendorwrite(p, PipeDSRst, 0);
306d5789509SDavid du Colombier 		vendorwrite(p, PipeUSRst, 0);
3075e4f5c78SDavid du Colombier 	}else{
308d5789509SDavid du Colombier 		if(unstall(ser->dev, p->epout, Eout) < 0)
3095e4f5c78SDavid du Colombier 			dprint(2, "disk: unstall epout: %r\n");
310d5789509SDavid du Colombier 		if(unstall(ser->dev, p->epin, Ein) < 0)
3115e4f5c78SDavid du Colombier 			dprint(2, "disk: unstall epin: %r\n");
312d5789509SDavid du Colombier 		if(unstall(ser->dev, p->epintr, Ein) < 0)
3135e4f5c78SDavid du Colombier 			dprint(2, "disk: unstall epintr: %r\n");
3145e4f5c78SDavid du Colombier 	}
3154d52e0f0SDavid du Colombier 	return 0;
3165e4f5c78SDavid du Colombier }
3175e4f5c78SDavid du Colombier 
3185e4f5c78SDavid du Colombier static int
setctlline(Serialport * p,uchar val)319d5789509SDavid du Colombier setctlline(Serialport *p, uchar val)
3205e4f5c78SDavid du Colombier {
321d5789509SDavid du Colombier 	Serial *ser;
322d5789509SDavid du Colombier 
323d5789509SDavid du Colombier 	ser = p->s;
3245e4f5c78SDavid du Colombier 	return usbcmd(ser->dev, Rh2d | Rclass | Riface, SetCtlReq,
3255e4f5c78SDavid du Colombier 		val, 0, nil, 0);
3265e4f5c78SDavid du Colombier }
3275e4f5c78SDavid du Colombier 
3285e4f5c78SDavid du Colombier static void
composectl(Serialport * p)329d5789509SDavid du Colombier composectl(Serialport *p)
3305e4f5c78SDavid du Colombier {
331d5789509SDavid du Colombier 	if(p->rts)
332d5789509SDavid du Colombier 		p->ctlstate |= CtlRTS;
3335e4f5c78SDavid du Colombier 	else
334d5789509SDavid du Colombier 		p->ctlstate &= ~CtlRTS;
335d5789509SDavid du Colombier 	if(p->dtr)
336d5789509SDavid du Colombier 		p->ctlstate |= CtlDTR;
3375e4f5c78SDavid du Colombier 	else
338d5789509SDavid du Colombier 		p->ctlstate &= ~CtlDTR;
3395e4f5c78SDavid du Colombier }
3405e4f5c78SDavid du Colombier 
341d5789509SDavid du Colombier static int
plsendlines(Serialport * p)342d5789509SDavid du Colombier plsendlines(Serialport *p)
3435e4f5c78SDavid du Colombier {
3445e4f5c78SDavid du Colombier 	int res;
3455e4f5c78SDavid du Colombier 
346d5789509SDavid du Colombier 	dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate);
347d5789509SDavid du Colombier 	composectl(p);
348d5789509SDavid du Colombier 	res = setctlline(p, p->ctlstate);
34980e9508eSDavid du Colombier 	dsprint(2, "serial: sendlines res: %d\n", res);
3504d52e0f0SDavid du Colombier 	return 0;
3515e4f5c78SDavid du Colombier }
3525e4f5c78SDavid du Colombier 
3535e4f5c78SDavid du Colombier static int
plreadstatus(Serialport * p)354d5789509SDavid du Colombier plreadstatus(Serialport *p)
3555e4f5c78SDavid du Colombier {
3565e4f5c78SDavid du Colombier 	int nr, dfd;
3575e4f5c78SDavid du Colombier 	char err[40];
35880e9508eSDavid du Colombier 	uchar buf[VendorReqSz];
359d5789509SDavid du Colombier 	Serial *ser;
360d5789509SDavid du Colombier 
361d5789509SDavid du Colombier 	ser = p->s;
3625e4f5c78SDavid du Colombier 
3635e4f5c78SDavid du Colombier 	qlock(ser);
3645e4f5c78SDavid du Colombier 	dsprint(2, "serial: reading from interrupt\n");
365d5789509SDavid du Colombier 	dfd = p->epintr->dfd;
3665e4f5c78SDavid du Colombier 
3675e4f5c78SDavid du Colombier 	qunlock(ser);
3685e4f5c78SDavid du Colombier 	nr = read(dfd, buf, sizeof buf);
3695e4f5c78SDavid du Colombier 	qlock(ser);
3705e4f5c78SDavid du Colombier 	snprint(err, sizeof err, "%r");
3715e4f5c78SDavid du Colombier 	dsprint(2, "serial: interrupt read %d %r\n", nr);
3725e4f5c78SDavid du Colombier 
37313522ed5SDavid du Colombier 	if(nr < 0 && strstr(err, "timed out") == nil){
3745e4f5c78SDavid du Colombier 		dsprint(2, "serial: need to recover, status read %d %r\n", nr);
375*c8a340cdSDavid du Colombier 		if(serialrecover(ser, nil, nil, err) < 0){
3765e4f5c78SDavid du Colombier 			qunlock(ser);
3775e4f5c78SDavid du Colombier 			return -1;
3785e4f5c78SDavid du Colombier 		}
3795e4f5c78SDavid du Colombier 	}
3805e4f5c78SDavid du Colombier 	if(nr < 0)
3815e4f5c78SDavid du Colombier 		dsprint(2, "serial: reading status: %r");
3825e4f5c78SDavid du Colombier 	else if(nr >= sizeof buf - 1){
383d5789509SDavid du Colombier 		p->dcd = buf[8] & DcdStatus;
384d5789509SDavid du Colombier 		p->dsr = buf[8] & DsrStatus;
385d5789509SDavid du Colombier 		p->cts = buf[8] & BreakerrStatus;
386d5789509SDavid du Colombier 		p->ring = buf[8] & RingStatus;
387d5789509SDavid du Colombier 		p->cts = buf[8] & CtsStatus;
3885e4f5c78SDavid du Colombier 		if(buf[8] & FrerrStatus)
389d5789509SDavid du Colombier 			p->nframeerr++;
3905e4f5c78SDavid du Colombier 		if(buf[8] & ParerrStatus)
391d5789509SDavid du Colombier 			p->nparityerr++;
3925e4f5c78SDavid du Colombier 		if(buf[8] & OvererrStatus)
393d5789509SDavid du Colombier 			p->novererr++;
3945e4f5c78SDavid du Colombier 	} else
3955e4f5c78SDavid du Colombier 		dsprint(2, "serial: bad status read %d\n", nr);
3965e4f5c78SDavid du Colombier 	dsprint(2, "serial: finished read from interrupt %d\n", nr);
3975e4f5c78SDavid du Colombier 	qunlock(ser);
3985e4f5c78SDavid du Colombier 	return 0;
3995e4f5c78SDavid du Colombier }
4005e4f5c78SDavid du Colombier 
4015e4f5c78SDavid du Colombier static void
statusreader(void * u)4025e4f5c78SDavid du Colombier statusreader(void *u)
4035e4f5c78SDavid du Colombier {
404d5789509SDavid du Colombier 	Serialport *p;
4055e4f5c78SDavid du Colombier 	Serial *ser;
4065e4f5c78SDavid du Colombier 
407d5789509SDavid du Colombier 	p = u;
408d5789509SDavid du Colombier 	ser = p->s;
4095e4f5c78SDavid du Colombier 	threadsetname("statusreaderproc");
410d5789509SDavid du Colombier 	while(plreadstatus(p) >= 0)
4115e4f5c78SDavid du Colombier 		;
41280e9508eSDavid du Colombier 	fprint(2, "serial: statusreader exiting\n");
4135e4f5c78SDavid du Colombier 	closedev(ser->dev);
4145e4f5c78SDavid du Colombier }
4155e4f5c78SDavid du Colombier 
41680e9508eSDavid du Colombier /*
41780e9508eSDavid du Colombier  * Maximum number of bytes transferred per frame
41880e9508eSDavid du Colombier  * The output buffer size cannot be increased due to the size encoding
41980e9508eSDavid du Colombier  */
42080e9508eSDavid du Colombier 
42180e9508eSDavid du Colombier static int
plseteps(Serialport * p)422d5789509SDavid du Colombier plseteps(Serialport *p)
42380e9508eSDavid du Colombier {
424d5789509SDavid du Colombier 	devctl(p->epin,  "maxpkt 256");
425d5789509SDavid du Colombier 	devctl(p->epout, "maxpkt 256");
42680e9508eSDavid du Colombier 	return 0;
42780e9508eSDavid du Colombier }
42880e9508eSDavid du Colombier 
4295e4f5c78SDavid du Colombier Serialops plops = {
4305e4f5c78SDavid du Colombier 	.init		= plinit,
4315e4f5c78SDavid du Colombier 	.getparam	= plgetparam,
4325e4f5c78SDavid du Colombier 	.setparam	= plsetparam,
4335e4f5c78SDavid du Colombier 	.clearpipes	= plclearpipes,
4345e4f5c78SDavid du Colombier 	.sendlines	= plsendlines,
4355e4f5c78SDavid du Colombier 	.modemctl	= plmodemctl,
4365e4f5c78SDavid du Colombier 	.setbreak	= plsetbreak,
43780e9508eSDavid du Colombier 	.seteps		= plseteps,
4385e4f5c78SDavid du Colombier };
439