fix __AROS_SETVECADDR invocations.
[AROS.git] / workbench / devs / parallel / parallel_init.c
blob42ef30c90ababaced9202553d24f9e53513017a1
1 /*
2 Copyright © 1995-2017, 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 memset( &PU->pu_QReadCommandPort, 0, sizeof( PU->pu_QReadCommandPort ) );
154 NEWLIST(&PU->pu_QReadCommandPort.mp_MsgList);
155 PU->pu_QReadCommandPort.mp_Node.ln_Type = NT_MSGPORT;
157 memset( &PU->pu_QWriteCommandPort, 0, sizeof( PU->pu_QWriteCommandPort ) );
158 NEWLIST(&PU->pu_QWriteCommandPort.mp_MsgList);
159 PU->pu_QWriteCommandPort.mp_Node.ln_Type= NT_MSGPORT;
161 InitSemaphore(&PU->pu_Lock);
162 /* do further initilization here. Like getting the ParallelUnit Object etc. */
164 PU->pu_Unit = HIDD_Parallel_NewUnit(ParallelDevice->ParallelObject, unitnum);
165 if (NULL != PU->pu_Unit)
167 HIDD_ParallelUnit_Init(PU->pu_Unit, RBF_InterruptHandler, NULL, WBE_InterruptHandler, NULL);
168 ioreq->io_Device = (struct Device *)ParallelDevice;
169 ioreq->io_Unit = (struct Unit *)PU;
172 ** put it in the list of open units
174 AddHead(&ParallelDevice->UnitList, (struct Node *)PU);
176 ioreq->io_Error = 0;
178 D(bug("%s: Unit %d opened\n", __func__, unitnum));
179 return TRUE;
182 D(bug("ParallelUnit could not be created!\n"));
184 FreeMem(PU, sizeof(struct ParallelUnit));
186 ioreq->io_Error = ParErr_DevBusy;
189 else
191 /* the unit does already exist. */
193 ** Check whether one more opener to this unit is tolerated
195 if (0 != (PU->pu_Flags & PARF_SHARED))
198 ** This unit is in shared mode and one more opener
199 ** won't hurt.
201 ioreq->io_Device = (struct Device *)ParallelDevice;
202 ioreq->io_Unit = (struct Unit *)PU;
203 ioreq->io_Error = 0;
205 PU->pu_OpenerCount++;
207 else
210 ** I don't allow another opener
212 ioreq->io_Error = ParErr_DevBusy;
213 D(bug("%s: Unit %d already busy\n", __func__, unitnum));
218 return TRUE;
222 /****************************************************************************************/
224 static int GM_UNIQUENAME(Close)
226 LIBBASETYPEPTR ParallelDevice,
227 struct IORequest *ioreq
230 struct ParallelUnit * PU = (struct ParallelUnit *)ioreq->io_Unit;
233 ** Check whether I am the last opener to this unit
235 if (1 == PU->pu_OpenerCount)
238 ** I was the last opener. So let's get rid of it.
241 ** Remove the unit from the list
243 Remove((struct Node *)&PU->pu_Node);
245 HIDD_Parallel_DisposeUnit(ParallelDevice->ParallelObject, PU->pu_Unit);
247 FreeMem(PU, sizeof(struct ParallelUnit));
250 else
253 ** There are still openers. Decrease the counter.
255 PU->pu_OpenerCount--;
258 return TRUE;
261 /****************************************************************************************/
263 static int GM_UNIQUENAME(Expunge)(LIBBASETYPEPTR ParallelDevice)
265 if (NULL != ParallelDevice->ParallelObject)
268 ** Throw away the HIDD object and close the library
270 OOP_DisposeObject(ParallelDevice->ParallelObject);
271 CloseLibrary(ParallelDevice->ParallelHidd);
272 ParallelDevice->ParallelHidd = NULL;
273 ParallelDevice->ParallelObject = NULL;
275 if (ParallelDevice->oopBase) CloseLibrary(ParallelDevice->oopBase);
277 return TRUE;
280 /****************************************************************************************/
282 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
283 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge), 0)
284 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
285 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
287 /****************************************************************************************/
289 #define ioStd(x) ((struct IOStdReq *)x)
290 AROS_LH1(void, beginio,
291 AROS_LHA(struct IOExtPar *, ioreq, A1),
292 struct parallelbase *, ParallelDevice, 5, Parallel)
294 AROS_LIBFUNC_INIT
296 struct ParallelUnit * PU = (struct ParallelUnit *)ioreq->IOPar.io_Unit;
298 D(bug("parallel device: beginio(ioreq=%p)\n", ioreq));
300 /* WaitIO will look into this */
301 ioreq->IOPar.io_Message.mn_Node.ln_Type=NT_MESSAGE;
304 ** As a lot of "public" data can be modified in the following lines
305 ** I protect it from other tasks by this semaphore
307 ObtainSemaphore(&PU->pu_Lock);
309 switch (ioreq->IOPar.io_Command)
311 #if NEWSTYLE_DEVICE
312 case NSCMD_DEVICEQUERY:
313 if(ioreq->IOPar.io_Length < ((IPTR)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
315 ioreq->IOPar.io_Error = IOERR_BADLENGTH;
317 else
319 struct NSDeviceQueryResult *d;
321 d = (struct NSDeviceQueryResult *)ioreq->IOPar.io_Data;
323 d->DevQueryFormat = 0;
324 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
325 d->DeviceType = NSDEVTYPE_PARALLEL;
326 d->DeviceSubType = 0;
327 d->SupportedCommands = (UWORD *)SupportedCommands;
329 ioreq->IOPar.io_Actual = sizeof(struct NSDeviceQueryResult);
330 ioreq->IOPar.io_Error = 0;
333 ** The request could be completed immediately.
334 ** Check if I have to reply the message
336 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
337 ReplyMsg(&ioreq->IOPar.io_Message);
339 break;
340 #endif
342 /*******************************************************************/
343 case CMD_READ:
345 ** Let me see whether I can copy any data at all and
346 ** whether nobody else is using this device now
348 ioreq->IOPar.io_Actual = 0;
350 Disable();
352 PU->pu_Status |= STATUS_READS_PENDING;
353 D(bug("Queuing the read request.\n"));
355 ** Everything that falls down here could not be completely
356 ** satisfied
358 if (NULL == PU->pu_ActiveRead)
359 PU->pu_ActiveRead = &ioreq->IOPar.io_Message;
360 else
361 PutMsg(&PU->pu_QReadCommandPort,
362 &ioreq->IOPar.io_Message);
364 Enable();
366 ** As I am returning immediately I will tell that this
367 ** could not be done QUICK
369 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
370 break;
372 /*******************************************************************/
374 case CMD_WRITE:
375 /* Write data to the ParallelUnit */
376 ioreq->IOPar.io_Actual = 0;
378 Disable();
380 /* Check whether I can write some data immediately */
381 if (0 == (PU->pu_Status & STATUS_WRITES_PENDING))
383 ULONG writtenbytes;
384 BOOL complete = FALSE;
386 Writing the first few bytes to the UART has to have the
387 effect that whenever the UART can receive new data
388 a HW interrupt must happen. So this writing to the
389 UART should get the sequence of HW-interrupts going
390 until there is no more data to write
392 if (-1 == ioreq->IOPar.io_Length)
394 int stringlen = strlen(ioreq->IOPar.io_Data);
395 D(bug("Transmitting NULL termninated string.\n"));
397 ** Supposed to write the buffer to the port until a '\0'
398 ** is encountered.
401 writtenbytes = HIDD_ParallelUnit_Write(PU->pu_Unit,
402 ioreq->IOPar.io_Data,
403 stringlen);
404 if (writtenbytes == stringlen)
405 complete = TRUE;
406 else
407 PU->pu_WriteLength = stringlen-writtenbytes;
409 else
411 writtenbytes = HIDD_ParallelUnit_Write(PU->pu_Unit,
412 ioreq->IOPar.io_Data,
413 ioreq->IOPar.io_Length);
414 if (writtenbytes == ioreq->IOPar.io_Length)
415 complete = TRUE;
416 else
417 PU->pu_WriteLength = ioreq->IOPar.io_Length-writtenbytes;
420 ** A consistency check between the STATUS_WRITES_PENDING flag
421 ** and the pointer PU->pu_ActiveWrite which both have to be
422 ** set or cleared at the same time.
424 if (NULL != PU->pu_ActiveWrite)
426 D(bug("error!!"));
429 if (complete == TRUE)
431 D(bug("completely sended the stream!\n"));
433 ** The request could be completed immediately.
434 ** Check if I have to reply the message
436 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
437 ReplyMsg(&ioreq->IOPar.io_Message);
439 else
442 ** The request could not be completed immediately
443 ** Clear the flag.
445 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
446 PU->pu_ActiveWrite = (struct Message *)ioreq;
447 PU->pu_Status |= STATUS_WRITES_PENDING;
448 PU->pu_NextToWrite = writtenbytes;
451 else
454 I could not write the data immediately as another request
455 is already there. So I will make this
456 the responsibility of the interrupt handler to use this
457 request once it is done with the active request.
459 PutMsg(&PU->pu_QWriteCommandPort,
460 (struct Message *)ioreq);
461 PU->pu_Status |= STATUS_WRITES_PENDING;
463 ** As I am returning immediately I will tell that this
464 ** could not be done QUICK
466 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
469 Enable();
470 break;
472 case CMD_CLEAR:
473 /* Simply reset the input buffer pointer no matter what */
474 ioreq->IOPar.io_Error = 0;
476 ** The request could be completed immediately.
477 ** Check if I have to reply the message
479 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
480 ReplyMsg(&ioreq->IOPar.io_Message);
481 break;
483 /*******************************************************************/
485 case CMD_RESET:
486 Disable();
487 /* All IORequests, including the active ones, are aborted */
489 /* Abort the active IORequests */
490 PU->pu_Status &= ~(STATUS_READS_PENDING|STATUS_WRITES_PENDING);
492 if (NULL != PU->pu_ActiveRead)
494 ((struct IOStdReq *)PU->pu_ActiveRead)->io_Error = IOERR_ABORTED;
495 ReplyMsg(PU->pu_ActiveRead);
498 if (NULL != PU->pu_ActiveWrite)
500 ((struct IOStdReq *)PU->pu_ActiveWrite)->io_Error = IOERR_ABORTED;
501 ReplyMsg(PU->pu_ActiveWrite);
503 Enable();
505 /*******************************************************************/
507 case CMD_FLUSH:
509 ** Clear all queued IO request for the given parallel unit except
510 ** for the active ones.
512 Disable();
514 while (TRUE)
516 struct IOStdReq * iopreq =
517 (struct IOStdReq *)GetMsg(&PU->pu_QReadCommandPort);
518 if (NULL == iopreq)
519 break;
520 iopreq->io_Error = IOERR_ABORTED;
521 ReplyMsg((struct Message *)iopreq);
524 while (TRUE)
526 struct IOStdReq * iopreq =
527 (struct IOStdReq *)GetMsg(&PU->pu_QWriteCommandPort);
528 if (NULL == iopreq)
529 break;
530 iopreq->io_Error = IOERR_ABORTED;
531 ReplyMsg((struct Message *)iopreq);
533 ioreq->IOPar.io_Error = 0;
535 Enable();
537 ** The request could be completed immediately.
538 ** Check if I have to reply the message
540 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
541 ReplyMsg(&ioreq->IOPar.io_Message);
542 break;
544 /*******************************************************************/
546 case CMD_START:
547 break;
549 /*******************************************************************/
551 case CMD_STOP:
552 break;
554 /*******************************************************************/
556 case PDCMD_QUERY:
558 PU->pu_Status = 0;
561 ** set the io_Status to the status of the parallel port
563 // !!! missing code
564 ioreq->io_Status = 0;
567 ** The request could be completed immediately.
568 ** Check if I have to reply the message
570 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
571 ReplyMsg(&ioreq->IOPar.io_Message);
573 break;
575 /*******************************************************************/
577 case PDCMD_SETPARAMS:
579 /* Change of buffer size for input buffer? */
582 /* Copy the Flags from the iorequest to the Unit's Flags */
583 PU->pu_Flags = ioreq->io_ParFlags;
585 /* Copy the TermArray */
586 PU->pu_PTermArray = ioreq->io_PTermArray;
589 ** The request could be completed immediately.
590 ** Check if I have to reply the message
592 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
593 ReplyMsg(&ioreq->IOPar.io_Message);
594 break;
596 /*******************************************************************/
598 default:
599 /* unknown command */
600 ioreq->IOPar.io_Error = IOERR_NOCMD;
603 ** The request could be completed immediately.
604 ** Check if I have to reply the message
606 if (0 == (ioreq->IOPar.io_Flags & IOF_QUICK))
607 ReplyMsg(&ioreq->IOPar.io_Message);
609 } /* switch () */
611 ReleaseSemaphore(&PU->pu_Lock);
613 D(bug("id: Return from BeginIO()\n"));
615 AROS_LIBFUNC_EXIT
618 /****************************************************************************************/
620 AROS_LH1(LONG, abortio,
621 AROS_LHA(struct IORequest *, ioreq, A1),
622 struct parallelbase *, ParallelDevice, 6, Parallel)
624 AROS_LIBFUNC_INIT
626 struct ParallelUnit * PU = (struct ParallelUnit *)ioreq->io_Unit;
629 ** is it the active request?
632 Disable();
633 if ((struct Message *)ioreq == PU->pu_ActiveRead)
636 ** It's the active reuquest. I make the next available
637 ** one the active request.
639 PU->pu_ActiveRead = GetMsg(&PU->pu_QReadCommandPort);
640 ReplyMsg(&ioreq->io_Message);
642 else
645 ** It's not the active request. So I'll take it out of the
646 ** list of queued messages and reply the message.
648 Remove(&ioreq->io_Message.mn_Node);
649 ReplyMsg(&ioreq->io_Message);
651 Enable();
653 return 0;
654 AROS_LIBFUNC_EXIT
657 /****************************************************************************************/