Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / classes / cdcacm / dev.c
blobcfd5ae326add877aa21f5ca66b5f7751ff875a93
1 /* dev.c - usbmodem.device by Chris Hodges
2 */
4 #include "debug.h"
6 #include "cdcacm.class.h"
8 AROS_UFH3(DEVBASETYPEPTR, devInit,
9 AROS_UFHA(DEVBASETYPEPTR, base, D0),
10 AROS_UFHA(BPTR, seglist, A0),
11 AROS_UFHA(struct ExecBase *, SysBase, A6))
13 AROS_USERFUNC_INIT
15 KPRINTF(10, ("devInit base: 0x%08lx seglist: 0x%08lx SysBase: 0x%08lx\n",
16 base, seglist, SysBase));
18 base->np_Library.lib_Node.ln_Type = NT_DEVICE;
19 base->np_Library.lib_Node.ln_Name = DEVNAME;
20 base->np_Library.lib_Flags = LIBF_SUMUSED|LIBF_CHANGED;
21 base->np_Library.lib_Version = VERSION_NUMBER;
22 base->np_Library.lib_Revision = REVISION_NUMBER;
23 base->np_Library.lib_IdString = VERSION_STRING;
25 /* Store segment */
26 base->np_SegList = seglist;
28 if((base->np_UtilityBase = OpenLibrary("utility.library", 0)))
30 KPRINTF(10, ("devInit: Ok\n"));
31 KPRINTF(10, ("devInit: openCnt = %ld\n", base->np_Library.lib_OpenCnt));
32 return(base);
34 else
36 return(NULL);
38 return(base);
40 AROS_USERFUNC_EXIT
43 #undef UtilityBase
44 #define UtilityBase base->np_UtilityBase
46 AROS_LH3(DEVBASETYPEPTR, devOpen,
47 AROS_LHA(struct IOExtSer *, ioreq, A1),
48 AROS_LHA(ULONG, unit, D0),
49 AROS_LHA(ULONG, flags, D1),
50 DEVBASETYPEPTR, base, 1, dev)
52 AROS_LIBFUNC_INIT
54 struct NepClassSerial *ncp;
56 KPRINTF(10, ("devOpen ioreq: 0x%08lx unit: %ld flags: 0x%08lx base: 0x%08lx\n",
57 ioreq, unit, flags, base));
59 ++base->np_Library.lib_OpenCnt;
60 base->np_Library.lib_Flags &= ~LIBF_DELEXP;
62 KPRINTF(10, ("devOpen: openCnt = %ld\n", base->np_Library.lib_OpenCnt));
63 /* Damn f*cking programs which leave this field to zero! */
64 if(ioreq->IOSer.io_Message.mn_Length && (ioreq->IOSer.io_Message.mn_Length < sizeof(struct IOExtSer)))
66 KPRINTF(20, ("devOpen: invalid MN_LENGTH (%ld < %ld)!\n",
67 ioreq->IOSer.io_Message.mn_Length, sizeof(struct IOExtSer)));
69 ioreq->IOSer.io_Error = IOERR_BADLENGTH;
70 } else {
71 /* Default to open failure. */
72 ioreq->IOSer.io_Error = IOERR_OPENFAIL;
74 ioreq->IOSer.io_Unit = NULL;
75 ncp = (struct NepClassSerial *) base->np_ClsBase->nh_Units.lh_Head;
76 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
78 if(ncp->ncp_UnitNo == unit && ncp->ncp_Task )
80 if(ncp->ncp_Unit.unit_OpenCnt)
82 ioreq->IOSer.io_Error = IOERR_UNITBUSY;
83 } else {
84 ioreq->IOSer.io_Unit = (struct Unit *) ncp;
86 break;
88 ncp = (struct NepClassSerial *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
91 if(!ioreq->IOSer.io_Unit)
93 ioreq->IOSer.io_Error = IOERR_OPENFAIL;
94 KPRINTF(20, ("devOpen: could not open unit!\n"));
95 } else {
96 /* Opended ok! */
97 ioreq->IOSer.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
98 ioreq->IOSer.io_Error = 0;
99 ioreq->IOSer.io_Unit->unit_OpenCnt++;
101 ioreq->io_CtlChar = SER_DEFAULT_CTLCHAR;
102 ioreq->io_RBufLen = DEFREADBUFLEN;
103 ioreq->io_ExtFlags = 0;
104 ioreq->io_Baud = 9600;
105 ioreq->io_BrkTime = 250000;
106 ioreq->io_TermArray.TermArray0 = 0;
107 ioreq->io_TermArray.TermArray1 = 0;
108 ioreq->io_ReadLen = 8;
109 ioreq->io_WriteLen = 8;
110 ioreq->io_StopBits = 1;
111 if(ioreq->io_SerFlags & SERF_RAD_BOOGIE)
113 ioreq->io_SerFlags |= SERF_XDISABLED;
114 ioreq->io_SerFlags &= ~SERF_PARTY_ON|SERF_PARTY_ODD;
117 /* Allow queuing */
118 ncp->ncp_DenyRequests = FALSE;
120 /* initial settings */
121 ioreq->IOSer.io_Command = SDCMD_SETPARAMS;
122 ioreq->IOSer.io_Flags &= ~IOF_QUICK;
123 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
124 while(!GetMsg(&ncp->ncp_Unit.unit_MsgPort))
126 WaitPort(&ncp->ncp_Unit.unit_MsgPort);
128 return base;
132 ioreq->IOSer.io_Unit = (APTR) -1;
133 ioreq->IOSer.io_Device = (APTR) -1;
134 base->np_Library.lib_OpenCnt--;
136 return(NULL);
138 AROS_LIBFUNC_EXIT
142 AROS_LH1(BPTR, devClose,
143 AROS_LHA(struct IOExtSer *, ioreq, A1),
144 DEVBASETYPEPTR, base, 2, dev)
146 AROS_LIBFUNC_INIT
148 BPTR ret;
149 struct NepClassSerial *ncp = (struct NepClassSerial *) ioreq->IOSer.io_Unit;
151 KPRINTF(10, ("devClose ioreq: 0x%08lx base: 0x%08lx\n", ioreq, base));
153 ret = BNULL;
155 /* Don't allow queuing */
156 ncp->ncp_DenyRequests = TRUE;
158 ncp->ncp_Unit.unit_OpenCnt--;
159 ioreq->IOSer.io_Unit = (APTR) -1;
160 ioreq->IOSer.io_Device = (APTR) -1;
162 if(--base->np_Library.lib_OpenCnt == 0)
164 if(base->np_Library.lib_Flags & LIBF_DELEXP)
166 KPRINTF(5, ("devClose: calling expunge...\n"));
167 ret = AROS_LC1(BPTR, devExpunge,
168 AROS_LCA(DEVBASETYPEPTR, base, D0),
169 DEVBASETYPEPTR, base, 3, dev);
173 KPRINTF(5, ("devClose: lib_OpenCnt = %ld\n", base->np_Library.lib_OpenCnt));
175 return(ret);
177 AROS_LIBFUNC_EXIT
181 AROS_LH1(BPTR, devExpunge,
182 AROS_LHA(DEVBASETYPEPTR, extralh, D0),
183 DEVBASETYPEPTR, base, 3, dev)
185 AROS_LIBFUNC_INIT
187 BPTR ret;
189 KPRINTF(10, ("devExpunge base: 0x%08lx\n", base));
191 ret = BNULL;
193 if(base->np_Library.lib_OpenCnt == 0)
195 KPRINTF(5, ("devExpunge: Unloading...\n"));
197 CloseLibrary(base->np_UtilityBase);
199 ret = base->np_SegList;
201 KPRINTF(5, ("devExpunge: removing device node 0x%08lx\n",
202 &base->np_Library.lib_Node));
203 Remove(&base->np_Library.lib_Node);
205 KPRINTF(5, ("devExpunge: FreeMem()...\n"));
206 FreeMem((char *) base - base->np_Library.lib_NegSize,
207 (ULONG) (base->np_Library.lib_NegSize + base->np_Library.lib_PosSize));
209 KPRINTF(5, ("devExpunge: Unloading done! " DEVNAME " expunged!\n\n"));
211 return(ret);
213 else
215 KPRINTF(5, ("devExpunge: Could not expunge, LIBF_DELEXP set!\n"));
216 base->np_Library.lib_Flags |= LIBF_DELEXP;
219 return(BNULL);
221 AROS_LIBFUNC_EXIT
224 AROS_LH0(DEVBASETYPEPTR, devReserved,
225 DEVBASETYPEPTR, base, 4, dev)
227 AROS_LIBFUNC_INIT
228 return NULL;
229 AROS_LIBFUNC_EXIT
232 AROS_LH1(void, devBeginIO,
233 AROS_LHA(struct IOExtSer *, ioreq, A1),
234 DEVBASETYPEPTR, base, 5, dev)
236 AROS_LIBFUNC_INIT
238 struct NepClassSerial *ncp = (struct NepClassSerial *) ioreq->IOSer.io_Unit;
239 WORD ret = IOERR_NOCMD;
241 KPRINTF(1, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu len: %ld\n", ioreq, base, ioreq->IOSer.io_Command, ioreq->IOSer.io_Length));
243 ioreq->IOSer.io_Message.mn_Node.ln_Type = NT_MESSAGE;
244 ioreq->IOSer.io_Error = 0;
246 if(ioreq->IOSer.io_Command < NSCMD_DEVICEQUERY)
248 switch (ioreq->IOSer.io_Command)
250 case CMD_READ:
251 if(ncp->ncp_EPInStream && (!ncp->ncp_DenyRequests))
253 ioreq->IOSer.io_Flags &= ~IOF_QUICK;
254 Forbid();
255 AddTail(&ncp->ncp_ReadQueue, &ioreq->IOSer.io_Message.mn_Node);
256 if(ncp->ncp_Task)
258 Signal(ncp->ncp_Task, 1UL<<ncp->ncp_TaskMsgPort->mp_SigBit);
260 Permit();
261 ret = RC_DONTREPLY;
262 } else {
263 ret = IOERR_ABORTED;
265 break;
267 case CMD_WRITE:
268 if(!ncp->ncp_DenyRequests)
270 if(ioreq->IOSer.io_Length == -1)
272 ioreq->IOSer.io_Length = strlen(ioreq->IOSer.io_Data);
274 ioreq->IOSer.io_Flags &= ~IOF_QUICK;
275 Forbid();
276 AddTail(&ncp->ncp_WriteQueue, &ioreq->IOSer.io_Message.mn_Node);
277 if(ncp->ncp_Task)
279 Signal(ncp->ncp_Task, 1UL<<ncp->ncp_TaskMsgPort->mp_SigBit);
281 Permit();
282 ret = RC_DONTREPLY;
283 } else {
284 ret = IOERR_ABORTED;
286 break;
288 case CMD_START:
289 ncp->ncp_DevSuspend = FALSE;
290 ret = RC_OK;
291 break;
293 case CMD_STOP:
294 ncp->ncp_DevSuspend = TRUE;
295 ret = RC_OK;
296 break;
298 case CMD_CLEAR:
299 case CMD_RESET:
300 case CMD_FLUSH:
301 case SDCMD_QUERY:
302 case SDCMD_SETPARAMS:
303 case SDCMD_BREAK:
304 if(!ncp->ncp_DenyRequests)
306 ioreq->IOSer.io_Flags &= ~IOF_QUICK;
307 ret = RC_DONTREPLY;
308 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
309 } else {
310 ioreq->IOSer.io_Actual = 0;
311 ret = IOERR_ABORTED;
313 break;
315 default:
316 ret = IOERR_NOCMD;
317 break;
319 } else {
320 switch(ioreq->IOSer.io_Command)
322 case NSCMD_DEVICEQUERY:
323 ret = cmdNSDeviceQuery((struct IOStdReq *) ioreq, ncp, base);
324 break;
326 default:
327 ret = IOERR_NOCMD;
328 break;
332 if(ret != RC_DONTREPLY)
334 KPRINTF(1, ("TermIO\n"));
335 if (ret != RC_OK)
337 /* Set error codes
339 ioreq->IOSer.io_Error = ret & 0xff;
341 /* Terminate the iorequest
343 TermIO(ioreq, base);
346 AROS_LIBFUNC_EXIT
349 AROS_LH1(LONG, devAbortIO,
350 AROS_LHA(struct IOExtSer *, ioreq, A1),
351 DEVBASETYPEPTR, base, 6, dev)
353 AROS_LIBFUNC_INIT
355 struct NepClassSerial *ncp = (struct NepClassSerial *) ioreq->IOSer.io_Unit;
357 struct IOExtSer *iocmp;
359 KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq));
361 /* Is it pending?
363 Forbid();
364 if(ioreq->IOSer.io_Message.mn_Node.ln_Type == NT_MESSAGE)
366 /* check if it's the writing pipe */
367 if(ioreq == ncp->ncp_WritePending)
369 if(ncp->ncp_AbortSignal >= 0)
371 /* prod the subtask */
372 Signal(ncp->ncp_Task, 1UL<<ncp->ncp_AbortSignal);
374 Permit();
375 return(0);
377 iocmp = (struct IOExtSer *) ncp->ncp_ReadQueue.lh_Head;
378 while(iocmp->IOSer.io_Message.mn_Node.ln_Succ)
380 if(iocmp == ioreq)
382 Remove((struct Node *) ioreq);
383 ioreq->IOSer.io_Error = IOERR_ABORTED;
384 ReplyMsg(&ioreq->IOSer.io_Message);
385 Permit();
386 return(0);
388 iocmp = (struct IOExtSer *) iocmp->IOSer.io_Message.mn_Node.ln_Succ;
390 iocmp = (struct IOExtSer *) ncp->ncp_WriteQueue.lh_Head;
391 while(iocmp->IOSer.io_Message.mn_Node.ln_Succ)
393 if(iocmp == ioreq)
395 Remove((struct Node *)ioreq);
396 ioreq->IOSer.io_Error = IOERR_ABORTED;
397 ReplyMsg(&ioreq->IOSer.io_Message);
398 Permit();
399 return(0);
401 iocmp = (struct IOExtSer *) iocmp->IOSer.io_Message.mn_Node.ln_Succ;
404 Permit();
405 return(-1);
407 AROS_LIBFUNC_EXIT
410 /* NSD stuff
413 static
414 const UWORD NSDSupported[] =
416 CMD_CLEAR, CMD_RESET,
417 CMD_FLUSH, CMD_READ,
418 CMD_WRITE, CMD_START,
419 CMD_STOP, SDCMD_QUERY,
420 SDCMD_SETPARAMS,
421 SDCMD_BREAK,
422 NSCMD_DEVICEQUERY, 0
425 WORD cmdNSDeviceQuery(struct IOStdReq *ioreq,
426 struct NepClassSerial *ncp,
427 struct NepSerDevBase *base)
429 struct my_NSDeviceQueryResult *query;
431 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
433 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq, query));
435 /* NULL ptr?
436 Enough data?
437 Valid request?
439 if((!query) ||
440 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
441 (query->DevQueryFormat != 0) ||
442 (query->SizeAvailable != 0))
444 /* Return error. This is special handling, since iorequest is only
445 guaranteed to be sizeof(struct IOStdReq). If we'd let our
446 devBeginIO dispatcher return the error, it would trash some
447 memory past end of the iorequest (ios2_WireError field).
449 ioreq->io_Error = IOERR_NOCMD;
450 TermIO((struct IOExtSer *) ioreq, base);
452 /* Don't reply, we already did.
454 return RC_DONTREPLY;
457 ioreq->io_Actual = query->SizeAvailable
458 = sizeof(struct my_NSDeviceQueryResult);
459 query->DeviceType = NSDEVTYPE_SERIAL;
460 query->DeviceSubType = 0;
461 query->SupportedCommands = NSDSupported;
463 /* Return success (note that this will NOT poke ios2_WireError).
465 return RC_OK;
469 *===========================================================
470 * TermIO(ioreq, base)
471 *===========================================================
473 * Return completed ioreq to sender.
477 void TermIO(struct IOExtSer *ioreq,
478 struct NepSerDevBase *base)
480 ioreq->IOSer.io_Message.mn_Node.ln_Type = NT_FREEMSG;
482 /* If not quick I/O, reply the message
484 if(!(ioreq->IOSer.io_Flags & IOF_QUICK))
486 ReplyMsg(&ioreq->IOSer.io_Message);