MME_ERROR MME_MessageQueue_Init(MMEMessageQueue * msgQ, int maxEntries)
{
	MME_ERROR err;
        int size = maxEntries * sizeof(MMEMessageQueueEntry);

	MME_Info(MME_INFO_QUEUE, (">>>MME_MessageQueue_Init(0x%08x, %d)\n", 
	                          (unsigned) msgQ, maxEntries));

	msgQ->maxEntries = maxEntries;

	msgQ->queue = (MMEMessageQueueEntry*) EMBX_OS_MemAlloc(size);

	if (msgQ->queue == NULL) {
		MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Init = MME_NOMEM\n"));
		return MME_NOMEM;
	}
        memset(msgQ->queue, 0, size);

	if (!EMBX_OS_MUTEX_INIT(&msgQ->queueLock)) {
		MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Init = MME_NOMEM\n"));
		return MME_NOMEM;
	}

	err = MME_MessageQueue_RemoveAll(msgQ);
	MME_Assert(MME_SUCCESS == err); /* currently has no failure path */


	MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Init = MME_SUCCESS\n"));
	return MME_SUCCESS;
}
/*
 * Transport method to open a handle
 */
static EMBX_ERROR openHandle (EMBX_Transport_t        *tp,
                              EMBX_TransportHandle_t **tph)
{
    EMBXSHM_TransportHandle_t *handle;

    EMBX_Info (EMBX_INFO_TRANSPORT, (">>>openHandle()\n"));
    EMBX_Assert (tp);
    EMBX_Assert (tph);

    /*
     * Allocate memory for handle
     */
    handle = (EMBXSHM_TransportHandle_t *)EMBX_OS_MemAlloc (sizeof (EMBXSHM_TransportHandle_t));
    if (handle != NULL)
    {
        /*
         * Copy default structure contents.
         */
        memcpy (handle, &EMBXSHM_transportHandleTemplate, sizeof (EMBXSHM_TransportHandle_t));
        *tph = (EMBX_TransportHandle_t *)handle;

        EMBX_OS_MODULE_REF();

        EMBX_Info (EMBX_INFO_TRANSPORT, ("<<<openHandle = EMBX_SUCCESS\n"));
        return EMBX_SUCCESS;
    }
    else
    {
        EMBX_Info (EMBX_INFO_TRANSPORT, ("<<<openHandle = EMBX_NOMEM\n"));
        return EMBX_NOMEM;
    }
}
static EMBX_ERROR create_remote_port(EMBXLB_LocalPortHandle_t *localPort, EMBX_RemotePortHandle_t **port)
{
EMBXLB_RemotePortHandle_t *remotePort;

    remotePort = (EMBXLB_RemotePortHandle_t *)EMBX_OS_MemAlloc(sizeof(EMBXLB_RemotePortHandle_t));
    if(remotePort != 0)
    {
        memcpy(remotePort, &_embxlb_remoteport_handle_template, sizeof(EMBXLB_RemotePortHandle_t));

        remotePort->destination    = localPort;
        remotePort->nextConnection = localPort->remote_connections;

        if(localPort->remote_connections != 0)
            localPort->remote_connections->prevConnection = remotePort;


        localPort->remote_connections = remotePort;

        *port = &remotePort->port;
        return EMBX_SUCCESS;
    }

    *port = 0;
    return EMBX_NOMEM;
}
Exemple #4
0
static MME_ERROR createTransportInfo(const char *name, TransportInfo_t **tpInfo_p)
{
	const char portName[] = "MMEHostReplyPort#0";

	TransportInfo_t *tpInfo;
	EMBX_ERROR err;
	
	/* Allocate space for the transport descriptor */
	tpInfo = EMBX_OS_MemAlloc(sizeof(TransportInfo_t));
	if (!tpInfo) {
		return MME_NOMEM;
	}
	memset(tpInfo, 0, sizeof(TransportInfo_t));

	/* Open a transport handle */
	err = EMBX_OpenTransport(name, &tpInfo->handle);
	if (EMBX_SUCCESS != err) {
		goto error_recovery;
	}

	/* Create the reply port. */
	memcpy(tpInfo->replyPortName, portName, sizeof(portName));

	/* MULTIHOST support */
	do {
		MME_Info(MME_INFO_MANAGER, ("   EMBX_CreatePort(), port name <%s>...\n", 
					    tpInfo->replyPortName));
		
		/* Create the reply port. This port is purely synchronous (it only receives
		 * messages that are replies to outstanding messages) and as such does not
		 * need its own management thread.
		 */
		err = EMBX_CreatePort(tpInfo->handle, tpInfo->replyPortName, &tpInfo->replyPort);

	} while (EMBX_ALREADY_BIND == err && 
	         tpInfo->replyPortName[sizeof(portName)-2]++ < '9');

	if (EMBX_SUCCESS != err) {
		goto error_recovery;
	}
	
	*tpInfo_p = tpInfo;
	return MME_SUCCESS;

    error_recovery:
    
    	if (tpInfo->handle) {
    		err = EMBX_CloseTransport(tpInfo->handle);
    		MME_Assert(EMBX_SUCCESS == err);
    	}
    	EMBX_OS_MemFree(tpInfo);
    	
    	return MME_EMBX_ERROR;
}
Exemple #5
0
MME_ERROR MME_RegisterTransformer(const char *name,
                                  MME_AbortCommand_t abortCommand,
                                  MME_GetTransformerCapability_t getTransformerCapability,
                                  MME_InitTransformer_t initTransformer,
                                  MME_ProcessCommand_t processCommand,
                                  MME_TermTransformer_t termTransformer)
{
	RegisteredLocalTransformer_t *elem;

#ifndef MME_LEAN_AND_MEAN
	if (NULL == manager) {
		return MME_DRIVER_NOT_INITIALIZED;
	}

	if (NULL == name) {
		return MME_INVALID_ARGUMENT;
	}
#endif

	EMBX_OS_MUTEX_TAKE(&manager->monitorMutex);

	/* check for multiple registrations */
	for (elem = manager->localTransformerList; elem; elem = elem->next) {
		if (0 == strcmp(name, elem->name)) {
			EMBX_OS_MUTEX_RELEASE(&manager->monitorMutex);
			return MME_INVALID_ARGUMENT;
		}
	}

	/* register the transformer */
	elem = EMBX_OS_MemAlloc(sizeof(*elem) + strlen(name) + 1);
	
	/* populate and enqueue the structure */
	elem->name = (char *) (elem + 1);
	strcpy(elem->name, name);

	elem->vtable.AbortCommand = abortCommand;
	elem->vtable.GetTransformerCapability = getTransformerCapability;
	elem->vtable.InitTransformer = initTransformer;
	elem->vtable.ProcessCommand = processCommand;
	elem->vtable.TermTransformer = termTransformer;

	elem->inUseCount = 0;

	elem->next = manager->localTransformerList;
	manager->localTransformerList = elem;

	EMBX_OS_MUTEX_RELEASE(&manager->monitorMutex);
	return MME_SUCCESS;
}
Exemple #6
0
EMBX_EVENT EMBX_OS_EventCreate(void)
{
    EMBX_EVENT ev = NULL;

    /* This is not multithread safe - perhaps use an atomic test&set ? */
    if (!cacheInitialised)
    {
        cacheInitialised = 1;
	(void) EMBX_OS_MUTEX_INIT(&cacheLock);
    }
    
    EMBX_OS_MUTEX_TAKE(&cacheLock);
    
    if ((ev = cacheHead) != NULL)
    {
        cacheHead = cacheHead->next;

	/* Mark desc as being in use */
	ev->next = (EMBX_EVENT) EMBX_HANDLE_VALID;

	EMBX_OS_MUTEX_RELEASE(&cacheLock);
    }
    else
    {
        EMBX_OS_MUTEX_RELEASE(&cacheLock);
      
	/* Dynamically allocate a new cache container
	 * and initialise the event inside it
	 */
	ev = EMBX_OS_MemAlloc(sizeof(*ev));
	
	if (ev)
	{
	    /* Mark desc as being in use */
	    ev->next = (EMBX_EVENT) EMBX_HANDLE_VALID;

	    ev->event = semaphore_create_fifo(0);
	}
    }
    
    return ev;
}
static EMBX_ERROR connect_block(EMBX_TransportHandle_t *tp, const EMBX_CHAR *portName, EMBX_EventState_t *es, EMBX_RemotePortHandle_t **port)
{
EMBX_ERROR res;

    res = connect_async(tp,portName,port);
    if(res == EMBX_PORT_NOT_BIND)
    {
    EMBXLB_ConnectBlockList_t *node;
    EMBXLB_Transport_t        *tplb;

        /* Portname not found so try and block the task until it is created */
        node = (EMBXLB_ConnectBlockList_t *)EMBX_OS_MemAlloc(sizeof(EMBXLB_ConnectBlockList_t));
        if(node == 0)
            return EMBX_NOMEM;


        strcpy(node->portName, portName);

        /* In this transport we can directly access the connect block list
         * without any additional locking.
         */
        tplb = (EMBXLB_Transport_t *)tp->transport;

        node->ev   = es;
        node->port = port;
        node->requestingHandle = tp; /* Needed for close_handle to clean up its blocked connections */
        node->prev = 0;
        node->next = tplb->connectionRequests;
        
        if(node->next != 0)
            node->next->prev = node;


        tplb->connectionRequests = node;

        return EMBX_BLOCK;
    }
    else
    {
        return res;
    }
}
Exemple #8
0
MMELookupTable_t * MME_LookupTable_Create(int max, int temporal)
{
	MMELookupTable_t *tbl;
        int size = sizeof(MMELookupTable_t) + (max-1) * sizeof(void *);

	MME_Assert(max > 0);
	MME_Assert(0 == temporal || 1 == temporal);

	/* allocation */
        tbl = EMBX_OS_MemAlloc(size);
        if (!tbl) {
                return NULL;
        }
        memset(tbl, 0, size);

	tbl->maxEntries = max;
	tbl->temporallyUnique = temporal;

	return tbl;
}
Exemple #9
0
MME_ERROR MME_HostInit(void)
#endif
{
	if (NULL != manager) {
		return MME_DRIVER_ALREADY_INITIALIZED;
	}

	manager = EMBX_OS_MemAlloc(sizeof(HostManager_t));
	if (!manager) {
		return MME_NOMEM;
	}
	memset(manager, 0, sizeof(HostManager_t));

	manager->transformerInstances = MME_LookupTable_Create(MAX_TRANSFORMER_INSTANCES, 1);
	if (!manager->transformerInstances) {
		goto error_path;
	}

	if (EMBX_FALSE == EMBX_OS_MUTEX_INIT(&manager->monitorMutex)) {
		goto error_path;
	}
	if (EMBX_FALSE == EMBX_OS_MUTEX_INIT(&manager->eventLock)) {
		goto error_path;
	}
	if (EMBX_FALSE == EMBX_OS_EVENT_INIT(&manager->waitorDone)) {
		goto error_path;
	}
	return MME_SUCCESS;

    error_path:

	if (manager->transformerInstances) {
		MME_LookupTable_Delete(manager->transformerInstances);
	}
	EMBX_OS_MemFree(manager);
	manager = NULL;
	
	return MME_NOMEM;
}
static EMBX_ERROR grow_port_table(EMBXLB_Transport_t *tplb, EMBX_INT *freeSlot)
{
EMBXLB_LocalPortHandle_t **newTable;
EMBX_UINT                  newTableSize;
EMBX_UINT                  nBytes;

    *freeSlot = tplb->portTableSize;

    newTableSize = tplb->portTableSize * 2;

    if(newTableSize < tplb->portTableSize)
    {
        EMBX_DebugMessage(("EMBXLB::grow_port_table 'table size overflowed!!!'\n"));
        return EMBX_NOMEM;
    }


    nBytes   = newTableSize*sizeof(EMBXLB_LocalPortHandle_t *);
    newTable = (EMBXLB_LocalPortHandle_t **)EMBX_OS_MemAlloc(nBytes);
    if(newTable != 0)
    {
        memset(newTable, 0, nBytes);
        memcpy(newTable, tplb->portTable, tplb->portTableSize*sizeof(EMBXLB_LocalPortHandle_t *));

        EMBX_OS_MemFree(tplb->portTable);

        tplb->portTable     = newTable;
        tplb->portTableSize = newTableSize;

        EMBX_DebugMessage(("EMBXLB::grow_port_table 'new port table size = %u'\n", newTableSize));

        return EMBX_SUCCESS;
    }

    EMBX_DebugMessage(("EMBXLB::grow_port_table 'could not grow port table'\n"));
    return EMBX_NOMEM;
}
Transformer_t* MME_RemoteTransformer_Create(HostManager_t *manager, TransportInfo_t* info, EMBX_PORT adminPort)
{
	static const TransformerVTable_t vtable = {
	        RemoteTransformer_Destroy,
	        RemoteTransformer_Init,
	        RemoteTransformer_Term,
	        RemoteTransformer_Kill,
	        RemoteTransformer_AbortCommand,
		RemoteTransformer_KillCommand,
	        RemoteTransformer_SendCommand,
	        RemoteTransformer_IsStillAlive,
	        RemoteTransformer_GetTransformerCapability,
		RemoteTransformer_WaitForMessage,
		RemoteTransformer_LookupCommand,
		RemoteTransformer_ReleaseCommandSlot
	};

	RemoteTransformer_t* remoteTransformer;
	int i;
	
	remoteTransformer = EMBX_OS_MemAlloc(sizeof(RemoteTransformer_t));
	if (!remoteTransformer) {
		return NULL;
	}

	/* zero the structure */
	memset(remoteTransformer, 0, sizeof(RemoteTransformer_t));

	/* initialize the non-zero elements */
	remoteTransformer->super.vtable     = &vtable;
	remoteTransformer->super.manager    = manager;
	remoteTransformer->super.info       = info;
	remoteTransformer->adminPort        = adminPort;
	remoteTransformer->maxCommandSlots  = MAX_TRANSFORMER_SEND_OPS;

	/* allocate the command slots (used to keep track of in-flight commands) */
	remoteTransformer->commandSlots = EMBX_OS_MemAlloc(sizeof(CommandSlot_t) *
							   remoteTransformer->maxCommandSlots);
	if (0 == remoteTransformer->commandSlots) {
		goto error_recovery;
	}
	
	for (i=0; i<remoteTransformer->maxCommandSlots; i++) {
		remoteTransformer->commandSlots[i].command = 0;
		remoteTransformer->commandSlots[i].status = MME_COMMAND_COMPLETED_EVT;
	}

	if (!EMBX_OS_EVENT_INIT(&remoteTransformer->terminateWasReplied)) {
		goto error_recovery;
	}
	
	if (!EMBX_OS_MUTEX_INIT(&remoteTransformer->commandSlotLock)) {
		EMBX_OS_EVENT_DESTROY(&remoteTransformer->terminateWasReplied);	
		goto error_recovery;
	}
	
	/* reference the transport info structure (so it can't be deregistered) */
	info->referenceCount++;
	
	return &remoteTransformer->super;
	
    error_recovery:
    	
    	/* EMBX_OS_MemFree() will ignore NULL pointers */
    	EMBX_OS_MemFree(remoteTransformer->commandSlots);
    	EMBX_OS_MemFree(remoteTransformer);

    	return NULL;
}
EMBX_Transport_t *EMBXLB_loopback_factory(void *param)
{
EMBXLB_Config_t *config = (EMBXLB_Config_t *)param;
EMBXLB_Transport_t *tp;

    if(config->name == 0)
        return 0;

    if(strlen(config->name) > EMBX_MAX_TRANSPORT_NAME)
        return 0;


    /* The transport structure _must_ be allocated from OS
     * memory. It is managed from now on by the framework.
     */
    tp = (EMBXLB_Transport_t *)EMBX_OS_MemAlloc(sizeof(EMBXLB_Transport_t));
    if(tp == 0)
        return 0;


    /* Decide which type of initialization to do. 
     * PLEASE NOTE: This is for the purposes of testing
     * the behaviour of the framework ONLY, a more realistic
     * transport implementation would either block, or not,
     * depending on the nature of its initialization
     * requirements. 
     */
    if(config->blockInit)
    {
        memcpy(tp,&_embxlb_blocktransport_template,sizeof(EMBXLB_Transport_t));
    }
    else
    {
        memcpy(tp,&_embxlb_transport_template,sizeof(EMBXLB_Transport_t));
    }


    /* Limiting the number of alocations is for testing the framework
     * error handling only. A more realistic transport would not do this.
     */
    tp->maxAllocations = config->maxAllocations; /* 0 = no limit */

    /* A more realistic transport would likely support only one of the
     * connection semantics. This configuration is for the purposes of
     * testing the framework.
     */
    tp->transport.transportInfo.allowsMultipleConnections = config->multiConnect;

    tp->transport.transportInfo.maxPorts = config->maxPorts; /* 0 = no limit */

    strcpy(tp->transport.transportInfo.name,config->name);


    if(config->maxObjects > 0)
    {
        if(!EMBX_HandleManager_SetSize(&tp->objectHandleManager, config->maxObjects))
        {
            EMBX_OS_MemFree(tp);
            return 0;
        }
    }
    else
    {
        EMBX_HandleManager_SetSize(&tp->objectHandleManager, EMBX_HANDLE_DEFAULT_TABLE_SIZE);
    }

    return &tp->transport;
}
static EMBX_ERROR do_send(EMBXLB_RemotePortHandle_t *phlb  ,
                          EMBX_RECEIVE_TYPE          evtype,
                          EMBX_HANDLE                handle,
                          EMBX_VOID                 *data  ,
                          EMBX_UINT                  offset,
                          EMBX_UINT                  size   )
{
    if(phlb->destination->blocked_receivers != 0)
    {
        EMBXLB_RecBlockList_t *receiver;

        /* Pick the first blocked receiver and put the object event info
         * directly into its receive event structure, then signal it to
         * wake up.
         */
        receiver = phlb->destination->blocked_receivers;
        phlb->destination->blocked_receivers = receiver->next;

        receiver->recev->handle = handle;
        receiver->recev->data   = data;
        receiver->recev->offset = offset;
        receiver->recev->size   = size;
        receiver->recev->type   = evtype;

        receiver->ev->result    = EMBX_SUCCESS;
        EMBX_OS_EVENT_POST(&receiver->ev->event);

        EMBX_OS_MemFree(receiver);
    }
    else
    {
        EMBXLB_RecEventList_t *node;

        /* Nobody is waiting for the message so we have to queue it
         * on the destination
         */
        node = (EMBXLB_RecEventList_t *)EMBX_OS_MemAlloc(sizeof(EMBXLB_RecEventList_t));
        if(node == 0)
            return EMBX_NOMEM;


        node->recev.handle = handle;
        node->recev.data   = data;
        node->recev.offset = offset;
        node->recev.size   = size;
        node->recev.type   = evtype;
        node->next         = 0;

        if(phlb->destination->pending_head != 0)
        {
            phlb->destination->pending_tail->next = node;
            phlb->destination->pending_tail       = node;
        }
        else
        {
            phlb->destination->pending_tail = node;
            phlb->destination->pending_head = node;
        }
    }

    return EMBX_SUCCESS;
}
static EMBX_ERROR create_port(EMBX_TransportHandle_t *tp, const EMBX_CHAR *portName, EMBX_LocalPortHandle_t **port)
{
EMBX_ERROR res;
EMBX_INT   freeSlot;
EMBXLB_LocalPortHandle_t *phlb;
EMBXLB_Transport_t       *tplb;


    tplb = (EMBXLB_Transport_t *)tp->transport;

    res = find_free_port_table_entry(tplb, portName, &freeSlot);
    
    switch (res)
    {
        case EMBX_SUCCESS:
        {
            break;
        } /* EMBX_SUCCESS */
        case EMBX_NOMEM:
        {
            /*
             * If we have got to this point then there is no fixed
             * transport limit to number of ports (this is checked
             * in the shell) so try and grow the port table.
             */
            if(grow_port_table(tplb, &freeSlot) != EMBX_SUCCESS)
                return EMBX_NOMEM;


            break;
        } /* EMBX_NOMEM */
        default:
        {
            return res;
        }
    }


    phlb = (EMBXLB_LocalPortHandle_t *)EMBX_OS_MemAlloc(sizeof(EMBXLB_LocalPortHandle_t));
    if(phlb != 0)
    {
        memcpy(phlb, &_embxlb_localport_handle_template, sizeof(EMBXLB_LocalPortHandle_t));

        tplb->portTable[freeSlot] = phlb;
        *port = &phlb->port;

        /*
         * The transportHandle,port name and state members of the local port base
         * structure are filled in by the framework.
         */

        /*
         * Finally, make connections for any blocked connection requests waiting
         * for this new port name.
         */
        make_connections(tplb, phlb, portName);

        return EMBX_SUCCESS;
    }

    return EMBX_NOMEM;
}
Exemple #15
0
MME_ERROR MME_AllocDataBuffer(MME_TransformerHandle_t handle, MME_UINT size,
			      MME_AllocationFlags_t flags, MME_DataBuffer_t ** dataBuffer_p) 
{
	static const MME_AllocationFlags_t illegalFlags = (MME_AllocationFlags_t)
		~(MME_ALLOCATION_PHYSICAL | MME_ALLOCATION_CACHED | MME_ALLOCATION_UNCACHED);

	Transformer_t *transformer;
	struct InternalDataBuffer *buf;
	unsigned localSize;

#ifndef MME_LEAN_AND_MEAN
        if (manager == NULL) {
 	        MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Driver not initialized\n"));
                return MME_DRIVER_NOT_INITIALIZED;      /* the manager must exist */
        }

	if (0 == size || NULL == dataBuffer_p || (flags & illegalFlags)) {
 	        MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "size==0 ||  NULL == dataBuffer_p || (flags & illegalFlags)\n"));
		return MME_INVALID_ARGUMENT;
	}

	if (0 > (int) size) {
 	        MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "size<0\n"));
		return MME_NOMEM;
	}
