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"
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
;
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
;
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 */
141 D(bug("Creating Unit %d\n",unitnum
));
142 PU
= AllocMem(sizeof(struct ParallelUnit
), MEMF_CLEAR
|MEMF_PUBLIC
);
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
);
175 D(bug("%s: Unit %d opened\n", __func__
, unitnum
));
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
;
210 D(bug("%s: Unit %d already busy\n", __func__
, unitnum
));
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
));
250 ** There are still openers. Decrease the counter.
252 PU
->pu_OpenerCount
--;
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
);
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
)
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
)
309 case NSCMD_DEVICEQUERY
:
310 if(ioreq
->IOPar
.io_Length
< ((IPTR
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
312 ioreq
->IOPar
.io_Error
= IOERR_BADLENGTH
;
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
);
339 /*******************************************************************/
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;
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
355 if (NULL
== PU
->pu_ActiveRead
)
356 PU
->pu_ActiveRead
= &ioreq
->IOPar
.io_Message
;
358 PutMsg(&PU
->pu_QReadCommandPort
,
359 &ioreq
->IOPar
.io_Message
);
363 ** As I am returning immediately I will tell that this
364 ** could not be done QUICK
366 ioreq
->IOPar
.io_Flags
&= ~IOF_QUICK
;
369 /*******************************************************************/
372 /* Write data to the ParallelUnit */
373 ioreq
->IOPar
.io_Actual
= 0;
377 /* Check whether I can write some data immediately */
378 if (0 == (PU
->pu_Status
& STATUS_WRITES_PENDING
))
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'
398 writtenbytes
= HIDD_ParallelUnit_Write(PU
->pu_Unit
,
399 ioreq
->IOPar
.io_Data
,
401 if (writtenbytes
== stringlen
)
404 PU
->pu_WriteLength
= stringlen
-writtenbytes
;
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
)
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
)
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
);
439 ** The request could not be completed immediately
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
;
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
;
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
);
480 /*******************************************************************/
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
);
502 /*******************************************************************/
506 ** Clear all queued IO request for the given parallel unit except
507 ** for the active ones.
513 struct IOStdReq
* iopreq
=
514 (struct IOStdReq
*)GetMsg(&PU
->pu_QReadCommandPort
);
517 iopreq
->io_Error
= IOERR_ABORTED
;
518 ReplyMsg((struct Message
*)iopreq
);
523 struct IOStdReq
* iopreq
=
524 (struct IOStdReq
*)GetMsg(&PU
->pu_QWriteCommandPort
);
527 iopreq
->io_Error
= IOERR_ABORTED
;
528 ReplyMsg((struct Message
*)iopreq
);
530 ioreq
->IOPar
.io_Error
= 0;
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
);
541 /*******************************************************************/
546 /*******************************************************************/
551 /*******************************************************************/
558 ** set the io_Status to the status of the parallel port
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
);
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
);
593 /*******************************************************************/
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
);
608 ReleaseSemaphore(&PU
->pu_Lock
);
610 D(bug("id: Return from BeginIO()\n"));
615 /****************************************************************************************/
617 AROS_LH1(LONG
, abortio
,
618 AROS_LHA(struct IORequest
*, ioreq
, A1
),
619 struct parallelbase
*, ParallelDevice
, 6, Parallel
)
623 struct ParallelUnit
* PU
= (struct ParallelUnit
*)ioreq
->io_Unit
;
626 ** is it the active request?
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
);
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
);
654 /****************************************************************************************/