/* *FUNC= IoCreate D0/D1/A0 *FUNC= IoDelete D0 *FUNC= IoOpen D0/D1/A0 *FUNC= IoClose A0 ;FUNC= IoCtl D0/D1/D2/A0 *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - */ #include #include typedef long (*FPTR)(); #define HAN struct _HAN #define MHAN struct _MHAN #define HANSIZE 8 HAN { long Reserved; MHAN *MHan; /* Related MHandle */ /* USER STRUCTURE */ }; MHAN { NODE Node; long (*IoCtlFunc)(); /* Control Function / NULL */ uword Refs; /* Total References */ uword HanSize; /* Size of a HANdle */ }; #asm MHA_IOCTLFUNC equ 14 #endasm static MLIST MList = { (MNODE *)&MList.mlh_Tail, NULL, (MNODE *)&MList.mlh_Head }; static long Lock[2] = { 0,0 }; lIoCreate(name, func, hansize) char *name; long (*func)(); { register MHAN *mh; long res = -1; hansize += HANSIZE; LockAddr(Lock); for (mh = GetHead(&MList); mh; mh = GetSucc(mh)) { if (strcmp(name, mh->Node.ln_Name) == 0) goto fail; } if ((mh = AllocMem(sizeof(MHAN), MEMF_PUBLIC|MEMF_CLEAR)) == NULL) goto fail; if ((mh->Node.ln_Name = AllocMem(strlen(name)+1, MEMF_PUBLIC)) == NULL) { FreeMem(mh, sizeof(MHAN)); goto fail; } strcpy(mh->Node.ln_Name, name); mh->IoCtlFunc = func; mh->HanSize = HANSIZE + hansize; AddHead(&MList, mh); fioctl(func, _IOC_CREATE, NULL, 0); res = 0; fail: UnLockAddr(Lock); return(res); } /* * Delete an IO device. The device's name is removed from the nameslist * and any further non-internal IoCtl's on active connections will return * -1. */ lIoDelete(name) char *name; { register MHAN *mh; long (*func)(); LockAddr(Lock); for (mh = GetHead(&MList); mh; mh = GetSucc(mh)) { if (mh->Node.ln_Name && strcmp(name, mh->Node.ln_Name) == 0) break; } if (!mh) { UnLockAddr(mh); return(-1); } /* Prevent further opens & flag for removal */ FreeMem(mh->Node.ln_Name, strlen(mh->Node.ln_Name)+1); mh->Node.ln_Name = NULL; func = mh->IoCtlFunc; mh->IoCtlFunc = NULL; /* Call _IOC_DELETE if no more references & delete */ UnLockAddr(Lock); fioctl(func, _IOC_DELETE, NULL, 0); if (mh->Refs == 0) { Remove(mh); FreeMem(mh, sizeof(MHAN)); return(0); } return(1); } HAN * lIoOpen(name, arg1, arg2) char *name; ulong arg1, arg2; { register MHAN *mh; register HAN *han; LockAddr(Lock); for (mh = GetHead(&MList); mh; mh = GetSucc(mh)) { if (mh->Node.ln_Name && strcmp(name, mh->Node.ln_Name) == 0) break; } if (!mh) { UnLockAddr(Lock); return(NULL); } if (!(han = AllocMem(mh->HanSize, MEMF_CLEAR|MEMF_PUBLIC))) { UnLockAddr(Lock); return(NULL); } ++mh->Refs; UnLockAddr(Lock); han->MHan = mh; if (IoCtl(han, _IOC_OPEN, arg1, arg2) == -1) { FreeMem(han, mh->HanSize); LockAddr(Lock); if (--mh->Refs == 0 && mh->Node.ln_Name == NULL) { Remove(mh); FreeMem(mh, sizeof(MHAN)); } UnLockAddr(Lock); return(NULL); } UnLockAddr(Lock); return(han); } lIoClose(han) register HAN *han; { register MHAN *mh = han->MHan; long hansize = mh->HanSize; IoCtl(han, _IOC_CLOSE, NULL, NULL); /* finishup */ LockAddr(Lock); if (--mh->Refs == 0 && mh->Node.ln_Name == NULL) { Remove(mh); FreeMem(mh, sizeof(MHAN)); } UnLockAddr(Lock); FreeMem(han, hansize); return(0); } #asm ; IoCtl(han:D0, cmd:D1, buf:D2, bytes:A0) ; ; (1) Call IoctlFunc if it exists, (*func)(han,cmd,buf,bytes) ; (2) else call internal function or if IoctlFunc returns -1 public _lIoCtl public _AutoFunc _lIoCtl: addq.l #8,D0 ; skip handle header movem.l D2/D3/A4/A5/A6,-(sp) ; C compatibility movem.l D0/D1/D2/A0,-(sp) ; function call params move.l D0,A0 move.l -4(A0),A0 ; A0 = master handle move.l MHA_IOCTLFUNC(A0),A1 ; A1 = function to call move.l A1,D0 ; NULL function beq .iocn jsr (A1) cmp.l #-1,D0 ; result -1 ? bne .iocr .iocn lea _AutoFunc,A1 ; error, try internal func jsr (A1) .iocr lea 16(sp),sp movem.l (sp)+,D2/D3/A4/A5/A6 rts ; fioctl(func, cmd, buf1, buf2) .. called as: (NULL,cmd,buf1,buf2) ; (i.e. handleless) _fioctl: movem.l 4(sp),D0/D1/A0/A1 ; get stack args movem.l D2/D3/A4/A5/A6,-(sp) ; save regs that might get trashed move.l D0,A6 ; function to call moveq.l #0,D0 ; (usually is the handle) movem.l D0/D1/A0/A1,-(sp) ; push args jsr (A6) ; make call lea 16(sp),sp ; pop args movem.l (sp)+,D2/D3/A4/A5/A6 ; restore regs rts #endasm AutoFunc(han, cmd, arg1, arg2) register HAN *han; ulong cmd, arg1, arg2; { han = (HAN *)((char *)han - 8); switch(cmd) { case IOC_GETFUNC: return ((long)han->MHan->IoCtlFunc); case IOC_SETFUNC: han->MHan->IoCtlFunc = (FPTR)arg1; return(0); case IOC_DEVCLAS: return(0); case IOC_DUP: { register long hansize = han->MHan->HanSize; register HAN *new = AllocMem(hansize, MEMF_PUBLIC); register long res; if (new) { BMov(han, new, hansize); res = IoCtl(new, _IOC_DUP, arg1, arg2); if (res != -1) return((long)new); FreeMem(new, hansize); } } break; } return(-1); }