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
;
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 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
);
176 D(bug("%s: Unit %d opened\n", __func__
, unitnum
));
180 D(bug("ParallelUnit could not be created!\n"));
182 FreeMem(PU
, sizeof(struct ParallelUnit
));
184 ioreq
->io_Error
= ParErr_DevBusy
;
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
199 ioreq
->io_Device
= (struct Device
*)ParallelDevice
;
200 ioreq
->io_Unit
= (struct Unit
*)PU
;
203 PU
->pu_OpenerCount
++;
208 ** I don't allow another opener
210 ioreq
->io_Error
= ParErr_DevBusy
;
211 D(bug("%s: Unit %d already busy\n", __func__
, unitnum
));
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
));
251 ** There are still openers. Decrease the counter.
253 PU
->pu_OpenerCount
--;
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
);
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
)
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
)
310 case NSCMD_DEVICEQUERY
:
311 if(ioreq
->IOPar
.io_Length
< ((IPTR
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
313 ioreq
->IOPar
.io_Error
= IOERR_BADLENGTH
;
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
);
340 /*******************************************************************/
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;
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
356 if (NULL
== PU
->pu_ActiveRead
)
357 PU
->pu_ActiveRead
= &ioreq
->IOPar
.io_Message
;
359 PutMsg(&PU
->pu_QReadCommandPort
,
360 &ioreq
->IOPar
.io_Message
);
364 ** As I am returning immediately I will tell that this
365 ** could not be done QUICK
367 ioreq
->IOPar
.io_Flags
&= ~IOF_QUICK
;
370 /*******************************************************************/
373 /* Write data to the ParallelUnit */
374 ioreq
->IOPar
.io_Actual
= 0;
378 /* Check whether I can write some data immediately */
379 if (0 == (PU
->pu_Status
& STATUS_WRITES_PENDING
))
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'
399 writtenbytes
= HIDD_ParallelUnit_Write(PU
->pu_Unit
,
400 ioreq
->IOPar
.io_Data
,
402 if (writtenbytes
== stringlen
)
405 PU
->pu_WriteLength
= stringlen
-writtenbytes
;
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
)
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
)
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
);
440 ** The request could not be completed immediately
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
;
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
;
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
);
481 /*******************************************************************/
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
);
503 /*******************************************************************/
507 ** Clear all queued IO request for the given parallel unit except
508 ** for the active ones.
514 struct IOStdReq
* iopreq
=
515 (struct IOStdReq
*)GetMsg(&PU
->pu_QReadCommandPort
);
518 iopreq
->io_Error
= IOERR_ABORTED
;
519 ReplyMsg((struct Message
*)iopreq
);
524 struct IOStdReq
* iopreq
=
525 (struct IOStdReq
*)GetMsg(&PU
->pu_QWriteCommandPort
);
528 iopreq
->io_Error
= IOERR_ABORTED
;
529 ReplyMsg((struct Message
*)iopreq
);
531 ioreq
->IOPar
.io_Error
= 0;
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
);
542 /*******************************************************************/
547 /*******************************************************************/
552 /*******************************************************************/
559 ** set the io_Status to the status of the parallel port
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
);
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
);
594 /*******************************************************************/
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
);
609 ReleaseSemaphore(&PU
->pu_Lock
);
611 D(bug("id: Return from BeginIO()\n"));
616 /****************************************************************************************/
618 AROS_LH1(LONG
, abortio
,
619 AROS_LHA(struct IORequest
*, ioreq
, A1
),
620 struct parallelbase
*, ParallelDevice
, 6, Parallel
)
624 struct ParallelUnit
* PU
= (struct ParallelUnit
*)ioreq
->io_Unit
;
627 ** is it the active request?
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
);
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
);
655 /****************************************************************************************/