Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / classes / cdcacm / cdcacm.class.c
blobbe9fee237399997ba45effbf80ab617f3f8a90fc
1 /*
2 *----------------------------------------------------------------------------
3 * cdcacm class for poseidon
4 *----------------------------------------------------------------------------
5 * By Chris Hodges <chrisly@platon42.de>
6 */
8 #include "debug.h"
9 #include "cdcacm.class.h"
11 /* /// "Lib Stuff" */
12 static const STRPTR libname = MOD_NAME_STRING;
14 static
15 const APTR DevFuncTable[] =
17 &AROS_SLIB_ENTRY(devOpen, dev, 1),
18 &AROS_SLIB_ENTRY(devClose, dev, 2),
19 &AROS_SLIB_ENTRY(devExpunge, dev, 3),
20 &AROS_SLIB_ENTRY(devReserved, dev, 4),
21 &AROS_SLIB_ENTRY(devBeginIO, dev, 5),
22 &AROS_SLIB_ENTRY(devAbortIO, dev, 6),
23 (APTR) -1,
26 static const struct NepClassSerial fake_binding;
28 static int libInit(LIBBASETYPEPTR nh)
30 struct NepSerialBase *ret = NULL;
32 KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase));
34 nh->nh_UtilityBase = OpenLibrary("utility.library", 39);
36 #define UtilityBase nh->nh_UtilityBase
38 if(UtilityBase)
40 NewList(&nh->nh_Units);
42 if((nh->nh_DevBase = (struct NepSerDevBase *) MakeLibrary((APTR) DevFuncTable, NULL, (APTR) devInit,
43 sizeof(struct NepSerDevBase), NULL)))
45 nh->nh_DevBase->np_ClsBase = nh;
46 Forbid();
47 AddDevice((struct Device *) nh->nh_DevBase);
48 nh->nh_DevBase->np_Library.lib_OpenCnt++;
49 Permit();
50 ret = nh;
51 } else {
52 KPRINTF(20, ("failed to create cdcacm.device\n"));
54 if(!ret)
56 CloseLibrary(UtilityBase);
58 } else {
59 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
62 KPRINTF(10, ("libInit: Ok\n"));
63 return(ret ? TRUE : FALSE);
66 static int libExpunge(LIBBASETYPEPTR nh)
68 struct NepClassSerial *ncp;
70 KPRINTF(10, ("libExpunge nh: 0x%08lx\n", nh));
72 if(nh->nh_DevBase->np_Library.lib_OpenCnt == 1)
74 KPRINTF(1, ("libExpunge: closelibrary utilitybase 0x%08lx\n",
75 UtilityBase));
76 CloseLibrary((struct Library *) UtilityBase);
78 ncp = (struct NepClassSerial *) nh->nh_Units.lh_Head;
79 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
81 Remove((struct Node *) ncp);
82 FreeVec(ncp);
83 ncp = (struct NepClassSerial *) nh->nh_Units.lh_Head;
86 nh->nh_DevBase->np_Library.lib_OpenCnt--;
87 RemDevice((struct Device *) nh->nh_DevBase);
89 KPRINTF(5, ("libExpunge: Unloading done! cdcacm.class expunged!\n\n"));
90 } else {
91 KPRINTF(5, ("libExpunge: Could not expunge, LIBF_DELEXP set!\n"));
92 return(FALSE);
95 return(TRUE);
98 ADD2INITLIB(libInit, 0)
99 ADD2EXPUNGELIB(libExpunge, 0)
100 /* \\\ */
102 void SendBulk( struct PsdDevice *pd,UBYTE *cmd,ULONG len)
104 struct Library *ps;
105 struct MsgPort *mp;
106 struct PsdPipe *pp;
107 struct PsdInterface *DataIf = 0;
108 struct PsdEndpoint *EPOut;
109 IPTR EPnum=0,IFnum=0,IFEPnum=0;
111 if((ps = OpenLibrary("poseidon.library", 4)))
113 bug("SendBulk: FindInterface...");
114 if( ( DataIf = psdFindInterface( pd , DataIf , TAG_END ) ) ){
116 psdGetAttrs(PGA_INTERFACE,DataIf,
117 IFA_InterfaceNum,&IFnum,
118 IFA_NumEndpoints,&IFEPnum,
119 TAG_END);
120 bug(" ...OK num:%d number of endpoints:%d\n",IFnum,IFEPnum);
122 bug("Find BULK OUT Endpoint...");
123 EPOut = psdFindEndpoint( DataIf, NULL,
124 EA_IsIn, FALSE,
125 EA_TransferType, USEAF_BULK,
126 TAG_END);
127 if( EPOut ){
128 psdGetAttrs(PGA_ENDPOINT,EPOut,
129 EA_EndpointNum, &EPnum,
130 TAG_END);
131 bug(" ...OK address:%d\n",EPnum);
133 if((mp = CreateMsgPort())){
134 bug("OpenPipe...\n");
135 if((pp = psdAllocPipe(pd, mp, EPOut))){
136 psdSetAttrs(PGA_PIPE, pp,
137 PPA_NakTimeout,TRUE,
138 PPA_NakTimeoutTime, 5000,
139 TAG_END);
140 bug("Write %d bytes ...\n",len);
141 bug("Error = %d\n", psdDoPipe( pp , cmd , len ));
142 psdFreePipe(pp);
144 DeleteMsgPort(mp);
148 CloseLibrary(ps);
153 * ***********************************************************************
154 * * Library functions *
155 * ***********************************************************************
158 /* /// "usbAttemptInterfaceBinding()" */
159 struct NepClassSerial * usbAttemptInterfaceBinding(struct NepSerialBase *nh, struct PsdInterface *pif)
161 struct Library *ps;
162 IPTR ifclass;
163 IPTR subclass;
164 IPTR proto;
165 IPTR NumEndpoints;
166 struct PsdConfig *pc;
167 struct PsdDevice *pd;
168 IPTR prodid;
169 IPTR vendid;
170 IPTR numintf;
171 struct PsdPipe *pp;
172 struct MsgPort *mp;
174 KPRINTF(1, ("nepSerialAttemptInterfaceBinding(%08lx)\n", pif));
175 if((ps = OpenLibrary("poseidon.library", 4)))
178 psdGetAttrs(PGA_INTERFACE, pif,
179 IFA_Class, &ifclass,
180 IFA_SubClass, &subclass,
181 IFA_Protocol, &proto,
182 IFA_NumEndpoints, &NumEndpoints,
183 IFA_Config, &pc,
184 TAG_DONE);
186 psdGetAttrs(PGA_CONFIG, pc,
187 CA_Device, &pd,
188 CA_NumInterfaces, &numintf,
189 TAG_END);
191 psdGetAttrs(PGA_DEVICE, pd,
192 DA_ProductID, &prodid,
193 DA_VendorID, &vendid,
194 TAG_END);
196 // bug("cdcacm.class:AttemptInterfaceBinding vendor id=%x product id=%x\n",vendid,prodid);
198 // ZTE ModeSwitch
199 if( vendid == 0x19d2 && prodid == 0x2000 ){
201 UBYTE cmd[31];
202 // from BSD u3g.c
203 memset(cmd, 0, sizeof(cmd));
204 cmd[0] = 0x55;
205 cmd[1] = 0x53;
206 cmd[2] = 0x42;
207 cmd[3] = 0x43;
208 cmd[4] = 0x01;
209 cmd[14] = 0x06;
210 cmd[15] = 0x1b;
211 cmd[19] = 0x02;
213 SendBulk(pd,cmd,sizeof(cmd));
215 CloseLibrary(ps);
216 if( ifclass == MASSSTORE_CLASSCODE ){
217 bug("cdcacm.class: fake massstorage binding\n");
218 return (struct NepClassSerial *)&fake_binding;
220 return(NULL);
223 // huawei ModeSwitch
224 if( (vendid == 0x12d1 ) && ( numintf < 4 ) && (
225 prodid == 0x1001 || // e169
226 prodid == 0x1003 // e220
228 if((mp = CreateMsgPort()))
230 if((pp = psdAllocPipe(pd, mp, NULL)))
232 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
233 "Huawei ModeSwitch...");
234 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE,
235 USR_SET_FEATURE, UFS_DEVICE_REMOTE_WAKEUP, 0);
236 psdDoPipe(pp, NULL, 0);
237 psdFreePipe(pp);
239 DeleteMsgPort(mp);
241 CloseLibrary(ps);
242 if( ifclass == MASSSTORE_CLASSCODE ){
243 bug("cdcacm.class: fake massstorage binding\n");
244 return (struct NepClassSerial *)&fake_binding;
246 return(NULL);
250 // Huawei, e122 and many others.
251 if( (vendid == 0x12d1 ) && ( prodid == 0x1446 )){
253 UBYTE magic_cmd[31];
254 // magic command from BSD u3g driver sources.
255 memset(magic_cmd, 0, sizeof(magic_cmd));
256 magic_cmd[0] = 0x55;
257 magic_cmd[1] = 0x53;
258 magic_cmd[2] = 0x42;
259 magic_cmd[3] = 0x43;
260 magic_cmd[15]= 0x11;
261 magic_cmd[16]= 0x06;
263 SendBulk(pd,magic_cmd,sizeof(magic_cmd));
265 CloseLibrary(ps);
266 if( ifclass == MASSSTORE_CLASSCODE ){
267 bug("cdcacm.class: fake massstorage binding\n");
268 return (struct NepClassSerial *)&fake_binding;
270 return(NULL);
273 CloseLibrary(ps);
275 // ZTE
276 if( (vendid == 0x19d2) && (
277 prodid == 0x0001 ||
278 prodid == 0x0002 ||
279 prodid == 0x0015 ||
280 prodid == 0x0016 ||
281 prodid == 0x0017 ||
282 prodid == 0x0031 ||
283 prodid == 0x0037 ||
284 prodid == 0x0052 ||
285 prodid == 0x0055 ||
286 prodid == 0x0063 ||
287 prodid == 0x0064 ||
288 prodid == 0x0108 ||
289 prodid == 0x0128
291 if( ifclass == MASSSTORE_CLASSCODE ){
292 bug("cdcacm.class: fake massstorage binding\n");
293 return (struct NepClassSerial *)&fake_binding;
296 if((ifclass == 255) && (subclass == 255) && (proto == 255) && (NumEndpoints == 3)){
297 return(usbForceInterfaceBinding(nh, pif));
302 // Huawei
303 if( (vendid == 0x12d1) && (
304 prodid == 0x1001 || // e169
305 prodid == 0x1003 || // e220
306 prodid == 0x1406 ||
307 prodid == 0x140b ||
308 prodid == 0x140c ||
309 prodid == 0x1412 ||
310 prodid == 0x141b ||
311 prodid == 0x14ac
313 if( ifclass == MASSSTORE_CLASSCODE ){
314 bug("cdcacm.class: fake massstorage binding\n");
315 return (struct NepClassSerial *)&fake_binding;
318 if((ifclass == 255) && (subclass == 255) && (proto == 255) && (NumEndpoints == 3)){
319 return(usbForceInterfaceBinding(nh, pif));
323 // Novatel (Toshiba) wireless HSDPA modem
324 if( (vendid == 0x0930) && (prodid == 0x1302) )
326 return(usbForceInterfaceBinding(nh, pif));
329 if((ifclass == CDCCTRL_CLASSCODE) &&
330 (subclass == CDC_ACM_SUBCLASS) &&
331 //(proto == CDC_PROTO_HAYES)
332 ((proto >= 1) && (proto <= 6))) //found in some linux driver source
334 return(usbForceInterfaceBinding(nh, pif));
337 if((ifclass == CDCCTRL_CLASSCODE) &&
338 (subclass == CDC_OBEX_SUBCLASS))
340 return(usbForceInterfaceBinding(nh, pif));
345 return(NULL);
348 /* \\\ */
350 /* /// "usbForceInterfaceBinding()" */
351 struct NepClassSerial * usbForceInterfaceBinding(struct NepSerialBase *nh, struct PsdInterface *pif)
353 struct Library *ps;
354 struct NepClassSerial *ncp;
355 struct PsdConfig *pc;
356 struct PsdDevice *pd;
357 STRPTR devname;
358 IPTR altifnum;
359 IPTR ifnum;
360 IPTR prodid;
361 IPTR vendid;
362 ULONG unitno;
363 IPTR subclass;
364 BOOL unitfound;
365 UBYTE buf[64];
366 struct Task *tmptask;
368 KPRINTF(1, ("nepSerialForceInterfaceBinding(%08lx)\n", pif));
369 if((ps = OpenLibrary("poseidon.library", 4)))
371 psdGetAttrs(PGA_INTERFACE, pif,
372 IFA_InterfaceNum, &ifnum,
373 IFA_AlternateNum, &altifnum,
374 IFA_SubClass, &subclass,
375 IFA_Config, &pc,
376 TAG_DONE);
377 psdGetAttrs(PGA_CONFIG, pc,
378 CA_Device, &pd,
379 TAG_END);
380 psdGetAttrs(PGA_DEVICE, pd,
381 DA_ProductID, &prodid,
382 DA_VendorID, &vendid,
383 DA_ProductName, &devname,
384 TAG_END);
385 Forbid();
386 /* Find next free unit number */
387 unitno = 0;
388 ncp = (struct NepClassSerial *) nh->nh_Units.lh_Head;
389 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
391 if(ncp->ncp_UnitNo == unitno)
393 unitno++;
394 ncp = (struct NepClassSerial *) nh->nh_Units.lh_Head;
395 } else {
396 ncp = (struct NepClassSerial *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
399 unitfound = FALSE;
400 ncp = (struct NepClassSerial *) nh->nh_Units.lh_Head;
401 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
403 if((ncp->ncp_UnitAltIfNum == altifnum) && (ncp->ncp_UnitIfNum == ifnum) &&
404 (ncp->ncp_UnitProdID == prodid) && (ncp->ncp_UnitVendorID == vendid))
406 unitno = ncp->ncp_UnitNo;
407 unitfound = TRUE;
408 break;
410 ncp = (struct NepClassSerial *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
412 if(!unitfound)
414 /* as units are freed in the expunge-vector, the memory is
415 outside the scope of the poseidon library */
416 if(!(ncp = AllocVec(sizeof(struct NepClassSerial), MEMF_PUBLIC|MEMF_CLEAR)))
418 Permit();
419 CloseLibrary(ps);
420 return(NULL);
422 /* IORequests may be queued even if the task is gone. */
423 NewList(&ncp->ncp_Unit.unit_MsgPort.mp_MsgList);
424 NewList(&ncp->ncp_ReadQueue);
425 NewList(&ncp->ncp_WriteQueue);
426 AddTail(&nh->nh_Units, &ncp->ncp_Unit.unit_MsgPort.mp_Node);
427 ncp->ncp_DenyRequests = TRUE;
429 ncp->ncp_UnitNo = unitno;
430 ncp->ncp_Interface = pif;
431 ncp->ncp_Device = pd;
432 ncp->ncp_UnitAltIfNum = altifnum;
433 ncp->ncp_UnitIfNum = ifnum;
434 ncp->ncp_UnitProdID = prodid;
435 ncp->ncp_UnitVendorID = vendid;
436 Permit();
438 psdSafeRawDoFmt(buf, 64, "cdcacm.class<%08lx>", ncp);
439 ncp->ncp_ReadySignal = SIGB_SINGLE;
440 ncp->ncp_ReadySigTask = FindTask(NULL);
441 SetSignal(0, SIGF_SINGLE);
442 if((tmptask = psdSpawnSubTask(buf, nSerialTask, ncp)))
444 psdBorrowLocksWait(tmptask, 1UL<<ncp->ncp_ReadySignal);
445 //Wait(1UL<<ncp->ncp_ReadySignal);
446 if(ncp->ncp_Task)
448 ncp->ncp_ReadySigTask = NULL;
449 //FreeSignal(ncp->ncp_ReadySignal);
450 if(subclass != CDC_OBEX_SUBCLASS)
452 bug("Modem '%s' at %s unit %ld!\n",
453 devname, nh->nh_DevBase->np_Library.lib_Node.ln_Name,
454 ncp->ncp_UnitNo);
455 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
456 "Mode(m) mess '%s' at %s unit %ld!",
457 devname, nh->nh_DevBase->np_Library.lib_Node.ln_Name,
458 ncp->ncp_UnitNo);
459 } else {
460 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
461 "OBject EXchange (OBEX) '%s' at %s unit %ld!",
462 devname, nh->nh_DevBase->np_Library.lib_Node.ln_Name,
463 ncp->ncp_UnitNo);
465 CloseLibrary(ps);
466 return(ncp);
469 ncp->ncp_ReadySigTask = NULL;
470 //FreeSignal(ncp->ncp_ReadySignal);
471 /* Get rid of unit structure */
472 /*Forbid();
473 Remove((struct Node *) ncp);
474 FreeVec(ncp);
475 Permit();*/
476 CloseLibrary(ps);
478 return(NULL);
480 /* \\\ */
482 /* /// "usbReleaseInterfaceBinding()" */
483 void usbReleaseInterfaceBinding(struct NepSerialBase *nh, struct NepClassSerial *ncp)
485 struct Library *ps;
486 STRPTR devname;
488 KPRINTF(1, ("nepSerialReleaseInterfaceBinding(%08lx)\n", ncp));
490 if( ncp == &fake_binding ){
491 bug("cdcacm.class: fake massstorage binding released\n");
492 return;
495 if((ps = OpenLibrary("poseidon.library", 4)))
497 Forbid();
498 ncp->ncp_ReadySignal = SIGB_SINGLE;
499 ncp->ncp_ReadySigTask = FindTask(NULL);
500 if(ncp->ncp_Task)
502 Signal(ncp->ncp_Task, SIGBREAKF_CTRL_C);
504 Permit();
505 while(ncp->ncp_Task)
507 Wait(1UL<<ncp->ncp_ReadySignal);
509 //FreeSignal(ncp->ncp_ReadySignal);
510 psdGetAttrs(PGA_DEVICE, ncp->ncp_Device, DA_ProductName, &devname, TAG_END);
511 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
512 "Kicked '%s' from the catwalk.",
513 devname);
514 /*psdFreeVec(ncp);*/
515 CloseLibrary(ps);
518 /* \\\ */
520 /* /// "usbGetAttrsA()" */
521 AROS_LH3(LONG, usbGetAttrsA,
522 AROS_LHA(ULONG, type, D0),
523 AROS_LHA(APTR, usbstruct, A0),
524 AROS_LHA(struct TagItem *, tags, A1),
525 LIBBASETYPEPTR, nh, 5, nep)
527 AROS_LIBFUNC_INIT
529 struct TagItem *ti;
530 LONG count = 0;
532 KPRINTF(1, ("nepHidGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags));
533 switch(type)
535 case UGA_CLASS:
536 if((ti = FindTagItem(UCCA_Priority, tags)))
538 *((SIPTR *) ti->ti_Data) = 1;
539 count++;
541 if((ti = FindTagItem(UCCA_Description, tags)))
543 *((STRPTR *) ti->ti_Data) = "USB modems and OBEX via usbmodem.device";
544 count++;
546 if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags)))
548 *((IPTR *) ti->ti_Data) = FALSE;
549 count++;
551 if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags)))
553 *((IPTR *) ti->ti_Data) = FALSE;
554 count++;
556 if((ti = FindTagItem(UCCA_AfterDOSRestart, tags)))
558 *((IPTR *) ti->ti_Data) = FALSE;
559 count++;
561 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
563 *((IPTR *) ti->ti_Data) = TRUE;
564 count++;
566 break;
568 case UGA_BINDING:
569 if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags)))
571 *((IPTR *) ti->ti_Data) = TRUE;
572 count++;
574 break;
576 return(count);
577 AROS_LIBFUNC_EXIT
579 /* \\\ */
581 /* /// "usbSetAttrsA()" */
582 AROS_LH3(LONG, usbSetAttrsA,
583 AROS_LHA(ULONG, type, D0),
584 AROS_LHA(APTR, usbstruct, A0),
585 AROS_LHA(struct TagItem *, tags, A1),
586 LIBBASETYPEPTR, nh, 6, nep)
588 AROS_LIBFUNC_INIT
589 return(0);
590 AROS_LIBFUNC_EXIT
592 /* \\\ */
594 /* /// "usbDoMethodA()" */
595 AROS_LH2(IPTR, usbDoMethodA,
596 AROS_LHA(ULONG, methodid, D0),
597 AROS_LHA(IPTR *, methoddata, A1),
598 LIBBASETYPEPTR, nh, 7, nep)
600 AROS_LIBFUNC_INIT
602 KPRINTF(10, ("Do Method %ld\n", methodid));
603 switch(methodid)
605 case UCM_AttemptInterfaceBinding:
606 return((IPTR) usbAttemptInterfaceBinding(nh, (struct PsdInterface *) methoddata[0]));
608 case UCM_ForceInterfaceBinding:
609 return((IPTR) usbForceInterfaceBinding(nh, (struct PsdInterface *) methoddata[0]));
611 case UCM_ReleaseInterfaceBinding:
612 usbReleaseInterfaceBinding(nh, (struct NepClassSerial *) methoddata[0]);
613 return(TRUE);
615 default:
616 break;
618 return(0);
619 AROS_LIBFUNC_EXIT
621 /* \\\ */
623 /**************************************************************************/
625 #undef ps
626 #define ps ncp->ncp_Base
628 /* /// "nSetSerialMode()" */
629 void nSetSerialMode(struct NepClassSerial *ncp, struct IOExtSer *ioreq)
631 struct UsbCDCLineCoding ulc;
632 LONG ioerr;
633 ULONG bufsize = ioreq->io_RBufLen / NUMREADPIPES;
635 if(bufsize < 1024)
637 bufsize = 1024;
639 bufsize = (bufsize + 127) & (~127);
641 psdSetAttrs(PGA_PIPESTREAM, ncp->ncp_EPInStream,
642 PSA_BufferSize, bufsize,
643 TAG_END);
644 if(ioreq->io_SerFlags & SERF_EOFMODE)
646 psdSetAttrs(PGA_PIPESTREAM, ncp->ncp_EPInStream,
647 PSA_TermArray, &ioreq->io_TermArray,
648 TAG_END);
649 psdSetAttrs(PGA_PIPESTREAM, ncp->ncp_EPOutStream,
650 PSA_TermArray, &ioreq->io_TermArray,
651 TAG_END);
652 } else {
653 psdSetAttrs(PGA_PIPESTREAM, ncp->ncp_EPInStream,
654 PSA_TermArray, NULL,
655 TAG_END);
656 psdSetAttrs(PGA_PIPESTREAM, ncp->ncp_EPOutStream,
657 PSA_TermArray, NULL,
658 TAG_END);
660 ulc.dwDTERate = AROS_LONG2LE(ioreq->io_Baud);
661 if(ioreq->io_StopBits == 1)
663 ulc.bCharFormat = 0;
665 else if(ioreq->io_StopBits == 2)
667 ulc.bCharFormat = 2;
668 } else {
669 ioreq->IOSer.io_Error = SerErr_InvParam;
670 ulc.bCharFormat = 0;
672 ulc.bParityType = 0; /* no parity */
673 if(ioreq->io_SerFlags & SERF_PARTY_ON)
675 if(ioreq->io_SerFlags & SERF_PARTY_ODD)
677 ulc.bParityType = 1; /* odd parity */
678 } else {
679 ulc.bParityType = 2; /* even parity */
682 if(ioreq->io_ExtFlags & SEXTF_MSPON)
684 ioreq->io_SerFlags |= SERF_PARTY_ON;
685 if(ioreq->io_ExtFlags & SEXTF_MARK)
687 ulc.bParityType = 3; /* mark parity */
688 } else {
689 ulc.bParityType = 4; /* space parity */
692 ulc.bDataBits = ioreq->io_ReadLen;
693 if(ioreq->io_SerFlags & SERF_RAD_BOOGIE)
695 ulc.bCharFormat = 0; /* 1 stop bit */
696 ulc.bParityType = 0; /* no parity */
697 ulc.bDataBits = 8; /* 8 data bits */
700 psdPipeSetup(ncp->ncp_EP0Pipe, URTF_CLASS|URTF_INTERFACE,
701 UCDCR_SET_LINE_CODING, 0, (ULONG) ncp->ncp_UnitIfNum);
702 ioerr = psdDoPipe(ncp->ncp_EP0Pipe, &ulc, 7);
703 if(ioerr)
705 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
706 "SET_LINE_CODING failed: %s (%ld)",
707 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
708 ioreq->IOSer.io_Error = SerErr_LineErr;
710 /* Activate RTS/CTS */
711 psdPipeSetup(ncp->ncp_EP0Pipe, URTF_CLASS|URTF_INTERFACE,
712 UCDCR_SET_CONTROL_LINE_STATE, (ULONG) ((ioreq->io_SerFlags & SERF_7WIRE) ? 0 : 3), (ULONG) ncp->ncp_UnitIfNum);
713 ioerr = psdDoPipe(ncp->ncp_EP0Pipe, NULL, 0);
714 if(ioerr)
716 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
717 "SET_CONTROL_LINE_STATE failed: %s (%ld)",
718 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
719 ioreq->IOSer.io_Error = SerErr_LineErr;
722 /* \\\ */
724 /* /// "nSerialTask()" */
725 AROS_UFH0(void, nSerialTask)
727 AROS_USERFUNC_INIT
729 struct NepClassSerial *ncp;
730 struct PsdPipe *pp;
731 ULONG sigmask;
732 ULONG sigs;
733 LONG ioerr;
734 LONG len;
735 IPTR pending;
736 struct IOExtSer *ioreq;
737 struct IOExtSer *ioreq2;
738 UWORD serstate;
740 if((ncp = nAllocSerial()))
742 Forbid();
743 if(ncp->ncp_ReadySigTask)
745 Signal(ncp->ncp_ReadySigTask, 1UL<<ncp->ncp_ReadySignal);
747 Permit();
749 /* Main task */
750 if(ncp->ncp_EPIntPipe)
752 psdPipeSetup(ncp->ncp_EPIntPipe, URTF_IN|URTF_CLASS|URTF_INTERFACE,
753 UCDCR_SERIAL_STATE, 0, (ULONG) ncp->ncp_UnitIfNum);
754 psdSendPipe(ncp->ncp_EPIntPipe, &ncp->ncp_SerialStateReq, sizeof(ncp->ncp_SerialStateReq));
756 /* start readahead */
758 sigmask = (1UL<<ncp->ncp_Unit.unit_MsgPort.mp_SigBit)|(1UL<<ncp->ncp_TaskMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
760 struct MsgPort *tmpmp = NULL;
761 psdGetAttrs(PGA_PIPESTREAM, ncp->ncp_EPInStream, PSA_MessagePort, &tmpmp, TAG_END);
762 if(tmpmp)
764 sigmask |= (1UL<<tmpmp->mp_SigBit);
769 psdStreamRead(ncp->ncp_EPInStream, NULL, 0);
770 while((pp = (struct PsdPipe *) GetMsg(ncp->ncp_TaskMsgPort)))
772 KPRINTF(1, ("Pipe back %08lx\n", pp));
773 if(pp == ncp->ncp_EPIntPipe)
775 KPRINTF(5, ("Int serial state back %04lx\n", ncp->ncp_SerialStateReq.uss_State));
776 ioerr = psdGetPipeError(pp);
777 len = psdGetPipeActual(pp);
778 if(ioerr && (ioerr != UHIOERR_RUNTPACKET))
780 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
781 "Serial state failed: %s (%ld), len = %d",
782 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr, (int)len);
783 psdDelayMS(100);
785 psdSendPipe(ncp->ncp_EPIntPipe, &ncp->ncp_SerialStateReq, sizeof(ncp->ncp_SerialStateReq));
786 break;
789 while((ioreq = (struct IOExtSer *) GetMsg(&ncp->ncp_Unit.unit_MsgPort)))
791 KPRINTF(5, ("command ioreq: 0x%08lx cmd: %lu len: %ld\n",
792 ioreq, ioreq->IOSer.io_Command, ioreq->IOSer.io_Length));
793 switch(ioreq->IOSer.io_Command)
795 case CMD_CLEAR:
796 psdStreamFlush(ncp->ncp_EPOutStream);
797 ReplyMsg((struct Message *) ioreq);
798 break;
800 case CMD_RESET:
801 /* Reset does a flush too */
802 case CMD_FLUSH:
803 Forbid();
804 ioreq2 = (struct IOExtSer *) ncp->ncp_WriteQueue.lh_Head;
805 while(ioreq2->IOSer.io_Message.mn_Node.ln_Succ)
807 Remove((struct Node *) ioreq2);
808 ioreq2->IOSer.io_Error = IOERR_ABORTED;
809 ReplyMsg((struct Message *) ioreq2);
810 ioreq2 = (struct IOExtSer *) ncp->ncp_WriteQueue.lh_Head;
812 ioreq2 = (struct IOExtSer *) ncp->ncp_ReadQueue.lh_Head;
813 while(ioreq2->IOSer.io_Message.mn_Node.ln_Succ)
815 Remove((struct Node *) ioreq2);
816 ioreq2->IOSer.io_Error = IOERR_ABORTED;
817 ReplyMsg((struct Message *) ioreq2);
818 ioreq2 = (struct IOExtSer *) ncp->ncp_ReadQueue.lh_Head;
820 ReplyMsg((struct Message *) ioreq);
821 Permit();
822 break;
824 case SDCMD_QUERY:
825 serstate = 0;
826 if(!(ncp->ncp_SerialStateReq.uss_State & 0x0100)) /* Carrier Detect */
827 serstate |= (1<<5);
828 if(!(ncp->ncp_SerialStateReq.uss_State & 0x0200)) /* DSR */
829 serstate |= (1<<3);
830 if(ncp->ncp_SerialStateReq.uss_State & 0x0400) /* Break */
831 serstate |= (1<<10);
832 if(ncp->ncp_SerialStateReq.uss_State & 0x0800) /* Ring */
833 serstate |= (1<<2);
834 if(ncp->ncp_SerialStateReq.uss_State & 0x7000) /* Framing, Parity, Hardware error */
835 serstate |= (1<<8);
837 ioreq->io_Status = serstate;
838 pending = 0;
839 psdGetAttrs(PGA_PIPESTREAM, ncp->ncp_EPInStream,
840 PSA_BytesPending, &pending,
841 TAG_END);
842 ioreq->IOSer.io_Actual = pending;
843 ReplyMsg((struct Message *) ioreq);
844 break;
846 case SDCMD_SETPARAMS:
847 nSetSerialMode(ncp, ioreq);
848 ReplyMsg((struct Message *) ioreq);
849 break;
851 case SDCMD_BREAK:
852 psdPipeSetup(ncp->ncp_EP0Pipe, URTF_CLASS|URTF_INTERFACE,
853 UCDCR_SEND_BREAK, ioreq->io_BrkTime, (ULONG) ncp->ncp_UnitIfNum);
854 ioerr = psdDoPipe(ncp->ncp_EP0Pipe, NULL, 0);
855 if(ioerr)
857 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
858 "SEND_BREAK failed: %s (%ld)",
859 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
860 ioreq->IOSer.io_Error = SerErr_LineErr;
862 ReplyMsg((struct Message *) ioreq);
863 break;
865 default:
866 ioreq->IOSer.io_Error = IOERR_NOCMD;
867 ReplyMsg((struct Message *) ioreq);
868 break;
871 if(!ncp->ncp_DevSuspend)
873 pending = 0;
874 psdGetAttrs(PGA_PIPESTREAM, ncp->ncp_EPInStream,
875 PSA_BytesPending, &pending,
876 TAG_END);
877 Forbid();
878 ioreq = (struct IOExtSer *) ncp->ncp_ReadQueue.lh_Head;
879 while(ioreq->IOSer.io_Message.mn_Node.ln_Succ && pending)
881 Remove((struct Node *) ioreq);
882 Permit();
883 ioreq->IOSer.io_Actual = psdStreamRead(ncp->ncp_EPInStream, ioreq->IOSer.io_Data, ioreq->IOSer.io_Length);
884 ioerr = psdGetStreamError(ncp->ncp_EPInStream);
885 if(ioerr == UHIOERR_NAKTIMEOUT)
887 Forbid();
888 AddHead(&ncp->ncp_ReadQueue, &ioreq->IOSer.io_Message.mn_Node);
889 break;
890 } else {
891 if(ioerr > 0)
893 ioreq->IOSer.io_Error = SerErr_LineErr;
894 } else {
895 ioreq->IOSer.io_Error = ioerr;
897 ReplyMsg((struct Message *) ioreq);
899 psdGetAttrs(PGA_PIPESTREAM, ncp->ncp_EPInStream,
900 PSA_BytesPending, &pending,
901 TAG_END);
902 Forbid();
903 ioreq = (struct IOExtSer *) ncp->ncp_ReadQueue.lh_Head;
905 ioreq = (struct IOExtSer *) ncp->ncp_WriteQueue.lh_Head;
906 while(ioreq->IOSer.io_Message.mn_Node.ln_Succ)
908 Remove((struct Node *) ioreq);
909 ncp->ncp_WritePending = ioreq;
910 Permit();
911 ioreq->IOSer.io_Actual = psdStreamWrite(ncp->ncp_EPOutStream, ioreq->IOSer.io_Data, ioreq->IOSer.io_Length);
912 ncp->ncp_WritePending = NULL;
913 ioerr = psdGetStreamError(ncp->ncp_EPInStream);
914 if(ioerr > 0)
916 ioreq->IOSer.io_Error = SerErr_LineErr;
917 } else {
918 ioreq->IOSer.io_Error = ioerr;
920 ReplyMsg((struct Message *) ioreq);
921 Forbid();
922 ioreq = (struct IOExtSer *) ncp->ncp_WriteQueue.lh_Head;
924 Permit();
926 sigs = Wait(sigmask);
927 } while(!(sigs & SIGBREAKF_CTRL_C));
928 KPRINTF(1, ("Going down...\n"));
929 /* Now remove all requests still pending *anywhere* */
930 ncp->ncp_DenyRequests = TRUE;
932 if(ncp->ncp_EPIntPipe)
934 psdAbortPipe(ncp->ncp_EPIntPipe);
935 psdWaitPipe(ncp->ncp_EPIntPipe);
938 /* Read/Write queues */
939 Forbid();
940 ioreq = (struct IOExtSer *) ncp->ncp_WriteQueue.lh_Head;
941 while(ioreq->IOSer.io_Message.mn_Node.ln_Succ)
943 Remove((struct Node *) ioreq);
944 ioreq->IOSer.io_Error = IOERR_ABORTED;
945 ReplyMsg((struct Message *) ioreq);
946 ioreq = (struct IOExtSer *) ncp->ncp_WriteQueue.lh_Head;
948 ioreq = (struct IOExtSer *) ncp->ncp_ReadQueue.lh_Head;
949 while(ioreq->IOSer.io_Message.mn_Node.ln_Succ)
951 Remove((struct Node *) ioreq);
952 ioreq->IOSer.io_Error = IOERR_ABORTED;
953 ReplyMsg((struct Message *) ioreq);
954 ioreq = (struct IOExtSer *) ncp->ncp_ReadQueue.lh_Head;
956 /* Command queue */
957 while((ioreq = (struct IOExtSer *) GetMsg(&ncp->ncp_Unit.unit_MsgPort)))
959 ioreq->IOSer.io_Error = IOERR_ABORTED;
960 ReplyMsg((struct Message *) ioreq);
962 Permit();
963 KPRINTF(20, ("Going down the river!\n"));
964 nFreeSerial(ncp);
967 AROS_USERFUNC_EXIT
969 /* \\\ */
971 /* /// "nAllocSerial()" */
972 struct NepClassSerial * nAllocSerial(void)
974 struct Task *thistask;
975 struct NepClassSerial *ncp;
976 struct PsdDescriptor *pdd;
977 UBYTE *descdata = NULL;
978 ULONG dataifnum = 0;
980 thistask = FindTask(NULL);
981 ncp = thistask->tc_UserData;
984 if(!(ncp->ncp_Base = OpenLibrary("poseidon.library", 4)))
986 Alert(AG_OpenLib);
987 break;
990 ncp->ncp_EPInt = psdFindEndpoint(ncp->ncp_Interface, NULL,
991 EA_IsIn, TRUE,
992 EA_TransferType, USEAF_INTERRUPT,
993 TAG_END);
995 // try to obtain correct data interface using the class specific interface descriptor
996 ncp->ncp_DataIf = NULL;
997 pdd = psdFindDescriptor(ncp->ncp_Device, NULL,
998 DDA_Interface, ncp->ncp_Interface,
999 DDA_DescriptorType, UDT_CS_INTERFACE,
1000 DDA_CS_SubType, UDST_CDC_CALLMGM,
1001 TAG_END);
1002 if(pdd)
1004 KPRINTF(1, ("Descriptor %08lx\n", pdd));
1005 psdGetAttrs(PGA_DESCRIPTOR, pdd,
1006 DDA_DescriptorData, &descdata,
1007 TAG_END);
1008 dataifnum = ((struct UsbCDCCallMgmDesc *) descdata)->bDataInterface;
1009 KPRINTF(1, ("Using Data Interface %ld\n", dataifnum));
1010 if(!ncp->ncp_EPInt)
1012 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "No notify endpoint?!?");
1013 KPRINTF(1, ("Ooops!?! No notify endpoint defined?\n"));
1014 break;
1016 } else {
1017 pdd = psdFindDescriptor(ncp->ncp_Device, NULL,
1018 DDA_Interface, ncp->ncp_Interface,
1019 DDA_DescriptorType, UDT_CS_INTERFACE,
1020 DDA_CS_SubType, UDST_CDC_UNION,
1021 TAG_END);
1022 if(pdd)
1024 KPRINTF(1, ("Descriptor %08lx\n", pdd));
1025 psdGetAttrs(PGA_DESCRIPTOR, pdd,
1026 DDA_DescriptorData, &descdata,
1027 TAG_END);
1028 dataifnum = ((struct UsbCDCUnionDesc *) descdata)->bSlaveInterface0;
1029 KPRINTF(1, ("Using Data Interface %ld\n", dataifnum));
1030 } else {
1031 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "No descriptor pointing to the data interface. Hm.");
1037 ncp->ncp_DataIf = psdFindInterface(ncp->ncp_Device, ncp->ncp_DataIf,
1038 IFA_Class, CDCDATA_CLASSCODE,
1039 IFA_InterfaceNum, dataifnum,
1040 IFA_AlternateNum, 0xffffffff,
1041 TAG_END);
1042 if(!ncp->ncp_DataIf)
1044 break;
1046 ncp->ncp_EPIn = psdFindEndpoint(ncp->ncp_DataIf, NULL,
1047 EA_IsIn, TRUE,
1048 EA_TransferType, USEAF_BULK,
1049 TAG_END);
1050 ncp->ncp_EPOut = psdFindEndpoint(ncp->ncp_DataIf, NULL,
1051 EA_IsIn, FALSE,
1052 EA_TransferType, USEAF_BULK,
1053 TAG_END);
1054 } while(!(ncp->ncp_EPOut && ncp->ncp_EPIn));
1056 if(!ncp->ncp_DataIf)// Huawei ? (this interface => interrupt + bulks in & out)
1058 ncp->ncp_EPIn = psdFindEndpoint(ncp->ncp_Interface, NULL,
1059 EA_IsIn, TRUE,
1060 EA_TransferType, USEAF_BULK,
1061 TAG_END);
1062 ncp->ncp_EPOut = psdFindEndpoint(ncp->ncp_Interface, NULL,
1063 EA_IsIn, FALSE,
1064 EA_TransferType, USEAF_BULK,
1065 TAG_END);
1066 if( ncp->ncp_EPInt && ncp->ncp_EPIn && ncp->ncp_EPOut ){
1067 ncp->ncp_DataIf = ncp->ncp_Interface;
1071 if(!ncp->ncp_DataIf)
1073 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "Data interface with IN and OUT interface missing?!?");
1074 KPRINTF(1, ("Ooops!?! No data interface defined?\n"));
1075 break;
1077 psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Using data interface %ld.", dataifnum);
1078 ncp->ncp_Unit.unit_MsgPort.mp_SigBit = AllocSignal(-1);
1079 ncp->ncp_Unit.unit_MsgPort.mp_SigTask = thistask;
1080 ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
1081 ncp->ncp_Unit.unit_MsgPort.mp_Flags = PA_SIGNAL;
1082 ncp->ncp_WritePending = NULL;
1084 if((ncp->ncp_TaskMsgPort = CreateMsgPort()))
1086 if((ncp->ncp_EP0Pipe = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, NULL)))
1088 psdSetAltInterface(ncp->ncp_EP0Pipe, ncp->ncp_DataIf);
1089 ncp->ncp_AbortSignal = AllocSignal(-1);
1090 if((ncp->ncp_EPOutStream = psdOpenStream(ncp->ncp_EPOut,
1091 PSA_BufferedWrite, FALSE,
1092 PSA_NoZeroPktTerm, FALSE,
1093 PSA_NakTimeout, TRUE,
1094 PSA_NakTimeoutTime, 5000,
1095 PSA_AbortSigMask, (1UL<<ncp->ncp_AbortSignal)|SIGBREAKF_CTRL_C,
1096 TAG_END)))
1098 if((ncp->ncp_EPInStream = psdOpenStream(ncp->ncp_EPIn,
1099 PSA_ReadAhead, TRUE,
1100 PSA_BufferedRead, TRUE,
1101 PSA_NumPipes, NUMREADPIPES,
1102 PSA_BufferSize, DEFREADBUFLEN,
1103 PSA_AllowRuntPackets, TRUE,
1104 PSA_DoNotWait, TRUE,
1105 PSA_AbortSigMask, SIGBREAKF_CTRL_C,
1106 TAG_END)))
1108 if(ncp->ncp_EPInt)
1110 if((ncp->ncp_EPIntPipe = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, ncp->ncp_EPInt)))
1112 ncp->ncp_Task = thistask;
1113 return(ncp);
1115 } else {
1116 ncp->ncp_Task = thistask;
1117 return(ncp);
1119 psdCloseStream(ncp->ncp_EPInStream);
1121 psdCloseStream(ncp->ncp_EPOutStream);
1123 FreeSignal(ncp->ncp_AbortSignal);
1124 psdFreePipe(ncp->ncp_EP0Pipe);
1126 DeleteMsgPort(ncp->ncp_TaskMsgPort);
1128 FreeSignal((LONG) ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
1129 } while(FALSE);
1130 CloseLibrary(ncp->ncp_Base);
1131 Forbid();
1132 ncp->ncp_Task = NULL;
1133 if(ncp->ncp_ReadySigTask)
1135 Signal(ncp->ncp_ReadySigTask, 1UL<<ncp->ncp_ReadySignal);
1137 return(NULL);
1139 /* \\\ */
1141 /* /// "nFreeSerial()" */
1142 void nFreeSerial(struct NepClassSerial *ncp)
1144 struct IOStdReq *ioreq;
1145 Forbid();
1146 FreeSignal(ncp->ncp_AbortSignal);
1147 ncp->ncp_AbortSignal = -1;
1148 /* Disable the message port, messages may still be queued */
1149 ncp->ncp_Unit.unit_MsgPort.mp_SigTask = NULL;
1150 ncp->ncp_Unit.unit_MsgPort.mp_Flags = PA_IGNORE;
1151 FreeSignal((LONG) ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
1152 // get rid of all messages that still have appeared here
1153 while((ioreq = (struct IOStdReq *) GetMsg(&ncp->ncp_Unit.unit_MsgPort)))
1155 ioreq->io_Error = IOERR_ABORTED;
1156 ReplyMsg((struct Message *) ioreq);
1158 Permit();
1160 psdCloseStream(ncp->ncp_EPInStream);
1161 psdCloseStream(ncp->ncp_EPOutStream);
1162 psdFreePipe(ncp->ncp_EPIntPipe);
1163 psdFreePipe(ncp->ncp_EP0Pipe);
1165 DeleteMsgPort(ncp->ncp_TaskMsgPort);
1166 CloseLibrary(ncp->ncp_Base);
1167 Forbid();
1168 ncp->ncp_Task = NULL;
1169 if(ncp->ncp_ReadySigTask)
1171 Signal(ncp->ncp_ReadySigTask, 1UL<<ncp->ncp_ReadySignal);
1174 /* \\\ */