Put pciehci.device in DEVS:USBHardware, like the other host-controller
[AROS.git] / workbench / devs / parallel / parallel_init.c
blobc84e48f3b40b898951d46e2b8aa244e1514b94b7
1 /*
2 Copyright © 1995-2001, 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 #define DEBUG 0
38 #include <aros/debug.h>
40 #include LC_LIBDEFS_FILE
42 /****************************************************************************************/
44 #define NEWSTYLE_DEVICE 1
46 struct parallelbase * pubParallelBase;
48 /****************************************************************************************/
50 #if NEWSTYLE_DEVICE
52 static const UWORD SupportedCommands[] =
54 CMD_READ,
55 CMD_WRITE,
56 CMD_CLEAR,
57 CMD_RESET,
58 CMD_FLUSH,
59 PDCMD_QUERY,
60 PDCMD_SETPARAMS,
61 NSCMD_DEVICEQUERY,
65 #endif
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)
82 return FALSE;
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;
90 return FALSE;
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;
101 return FALSE;
105 NEWLIST(&ParallelDevice->UnitList);
106 return TRUE;
110 /****************************************************************************************/
112 static int GM_UNIQUENAME(Open)
114 LIBBASETYPEPTR ParallelDevice,
115 struct IORequest *ioreq,
116 ULONG unitnum,
117 ULONG flags
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;
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 = 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);
174 ioreq->io_Error = 0;
176 return TRUE;
179 D(bug("ParallelUnit could not be created!\n"));
181 FreeMem(PU, sizeof(struct ParallelUnit));
183 ioreq->io_Error = ParErr_DevBusy;
186 else
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
196 ** won't hurt.
198 ioreq->io_Device = (struct Device *)ParallelDevice;
199 ioreq->io_Unit = (struct Unit *)PU;
200 ioreq->io_Error = 0;
202 PU->pu_OpenerCount++;
204 else
207 ** I don't allow another opener
209 ioreq->io_Error = ParErr_DevBusy;
214 return TRUE;
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));
246 else
249 ** There are still openers. Decrease the counter.
251 PU->pu_OpenerCount--;
254 return TRUE;
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);
273 return TRUE;
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)
290 AROS_LIBFUNC_INIT
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)
307 #if NEWSTYLE_DEVICE
308 case NSCMD_DEVICEQUERY:
309 if(ioreq->IOPar.io_Length < ((IPTR)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
311 ioreq->IOPar.io_Error = IOERR_BADLENGTH;
313 else
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);
335 break;
336 #endif
338 /*******************************************************************/
339 case CMD_READ:
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;
346 Disable();
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
352 ** satisfied
354 if (NULL == PU->pu_ActiveRead)
355 PU->pu_ActiveRead = &ioreq->IOPar.io_Message;
356 else
357 PutMsg(&PU->pu_QReadCommandPort,
358 &ioreq->IOPar.io_Message);
360 Enable();
362 ** As I am returning immediately I will tell that this
363 ** could not be done QUICK
365 ioreq->IOPar.io_Flags &= ~IOF_QUICK;
366 break;
368 /*******************************************************************/
370 case CMD_WRITE:
371 /* Write data to the ParallelUnit */
372 ioreq->IOPar.io_Actual = 0;
374 Disable();
376 /* Check whether I can write some data immediately */
377 if (0 == (PU->pu_Status & STATUS_WRITES_PENDING))
379 ULONG writtenbytes;
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'
394 ** is encountered.
397 writtenbytes = HIDD_ParallelUnit_Write(PU->pu_Unit,
398 ioreq->IOPar.io_Data,
399 stringlen);
400 if (writtenbytes == stringlen)
401 complete = TRUE;
402 else
403 PU->pu_WriteLength = stringlen-writtenbytes;
405 else
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)
411 complete = TRUE;
412 else
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)
422 D(bug("error!!"));
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);
435 else
438 ** The request could not be completed immediately
439 ** Clear the flag.
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;
447 else
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;
465 Enable();
466 break;
468 case CMD_CLEAR:
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);
477 break;
479 /*******************************************************************/
481 case CMD_RESET:
482 Disable();
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);
499 Enable();
501 /*******************************************************************/
503 case CMD_FLUSH:
505 ** Clear all queued IO request for the given parallel unit except
506 ** for the active ones.
508 Disable();
510 while (TRUE)
512 struct IOStdReq * iopreq =
513 (struct IOStdReq *)GetMsg(&PU->pu_QReadCommandPort);
514 if (NULL == iopreq)
515 break;
516 iopreq->io_Error = IOERR_ABORTED;
517 ReplyMsg((struct Message *)iopreq);
520 while (TRUE)
522 struct IOStdReq * iopreq =
523 (struct IOStdReq *)GetMsg(&PU->pu_QWriteCommandPort);
524 if (NULL == iopreq)
525 break;
526 iopreq->io_Error = IOERR_ABORTED;
527 ReplyMsg((struct Message *)iopreq);
529 ioreq->IOPar.io_Error = 0;
531 Enable();
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);
538 break;
540 /*******************************************************************/
542 case CMD_START:
543 break;
545 /*******************************************************************/
547 case CMD_STOP:
548 break;
550 /*******************************************************************/
552 case PDCMD_QUERY:
554 PU->pu_Status = 0;
557 ** set the io_Status to the status of the parallel port
559 // !!! missing code
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);
569 break;
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);
590 break;
592 /*******************************************************************/
594 default:
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);
605 } /* switch () */
607 ReleaseSemaphore(&PU->pu_Lock);
609 D(bug("id: Return from BeginIO()\n"));
611 AROS_LIBFUNC_EXIT
614 /****************************************************************************************/
616 AROS_LH1(LONG, abortio,
617 AROS_LHA(struct IORequest *, ioreq, A1),
618 struct parallelbase *, ParallelDevice, 6, Parallel)
620 AROS_LIBFUNC_INIT
622 struct ParallelUnit * PU = (struct ParallelUnit *)ioreq->io_Unit;
625 ** is it the active request?
628 Disable();
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);
638 else
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);
647 Enable();
649 return 0;
650 AROS_LIBFUNC_EXIT
653 /****************************************************************************************/