2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
9 /****************************************************************************************/
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>
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"
38 #include <aros/debug.h>
40 #include LC_LIBDEFS_FILE
42 /****************************************************************************************/
44 #define NEWSTYLE_DEVICE 1
46 struct parallelbase
* pubParallelBase
;
48 /****************************************************************************************/
52 static const UWORD SupportedCommands
[] =
67 /****************************************************************************************/
69 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR ParallelDevice
)
71 D(bug("parallel device: init\n"));
73 pubParallelBase
= ParallelDevice
;
75 /* open the parallel hidd */
76 if (NULL
== ParallelDevice
->ParallelHidd
)
78 ParallelDevice
->ParallelHidd
= OpenLibrary("DRIVERS:parallel.hidd",0);
79 D(bug("parallel.hidd base: 0x%x\n",ParallelDevice
->ParallelHidd
));
81 if (NULL
== ParallelDevice
->ParallelHidd
)
84 if (NULL
== ParallelDevice
->oopBase
)
85 ParallelDevice
->oopBase
= OpenLibrary(AROSOOP_NAME
, 0);
86 if (NULL
== ParallelDevice
->oopBase
)
88 CloseLibrary(ParallelDevice
->ParallelHidd
);
89 ParallelDevice
->ParallelHidd
= NULL
;
93 ParallelDevice
->ParallelObject
= OOP_NewObject(NULL
, CLID_Hidd_Parallel
, NULL
);
95 if (NULL
== ParallelDevice
->ParallelObject
)
97 CloseLibrary(ParallelDevice
->oopBase
);
98 ParallelDevice
->oopBase
= NULL
;
99 CloseLibrary(ParallelDevice
->ParallelHidd
);
100 ParallelDevice
->ParallelHidd
= NULL
;
105 NEWLIST(&ParallelDevice
->UnitList
);
110 /****************************************************************************************/
112 static int GM_UNIQUENAME(Open
)
114 LIBBASETYPEPTR ParallelDevice
,
115 struct IORequest
*ioreq
,
120 struct ParallelUnit
* PU
= NULL
;
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
;
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 */
142 D(bug("Creating Unit %d\n",unitnum
));
143 PU
= AllocMem(sizeof(struct ParallelUnit
), MEMF_CLEAR
|MEMF_PUBLIC
);
146 PU
->pu_OpenerCount
= 1;
147 PU
->pu_UnitNum
= unitnum
;
148 PU
->pu_Flags
= ioreq
->io_Flags
;
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
);
179 D(bug("ParallelUnit could not be created!\n"));
181 FreeMem(PU
, sizeof(struct ParallelUnit
));
183 ioreq
->io_Error
= ParErr_DevBusy
;
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
198 ioreq
->io_Device
= (struct Device
*)ParallelDevice
;
199 ioreq
->io_Unit
= (struct Unit
*)PU
;
202 PU
->pu_OpenerCount
++;
207 ** I don't allow another opener
209 ioreq
->io_Error
= ParErr_DevBusy
;
218 /****************************************************************************************/
220 static int GM_UNIQUENAME(Close
)
222 LIBBASETYPEPTR ParallelDevice
,
223 struct IORequest
*ioreq
226 struct ParallelUnit
* PU
= (struct ParallelUnit
*)ioreq
->io_Unit
;
229 ** Check whether I am the last opener to this unit
231 if (1 == PU
->pu_OpenerCount
)
234 ** I was the last opener. So let's get rid of it.
237 ** Remove the unit from the list
239 Remove((struct Node
*)&PU
->pu_Node
);
241 HIDD_Parallel_DisposeUnit(ParallelDevice
->ParallelObject
, PU
->pu_Unit
);
243 FreeMem(PU
, sizeof(struct ParallelUnit
));
249 ** There are still openers. Decrease the counter.
251 PU
->pu_OpenerCount
--;
257 /****************************************************************************************/
259 static int GM_UNIQUENAME(Expunge
)(LIBBASETYPEPTR ParallelDevice
)
261 if (NULL
!= ParallelDevice
->ParallelObject
)
264 ** Throw away the HIDD object and close the library
266 OOP_DisposeObject(ParallelDevice
->ParallelObject
);
267 CloseLibrary(ParallelDevice
->ParallelHidd
);
268 ParallelDevice
->ParallelHidd
= NULL
;
269 ParallelDevice
->ParallelObject
= NULL
;
271 if (ParallelDevice
->oopBase
) CloseLibrary(ParallelDevice
->oopBase
);
276 /****************************************************************************************/
278 ADD2INITLIB(GM_UNIQUENAME(Init
), 0)
279 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge
), 0)
280 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
281 ADD2CLOSEDEV(GM_UNIQUENAME(Close
), 0)
283 /****************************************************************************************/
285 #define ioStd(x) ((struct IOStdReq *)x)
286 AROS_LH1(void, beginio
,
287 AROS_LHA(struct IOExtPar
*, ioreq
, A1
),
288 struct parallelbase
*, ParallelDevice
, 5, Parallel
)
292 struct ParallelUnit
* PU
= (struct ParallelUnit
*)ioreq
->IOPar
.io_Unit
;
294 D(bug("parallel device: beginio(ioreq=%p)\n", ioreq
));
296 /* WaitIO will look into this */
297 ioreq
->IOPar
.io_Message
.mn_Node
.ln_Type
=NT_MESSAGE
;
300 ** As a lot of "public" data can be modified in the following lines
301 ** I protect it from other tasks by this semaphore
303 ObtainSemaphore(&PU
->pu_Lock
);
305 switch (ioreq
->IOPar
.io_Command
)
308 case NSCMD_DEVICEQUERY
:
309 if(ioreq
->IOPar
.io_Length
< ((IPTR
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
311 ioreq
->IOPar
.io_Error
= IOERR_BADLENGTH
;
315 struct NSDeviceQueryResult
*d
;
317 d
= (struct NSDeviceQueryResult
*)ioreq
->IOPar
.io_Data
;
319 d
->DevQueryFormat
= 0;
320 d
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
321 d
->DeviceType
= NSDEVTYPE_PARALLEL
;
322 d
->DeviceSubType
= 0;
323 d
->SupportedCommands
= (UWORD
*)SupportedCommands
;
325 ioreq
->IOPar
.io_Actual
= sizeof(struct NSDeviceQueryResult
);
326 ioreq
->IOPar
.io_Error
= 0;
329 ** The request could be completed immediately.
330 ** Check if I have to reply the message
332 if (0 == (ioreq
->IOPar
.io_Flags
& IOF_QUICK
))
333 ReplyMsg(&ioreq
->IOPar
.io_Message
);
338 /*******************************************************************/
341 ** Let me see whether I can copy any data at all and
342 ** whether nobody else is using this device now
344 ioreq
->IOPar
.io_Actual
= 0;
348 PU
->pu_Status
|= STATUS_READS_PENDING
;
349 D(bug("Queuing the read request.\n"));
351 ** Everything that falls down here could not be completely
354 if (NULL
== PU
->pu_ActiveRead
)
355 PU
->pu_ActiveRead
= &ioreq
->IOPar
.io_Message
;
357 PutMsg(&PU
->pu_QReadCommandPort
,
358 &ioreq
->IOPar
.io_Message
);
362 ** As I am returning immediately I will tell that this
363 ** could not be done QUICK
365 ioreq
->IOPar
.io_Flags
&= ~IOF_QUICK
;
368 /*******************************************************************/
371 /* Write data to the ParallelUnit */
372 ioreq
->IOPar
.io_Actual
= 0;
376 /* Check whether I can write some data immediately */
377 if (0 == (PU
->pu_Status
& STATUS_WRITES_PENDING
))
380 BOOL complete
= FALSE
;
382 Writing the first few bytes to the UART has to have the
383 effect that whenever the UART can receive new data
384 a HW interrupt must happen. So this writing to the
385 UART should get the sequence of HW-interrupts going
386 until there is no more data to write
388 if (-1 == ioreq
->IOPar
.io_Length
)
390 int stringlen
= strlen(ioreq
->IOPar
.io_Data
);
391 D(bug("Transmitting NULL termninated string.\n"));
393 ** Supposed to write the buffer to the port until a '\0'
397 writtenbytes
= HIDD_ParallelUnit_Write(PU
->pu_Unit
,
398 ioreq
->IOPar
.io_Data
,
400 if (writtenbytes
== stringlen
)
403 PU
->pu_WriteLength
= stringlen
-writtenbytes
;
407 writtenbytes
= HIDD_ParallelUnit_Write(PU
->pu_Unit
,
408 ioreq
->IOPar
.io_Data
,
409 ioreq
->IOPar
.io_Length
);
410 if (writtenbytes
== ioreq
->IOPar
.io_Length
)
413 PU
->pu_WriteLength
= ioreq
->IOPar
.io_Length
-writtenbytes
;
416 ** A consistency check between the STATUS_WRITES_PENDING flag
417 ** and the pointer PU->pu_ActiveWrite which both have to be
418 ** set or cleared at the same time.
420 if (NULL
!= PU
->pu_ActiveWrite
)
425 if (complete
== TRUE
)
427 D(bug("completely sended the stream!\n"));
429 ** The request could be completed immediately.
430 ** Check if I have to reply the message
432 if (0 == (ioreq
->IOPar
.io_Flags
& IOF_QUICK
))
433 ReplyMsg(&ioreq
->IOPar
.io_Message
);
438 ** The request could not be completed immediately
441 ioreq
->IOPar
.io_Flags
&= ~IOF_QUICK
;
442 PU
->pu_ActiveWrite
= (struct Message
*)ioreq
;
443 PU
->pu_Status
|= STATUS_WRITES_PENDING
;
444 PU
->pu_NextToWrite
= writtenbytes
;
450 I could not write the data immediately as another request
451 is already there. So I will make this
452 the responsibility of the interrupt handler to use this
453 request once it is done with the active request.
455 PutMsg(&PU
->pu_QWriteCommandPort
,
456 (struct Message
*)ioreq
);
457 PU
->pu_Status
|= STATUS_WRITES_PENDING
;
459 ** As I am returning immediately I will tell that this
460 ** could not be done QUICK
462 ioreq
->IOPar
.io_Flags
&= ~IOF_QUICK
;
469 /* Simply reset the input buffer pointer no matter what */
470 ioreq
->IOPar
.io_Error
= 0;
472 ** The request could be completed immediately.
473 ** Check if I have to reply the message
475 if (0 == (ioreq
->IOPar
.io_Flags
& IOF_QUICK
))
476 ReplyMsg(&ioreq
->IOPar
.io_Message
);
479 /*******************************************************************/
483 /* All IORequests, including the active ones, are aborted */
485 /* Abort the active IORequests */
486 PU
->pu_Status
&= ~(STATUS_READS_PENDING
|STATUS_WRITES_PENDING
);
488 if (NULL
!= PU
->pu_ActiveRead
)
490 ((struct IOStdReq
*)PU
->pu_ActiveRead
)->io_Error
= IOERR_ABORTED
;
491 ReplyMsg(PU
->pu_ActiveRead
);
494 if (NULL
!= PU
->pu_ActiveWrite
)
496 ((struct IOStdReq
*)PU
->pu_ActiveWrite
)->io_Error
= IOERR_ABORTED
;
497 ReplyMsg(PU
->pu_ActiveWrite
);
501 /*******************************************************************/
505 ** Clear all queued IO request for the given parallel unit except
506 ** for the active ones.
512 struct IOStdReq
* iopreq
=
513 (struct IOStdReq
*)GetMsg(&PU
->pu_QReadCommandPort
);
516 iopreq
->io_Error
= IOERR_ABORTED
;
517 ReplyMsg((struct Message
*)iopreq
);
522 struct IOStdReq
* iopreq
=
523 (struct IOStdReq
*)GetMsg(&PU
->pu_QWriteCommandPort
);
526 iopreq
->io_Error
= IOERR_ABORTED
;
527 ReplyMsg((struct Message
*)iopreq
);
529 ioreq
->IOPar
.io_Error
= 0;
533 ** The request could be completed immediately.
534 ** Check if I have to reply the message
536 if (0 == (ioreq
->IOPar
.io_Flags
& IOF_QUICK
))
537 ReplyMsg(&ioreq
->IOPar
.io_Message
);
540 /*******************************************************************/
545 /*******************************************************************/
550 /*******************************************************************/
557 ** set the io_Status to the status of the parallel port
560 ioreq
->io_Status
= 0;
563 ** The request could be completed immediately.
564 ** Check if I have to reply the message
566 if (0 == (ioreq
->IOPar
.io_Flags
& IOF_QUICK
))
567 ReplyMsg(&ioreq
->IOPar
.io_Message
);
571 /*******************************************************************/
573 case PDCMD_SETPARAMS
:
575 /* Change of buffer size for input buffer? */
578 /* Copy the Flags from the iorequest to the Unit's Flags */
579 PU
->pu_Flags
= ioreq
->io_ParFlags
;
581 /* Copy the TermArray */
582 PU
->pu_PTermArray
= ioreq
->io_PTermArray
;
585 ** The request could be completed immediately.
586 ** Check if I have to reply the message
588 if (0 == (ioreq
->IOPar
.io_Flags
& IOF_QUICK
))
589 ReplyMsg(&ioreq
->IOPar
.io_Message
);
592 /*******************************************************************/
595 /* unknown command */
596 ioreq
->IOPar
.io_Error
= IOERR_NOCMD
;
599 ** The request could be completed immediately.
600 ** Check if I have to reply the message
602 if (0 == (ioreq
->IOPar
.io_Flags
& IOF_QUICK
))
603 ReplyMsg(&ioreq
->IOPar
.io_Message
);
607 ReleaseSemaphore(&PU
->pu_Lock
);
609 D(bug("id: Return from BeginIO()\n"));
614 /****************************************************************************************/
616 AROS_LH1(LONG
, abortio
,
617 AROS_LHA(struct IORequest
*, ioreq
, A1
),
618 struct parallelbase
*, ParallelDevice
, 6, Parallel
)
622 struct ParallelUnit
* PU
= (struct ParallelUnit
*)ioreq
->io_Unit
;
625 ** is it the active request?
629 if ((struct Message
*)ioreq
== PU
->pu_ActiveRead
)
632 ** It's the active reuquest. I make the next available
633 ** one the active request.
635 PU
->pu_ActiveRead
= GetMsg(&PU
->pu_QReadCommandPort
);
636 ReplyMsg(&ioreq
->io_Message
);
641 ** It's not the active request. So I'll take it out of the
642 ** list of queued messages and reply the message.
644 Remove(&ioreq
->io_Message
.mn_Node
);
645 ReplyMsg(&ioreq
->io_Message
);
653 /****************************************************************************************/