Fixed compatibility of output.
[AROS.git] / workbench / devs / parallel / parallel_init.c
blob7abc26d16fb660fbc4ae865b1faed01ebac061f5
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;
120 struct IOExtPar *iopar = (struct IOExtPar *)ioreq;
122 D(bug("parallel device: Open unit %d\n",unitnum));
124 if (ioreq->io_Message.mn_Length < sizeof(struct IOExtPar))
126 D(bug("parallel.device/open: IORequest structure passed to OpenDevice is too small!\n"));
127 ioreq->io_Error = IOERR_OPENFAIL;
128 return FALSE;
131 ioreq->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
133 /* In the list of available units look for the one with the same
134 UnitNumber as the given one */
135 if (0 == ioreq->io_Error)
137 PU = findUnit(ParallelDevice, unitnum);
139 /* If there is no such unit, yet, then create it */
140 if (NULL == PU)
142 D(bug("Creating Unit %d\n",unitnum));
143 PU = AllocMem(sizeof(struct ParallelUnit), MEMF_CLEAR|MEMF_PUBLIC);
144 if (NULL != PU)
146 PU->pu_OpenerCount = 1;
147 PU->pu_UnitNum = unitnum;
148 PU->pu_Flags = iopar->io_ParFlags;
151 ** Initialize the message ports
153 NEWLIST(&PU->pu_QReadCommandPort.mp_MsgList);
154 PU->pu_QReadCommandPort.mp_Node.ln_Type = NT_MSGPORT;
156 NEWLIST(&PU->pu_QWriteCommandPort.mp_MsgList);
157 PU->pu_QWriteCommandPort.mp_Node.ln_Type= NT_MSGPORT;
159 InitSemaphore(&PU->pu_Lock);
160 /* do further initilization here. Like getting the ParallelUnit Object etc. */
162 PU->pu_Unit = HIDD_Parallel_NewUnit(ParallelDevice->ParallelObject, unitnum);
163 if (NULL != PU->pu_Unit)
165 HIDD_ParallelUnit_Init(PU->pu_Unit, RBF_InterruptHandler, NULL, WBE_InterruptHandler, NULL);
166 ioreq->io_Device = (struct Device *)ParallelDevice;
167 ioreq->io_Unit = (struct Unit *)PU;
170 ** put it in the list of open units
172 AddHead(&ParallelDevice->UnitList, (struct Node *)PU);
174 ioreq->io_Error = 0;
176 D(bug("%s: Unit %d opened\n", __func__, unitnum));
177 return TRUE;
180 D(bug("ParallelUnit could not be created!\n"));
182 FreeMem(PU, sizeof(struct ParallelUnit));
184 ioreq->io_Error = ParErr_DevBusy;
187 else
189 /* the unit does already exist. */
191 ** Check whether one more opener to this unit is tolerated
193 if (0 != (PU->pu_Flags & PARF_SHARED))
196 ** This unit is in shared mode and one more opener
197 ** won't hurt.
199 ioreq->io_Device = (struct Device *)ParallelDevice;
200 ioreq->io_Unit = (struct Unit *)PU;
201 ioreq->io_Error = 0;
203 PU->pu_OpenerCount++;
205 else
208 ** I don't allow another opener
210 ioreq->io_Error = ParErr_DevBusy;
211 D(bug("%s: Unit %d already busy\n", __func__, unitnum));
216 return TRUE;
220 /****************************************************************************************/
222 static int GM_UNIQUENAME(Close)
224 LIBBASETYPEPTR ParallelDevice,
225 struct IORequest *ioreq
228 struct ParallelUnit * PU = (struct ParallelUnit *)ioreq->io_Unit;
231 ** Check whether I am the last opener to this unit
233 if (1 == PU->pu_OpenerCount)
236 ** I was the last opener. So let's get rid of it.
239 ** Remove the unit from the list
241 Remove((struct Node *)&PU->pu_Node);
243 HIDD_Parallel_DisposeUnit(ParallelDevice->ParallelObject, PU->pu_Unit);
245 FreeMem(PU, sizeof(struct ParallelUnit));
248 else
251 ** There are still openers. Decrease the counter.
253 PU->pu_OpenerCount--;
256 return TRUE;
259 /****************************************************************************************/
261 static int GM_UNIQUENAME(Expunge)(LIBBASETYPEPTR ParallelDevice)
263 if (NULL != ParallelDevice->ParallelObject)
266 ** Throw away the HIDD object and close the library
268 OOP_DisposeObject(ParallelDevice->ParallelObject);
269 CloseLibrary(ParallelDevice->ParallelHidd);
270 ParallelDevice->ParallelHidd = NULL;
271 ParallelDevice->ParallelObject = NULL;
273 if (ParallelDevice->oopBase) CloseLibrary(ParallelDevice->oopBase);
275 return TRUE;
278 /****************************************************************************************/
280 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
281 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge), 0)
282 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
283 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
285 /****************************************************************************************/
287 #define ioStd(x) ((struct IOStdReq *)x)
288 AROS_LH1(void, beginio,
289 AROS_LHA(struct IOExtPar *, ioreq, A1),
290 struct parallelbase *, ParallelDevice, 5, Parallel)
292 AROS_LIBFUNC_INIT
294 struct ParallelUnit * PU = (struct ParallelUnit *)ioreq->IOPar.io_Unit;
296 D(bug("parallel device: beginio(ioreq=%p)\n", ioreq));
298 /* WaitIO will look into this */
299 ioreq->IOPar.io_Message.mn_Node.ln_Type=NT_MESSAGE;
302 ** As a lot of "public" data can be modified in the following lines
303 ** I protect it from other tasks by this semaphore
305 ObtainSemaphore(&PU->pu_Lock);
307 switch (ioreq->IOPar.io_Command)
309 #if NEWSTYLE_DEVICE
310 case NSCMD_DEVICEQUERY:
311 if(ioreq->IOPar.io_Length < ((IPTR)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
313 ioreq->IOPar.io_Error = IOERR_BADLENGTH;
315 else
317 struct NSDeviceQueryResult *d;
319 d = (struct NSDeviceQueryResult *)ioreq->IOPar.io_Data;
321 d->DevQueryFormat = 0;
322 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
323 d->DeviceType = NSDEVTYPE_PARALLEL;
324 d->DeviceSubType = 0;
325 d->SupportedCommands = (UWORD *)SupportedCommands;
327 ioreq->IOPar.io_Actual = sizeof(struct NSDeviceQueryResult);
328 ioreq->IOPar.io_Error = 0;
331 ** The request could be completed immediately.
332 ** Check if I have to reply the message
334 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
335 ReplyMsg(&ioreq->IOPar.io_Message);
337 break;
338 #endif
340 /*******************************************************************/
341 case CMD_READ:
343 ** Let me see whether I can copy any data at all and
344 ** whether nobody else is using this device now
346 ioreq->IOPar.io_Actual = 0;
348 Disable();
350 PU->pu_Status |= STATUS_READS_PENDING;
351 D(bug("Queuing the read request.\n"));
353 ** Everything that falls down here could not be completely
354 ** satisfied
356 if (NULL == PU->pu_ActiveRead)
357 PU->pu_ActiveRead = &ioreq->IOPar.io_Message;
358 else
359 PutMsg(&PU->pu_QReadCommandPort,
360 &ioreq->IOPar.io_Message);
362 Enable();
364 ** As I am returning immediately I will tell that this
365 ** could not be done QUICK
367 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
368 break;
370 /*******************************************************************/
372 case CMD_WRITE:
373 /* Write data to the ParallelUnit */
374 ioreq->IOPar.io_Actual = 0;
376 Disable();
378 /* Check whether I can write some data immediately */
379 if (0 == (PU->pu_Status & STATUS_WRITES_PENDING))
381 ULONG writtenbytes;
382 BOOL complete = FALSE;
384 Writing the first few bytes to the UART has to have the
385 effect that whenever the UART can receive new data
386 a HW interrupt must happen. So this writing to the
387 UART should get the sequence of HW-interrupts going
388 until there is no more data to write
390 if (-1 == ioreq->IOPar.io_Length)
392 int stringlen = strlen(ioreq->IOPar.io_Data);
393 D(bug("Transmitting NULL termninated string.\n"));
395 ** Supposed to write the buffer to the port until a '\0'
396 ** is encountered.
399 writtenbytes = HIDD_ParallelUnit_Write(PU->pu_Unit,
400 ioreq->IOPar.io_Data,
401 stringlen);
402 if (writtenbytes == stringlen)
403 complete = TRUE;
404 else
405 PU->pu_WriteLength = stringlen-writtenbytes;
407 else
409 writtenbytes = HIDD_ParallelUnit_Write(PU->pu_Unit,
410 ioreq->IOPar.io_Data,
411 ioreq->IOPar.io_Length);
412 if (writtenbytes == ioreq->IOPar.io_Length)
413 complete = TRUE;
414 else
415 PU->pu_WriteLength = ioreq->IOPar.io_Length-writtenbytes;
418 ** A consistency check between the STATUS_WRITES_PENDING flag
419 ** and the pointer PU->pu_ActiveWrite which both have to be
420 ** set or cleared at the same time.
422 if (NULL != PU->pu_ActiveWrite)
424 D(bug("error!!"));
427 if (complete == TRUE)
429 D(bug("completely sended the stream!\n"));
431 ** The request could be completed immediately.
432 ** Check if I have to reply the message
434 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
435 ReplyMsg(&ioreq->IOPar.io_Message);
437 else
440 ** The request could not be completed immediately
441 ** Clear the flag.
443 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
444 PU->pu_ActiveWrite = (struct Message *)ioreq;
445 PU->pu_Status |= STATUS_WRITES_PENDING;
446 PU->pu_NextToWrite = writtenbytes;
449 else
452 I could not write the data immediately as another request
453 is already there. So I will make this
454 the responsibility of the interrupt handler to use this
455 request once it is done with the active request.
457 PutMsg(&PU->pu_QWriteCommandPort,
458 (struct Message *)ioreq);
459 PU->pu_Status |= STATUS_WRITES_PENDING;
461 ** As I am returning immediately I will tell that this
462 ** could not be done QUICK
464 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
467 Enable();
468 break;
470 case CMD_CLEAR:
471 /* Simply reset the input buffer pointer no matter what */
472 ioreq->IOPar.io_Error = 0;
474 ** The request could be completed immediately.
475 ** Check if I have to reply the message
477 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
478 ReplyMsg(&ioreq->IOPar.io_Message);
479 break;
481 /*******************************************************************/
483 case CMD_RESET:
484 Disable();
485 /* All IORequests, including the active ones, are aborted */
487 /* Abort the active IORequests */
488 PU->pu_Status &= ~(STATUS_READS_PENDING|STATUS_WRITES_PENDING);
490 if (NULL != PU->pu_ActiveRead)
492 ((struct IOStdReq *)PU->pu_ActiveRead)->io_Error = IOERR_ABORTED;
493 ReplyMsg(PU->pu_ActiveRead);
496 if (NULL != PU->pu_ActiveWrite)
498 ((struct IOStdReq *)PU->pu_ActiveWrite)->io_Error = IOERR_ABORTED;
499 ReplyMsg(PU->pu_ActiveWrite);
501 Enable();
503 /*******************************************************************/
505 case CMD_FLUSH:
507 ** Clear all queued IO request for the given parallel unit except
508 ** for the active ones.
510 Disable();
512 while (TRUE)
514 struct IOStdReq * iopreq =
515 (struct IOStdReq *)GetMsg(&PU->pu_QReadCommandPort);
516 if (NULL == iopreq)
517 break;
518 iopreq->io_Error = IOERR_ABORTED;
519 ReplyMsg((struct Message *)iopreq);
522 while (TRUE)
524 struct IOStdReq * iopreq =
525 (struct IOStdReq *)GetMsg(&PU->pu_QWriteCommandPort);
526 if (NULL == iopreq)
527 break;
528 iopreq->io_Error = IOERR_ABORTED;
529 ReplyMsg((struct Message *)iopreq);
531 ioreq->IOPar.io_Error = 0;
533 Enable();
535 ** The request could be completed immediately.
536 ** Check if I have to reply the message
538 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
539 ReplyMsg(&ioreq->IOPar.io_Message);
540 break;
542 /*******************************************************************/
544 case CMD_START:
545 break;
547 /*******************************************************************/
549 case CMD_STOP:
550 break;
552 /*******************************************************************/
554 case PDCMD_QUERY:
556 PU->pu_Status = 0;
559 ** set the io_Status to the status of the parallel port
561 // !!! missing code
562 ioreq->io_Status = 0;
565 ** The request could be completed immediately.
566 ** Check if I have to reply the message
568 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
569 ReplyMsg(&ioreq->IOPar.io_Message);
571 break;
573 /*******************************************************************/
575 case PDCMD_SETPARAMS:
577 /* Change of buffer size for input buffer? */
580 /* Copy the Flags from the iorequest to the Unit's Flags */
581 PU->pu_Flags = ioreq->io_ParFlags;
583 /* Copy the TermArray */
584 PU->pu_PTermArray = ioreq->io_PTermArray;
587 ** The request could be completed immediately.
588 ** Check if I have to reply the message
590 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
591 ReplyMsg(&ioreq->IOPar.io_Message);
592 break;
594 /*******************************************************************/
596 default:
597 /* unknown command */
598 ioreq->IOPar.io_Error = IOERR_NOCMD;
601 ** The request could be completed immediately.
602 ** Check if I have to reply the message
604 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
605 ReplyMsg(&ioreq->IOPar.io_Message);
607 } /* switch () */
609 ReleaseSemaphore(&PU->pu_Lock);
611 D(bug("id: Return from BeginIO()\n"));
613 AROS_LIBFUNC_EXIT
616 /****************************************************************************************/
618 AROS_LH1(LONG, abortio,
619 AROS_LHA(struct IORequest *, ioreq, A1),
620 struct parallelbase *, ParallelDevice, 6, Parallel)
622 AROS_LIBFUNC_INIT
624 struct ParallelUnit * PU = (struct ParallelUnit *)ioreq->io_Unit;
627 ** is it the active request?
630 Disable();
631 if ((struct Message *)ioreq == PU->pu_ActiveRead)
634 ** It's the active reuquest. I make the next available
635 ** one the active request.
637 PU->pu_ActiveRead = GetMsg(&PU->pu_QReadCommandPort);
638 ReplyMsg(&ioreq->io_Message);
640 else
643 ** It's not the active request. So I'll take it out of the
644 ** list of queued messages and reply the message.
646 Remove(&ioreq->io_Message.mn_Node);
647 ReplyMsg(&ioreq->io_Message);
649 Enable();
651 return 0;
652 AROS_LIBFUNC_EXIT
655 /****************************************************************************************/