Fixed compatibility of output.
[AROS.git] / rom / usb / classes / serialcp210x / dev.c
blobedfe6faf1e83e14d48de291cd3cdaa98c32f2983
1 /* dev.c - serialcp210x.device by Chris Hodges
2 */
4 #include "debug.h"
6 #include "serialcp210x.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)
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);
129 return base;
133 ioreq->IOSer.io_Unit = (APTR) -1;
134 ioreq->IOSer.io_Device = (APTR) -1;
135 base->np_Library.lib_OpenCnt--;
137 return(NULL);
139 AROS_LIBFUNC_EXIT
143 AROS_LH1(BPTR, devClose,
144 AROS_LHA(struct IOExtSer *, ioreq, A1),
145 DEVBASETYPEPTR, base, 2, dev)
147 AROS_LIBFUNC_INIT
149 BPTR ret;
150 struct NepClassSerial *ncp = (struct NepClassSerial *) ioreq->IOSer.io_Unit;
152 KPRINTF(10, ("devClose ioreq: 0x%08lx base: 0x%08lx\n", ioreq, base));
154 ret = BNULL;
156 /* Don't allow queuing */
157 ncp->ncp_DenyRequests = TRUE;
159 ncp->ncp_Unit.unit_OpenCnt--;
160 ioreq->IOSer.io_Unit = (APTR) -1;
161 ioreq->IOSer.io_Device = (APTR) -1;
163 if(--base->np_Library.lib_OpenCnt == 0)
165 if(base->np_Library.lib_Flags & LIBF_DELEXP)
167 KPRINTF(5, ("devClose: calling expunge...\n"));
168 ret = AROS_LC1(BPTR, devExpunge,
169 AROS_LCA(DEVBASETYPEPTR, base, D0),
170 DEVBASETYPEPTR, base, 3, dev);
174 KPRINTF(5, ("devClose: lib_OpenCnt = %ld\n", base->np_Library.lib_OpenCnt));
176 return(ret);
178 AROS_LIBFUNC_EXIT
182 AROS_LH1(BPTR, devExpunge,
183 AROS_LHA(DEVBASETYPEPTR, extralh, D0),
184 DEVBASETYPEPTR, base, 3, dev)
186 AROS_LIBFUNC_INIT
188 BPTR ret;
190 KPRINTF(10, ("devExpunge base: 0x%08lx\n", base));
192 ret = BNULL;
194 if(base->np_Library.lib_OpenCnt == 0)
196 KPRINTF(5, ("devExpunge: Unloading...\n"));
198 CloseLibrary(base->np_UtilityBase);
200 ret = base->np_SegList;
202 KPRINTF(5, ("devExpunge: removing device node 0x%08lx\n",
203 &base->np_Library.lib_Node));
204 Remove(&base->np_Library.lib_Node);
206 KPRINTF(5, ("devExpunge: FreeMem()...\n"));
207 FreeMem((char *) base - base->np_Library.lib_NegSize,
208 (ULONG) (base->np_Library.lib_NegSize + base->np_Library.lib_PosSize));
210 KPRINTF(5, ("devExpunge: Unloading done! " DEVNAME " expunged!\n\n"));
212 return(ret);
214 else
216 KPRINTF(5, ("devExpunge: Could not expunge, LIBF_DELEXP set!\n"));
217 base->np_Library.lib_Flags |= LIBF_DELEXP;
220 return(BNULL);
222 AROS_LIBFUNC_EXIT
225 AROS_LH0(DEVBASETYPEPTR, devReserved,
226 DEVBASETYPEPTR, base, 4, dev)
228 AROS_LIBFUNC_INIT
229 return NULL;
230 AROS_LIBFUNC_EXIT
233 AROS_LH1(void, devBeginIO,
234 AROS_LHA(struct IOExtSer *, ioreq, A1),
235 DEVBASETYPEPTR, base, 5, dev)
237 AROS_LIBFUNC_INIT
239 struct NepClassSerial *ncp = (struct NepClassSerial *) ioreq->IOSer.io_Unit;
240 WORD ret = IOERR_NOCMD;
242 //KPRINTF(1, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu\n", ioreq, base, ioreq->IOSer.io_Command));
244 ioreq->IOSer.io_Message.mn_Node.ln_Type = NT_MESSAGE;
245 ioreq->IOSer.io_Error = 0;
247 if(ioreq->IOSer.io_Command < NSCMD_DEVICEQUERY)
249 switch (ioreq->IOSer.io_Command)
251 case CMD_READ:
252 if(ncp->ncp_EPInStream && (!ncp->ncp_DenyRequests))
254 ioreq->IOSer.io_Flags &= ~IOF_QUICK;
255 Forbid();
256 AddTail(&ncp->ncp_ReadQueue, &ioreq->IOSer.io_Message.mn_Node);
257 if(ncp->ncp_Task)
259 Signal(ncp->ncp_Task, 1UL<<ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
261 Permit();
262 ret = RC_DONTREPLY;
263 } else {
264 ret = IOERR_ABORTED;
266 break;
268 case CMD_WRITE:
269 if(!ncp->ncp_DenyRequests)
271 if(ioreq->IOSer.io_Length == -1)
273 ioreq->IOSer.io_Length = strlen(ioreq->IOSer.io_Data);
275 ioreq->IOSer.io_Flags &= ~IOF_QUICK;
276 Forbid();
277 AddTail(&ncp->ncp_WriteQueue, &ioreq->IOSer.io_Message.mn_Node);
278 if(ncp->ncp_Task)
280 Signal(ncp->ncp_Task, 1UL<<ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
282 Permit();
283 ret = RC_DONTREPLY;
284 } else {
285 ret = IOERR_ABORTED;
287 break;
289 case CMD_START:
290 ncp->ncp_DevSuspend = FALSE;
291 ret = RC_OK;
292 break;
294 case CMD_STOP:
295 ncp->ncp_DevSuspend = TRUE;
296 ret = RC_OK;
297 break;
299 case CMD_CLEAR:
300 case CMD_RESET:
301 case CMD_FLUSH:
302 case SDCMD_QUERY:
303 case SDCMD_SETPARAMS:
304 case SDCMD_BREAK:
305 if(!ncp->ncp_DenyRequests)
307 ioreq->IOSer.io_Flags &= ~IOF_QUICK;
308 ret = RC_DONTREPLY;
309 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
310 } else {
311 ioreq->IOSer.io_Actual = 0;
312 ret = IOERR_ABORTED;
314 break;
316 default:
317 ret = IOERR_NOCMD;
318 break;
320 } else {
321 switch(ioreq->IOSer.io_Command)
323 case NSCMD_DEVICEQUERY:
324 ret = cmdNSDeviceQuery((struct IOStdReq *) ioreq, ncp, base);
325 break;
327 default:
328 ret = IOERR_NOCMD;
329 break;
333 if(ret != RC_DONTREPLY)
335 KPRINTF(1, ("TermIO\n"));
336 if (ret != RC_OK)
338 /* Set error codes
340 ioreq->IOSer.io_Error = ret & 0xff;
342 /* Terminate the iorequest
344 TermIO(ioreq, base);
347 AROS_LIBFUNC_EXIT
350 AROS_LH1(LONG, devAbortIO,
351 AROS_LHA(struct IOExtSer *, ioreq, A1),
352 DEVBASETYPEPTR, base, 6, dev)
354 AROS_LIBFUNC_INIT
356 struct NepClassSerial *ncp = (struct NepClassSerial *) ioreq->IOSer.io_Unit;
358 struct IOExtSer *iocmp;
360 KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq));
362 /* Is it pending?
364 Forbid();
365 if(ioreq->IOSer.io_Message.mn_Node.ln_Type == NT_MESSAGE)
367 /* check if it's the writing pipe */
368 if(ioreq == ncp->ncp_WritePending)
370 if(ncp->ncp_AbortSignal >= 0)
372 /* prod the subtask */
373 Signal(ncp->ncp_Task, 1UL<<ncp->ncp_AbortSignal);
375 Permit();
376 return(0);
378 iocmp = (struct IOExtSer *) ncp->ncp_ReadQueue.lh_Head;
379 while(iocmp->IOSer.io_Message.mn_Node.ln_Succ)
381 if(iocmp == ioreq)
383 Remove((struct Node *) ioreq);
384 ioreq->IOSer.io_Error = IOERR_ABORTED;
385 ReplyMsg(&ioreq->IOSer.io_Message);
386 Permit();
387 return(0);
389 iocmp = (struct IOExtSer *) iocmp->IOSer.io_Message.mn_Node.ln_Succ;
391 iocmp = (struct IOExtSer *) ncp->ncp_WriteQueue.lh_Head;
392 while(iocmp->IOSer.io_Message.mn_Node.ln_Succ)
394 if(iocmp == ioreq)
396 Remove((struct Node *)ioreq);
397 ioreq->IOSer.io_Error = IOERR_ABORTED;
398 ReplyMsg(&ioreq->IOSer.io_Message);
399 Permit();
400 return(0);
402 iocmp = (struct IOExtSer *) iocmp->IOSer.io_Message.mn_Node.ln_Succ;
405 Permit();
406 return(-1);
408 AROS_LIBFUNC_EXIT
411 /* NSD stuff
414 static
415 const UWORD NSDSupported[] =
417 CMD_CLEAR, CMD_RESET,
418 CMD_FLUSH, CMD_READ,
419 CMD_WRITE, CMD_START,
420 CMD_STOP, SDCMD_QUERY,
421 SDCMD_SETPARAMS,
422 SDCMD_BREAK,
423 NSCMD_DEVICEQUERY, 0
426 WORD cmdNSDeviceQuery(struct IOStdReq *ioreq,
427 struct NepClassSerial *ncp,
428 struct NepSerDevBase *base)
430 struct my_NSDeviceQueryResult *query;
432 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
434 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq, query));
436 /* NULL ptr?
437 Enough data?
438 Valid request?
440 if((!query) ||
441 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
442 (query->DevQueryFormat != 0) ||
443 (query->SizeAvailable != 0))
445 /* Return error. This is special handling, since iorequest is only
446 guaranteed to be sizeof(struct IOStdReq). If we'd let our
447 devBeginIO dispatcher return the error, it would trash some
448 memory past end of the iorequest (ios2_WireError field).
450 ioreq->io_Error = IOERR_NOCMD;
451 TermIO((struct IOExtSer *) ioreq, base);
453 /* Don't reply, we already did.
455 return RC_DONTREPLY;
458 ioreq->io_Actual = query->SizeAvailable
459 = sizeof(struct my_NSDeviceQueryResult);
460 query->DeviceType = NSDEVTYPE_SERIAL;
461 query->DeviceSubType = 0;
462 query->SupportedCommands = NSDSupported;
464 /* Return success (note that this will NOT poke ios2_WireError).
466 return RC_OK;
470 *===========================================================
471 * TermIO(ioreq, base)
472 *===========================================================
474 * Return completed ioreq to sender.
478 void TermIO(struct IOExtSer *ioreq,
479 struct NepSerDevBase *base)
481 ioreq->IOSer.io_Message.mn_Node.ln_Type = NT_FREEMSG;
483 /* If not quick I/O, reply the message
485 if(!(ioreq->IOSer.io_Flags & IOF_QUICK))
487 ReplyMsg(&ioreq->IOSer.io_Message);