2 *----------------------------------------------------------------------------
3 * cdcacm class for poseidon
4 *----------------------------------------------------------------------------
5 * By Chris Hodges <chrisly@platon42.de>
9 #include "cdcacm.class.h"
12 static const STRPTR libname
= MOD_NAME_STRING
;
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),
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
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
;
47 AddDevice((struct Device
*) nh
->nh_DevBase
);
48 nh
->nh_DevBase
->np_Library
.lib_OpenCnt
++;
52 KPRINTF(20, ("failed to create cdcacm.device\n"));
56 CloseLibrary(UtilityBase
);
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",
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
);
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"));
91 KPRINTF(5, ("libExpunge: Could not expunge, LIBF_DELEXP set!\n"));
98 ADD2INITLIB(libInit
, 0)
99 ADD2EXPUNGELIB(libExpunge
, 0)
102 void SendBulk( struct PsdDevice
*pd
,UBYTE
*cmd
,ULONG len
)
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
,
120 bug(" ...OK num:%d number of endpoints:%d\n",IFnum
,IFEPnum
);
122 bug("Find BULK OUT Endpoint...");
123 EPOut
= psdFindEndpoint( DataIf
, NULL
,
125 EA_TransferType
, USEAF_BULK
,
128 psdGetAttrs(PGA_ENDPOINT
,EPOut
,
129 EA_EndpointNum
, &EPnum
,
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
,
138 PPA_NakTimeoutTime
, 5000,
140 bug("Write %d bytes ...\n",len
);
141 bug("Error = %d\n", psdDoPipe( pp
, cmd
, len
));
153 * ***********************************************************************
154 * * Library functions *
155 * ***********************************************************************
158 /* /// "usbAttemptInterfaceBinding()" */
159 struct NepClassSerial
* usbAttemptInterfaceBinding(struct NepSerialBase
*nh
, struct PsdInterface
*pif
)
166 struct PsdConfig
*pc
;
167 struct PsdDevice
*pd
;
174 KPRINTF(1, ("nepSerialAttemptInterfaceBinding(%08lx)\n", pif
));
175 if((ps
= OpenLibrary("poseidon.library", 4)))
178 psdGetAttrs(PGA_INTERFACE
, pif
,
180 IFA_SubClass
, &subclass
,
181 IFA_Protocol
, &proto
,
182 IFA_NumEndpoints
, &NumEndpoints
,
186 psdGetAttrs(PGA_CONFIG
, pc
,
188 CA_NumInterfaces
, &numintf
,
191 psdGetAttrs(PGA_DEVICE
, pd
,
192 DA_ProductID
, &prodid
,
193 DA_VendorID
, &vendid
,
196 // bug("cdcacm.class:AttemptInterfaceBinding vendor id=%x product id=%x\n",vendid,prodid);
199 if( vendid
== 0x19d2 && prodid
== 0x2000 ){
203 memset(cmd
, 0, sizeof(cmd
));
213 SendBulk(pd
,cmd
,sizeof(cmd
));
216 if( ifclass
== MASSSTORE_CLASSCODE
){
217 bug("cdcacm.class: fake massstorage binding\n");
218 return (struct NepClassSerial
*)&fake_binding
;
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);
242 if( ifclass
== MASSSTORE_CLASSCODE
){
243 bug("cdcacm.class: fake massstorage binding\n");
244 return (struct NepClassSerial
*)&fake_binding
;
250 // Huawei, e122 and many others.
251 if( (vendid
== 0x12d1 ) && ( prodid
== 0x1446 )){
254 // magic command from BSD u3g driver sources.
255 memset(magic_cmd
, 0, sizeof(magic_cmd
));
263 SendBulk(pd
,magic_cmd
,sizeof(magic_cmd
));
266 if( ifclass
== MASSSTORE_CLASSCODE
){
267 bug("cdcacm.class: fake massstorage binding\n");
268 return (struct NepClassSerial
*)&fake_binding
;
276 if( (vendid
== 0x19d2) && (
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
));
303 if( (vendid
== 0x12d1) && (
304 prodid
== 0x1001 || // e169
305 prodid
== 0x1003 || // e220
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
));
350 /* /// "usbForceInterfaceBinding()" */
351 struct NepClassSerial
* usbForceInterfaceBinding(struct NepSerialBase
*nh
, struct PsdInterface
*pif
)
354 struct NepClassSerial
*ncp
;
355 struct PsdConfig
*pc
;
356 struct PsdDevice
*pd
;
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
,
377 psdGetAttrs(PGA_CONFIG
, pc
,
380 psdGetAttrs(PGA_DEVICE
, pd
,
381 DA_ProductID
, &prodid
,
382 DA_VendorID
, &vendid
,
383 DA_ProductName
, &devname
,
386 /* Find next free unit number */
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
)
394 ncp
= (struct NepClassSerial
*) nh
->nh_Units
.lh_Head
;
396 ncp
= (struct NepClassSerial
*) ncp
->ncp_Unit
.unit_MsgPort
.mp_Node
.ln_Succ
;
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
;
410 ncp
= (struct NepClassSerial
*) ncp
->ncp_Unit
.unit_MsgPort
.mp_Node
.ln_Succ
;
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
)))
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
;
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);
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
,
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
,
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
,
469 ncp
->ncp_ReadySigTask
= NULL
;
470 //FreeSignal(ncp->ncp_ReadySignal);
471 /* Get rid of unit structure */
473 Remove((struct Node *) ncp);
482 /* /// "usbReleaseInterfaceBinding()" */
483 void usbReleaseInterfaceBinding(struct NepSerialBase
*nh
, struct NepClassSerial
*ncp
)
488 KPRINTF(1, ("nepSerialReleaseInterfaceBinding(%08lx)\n", ncp
));
490 if( ncp
== &fake_binding
){
491 bug("cdcacm.class: fake massstorage binding released\n");
495 if((ps
= OpenLibrary("poseidon.library", 4)))
498 ncp
->ncp_ReadySignal
= SIGB_SINGLE
;
499 ncp
->ncp_ReadySigTask
= FindTask(NULL
);
502 Signal(ncp
->ncp_Task
, SIGBREAKF_CTRL_C
);
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.",
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
)
532 KPRINTF(1, ("nepHidGetAttrsA(%ld, %08lx, %08lx)\n", type
, usbstruct
, tags
));
536 if((ti
= FindTagItem(UCCA_Priority
, tags
)))
538 *((SIPTR
*) ti
->ti_Data
) = 1;
541 if((ti
= FindTagItem(UCCA_Description
, tags
)))
543 *((STRPTR
*) ti
->ti_Data
) = "USB modems and OBEX via usbmodem.device";
546 if((ti
= FindTagItem(UCCA_HasClassCfgGUI
, tags
)))
548 *((IPTR
*) ti
->ti_Data
) = FALSE
;
551 if((ti
= FindTagItem(UCCA_HasBindingCfgGUI
, tags
)))
553 *((IPTR
*) ti
->ti_Data
) = FALSE
;
556 if((ti
= FindTagItem(UCCA_AfterDOSRestart
, tags
)))
558 *((IPTR
*) ti
->ti_Data
) = FALSE
;
561 if((ti
= FindTagItem(UCCA_UsingDefaultCfg
, tags
)))
563 *((IPTR
*) ti
->ti_Data
) = TRUE
;
569 if((ti
= FindTagItem(UCBA_UsingDefaultCfg
, tags
)))
571 *((IPTR
*) ti
->ti_Data
) = TRUE
;
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
)
594 /* /// "usbDoMethodA()" */
595 AROS_LH2(IPTR
, usbDoMethodA
,
596 AROS_LHA(ULONG
, methodid
, D0
),
597 AROS_LHA(IPTR
*, methoddata
, A1
),
598 LIBBASETYPEPTR
, nh
, 7, nep
)
602 KPRINTF(10, ("Do Method %ld\n", 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]);
623 /**************************************************************************/
626 #define ps ncp->ncp_Base
628 /* /// "nSetSerialMode()" */
629 void nSetSerialMode(struct NepClassSerial
*ncp
, struct IOExtSer
*ioreq
)
631 struct UsbCDCLineCoding ulc
;
633 ULONG bufsize
= ioreq
->io_RBufLen
/ NUMREADPIPES
;
639 bufsize
= (bufsize
+ 127) & (~127);
641 psdSetAttrs(PGA_PIPESTREAM
, ncp
->ncp_EPInStream
,
642 PSA_BufferSize
, bufsize
,
644 if(ioreq
->io_SerFlags
& SERF_EOFMODE
)
646 psdSetAttrs(PGA_PIPESTREAM
, ncp
->ncp_EPInStream
,
647 PSA_TermArray
, &ioreq
->io_TermArray
,
649 psdSetAttrs(PGA_PIPESTREAM
, ncp
->ncp_EPOutStream
,
650 PSA_TermArray
, &ioreq
->io_TermArray
,
653 psdSetAttrs(PGA_PIPESTREAM
, ncp
->ncp_EPInStream
,
656 psdSetAttrs(PGA_PIPESTREAM
, ncp
->ncp_EPOutStream
,
660 ulc
.dwDTERate
= AROS_LONG2LE(ioreq
->io_Baud
);
661 if(ioreq
->io_StopBits
== 1)
665 else if(ioreq
->io_StopBits
== 2)
669 ioreq
->IOSer
.io_Error
= SerErr_InvParam
;
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 */
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 */
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);
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);
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
;
724 /* /// "nSerialTask()" */
725 AROS_UFH0(void, nSerialTask
)
729 struct NepClassSerial
*ncp
;
736 struct IOExtSer
*ioreq
;
737 struct IOExtSer
*ioreq2
;
740 if((ncp
= nAllocSerial()))
743 if(ncp
->ncp_ReadySigTask
)
745 Signal(ncp
->ncp_ReadySigTask
, 1UL<<ncp
->ncp_ReadySignal
);
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
);
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
);
785 psdSendPipe(ncp
->ncp_EPIntPipe
, &ncp
->ncp_SerialStateReq
, sizeof(ncp
->ncp_SerialStateReq
));
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
)
796 psdStreamFlush(ncp
->ncp_EPOutStream
);
797 ReplyMsg((struct Message
*) ioreq
);
801 /* Reset does a flush too */
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
);
826 if(!(ncp
->ncp_SerialStateReq
.uss_State
& 0x0100)) /* Carrier Detect */
828 if(!(ncp
->ncp_SerialStateReq
.uss_State
& 0x0200)) /* DSR */
830 if(ncp
->ncp_SerialStateReq
.uss_State
& 0x0400) /* Break */
832 if(ncp
->ncp_SerialStateReq
.uss_State
& 0x0800) /* Ring */
834 if(ncp
->ncp_SerialStateReq
.uss_State
& 0x7000) /* Framing, Parity, Hardware error */
837 ioreq
->io_Status
= serstate
;
839 psdGetAttrs(PGA_PIPESTREAM
, ncp
->ncp_EPInStream
,
840 PSA_BytesPending
, &pending
,
842 ioreq
->IOSer
.io_Actual
= pending
;
843 ReplyMsg((struct Message
*) ioreq
);
846 case SDCMD_SETPARAMS
:
847 nSetSerialMode(ncp
, ioreq
);
848 ReplyMsg((struct Message
*) ioreq
);
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);
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
);
866 ioreq
->IOSer
.io_Error
= IOERR_NOCMD
;
867 ReplyMsg((struct Message
*) ioreq
);
871 if(!ncp
->ncp_DevSuspend
)
874 psdGetAttrs(PGA_PIPESTREAM
, ncp
->ncp_EPInStream
,
875 PSA_BytesPending
, &pending
,
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
);
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
)
888 AddHead(&ncp
->ncp_ReadQueue
, &ioreq
->IOSer
.io_Message
.mn_Node
);
893 ioreq
->IOSer
.io_Error
= SerErr_LineErr
;
895 ioreq
->IOSer
.io_Error
= ioerr
;
897 ReplyMsg((struct Message
*) ioreq
);
899 psdGetAttrs(PGA_PIPESTREAM
, ncp
->ncp_EPInStream
,
900 PSA_BytesPending
, &pending
,
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
;
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
);
916 ioreq
->IOSer
.io_Error
= SerErr_LineErr
;
918 ioreq
->IOSer
.io_Error
= ioerr
;
920 ReplyMsg((struct Message
*) ioreq
);
922 ioreq
= (struct IOExtSer
*) ncp
->ncp_WriteQueue
.lh_Head
;
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 */
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
;
957 while((ioreq
= (struct IOExtSer
*) GetMsg(&ncp
->ncp_Unit
.unit_MsgPort
)))
959 ioreq
->IOSer
.io_Error
= IOERR_ABORTED
;
960 ReplyMsg((struct Message
*) ioreq
);
963 KPRINTF(20, ("Going down the river!\n"));
971 /* /// "nAllocSerial()" */
972 struct NepClassSerial
* nAllocSerial(void)
974 struct Task
*thistask
;
975 struct NepClassSerial
*ncp
;
976 struct PsdDescriptor
*pdd
;
977 UBYTE
*descdata
= NULL
;
980 thistask
= FindTask(NULL
);
981 ncp
= thistask
->tc_UserData
;
984 if(!(ncp
->ncp_Base
= OpenLibrary("poseidon.library", 4)))
990 ncp
->ncp_EPInt
= psdFindEndpoint(ncp
->ncp_Interface
, NULL
,
992 EA_TransferType
, USEAF_INTERRUPT
,
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
,
1004 KPRINTF(1, ("Descriptor %08lx\n", pdd
));
1005 psdGetAttrs(PGA_DESCRIPTOR
, pdd
,
1006 DDA_DescriptorData
, &descdata
,
1008 dataifnum
= ((struct UsbCDCCallMgmDesc
*) descdata
)->bDataInterface
;
1009 KPRINTF(1, ("Using Data Interface %ld\n", dataifnum
));
1012 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
, "No notify endpoint?!?");
1013 KPRINTF(1, ("Ooops!?! No notify endpoint defined?\n"));
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
,
1024 KPRINTF(1, ("Descriptor %08lx\n", pdd
));
1025 psdGetAttrs(PGA_DESCRIPTOR
, pdd
,
1026 DDA_DescriptorData
, &descdata
,
1028 dataifnum
= ((struct UsbCDCUnionDesc
*) descdata
)->bSlaveInterface0
;
1029 KPRINTF(1, ("Using Data Interface %ld\n", dataifnum
));
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,
1042 if(!ncp
->ncp_DataIf
)
1046 ncp
->ncp_EPIn
= psdFindEndpoint(ncp
->ncp_DataIf
, NULL
,
1048 EA_TransferType
, USEAF_BULK
,
1050 ncp
->ncp_EPOut
= psdFindEndpoint(ncp
->ncp_DataIf
, NULL
,
1052 EA_TransferType
, USEAF_BULK
,
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
,
1060 EA_TransferType
, USEAF_BULK
,
1062 ncp
->ncp_EPOut
= psdFindEndpoint(ncp
->ncp_Interface
, NULL
,
1064 EA_TransferType
, USEAF_BULK
,
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"));
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
,
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
,
1110 if((ncp
->ncp_EPIntPipe
= psdAllocPipe(ncp
->ncp_Device
, ncp
->ncp_TaskMsgPort
, ncp
->ncp_EPInt
)))
1112 ncp
->ncp_Task
= thistask
;
1116 ncp
->ncp_Task
= thistask
;
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
);
1130 CloseLibrary(ncp
->ncp_Base
);
1132 ncp
->ncp_Task
= NULL
;
1133 if(ncp
->ncp_ReadySigTask
)
1135 Signal(ncp
->ncp_ReadySigTask
, 1UL<<ncp
->ncp_ReadySignal
);
1141 /* /// "nFreeSerial()" */
1142 void nFreeSerial(struct NepClassSerial
*ncp
)
1144 struct IOStdReq
*ioreq
;
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
);
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
);
1168 ncp
->ncp_Task
= NULL
;
1169 if(ncp
->ncp_ReadySigTask
)
1171 Signal(ncp
->ncp_ReadySigTask
, 1UL<<ncp
->ncp_ReadySignal
);