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