/* * EvGetEvent() retrieves an event from the event queue assigned to * the user id. * * If the user ID passed in is not a registed user then -ENOENT is * returned. If there are no pending events and waitflag is not * set then -EAGAIN is returned. If there are no events and waitflag * is set then the kernel thread associated with the user ID is * put to sleep. * * Otherwise the event packet pointer is placed in packet and a zero * is returned to indicate success. */ int EvGetEvent(EvUserID_t userID, int waitFlag, EvPacket_t **packet) { EvPacket_t *TmpPacket; EvKernelInfo_t *EventUser; unsigned long Flags; read_lock_irqsave(&EvUsersLock, Flags); /* Make sure this is a valile user ID. */ if ((EventUser = EvCheckUser(userID)) == NULL) { read_unlock_irqrestore(&EvUsersLock, Flags); *packet = NULL; return -EV_ERROR_USER_EXISTS; } spin_lock(&EventUser->EkiLock); read_unlock(&EvUsersLock); for (;;) { TmpPacket = EventUser->EkiHead; /* If there is a queued packet then get it and return. */ if (TmpPacket) { EventUser->EkiHead = TmpPacket->EpNext; if (EventUser->EkiHead == NULL) { EventUser->EkiTail = NULL; } EventUser->EkiQCount--; spin_unlock_irqrestore(&EventUser->EkiLock, Flags); *packet = TmpPacket; return EV_NOERR; } /* No queued packet and wait flag is not set then return * with a try again later indication. */ if (!waitFlag) { spin_unlock_irqrestore(&EventUser->EkiLock, Flags); *packet = NULL; return -EV_ERROR_NO_EVENT; } /* Other wise sleep waiting for ane event to arrive. */ spin_unlock_irqrestore(&EventUser->EkiLock, Flags); interruptible_sleep_on(&EventUser->EkiWaitQ); spin_lock_irqsave(&EventUser->EkiLock, Flags); } }
int EvSubscribeGroupEvents(EvUserID_t userID, EvGroupID_t groupID, EvAccess_t accessCode, int (*kernelCB)(EvUserID_t, int, EvGroupID_t, EvGroupID_t, EvClassID_t, EvEventID_t, int, int, int, int, int, void *)) { EvKernelInfo_t *EventUser; EvGroupInfo_t *EGroup; unsigned long Flags; read_lock_irqsave(&EvUsersLock, Flags); if ((EventUser = EvCheckUser(userID)) == NULL) { read_unlock_irqrestore(&EvUsersLock, Flags); return -EV_ERROR_USER_EXISTS; } write_lock(&EvGroupLock); read_unlock(&EvUsersLock); if ((EGroup = EvGetGroupBase(groupID)) == NULL) { write_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_GROUP_EXIST; } /* Check the access code for the group. */ if (EvCheckAccessCode(EGroup->EgiAccessCode, accessCode)) { write_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_GROUP_ACCESS; } /* Check that there are no current control processes. */ if (EGroup->EgiGroupDest.EdID != 0) { write_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_GROUP_BUSY; } EGroup->EgiGroupDest.EdPri = 0; /* Not used. */ EGroup->EgiGroupDest.EdID = userID; EGroup->EgiGroupDest.EdUinfo = NULL; EGroup->EgiGroupDest.EdCB = kernelCB; EGroup->EgiGroupDest.EdKinfo = EventUser; EGroup->EgiUseCount++; write_unlock_irqrestore(&EvGroupLock, Flags); return EV_NOERR; }
int EvUnSubscribeGroupEvents(EvUserID_t userID, EvGroupID_t groupID) { EvKernelInfo_t *EventUser; EvGroupInfo_t *EGroup; unsigned long Flags; read_lock_irqsave(&EvUsersLock, Flags); if ((EventUser = EvCheckUser(userID)) == NULL) { read_unlock_irqrestore(&EvUsersLock, Flags); return -EV_ERROR_USER_EXISTS; } write_lock(&EvGroupLock); read_unlock(&EvUsersLock); if ((EGroup = EvGetGroupBase(groupID)) == NULL) { write_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_GROUP_EXIST; } /* Check that there are no current control processes. */ if (EGroup->EgiGroupDest.EdID != userID) { write_unlock_irqrestore(&EvGroupLock, Flags); return -EV_ERROR_GROUP_ACCESS; } EGroup->EgiGroupDest.EdID = 0; EGroup->EgiGroupDest.EdUinfo = NULL; EGroup->EgiGroupDest.EdCB = NULL; EGroup->EgiGroupDest.EdKinfo = NULL; EGroup->EgiUseCount--; write_unlock_irqrestore(&EvGroupLock, Flags); return EV_NOERR; }
/* * 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; }