parallel.device: Clean up DEBUG
[AROS.git] / workbench / devs / parallel / parallel_init.c
blob93b0e4de0c4aa6efbaf0769f17009c1feeb7bef5
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Parallel device
6 Lang: English
7 */
9 /****************************************************************************************/
12 #include <string.h>
14 #include <exec/resident.h>
15 #include <exec/interrupts.h>
16 #include <exec/semaphores.h>
17 #include <exec/initializers.h>
18 #include <devices/parallel.h>
19 #include <devices/newstyle.h>
20 #include <proto/exec.h>
21 #include <proto/dos.h>
22 #include <proto/input.h>
23 #include <proto/oop.h>
24 #include <proto/utility.h>
25 #include <exec/memory.h>
26 #include <exec/errors.h>
27 #include <oop/oop.h>
28 #include <hidd/parallel.h>
29 #include <utility/tagitem.h>
30 #include <aros/libcall.h>
31 #include <aros/symbolsets.h>
32 #include <exec/lists.h>
33 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
34 # include "parallel_intern.h"
35 #endif
37 #include <aros/debug.h>
39 #include LC_LIBDEFS_FILE
41 /****************************************************************************************/
43 #define NEWSTYLE_DEVICE 1
45 struct parallelbase * pubParallelBase;
47 /****************************************************************************************/
49 #if NEWSTYLE_DEVICE
51 static const UWORD SupportedCommands[] =
53 CMD_READ,
54 CMD_WRITE,
55 CMD_CLEAR,
56 CMD_RESET,
57 CMD_FLUSH,
58 PDCMD_QUERY,
59 PDCMD_SETPARAMS,
60 NSCMD_DEVICEQUERY,
64 #endif
66 /****************************************************************************************/
68 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR ParallelDevice)
70 D(bug("parallel device: init\n"));
72 pubParallelBase = ParallelDevice;
74 /* open the parallel hidd */
75 if (NULL == ParallelDevice->ParallelHidd)
77 ParallelDevice->ParallelHidd = OpenLibrary("DRIVERS:parallel.hidd",0);
78 D(bug("parallel.hidd base: 0x%x\n",ParallelDevice->ParallelHidd));
80 if (NULL == ParallelDevice->ParallelHidd)
81 return FALSE;
83 if (NULL == ParallelDevice->oopBase)
84 ParallelDevice->oopBase = OpenLibrary(AROSOOP_NAME, 0);
85 if (NULL == ParallelDevice->oopBase)
87 CloseLibrary(ParallelDevice->ParallelHidd);
88 ParallelDevice->ParallelHidd = NULL;
89 return FALSE;
92 ParallelDevice->ParallelObject = OOP_NewObject(NULL, CLID_Hidd_Parallel, NULL);
94 if (NULL == ParallelDevice->ParallelObject)
96 CloseLibrary(ParallelDevice->oopBase);
97 ParallelDevice->oopBase = NULL;
98 CloseLibrary(ParallelDevice->ParallelHidd);
99 ParallelDevice->ParallelHidd = NULL;
100 return FALSE;
104 NEWLIST(&ParallelDevice->UnitList);
105 return TRUE;
109 /****************************************************************************************/
111 static int GM_UNIQUENAME(Open)
113 LIBBASETYPEPTR ParallelDevice,
114 struct IORequest *ioreq,
115 ULONG unitnum,
116 ULONG flags
119 struct ParallelUnit * PU = NULL;
121 D(bug("parallel device: Open unit %d\n",unitnum));
123 if (ioreq->io_Message.mn_Length < sizeof(struct IOExtPar))
125 D(bug("parallel.device/open: IORequest structure passed to OpenDevice is too small!\n"));
126 ioreq->io_Error = IOERR_OPENFAIL;
127 return FALSE;
130 ioreq->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
132 /* In the list of available units look for the one with the same
133 UnitNumber as the given one */
134 if (0 == ioreq->io_Error)
136 PU = findUnit(ParallelDevice, unitnum);
138 /* If there is no such unit, yet, then create it */
139 if (NULL == PU)
141 D(bug("Creating Unit %d\n",unitnum));
142 PU = AllocMem(sizeof(struct ParallelUnit), MEMF_CLEAR|MEMF_PUBLIC);
143 if (NULL != PU)
145 PU->pu_OpenerCount = 1;
146 PU->pu_UnitNum = unitnum;
147 PU->pu_Flags = ioreq->io_Flags;
150 ** Initialize the message ports
152 NEWLIST(&PU->pu_QReadCommandPort.mp_MsgList);
153 PU->pu_QReadCommandPort.mp_Node.ln_Type = NT_MSGPORT;
155 NEWLIST(&PU->pu_QWriteCommandPort.mp_MsgList);
156 PU->pu_QWriteCommandPort.mp_Node.ln_Type= NT_MSGPORT;
158 InitSemaphore(&PU->pu_Lock);
159 /* do further initilization here. Like getting the ParallelUnit Object etc. */
161 PU->pu_Unit = HIDD_Parallel_NewUnit(ParallelDevice->ParallelObject, unitnum);
162 if (NULL != PU->pu_Unit)
164 HIDD_ParallelUnit_Init(PU->pu_Unit, RBF_InterruptHandler, NULL, WBE_InterruptHandler, NULL);
165 ioreq->io_Device = (struct Device *)ParallelDevice;
166 ioreq->io_Unit = (struct Unit *)PU;
169 ** put it in the list of open units
171 AddHead(&ParallelDevice->UnitList, (struct Node *)PU);
173 ioreq->io_Error = 0;
175 D(bug("%s: Unit %d opened\n", __func__, unitnum));
176 return TRUE;
179 D(bug("ParallelUnit could not be created!\n"));
181 FreeMem(PU, sizeof(struct ParallelUnit));
183 ioreq->io_Error = ParErr_DevBusy;
186 else
188 /* the unit does already exist. */
190 ** Check whether one more opener to this unit is tolerated
192 if (0 != (PU->pu_Flags & PARF_SHARED))
195 ** This unit is in shared mode and one more opener
196 ** won't hurt.
198 ioreq->io_Device = (struct Device *)ParallelDevice;
199 ioreq->io_Unit = (struct Unit *)PU;
200 ioreq->io_Error = 0;
202 PU->pu_OpenerCount++;
204 else
207 ** I don't allow another opener
209 ioreq->io_Error = ParErr_DevBusy;
210 D(bug("%s: Unit %d already busy\n", __func__, unitnum));
215 return TRUE;
219 /****************************************************************************************/
221 static int GM_UNIQUENAME(Close)
223 LIBBASETYPEPTR ParallelDevice,
224 struct IORequest *ioreq
227 struct ParallelUnit * PU = (struct ParallelUnit *)ioreq->io_Unit;
230 ** Check whether I am the last opener to this unit
232 if (1 == PU->pu_OpenerCount)
235 ** I was the last opener. So let's get rid of it.
238 ** Remove the unit from the list
240 Remove((struct Node *)&PU->pu_Node);
242 HIDD_Parallel_DisposeUnit(ParallelDevice->ParallelObject, PU->pu_Unit);
244 FreeMem(PU, sizeof(struct ParallelUnit));
247 else
250 ** There are still openers. Decrease the counter.
252 PU->pu_OpenerCount--;
255 return TRUE;
258 /****************************************************************************************/
260 static int GM_UNIQUENAME(Expunge)(LIBBASETYPEPTR ParallelDevice)
262 if (NULL != ParallelDevice->ParallelObject)
265 ** Throw away the HIDD object and close the library
267 OOP_DisposeObject(ParallelDevice->ParallelObject);
268 CloseLibrary(ParallelDevice->ParallelHidd);
269 ParallelDevice->ParallelHidd = NULL;
270 ParallelDevice->ParallelObject = NULL;
272 if (ParallelDevice->oopBase) CloseLibrary(ParallelDevice->oopBase);
274 return TRUE;
277 /****************************************************************************************/
279 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
280 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge), 0)
281 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
282 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
284 /****************************************************************************************/
286 #define ioStd(x) ((struct IOStdReq *)x)
287 AROS_LH1(void, beginio,
288 AROS_LHA(struct IOExtPar *, ioreq, A1),
289 struct parallelbase *, ParallelDevice, 5, Parallel)
291 AROS_LIBFUNC_INIT
293 struct ParallelUnit * PU = (struct ParallelUnit *)ioreq->IOPar.io_Unit;
295 D(bug("parallel device: beginio(ioreq=%p)\n", ioreq));
297 /* WaitIO will look into this */
298 ioreq->IOPar.io_Message.mn_Node.ln_Type=NT_MESSAGE;
301 ** As a lot of "public" data can be modified in the following lines
302 ** I protect it from other tasks by this semaphore
304 ObtainSemaphore(&PU->pu_Lock);
306 switch (ioreq->IOPar.io_Command)
308 #if NEWSTYLE_DEVICE
309 case NSCMD_DEVICEQUERY:
310 if(ioreq->IOPar.io_Length < ((IPTR)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
312 ioreq->IOPar.io_Error = IOERR_BADLENGTH;
314 else
316 struct NSDeviceQueryResult *d;
318 d = (struct NSDeviceQueryResult *)ioreq->IOPar.io_Data;
320 d->DevQueryFormat = 0;
321 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
322 d->DeviceType = NSDEVTYPE_PARALLEL;
323 d->DeviceSubType = 0;
324 d->SupportedCommands = (UWORD *)SupportedCommands;
326 ioreq->IOPar.io_Actual = sizeof(struct NSDeviceQueryResult);
327 ioreq->IOPar.io_Error = 0;
330 ** The request could be completed immediately.
331 ** Check if I have to reply the message
333 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
334 ReplyMsg(&ioreq->IOPar.io_Message);
336 break;
337 #endif
339 /*******************************************************************/
340 case CMD_READ:
342 ** Let me see whether I can copy any data at all and
343 ** whether nobody else is using this device now
345 ioreq->IOPar.io_Actual = 0;
347 Disable();
349 PU->pu_Status |= STATUS_READS_PENDING;
350 D(bug("Queuing the read request.\n"));
352 ** Everything that falls down here could not be completely
353 ** satisfied
355 if (NULL == PU->pu_ActiveRead)
356 PU->pu_ActiveRead = &ioreq->IOPar.io_Message;
357 else
358 PutMsg(&PU->pu_QReadCommandPort,
359 &ioreq->IOPar.io_Message);
361 Enable();
363 ** As I am returning immediately I will tell that this
364 ** could not be done QUICK
366 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
367 break;
369 /*******************************************************************/
371 case CMD_WRITE:
372 /* Write data to the ParallelUnit */
373 ioreq->IOPar.io_Actual = 0;
375 Disable();
377 /* Check whether I can write some data immediately */
378 if (0 == (PU->pu_Status & STATUS_WRITES_PENDING))
380 ULONG writtenbytes;
381 BOOL complete = FALSE;
383 Writing the first few bytes to the UART has to have the
384 effect that whenever the UART can receive new data
385 a HW interrupt must happen. So this writing to the
386 UART should get the sequence of HW-interrupts going
387 until there is no more data to write
389 if (-1 == ioreq->IOPar.io_Length)
391 int stringlen = strlen(ioreq->IOPar.io_Data);
392 D(bug("Transmitting NULL termninated string.\n"));
394 ** Supposed to write the buffer to the port until a '\0'
395 ** is encountered.
398 writtenbytes = HIDD_ParallelUnit_Write(PU->pu_Unit,
399 ioreq->IOPar.io_Data,
400 stringlen);
401 if (writtenbytes == stringlen)
402 complete = TRUE;
403 else
404 PU->pu_WriteLength = stringlen-writtenbytes;
406 else
408 writtenbytes = HIDD_ParallelUnit_Write(PU->pu_Unit,
409 ioreq->IOPar.io_Data,
410 ioreq->IOPar.io_Length);
411 if (writtenbytes == ioreq->IOPar.io_Length)
412 complete = TRUE;
413 else
414 PU->pu_WriteLength = ioreq->IOPar.io_Length-writtenbytes;
417 ** A consistency check between the STATUS_WRITES_PENDING flag
418 ** and the pointer PU->pu_ActiveWrite which both have to be
419 ** set or cleared at the same time.
421 if (NULL != PU->pu_ActiveWrite)
423 D(bug("error!!"));
426 if (complete == TRUE)
428 D(bug("completely sended the stream!\n"));
430 ** The request could be completed immediately.
431 ** Check if I have to reply the message
433 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
434 ReplyMsg(&ioreq->IOPar.io_Message);
436 else
439 ** The request could not be completed immediately
440 ** Clear the flag.
442 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
443 PU->pu_ActiveWrite = (struct Message *)ioreq;
444 PU->pu_Status |= STATUS_WRITES_PENDING;
445 PU->pu_NextToWrite = writtenbytes;
448 else
451 I could not write the data immediately as another request
452 is already there. So I will make this
453 the responsibility of the interrupt handler to use this
454 request once it is done with the active request.
456 PutMsg(&PU->pu_QWriteCommandPort,
457 (struct Message *)ioreq);
458 PU->pu_Status |= STATUS_WRITES_PENDING;
460 ** As I am returning immediately I will tell that this
461 ** could not be done QUICK
463 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
466 Enable();
467 break;
469 case CMD_CLEAR:
470 /* Simply reset the input buffer pointer no matter what */
471 ioreq->IOPar.io_Error = 0;
473 ** The request could be completed immediately.
474 ** Check if I have to reply the message
476 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
477 ReplyMsg(&ioreq->IOPar.io_Message);
478 break;
480 /*******************************************************************/
482 case CMD_RESET:
483 Disable();
484 /* All IORequests, including the active ones, are aborted */
486 /* Abort the active IORequests */
487 PU->pu_Status &= ~(STATUS_READS_PENDING|STATUS_WRITES_PENDING);
489 if (NULL != PU->pu_ActiveRead)
491 ((struct IOStdReq *)PU->pu_ActiveRead)->io_Error = IOERR_ABORTED;
492 ReplyMsg(PU->pu_ActiveRead);
495 if (NULL != PU->pu_ActiveWrite)
497 ((struct IOStdReq *)PU->pu_ActiveWrite)->io_Error = IOERR_ABORTED;
498 ReplyMsg(PU->pu_ActiveWrite);
500 Enable();
502 /*******************************************************************/
504 case CMD_FLUSH:
506 ** Clear all queued IO request for the given parallel unit except
507 ** for the active ones.
509 Disable();
511 while (TRUE)
513 struct IOStdReq * iopreq =
514 (struct IOStdReq *)GetMsg(&PU->pu_QReadCommandPort);
515 if (NULL == iopreq)
516 break;
517 iopreq->io_Error = IOERR_ABORTED;
518 ReplyMsg((struct Message *)iopreq);
521 while (TRUE)
523 struct IOStdReq * iopreq =
524 (struct IOStdReq *)GetMsg(&PU->pu_QWriteCommandPort);
525 if (NULL == iopreq)
526 break;
527 iopreq->io_Error = IOERR_ABORTED;
528 ReplyMsg((struct Message *)iopreq);
530 ioreq->IOPar.io_Error = 0;
532 Enable();
534 ** The request could be completed immediately.
535 ** Check if I have to reply the message
537 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
538 ReplyMsg(&ioreq->IOPar.io_Message);
539 break;
541 /*******************************************************************/
543 case CMD_START:
544 break;
546 /*******************************************************************/
548 case CMD_STOP:
549 break;
551 /*******************************************************************/
553 case PDCMD_QUERY:
555 PU->pu_Status = 0;
558 ** set the io_Status to the status of the parallel port
560 // !!! missing code
561 ioreq->io_Status = 0;
564 ** The request could be completed immediately.
565 ** Check if I have to reply the message
567 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
568 ReplyMsg(&ioreq->IOPar.io_Message);
570 break;
572 /*******************************************************************/
574 case PDCMD_SETPARAMS:
576 /* Change of buffer size for input buffer? */
579 /* Copy the Flags from the iorequest to the Unit's Flags */
580 PU->pu_Flags = ioreq->io_ParFlags;
582 /* Copy the TermArray */
583 PU->pu_PTermArray = ioreq->io_PTermArray;
586 ** The request could be completed immediately.
587 ** Check if I have to reply the message
589 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
590 ReplyMsg(&ioreq->IOPar.io_Message);
591 break;
593 /*******************************************************************/
595 default:
596 /* unknown command */
597 ioreq->IOPar.io_Error = IOERR_NOCMD;
600 ** The request could be completed immediately.
601 ** Check if I have to reply the message
603 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
604 ReplyMsg(&ioreq->IOPar.io_Message);
606 } /* switch () */
608 ReleaseSemaphore(&PU->pu_Lock);
610 D(bug("id: Return from BeginIO()\n"));
612 AROS_LIBFUNC_EXIT
615 /****************************************************************************************/
617 AROS_LH1(LONG, abortio,
618 AROS_LHA(struct IORequest *, ioreq, A1),
619 struct parallelbase *, ParallelDevice, 6, Parallel)
621 AROS_LIBFUNC_INIT
623 struct ParallelUnit * PU = (struct ParallelUnit *)ioreq->io_Unit;
626 ** is it the active request?
629 Disable();
630 if ((struct Message *)ioreq == PU->pu_ActiveRead)
633 ** It's the active reuquest. I make the next available
634 ** one the active request.
636 PU->pu_ActiveRead = GetMsg(&PU->pu_QReadCommandPort);
637 ReplyMsg(&ioreq->io_Message);
639 else
642 ** It's not the active request. So I'll take it out of the
643 ** list of queued messages and reply the message.
645 Remove(&ioreq->io_Message.mn_Node);
646 ReplyMsg(&ioreq->io_Message);
648 Enable();
650 return 0;
651 AROS_LIBFUNC_EXIT
654 /****************************************************************************************/