poseidon: Fix a number of BPTR issues
[AROS.git] / rom / usb / classes / printer / dev.c
blob2b891dff9fe640b0c92e72c8738a476198669557
1 /* dev.c - usbparallel.device by Chris Hodges
2 */
4 #include "debug.h"
6 #include "printer.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 IOExtPar *, 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 NepClassPrinter *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 /* Turboprint has an illegal message length of 0 in its iorequests! */
64 if(ioreq->IOPar.io_Message.mn_Length && (ioreq->IOPar.io_Message.mn_Length < sizeof(struct IOExtPar)))
66 KPRINTF(20, ("devOpen: invalid MN_LENGTH (%ld < %ld)!\n",
67 ioreq->IOPar.io_Message.mn_Length, sizeof(struct IOExtPar)));
69 ioreq->IOPar.io_Error = IOERR_BADLENGTH;
70 } else {
71 /* Default to open failure. */
72 ioreq->IOPar.io_Error = IOERR_OPENFAIL;
74 ioreq->IOPar.io_Unit = NULL;
75 ncp = (struct NepClassPrinter *) 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->IOPar.io_Error = IOERR_UNITBUSY;
83 } else {
84 ioreq->IOPar.io_Unit = (struct Unit *) ncp;
86 break;
88 ncp = (struct NepClassPrinter *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
91 if(!ioreq->IOPar.io_Unit)
93 ioreq->IOPar.io_Error = IOERR_OPENFAIL;
94 KPRINTF(20, ("devOpen: could not open unit!\n"));
95 } else {
96 /* Opended ok! */
97 ioreq->IOPar.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
98 ioreq->IOPar.io_Error = 0;
99 ioreq->IOPar.io_Unit->unit_OpenCnt++;
101 /* Allow queuing */
102 ncp->ncp_FlushBuffer = FALSE;
103 ncp->ncp_DenyRequests = FALSE;
105 return base;
109 ioreq->IOPar.io_Unit = (APTR) -1;
110 ioreq->IOPar.io_Device = (APTR) -1;
111 base->np_Library.lib_OpenCnt--;
113 return(NULL);
115 AROS_LIBFUNC_EXIT
119 AROS_LH1(BPTR, devClose,
120 AROS_LHA(struct IOExtPar *, ioreq, A1),
121 DEVBASETYPEPTR, base, 2, dev)
123 AROS_LIBFUNC_INIT
125 BPTR ret;
126 struct NepClassPrinter *ncp = (struct NepClassPrinter *) ioreq->IOPar.io_Unit;
128 KPRINTF(10, ("devClose ioreq: 0x%08lx base: 0x%08lx\n", ioreq, base));
130 ret = BNULL;
131 /* Try to flush the last buffer */
132 Forbid();
133 ncp->ncp_FlushBuffer = TRUE;
134 if(ncp->ncp_Unit.unit_MsgPort.mp_SigTask)
136 Signal(ncp->ncp_Unit.unit_MsgPort.mp_SigTask, 1L<<(ncp->ncp_Unit.unit_MsgPort.mp_SigBit));
138 Permit();
140 /* Allow queuing */
141 ncp->ncp_DenyRequests = FALSE;
143 ncp->ncp_Unit.unit_OpenCnt--;
144 ioreq->IOPar.io_Unit = (APTR) -1;
145 ioreq->IOPar.io_Device = (APTR) -1;
147 if(--base->np_Library.lib_OpenCnt == 0)
149 if(base->np_Library.lib_Flags & LIBF_DELEXP)
151 KPRINTF(5, ("devClose: calling expunge...\n"));
152 ret = AROS_LC1(BPTR, devExpunge,
153 AROS_LCA(DEVBASETYPEPTR, base, D0),
154 DEVBASETYPEPTR, base, 3, dev);
158 KPRINTF(5, ("devClose: lib_OpenCnt = %ld\n", base->np_Library.lib_OpenCnt));
160 return(ret);
162 AROS_LIBFUNC_EXIT
166 AROS_LH1(BPTR, devExpunge,
167 AROS_LHA(DEVBASETYPEPTR, extralh, D0),
168 DEVBASETYPEPTR, base, 3, dev)
170 AROS_LIBFUNC_INIT
172 BPTR ret;
174 KPRINTF(10, ("devExpunge base: 0x%08lx\n", base));
176 ret = BNULL;
178 if(base->np_Library.lib_OpenCnt == 0)
180 KPRINTF(5, ("devExpunge: Unloading...\n"));
182 CloseLibrary(base->np_UtilityBase);
184 ret = base->np_SegList;
186 KPRINTF(5, ("devExpunge: removing device node 0x%08lx\n",
187 &base->np_Library.lib_Node));
188 Remove(&base->np_Library.lib_Node);
190 KPRINTF(5, ("devExpunge: FreeMem()...\n"));
191 FreeMem((char *) base - base->np_Library.lib_NegSize,
192 (ULONG) (base->np_Library.lib_NegSize + base->np_Library.lib_PosSize));
194 KPRINTF(5, ("devExpunge: Unloading done! " DEVNAME " expunged!\n\n"));
196 return(ret);
198 else
200 KPRINTF(5, ("devExpunge: Could not expunge, LIBF_DELEXP set!\n"));
201 base->np_Library.lib_Flags |= LIBF_DELEXP;
204 return(BNULL);
206 AROS_LIBFUNC_EXIT
209 AROS_LH0(DEVBASETYPEPTR, devReserved,
210 DEVBASETYPEPTR, base, 4, dev)
212 AROS_LIBFUNC_INIT
213 return NULL;
214 AROS_LIBFUNC_EXIT
217 AROS_LH1(void, devBeginIO,
218 AROS_LHA(struct IOExtPar *, ioreq, A1),
219 DEVBASETYPEPTR, base, 5, dev)
221 AROS_LIBFUNC_INIT
223 struct NepClassPrinter *ncp = (struct NepClassPrinter *) ioreq->IOPar.io_Unit;
224 WORD ret = IOERR_NOCMD;
226 KPRINTF(1, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu\n", ioreq, base, ioreq->IOPar.io_Command));
228 ioreq->IOPar.io_Message.mn_Node.ln_Type = NT_MESSAGE;
229 ioreq->IOPar.io_Error = 0;
231 if(ioreq->IOPar.io_Command < NSCMD_DEVICEQUERY)
233 switch (ioreq->IOPar.io_Command)
235 case CMD_READ:
236 if(ncp->ncp_EPInStream && (!ncp->ncp_DenyRequests))
238 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
239 Forbid();
240 AddTail(&ncp->ncp_ReadQueue, &ioreq->IOPar.io_Message.mn_Node);
241 if(ncp->ncp_Task)
243 Signal(ncp->ncp_Task, 1UL<<ncp->ncp_TaskMsgPort->mp_SigBit);
245 Permit();
246 ret = RC_DONTREPLY;
247 } else {
248 ret = IOERR_ABORTED;
250 break;
252 case CMD_WRITE:
253 if(!ncp->ncp_DenyRequests)
255 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
256 Forbid();
257 AddTail(&ncp->ncp_WriteQueue, &ioreq->IOPar.io_Message.mn_Node);
258 if(ncp->ncp_Task)
260 Signal(ncp->ncp_Task, 1UL<<ncp->ncp_TaskMsgPort->mp_SigBit);
262 Permit();
263 ret = RC_DONTREPLY;
264 } else {
265 ret = IOERR_ABORTED;
267 break;
269 case CMD_START:
270 ncp->ncp_DevSuspend = FALSE;
271 ret = RC_OK;
272 break;
274 case CMD_STOP:
275 ncp->ncp_DevSuspend = TRUE;
276 case PDCMD_SETPARAMS:
277 ret = RC_OK;
278 break;
280 case CMD_CLEAR:
281 case CMD_RESET:
282 case CMD_FLUSH:
283 case PDCMD_QUERY:
284 if(!ncp->ncp_DenyRequests)
286 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
287 ret = RC_DONTREPLY;
288 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
289 } else {
290 ret = IOERR_ABORTED;
292 break;
294 default:
295 ret = IOERR_NOCMD;
296 break;
298 } else {
299 switch(ioreq->IOPar.io_Command)
301 case NSCMD_DEVICEQUERY:
302 ret = cmdNSDeviceQuery((struct IOStdReq *) ioreq, ncp, base);
303 break;
305 default:
306 ret = IOERR_NOCMD;
307 break;
311 if(ret != RC_DONTREPLY)
313 KPRINTF(1, ("TermIO\n"));
314 if(ret != RC_OK)
316 /* Set error codes
318 ioreq->IOPar.io_Error = ret & 0xff;
320 /* Terminate the iorequest
322 TermIO(ioreq, base);
325 AROS_LIBFUNC_EXIT
328 AROS_LH1(LONG, devAbortIO,
329 AROS_LHA(struct IOExtPar *, ioreq, A1),
330 DEVBASETYPEPTR, base, 6, dev)
332 AROS_LIBFUNC_INIT
334 struct NepClassPrinter *ncp = (struct NepClassPrinter *) ioreq->IOPar.io_Unit;
335 struct IOExtPar *iocmp;
337 KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq));
339 /* Is it pending?
341 Forbid();
342 if(ioreq->IOPar.io_Message.mn_Node.ln_Type == NT_MESSAGE)
344 /* check if it's the writing pipe */
345 if(ioreq == ncp->ncp_WritePending)
347 if(ncp->ncp_AbortSignal >= 0)
349 /* prod the subtask */
350 Signal(ncp->ncp_Task, 1UL<<ncp->ncp_AbortSignal);
352 Permit();
353 return(0);
355 iocmp = (struct IOExtPar *) ncp->ncp_ReadQueue.lh_Head;
356 while(iocmp->IOPar.io_Message.mn_Node.ln_Succ)
358 if(iocmp == ioreq)
360 Remove((struct Node *) ioreq);
361 ioreq->IOPar.io_Error = IOERR_ABORTED;
362 ReplyMsg(&ioreq->IOPar.io_Message);
363 Permit();
364 return(0);
366 iocmp = (struct IOExtPar *) iocmp->IOPar.io_Message.mn_Node.ln_Succ;
368 iocmp = (struct IOExtPar *) ncp->ncp_WriteQueue.lh_Head;
369 while(iocmp->IOPar.io_Message.mn_Node.ln_Succ)
371 if(iocmp == ioreq)
373 Remove((struct Node *) ioreq);
374 ioreq->IOPar.io_Error = IOERR_ABORTED;
375 ReplyMsg(&ioreq->IOPar.io_Message);
376 Permit();
377 return(0);
379 iocmp = (struct IOExtPar *) iocmp->IOPar.io_Message.mn_Node.ln_Succ;
382 Permit();
383 return(-1);
385 AROS_LIBFUNC_EXIT
388 /* NSD stuff
391 static
392 const UWORD NSDSupported[] =
394 CMD_CLEAR, CMD_RESET,
395 CMD_FLUSH, CMD_READ,
396 CMD_WRITE, CMD_START,
397 CMD_STOP, PDCMD_QUERY,
398 PDCMD_SETPARAMS,
399 NSCMD_DEVICEQUERY, 0
402 WORD cmdNSDeviceQuery(struct IOStdReq *ioreq,
403 struct NepClassPrinter *ncp,
404 struct NepPrtDevBase *base)
406 struct my_NSDeviceQueryResult *query;
408 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
410 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq, query));
412 /* NULL ptr?
413 Enough data?
414 Valid request?
416 if((!query) ||
417 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
418 (query->DevQueryFormat != 0) ||
419 (query->SizeAvailable != 0))
421 /* Return error. This is special handling, since iorequest is only
422 guaranteed to be sizeof(struct IOStdReq). If we'd let our
423 devBeginIO dispatcher return the error, it would trash some
424 memory past end of the iorequest (ios2_WireError field).
426 ioreq->io_Error = IOERR_NOCMD;
427 TermIO((struct IOExtPar *) ioreq, base);
429 /* Don't reply, we already did.
431 return RC_DONTREPLY;
434 ioreq->io_Actual = query->SizeAvailable
435 = sizeof(struct my_NSDeviceQueryResult);
436 query->DeviceType = NSDEVTYPE_PARALLEL;
437 query->DeviceSubType = 0;
438 query->SupportedCommands = NSDSupported;
440 /* Return success (note that this will NOT poke ios2_WireError).
442 return RC_OK;
446 *===========================================================
447 * TermIO(ioreq, base)
448 *===========================================================
450 * Return completed ioreq to sender.
454 void TermIO(struct IOExtPar *ioreq,
455 struct NepPrtDevBase *base)
457 ioreq->IOPar.io_Message.mn_Node.ln_Type = NT_FREEMSG;
459 /* If not quick I/O, reply the message
461 if(!(ioreq->IOPar.io_Flags & IOF_QUICK))
463 ReplyMsg(&ioreq->IOPar.io_Message);