/* * EvGetEventClassName() finds the class name string associated with an event * class ID. This function works only locally because all event classes * should be known locally. * * If the event group cound not be found -EEXIST will be returned. If * the class identified by className is not registered the -ESRCH will * be returned. Else "class" will be filled with the unique class * ID assiged to className and a zero will be returned to indicates * success. */ int EvGetEventClassName(EvGroupID_t groupID, EvClassID_t classID, char *className) { EvGroupInfo_t *EGroup; EvClassInfo_t *HashBase; unsigned long Flags; int RetVal; /* Get the group info pointer and return with it locked. */ if ((RetVal = EvLockAndGetGroup(groupID, EV_ACCESS_IGNORE, EAC_NONE, &Flags, EV_LOCK_GROUP_READ, &EGroup))) { return RetVal; } HashBase = EvGetHashBase(EGroup, classID); while (HashBase->EciNext) { if (HashBase->EciClass == classID) { strncpy(className, HashBase->EciName, 16); read_unlock_irqrestore(&EGroup->EgiLock, Flags); return EV_NOERR; } HashBase = HashBase->EciNext; } read_unlock_irqrestore(&EGroup->EgiLock, Flags); return -EV_ERROR_CLASS_EXISTS; }
int EvSetClassAccessCode(EvGroupID_t groupID, EvClassID_t classID, EvAccess_t oldCode, EvAccess_t newCode) { EvGroupInfo_t *EGroup; EvClassInfo_t *HashBase; EvClassInfo_t *ClassBase; EvDestBase_t *EventBase; unsigned long Flags; read_lock_irqsave(&EvGroupLock, Flags); if ((EGroup = EvGetGroupBase(groupID)) == NULL) { read_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_GROUP_EXIST; } HashBase = EvGetHashBase(EGroup, classID); spin_lock(&HashBase->EciLock); read_unlock(&EvGroupLock); if ((EventBase = EvFindEventBase(classID,HashBase,&ClassBase))==NULL) { spin_unlock_irqrestore(&HashBase->EciLock, Flags); return -EV_ERROR_CLASS_EXISTS; } if (EvCheckAccessCode(ClassBase->EciAccessCode, oldCode)) { spin_unlock_irqrestore(&HashBase->EciLock, Flags); return -EV_ERROR_CLASS_ACCESS; } ClassBase->EciAccessCode = newCode; spin_unlock_irqrestore(&HashBase->EciLock, Flags); return EV_NOERR; }
/* * Connection daemon has recieved a message from the event master * that a new class is available for this member. This function * registers that new class. */ int EvRemoteRegisterEventClass(EvGroupID_t groupID, char *className, EvAccess_t groupAccessCode, EvAccess_t classAccessCode, int error, EvClassID_t classID) { EvGroupInfo_t *EGroup; EvPendRem_t *Pend; EvClassInfo_t *HashBase; unsigned long Flags; int RetVal; read_lock_irqsave(&EvGroupLock, Flags); if ((EGroup = EvGetGroupBase(groupID)) == NULL) { read_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_GROUP_EXIST; } write_lock(&EGroup->EgiLock); read_unlock(&EvGroupLock); /* Pend the pending control struct for this ID. * * If Pend is NULL then this is the master reporting a new event * class. */ if ((Pend = EvFindPendEntry(EGroup, EV_REM_REGISTER_EVENT_CLASS, groupAccessCode, classAccessCode, 0, 0, strlen(className)+1, className)) != NULL) { /* Fill in the return values. */ Pend->PrRetInfo.EpInfo[0] = error; Pend->PrRetInfo.EpInfo[1] = classID; /* Wake up the requester. */ wake_up_interruptible(&Pend->PrWaitQ); write_unlock_irqrestore(&EGroup->EgiLock, Flags); return EV_NOERR; } /* Register a new event class on a group member for the master. */ HashBase = EvGetHashBase(EGroup, classID); while (HashBase->EciNext != NULL) { HashBase = HashBase->EciNext; } RetVal=EvFillInHashInfo(HashBase, classAccessCode, className, &classID); write_unlock_irqrestore(&EGroup->EgiLock, Flags); return RetVal; }
/* * EvUnSubscribeEvent() removes the user id from the list of subscribers * waiting for the particular event to occur. * * If the user ID does not indicate a currently registered user then * -ENOENT is returned. If the event group is not a currently registered * group then -EEXIST is returned. If the class in not found in the this * of currently know classes then -EINVAL is returned. If the user is * not currently subscribed to recieve the event then -EBUSY is returned. * * Otherwise the subscription is removed and a zero is returned to * indicate susccess. */ int EvUnSubscribeEvent(EvUserID_t userID, EvGroupID_t groupID, EvClassID_t classID, EvEventID_t eventID) { EvDest_t *EventDestP = NULL; EvDest_t *FreeDest = NULL; EvDestBase_t *EventBase; EvDestBase_t *LastEventBase = NULL; EvKernelInfo_t *EventUser; EvGroupInfo_t *EGroup; EvClassInfo_t *HashBase; EvClassInfo_t *ClassBase; unsigned long Flags; /* Check the user id. */ read_lock_irqsave(&EvUsersLock, Flags); if ((EventUser = EvCheckUser(userID)) == NULL) { read_unlock_irqrestore(&EvUsersLock, Flags); return -EV_ERROR_USER_EXISTS; } read_lock(&EvGroupLock); read_unlock(&EvUsersLock); /* Get the base event group information. */ if ((EGroup = EvGetGroupBase(groupID)) == NULL) { read_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_GROUP_EXIST; } HashBase = EvGetHashBase(EGroup, classID); /* Find the top level entry for this class of events. */ if ((EventBase = EvFindEventBase(classID,HashBase,&ClassBase)) == NULL){ read_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_CLASS_EXISTS; } spin_lock(&ClassBase->EciLock); read_unlock(&EvGroupLock); /* search until the event is found in this catagory or until the * last blank element on the list if found. */ while (EventBase->EdbNext != NULL) { if (EventBase->EdbEvent == eventID) { EventDestP = &EventBase->EdbDestQ; break; } LastEventBase = EventBase; EventBase = EventBase->EdbNext; } /* If event type not found then the user process was obviously not * registered for this event. */ if (EventDestP == NULL) { spin_unlock_irqrestore(&ClassBase->EciLock, Flags); return -EV_ERROR_CLASS_NO_SUB; } if (EventDestP->EdID == userID) { if (EventDestP->EdNext == NULL) { /* This is the only element on the list so it * will be removed below. */ goto EvUnRegFreeBase; } EventDestP->EdUinfo = EventDestP->EdNext->EdUinfo; EventDestP->EdCB = EventDestP->EdNext->EdCB; EventDestP->EdID = EventDestP->EdNext->EdID; EventDestP->EdKinfo = EventDestP->EdNext->EdKinfo; FreeDest = EventDestP->EdNext; EventDestP->EdNext = EventDestP->EdNext->EdNext; goto EvUnRegFreeBase; } /* Allways search one ahead to help with single link list removal. */ while (EventDestP->EdNext->EdNext != NULL) { if (EventDestP->EdNext->EdID == userID) { FreeDest = EventDestP->EdNext; EventDestP->EdNext = EventDestP->EdNext->EdNext; goto EvUnRegFreeBase; } EventDestP = EventDestP->EdNext; } /* Entry not found in list. */ spin_unlock_irqrestore(&ClassBase->EciLock, Flags); return -EV_ERROR_CLASS_NO_SUB; EvUnRegFreeBase: EventBase->EdbUseCount--; if (EventBase->EdbUseCount == 0) { /* Nobody is registered to receive this event. */ if (LastEventBase == NULL) { /* Free the top element */ EventBase->EdbEvent = EventBase->EdbNext->EdbEvent; EventBase->EdbUseCount = EventBase->EdbNext->EdbUseCount; EventBase->EdbDestQ = EventBase->EdbNext->EdbDestQ; LastEventBase = EventBase->EdbNext; EventBase->EdbNext = LastEventBase->EdbNext; kfree(LastEventBase); } else { LastEventBase->EdbNext = EventBase->EdbNext; kfree(EventBase); } } ClassBase->EciUseCount--; kfree(FreeDest); spin_unlock_irqrestore(&ClassBase->EciLock, Flags); return EV_NOERR; }
/* * EvSubscribeEvent() subscribes a kernel component to recieve * an event. If the event call back function kernelCB is specified * events will be delivered by calling this function. Otherwise * events will be placed on an internal event queue and the queue must * be polled using the EvGetEvent function. * * This function subscribes to an event localy. It does not attempt to * inform a remote master that a subscriber has been attached. This * should be added in a later version of the function. */ int EvSubscribeEvent(EvUserID_t userID, EvPri_t pri, EvGroupID_t groupID, EvClassID_t classID, EvEventID_t eventID, EvAccess_t accessCode, int (*kernelCB)(EvUserID_t, EvPri_t, EvGroupID_t, EvGroupID_t, EvClassID_t, EvEventID_t, int, int, int, int, int, void *)) { EvDest_t *EventDestP = NULL; EvDest_t *TmpDestP = NULL; EvDest_t *LastEventDestP = NULL; EvDestBase_t *EventBase; EvKernelInfo_t *EventUser; EvGroupInfo_t *EGroup; EvClassInfo_t *HashBase; EvClassInfo_t *ClassBase; unsigned long Flags; /* Check the user ID for validity. */ read_lock_irqsave(&EvUsersLock, Flags); if ((EventUser = EvCheckUser(userID)) == NULL) { read_unlock_irqrestore(&EvUsersLock, Flags); return -EV_ERROR_USER_EXISTS; } /* Assume the Event user returned status will no change during * the life of this request. */ read_lock(&EvGroupLock); read_unlock(&EvUsersLock); /* Get the event group pointer. */ if ((EGroup = EvGetGroupBase(groupID)) == NULL) { read_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_GROUP_EXIST; } HashBase = EvGetHashBase(EGroup, classID); /* Find the top level entry for this class of events. */ if ((EventBase = EvFindEventBase(classID,HashBase,&ClassBase)) == NULL){ read_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_CLASS_EXISTS; } spin_lock(&ClassBase->EciLock); read_unlock(&EvGroupLock); /* Check permissions. */ if (EvCheckAccessCode(ClassBase->EciAccessCode, accessCode)) { spin_unlock_irqrestore(&ClassBase->EciLock, Flags); return -EV_ERROR_CLASS_ACCESS; } /* search until the event is found in this catagory or until the * last blank element on the list if found. */ while (EventBase->EdbNext != NULL) { if (EventBase->EdbEvent == eventID) { EventDestP = &EventBase->EdbDestQ; break; } EventBase = EventBase->EdbNext; } /* If no destination pointer has been identified for a chain * search then this event type has not yet been registered by anybody * so fill in the last empty list element and create a new empty one * to inidcate end of list. */ if (EventDestP == NULL) { EventBase->EdbEvent = eventID; EventBase->EdbUseCount = 0; /* Create the next empty element to indicate end of list. */ if ((EventBase->EdbNext = kmalloc(sizeof(EvDestBase_t), GFP_ATOMIC)) == NULL) { spin_unlock_irqrestore(&ClassBase->EciLock, Flags); return -EV_ERROR_MEM_ALLOC; } EventBase->EdbNext->EdbNext = NULL; EventDestP = &EventBase->EdbDestQ; EventDestP->EdNext = kmalloc(sizeof(EvDest_t), GFP_ATOMIC); EventDestP->EdNext->EdNext = NULL; goto EvFillInKernelRequestPacket; } /* Now search to see if this file descriptor already has registered * for this event type. */ while (EventDestP->EdNext != NULL) { if (EventDestP->EdID == userID) { spin_unlock_irqrestore(&ClassBase->EciLock, Flags); return -EV_ERROR_CLASS_BUSY; } LastEventDestP = EventDestP; EventDestP = EventDestP->EdNext; } /* Now record the destination and create a new empty element to * indicate end of list. */ /* Most registrations go at the end of the list. */ if ((LastEventDestP != NULL) && (LastEventDestP->EdPri >= pri)) { if ((EventDestP->EdNext = kmalloc(sizeof(EvDest_t), GFP_ATOMIC)) == NULL) { spin_unlock_irqrestore(&ClassBase->EciLock, Flags); return -EV_ERROR_MEM_ALLOC; } EventDestP->EdNext->EdNext = NULL; goto EvFillInKernelRequestPacket; } EventDestP = &EventBase->EdbDestQ; /* Check the priority against the top element */ if (EventDestP->EdPri >= pri) { /* Priority of event places it somewhere in the middle */ while (EventDestP->EdNext->EdPri >= pri) { EventDestP = EventDestP->EdNext; } } if ((TmpDestP = kmalloc(sizeof(EvDest_t), GFP_ATOMIC)) == NULL) { spin_unlock_irqrestore(&ClassBase->EciLock, Flags); return -EV_ERROR_MEM_ALLOC; } TmpDestP->EdPri = EventDestP->EdPri; TmpDestP->EdUinfo = EventDestP->EdUinfo; TmpDestP->EdCB = EventDestP->EdCB; TmpDestP->EdID = EventDestP->EdID; TmpDestP->EdKinfo = EventDestP->EdKinfo; TmpDestP->EdNext = EventDestP->EdNext; EventDestP->EdNext = TmpDestP; EvFillInKernelRequestPacket: EventBase->EdbUseCount++; EventDestP->EdPri = pri; EventDestP->EdUinfo = NULL; EventDestP->EdID = userID; EventDestP->EdCB = kernelCB; EventDestP->EdKinfo = EventUser; ClassBase->EciUseCount++; spin_unlock_irqrestore(&ClassBase->EciLock, Flags); return EV_NOERR; }
int EvInternalUnRegisterEventClass(EvGroupInfo_t *eGroup, EvClassID_t classID, EvAccess_t accessCode) { EvClassInfo_t *HashBase; EvClassInfo_t* HashDel; HashBase = EvGetHashBase(eGroup, classID); /* Does this hash have any classes assigned? */ if (HashBase->EciNext == NULL) { return -EV_ERROR_CLASS_EXISTS; } /* Is the top element his class? */ if (HashBase->EciClass == classID) { /* If subscribers use count is not zero then return error. */ if (HashBase->EciUseCount != 0) { return -EV_ERROR_CLASS_BUSY; } if (EvCheckAccessCode(HashBase->EciAccessCode, accessCode)) { return -EV_ERROR_CLASS_ACCESS; } HashDel = HashBase->EciNext; HashBase->EciClass = HashDel->EciClass; strncpy(HashBase->EciName, HashDel->EciName, 16); HashBase->EciEventQ = HashDel->EciEventQ; HashBase->EciNext = HashDel->EciNext; goto EvDelHashInfo; } HashDel = HashBase->EciNext; while(HashDel->EciNext != NULL) { if (HashDel->EciClass == classID) { break; } HashBase = HashDel; HashDel = HashDel->EciNext; } if (HashDel->EciNext == NULL) { return -EV_ERROR_CLASS_EXISTS; } if (HashDel->EciUseCount != 0) { return -EV_ERROR_CLASS_BUSY; } if (EvCheckAccessCode(HashDel->EciAccessCode, accessCode)) { return -EV_ERROR_CLASS_ACCESS; } HashBase->EciNext = HashDel->EciNext; EvDelHashInfo: /* Now reaquire the Group lock decrement the use count and send * remote packets. */ eGroup->EgiUseCount--; /* If this is a master send remove packets to all members. */ if (eGroup->EgiType == EG_MASTER) { EvSendUnRegClassToMembers(eGroup, classID, accessCode); } if (HashDel->EciEventQ) { kfree(HashDel->EciEventQ); } kfree(HashDel); return EV_NOERR; }
/* * The EvRegisterEventClass() function registers the className string as the * identifier of an event class and returns a unique token to identify that * class. The class is created as a part of an event group. * * If the event group is local then the event class is created as a part * of the local events and can be used only on the registering system. If * this system is the master for an event group then a local identity is * created on this system and notification is sent to remote systems to * inidcate this event has been created. If this event group is a member * on this system then the master is told to register this event class and * return the class ID and then a local copy of the registeration is made. * * If the event group defined by groupID does not exist then -EEXIST is * returned and no class is registered. If the event class defined by * className already exists -EBUSY is returned and not class is registered. * returned. If the kernel could not allocate enough memory for the * controling data structures -ENOSPC is returned and not class is * registered. Otherwise the class identified by className is registered, * a unique ID is allocated and placed in the class parameter and a * zero is returned to indicate success. */ int EvRegisterEventClass(EvGroupID_t groupID, char *className, EvAccess_t groupAccessCode, EvAccess_t classAccessCode, EvClassID_t *classID) { EvGroupInfo_t *EGroup; EvClassInfo_t *HashBase; unsigned long Flags; int RetVal; /* Get the group info pointer and return with it locked. */ if ((RetVal = EvLockAndGetGroup(groupID, EV_ACCESS_CHECK, groupAccessCode, &Flags, EV_LOCK_GROUP_WRITE, &EGroup))) { return RetVal; } /* Check to see if the class already exists */ if (EvCheckEventClass(EGroup, className, classID) > -1) { write_unlock_irqrestore(&EGroup->EgiLock, Flags); return -EV_ERROR_CLASS_EXISTS; } /* If the event class is not a local one then send a register to * the remote master. The remote master returns the class ID. */ if ((EGroup->EgiType == EG_MEMBER) && EGroup->EgiNextClass) { if ((RetVal = EvSendRegEventClass(EGroup, className, groupAccessCode, classAccessCode, classID, &Flags)) < 0) { write_unlock_irqrestore(&EGroup->EgiLock, Flags); return RetVal; } } else { /* Class is locally assigned */ *classID = EGroup->EgiNextClass++; /* If this is an event master then send class create event. */ if (EGroup->EgiType == EG_MASTER) { if ((RetVal = EvSendRegClassToMembers(EGroup, className, groupAccessCode, classAccessCode, *classID))) { write_unlock_irqrestore(&EGroup->EgiLock, Flags); return RetVal; } } } HashBase = EvGetHashBase(EGroup, *classID); while (HashBase->EciNext != NULL) { HashBase = HashBase->EciNext; } RetVal=EvFillInHashInfo(HashBase, classAccessCode, className, classID); EGroup->EgiUseCount++; write_unlock_irqrestore(&EGroup->EgiLock, Flags); return RetVal; }
int EvRemoteSendEvent(EvUserID_t senderID, EvGroupID_t memberID, EvPri_t pri, EvGroupID_t groupID, EvClassID_t classID, EvEventID_t eventID, EvAccess_t accessCode, int info0, int info1, int info2, int info3, int dataLen, void *data) { EvGroupInfo_t *EGroup; EvDestBase_t *EventBase; EvClassInfo_t *HashBase; EvClassInfo_t *ClassBase; unsigned long Flags; int RetVal; read_lock_irqsave(&EvGroupLock, Flags); if ((EGroup = EvGetGroupBase(groupID)) == NULL) { read_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_GROUP_EXIST; } /* If this a remote gen to the master then echo it back to * all members. */ if (EGroup->EgiType == EG_MASTER) { if (EGroup->EgiGroupDest.EdID != 0) { RetVal = EvGroupSendEvent(senderID, pri, EGroup->EgiID, EGroup->EgiMemberID, accessCode, classID, eventID, info0, info1, info2, info3, &EGroup->EgiGroupDest, dataLen, data); if (RetVal) { read_unlock_irqrestore(&EvGroupLock, Flags); return RetVal; } } } /* If the memberID issuing the event is the same as the member * id of this system then we have been echoed back an event * we sent tot he master. Ignore it. */ if ((EGroup->EgiType == EG_MEMBER) && (EGroup->EgiMemberID == memberID)) { read_unlock_irqrestore(&EvGroupLock, Flags); return EV_NOERR; } HashBase = EvGetHashBase(EGroup, classID); if ((EventBase = EvFindEventBase(classID, HashBase, &ClassBase))==NULL) { read_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_CLASS_EXISTS; } spin_lock(&ClassBase->EciLock); read_unlock(&EvGroupLock); RetVal = _EvSendEvent(EventBase, senderID, pri, groupID, memberID, classID, eventID, info0, info1, info2, info3, dataLen, data); spin_unlock_irqrestore(&ClassBase->EciLock, Flags); return RetVal; }