2 Copyright © 1995-2017, 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"
37 #include <aros/debug.h>
39 #include LC_LIBDEFS_FILE
41 /****************************************************************************************/
43 #define NEWSTYLE_DEVICE 1
45 struct parallelbase
* pubParallelBase
;
47 /****************************************************************************************/
51 static const UWORD SupportedCommands
[] =
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
)
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
;
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
;
104 NEWLIST(&ParallelDevice
->UnitList
);
109 /****************************************************************************************/
111 static int GM_UNIQUENAME(Open
)
113 LIBBASETYPEPTR ParallelDevice
,
114 struct IORequest
*ioreq
,
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
;
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
= 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
);
178 D(bug("%s: Unit %d opened\n", __func__
, unitnum
));
182 D(bug("ParallelUnit could not be created!\n"));
184 FreeMem(PU
, sizeof(struct ParallelUnit
));
186 ioreq
->io_Error
= ParErr_DevBusy
;
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
201 ioreq
->io_Device
= (struct Device
*)ParallelDevice
;
202 ioreq
->io_Unit
= (struct Unit
*)PU
;
205 PU
->pu_OpenerCount
++;
210 ** I don't allow another opener
212 ioreq
->io_Error
= ParErr_DevBusy
;
213 D(bug("%s: Unit %d already busy\n", __func__
, unitnum
));
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
));
253 ** There are still openers. Decrease the counter.
255 PU
->pu_OpenerCount
--;
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
);
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
)
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
)
312 case NSCMD_DEVICEQUERY
:
313 if(ioreq
->IOPar
.io_Length
< ((IPTR
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
315 ioreq
->IOPar
.io_Error
= IOERR_BADLENGTH
;
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
);
342 /*******************************************************************/
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;
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
358 if (NULL
== PU
->pu_ActiveRead
)
359 PU
->pu_ActiveRead
= &ioreq
->IOPar
.io_Message
;
361 PutMsg(&PU
->pu_QReadCommandPort
,
362 &ioreq
->IOPar
.io_Message
);
366 ** As I am returning immediately I will tell that this
367 ** could not be done QUICK
369 ioreq
->IOPar
.io_Flags
&= ~IOF_QUICK
;
372 /*******************************************************************/
375 /* Write data to the ParallelUnit */
376 ioreq
->IOPar
.io_Actual
= 0;
380 /* Check whether I can write some data immediately */
381 if (0 == (PU
->pu_Status
& STATUS_WRITES_PENDING
))
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'
401 writtenbytes
= HIDD_ParallelUnit_Write(PU
->pu_Unit
,
402 ioreq
->IOPar
.io_Data
,
404 if (writtenbytes
== stringlen
)
407 PU
->pu_WriteLength
= stringlen
-writtenbytes
;
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
)
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
)
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
);
442 ** The request could not be completed immediately
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
;
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
;
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
);
483 /*******************************************************************/
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
);
505 /*******************************************************************/
509 ** Clear all queued IO request for the given parallel unit except
510 ** for the active ones.
516 struct IOStdReq
* iopreq
=
517 (struct IOStdReq
*)GetMsg(&PU
->pu_QReadCommandPort
);
520 iopreq
->io_Error
= IOERR_ABORTED
;
521 ReplyMsg((struct Message
*)iopreq
);
526 struct IOStdReq
* iopreq
=
527 (struct IOStdReq
*)GetMsg(&PU
->pu_QWriteCommandPort
);
530 iopreq
->io_Error
= IOERR_ABORTED
;
531 ReplyMsg((struct Message
*)iopreq
);
533 ioreq
->IOPar
.io_Error
= 0;
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
);
544 /*******************************************************************/
549 /*******************************************************************/
554 /*******************************************************************/
561 ** set the io_Status to the status of the parallel port
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
);
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
);
596 /*******************************************************************/
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
);
611 ReleaseSemaphore(&PU
->pu_Lock
);
613 D(bug("id: Return from BeginIO()\n"));
618 /****************************************************************************************/
620 AROS_LH1(LONG
, abortio
,
621 AROS_LHA(struct IORequest
*, ioreq
, A1
),
622 struct parallelbase
*, ParallelDevice
, 6, Parallel
)
626 struct ParallelUnit
* PU
= (struct ParallelUnit
*)ioreq
->io_Unit
;
629 ** is it the active request?
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
);
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
);
657 /****************************************************************************************/