#endif

	/* lookup whether we should allocate using EMBX_OS_MemAlloc or EMBX_Alloc() */
	if (MME_SUCCESS != findTransformerInstance(handle, &transformer)) {
 	        MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "invalid transformer handle\n"));
		return MME_INVALID_HANDLE;
	}
	if (0 == transformer->info) {
		/* this is a local transformers so we can't allocate memory using EMBX_Alloc */
		flags |= MME_ALLOCATION_CACHED;
	}

	/* Allocate the buffer structure */
	/* Cannot present a "negative" value to EMBX_OS_MemAlloc on SHLINUX KERNEL mode
         * as it "succeeds" and returns a non-NULL value
         */
        localSize = (int) (sizeof(*buf) + (flags & MME_ALLOCATION_CACHED ? size + MME_MAX_CACHE_LINE-1 : 0));
        if (0 > (int) localSize) {
 	        MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "localSze <0\n"));
		return MME_NOMEM;
        }

	buf = EMBX_OS_MemAlloc(localSize);

	if (NULL == buf) {
 	        MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Cannot EMBX_OS_MemAlloc(%d)\n", 
                          sizeof(*buf) + (flags & MME_ALLOCATION_CACHED ? size : 0) ));
		return MME_NOMEM;
	}

	/* populate the buffer structure */
	memset(buf, 0, sizeof(*buf));
	buf->buffer.StructSize = sizeof(MME_DataBuffer_t);
	buf->buffer.NumberOfScatterPages = 1;
	buf->buffer.ScatterPages_p = buf->pages;
	buf->buffer.TotalSize = size;
	buf->flags = flags;
	buf->pages[0].Size = size;

	if (flags & MME_ALLOCATION_CACHED) {
		/* We MUST align the data buffer to a cacheline boundary to keep this safe */
		buf->pages[0].Page_p = (void *) MME_CACHE_LINE_ALIGN((buf + 1));
	} else {
		/* if transportHandle is 0 this will fail so we have no specific path to
		 * prevent uncached allocations for local transformers.
		 */
		EMBX_ERROR err = EMBX_Alloc(transformer->info->handle, size, 
					    &buf->pages[0].Page_p);

		if (EMBX_SUCCESS != err) {
     	                MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Cannot EMBX_Alloc(0x%08x, %d, 0x%08x)\n",
                                                     transformer->info->handle, size, (unsigned) &buf->pages[0].Page_p));
			EMBX_OS_MemFree(buf);
			return MME_NOMEM;
		}
	}

	*dataBuffer_p = &(buf->buffer);
	return MME_SUCCESS;
}