original files of m241
This commit is contained in:
@@ -0,0 +1,627 @@
|
||||
/* device.c - Device Infrastructure Library */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005-2009, 2011-2013, 2016 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01o,18may16,myt fix issue that fsmNameInstall cannot correctly add a XBD driver
|
||||
name of which length is equal to MAX_DEVNAME (VXW6-85215)
|
||||
01n,08oct13,dee eliminate unused local function
|
||||
01m,28jun13,xwu fix WIND00424201 Coverity issue: remain high impact defect of FS
|
||||
01l,24may13,xwu Replace mutex with spinlock for performance (WIND00337587)
|
||||
01k,27aug12,clx fix ddDelete memory leak issue. (WIND00365416)
|
||||
01j,13jan11,m_y Add devGetByName() (WIND00211541)
|
||||
01i,15oct09,h_k cleaned up compiler warnings for LP64.
|
||||
01h,29aug06,dee WIND00062547 - fix XBD resource limitation caused by queueing
|
||||
problem
|
||||
01g,01mar06,dee add unsafe devmap and unmap functions for coredump
|
||||
01f,11jul05,rfr Mark the struct device when removal is complete
|
||||
01e,04jul05,pcm added comments and sections for doc build
|
||||
01d,28apr05,rfr Added setting the dv_dev member in devAttach()
|
||||
01c,26apr05,rfr Fixed call to strncpy
|
||||
01b,20apr05,rfr Added devName() function
|
||||
01a,25mar05,rfr Removed prototype eventing system.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This library provides the interface for the device infrastructure.
|
||||
|
||||
INCLUDE FILES: drv/manager/device.h
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <semLib.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <intLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <spinLockLib.h>
|
||||
#include <stdio.h>
|
||||
#include <drv/manager/device.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
#define DEVICE_T_ITEM(d) (uint16_t)(((d) & 0xffff0000) >> 16)
|
||||
#define DEVICE_T_GEN(d) ((d) & 0xffff)
|
||||
|
||||
#define DEVICE_T_MAP(index, d) ((index)->ddh_map[DEVICE_T_ITEM(d)])
|
||||
#define ITEM_MAP(index, i) ((index)->ddh_map[(i)])
|
||||
|
||||
/* DEVICE_T_EXISTS() is nonzero if d is a legitimate device_t in index */
|
||||
#define DEVICE_T_EXISTS(index, d) ((index) != NULL &&\
|
||||
DEVICE_T_GEN(d) != 0 &&\
|
||||
DEVICE_T_ITEM(d) < (index)->ddh_size)
|
||||
|
||||
/* DEVICE_T_VALID() is nonzero if d is a valid mapping in index */
|
||||
#define DEVICE_T_VALID(index, d) (DEVICE_T_MAP((index), (d)).ddm_data != NULL &&\
|
||||
DEVICE_T_GEN(d) == DEVICE_T_MAP((index), (d)).ddm_generation)
|
||||
|
||||
#define NULLINDEX 0xffff /* represents end of list for the free list */
|
||||
|
||||
/* typedefs */
|
||||
|
||||
/*
|
||||
* struct ddMapRec represents individual mappings from device_t to struct device *
|
||||
* Each mapping is specified by an index and a generation number
|
||||
*/
|
||||
|
||||
struct ddMapRec
|
||||
{
|
||||
uint16_t ddm_generation; /* the generation of this mapping */
|
||||
uint16_t ddm_next; /* Index of the next free mapping */
|
||||
struct device *ddm_data; /* The Item of this mapping */
|
||||
struct device *ddm_cache; /* Cached device for marking on removal complete */
|
||||
unsigned ddm_refCount; /* The number of active devMap() */
|
||||
};
|
||||
|
||||
/*
|
||||
* struct ddHeader represents the entire mapping of device_t to struct device *
|
||||
*/
|
||||
|
||||
struct ddHeader
|
||||
{
|
||||
uint16_t ddh_size; /* The number of slots */
|
||||
uint16_t ddh_freeh; /* The head of the free list */
|
||||
uint16_t ddh_freet; /* The tail of the free list */
|
||||
spinlockTask_t ddh_lock; /* The lock of the mappings */
|
||||
struct ddMapRec ddh_map[1]; /* First element of the mappings */
|
||||
};
|
||||
|
||||
/* locals */
|
||||
|
||||
LOCAL struct ddHeader *dit_index = NULL;
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
LOCAL void ddFinishRemoval(struct ddHeader *index, uint16_t item);
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* ddInit -
|
||||
*
|
||||
* \NOMANUAL
|
||||
*/
|
||||
|
||||
LOCAL struct ddHeader *ddInit
|
||||
(
|
||||
uint16_t Size
|
||||
)
|
||||
{
|
||||
uint16_t i, last;
|
||||
struct ddHeader *retVal;
|
||||
|
||||
if (Size == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Allocate the index */
|
||||
retVal = malloc (sizeof (*retVal) +
|
||||
sizeof (struct ddMapRec) * (uint16_t)(Size - 1));
|
||||
|
||||
if (!retVal)
|
||||
return (NULL);
|
||||
|
||||
SPIN_LOCK_TASK_INIT(&retVal->ddh_lock, 0);
|
||||
|
||||
last = (uint16_t)(Size - 1);
|
||||
|
||||
retVal->ddh_size = Size;
|
||||
retVal->ddh_freeh = 0;
|
||||
retVal->ddh_freet = last;
|
||||
|
||||
/* Thread the individual mapping records together */
|
||||
|
||||
for (i = 0; i <= last; i++)
|
||||
{
|
||||
retVal->ddh_map[i].ddm_generation = 1;
|
||||
retVal->ddh_map[i].ddm_data = NULL;
|
||||
retVal->ddh_map[i].ddm_refCount = 0;
|
||||
|
||||
retVal->ddh_map[i].ddm_next = (uint16_t)(i + 1);
|
||||
}
|
||||
retVal->ddh_map[last].ddm_next = NULLINDEX;
|
||||
|
||||
return (retVal);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* ddInsert - allocate a device_t slot and put a struct device * in it
|
||||
*
|
||||
* This function must be called with the index mutex held. It only allocates
|
||||
* the device_t and inserts the device. Modifications to the struct device must
|
||||
* happen externally.
|
||||
*
|
||||
* RETURNS: 0 on success or an errno.h value on failure
|
||||
*
|
||||
* \NOMANUAL
|
||||
*/
|
||||
LOCAL int ddInsert
|
||||
(
|
||||
struct ddHeader *index,
|
||||
struct device *dev,
|
||||
device_t *result
|
||||
)
|
||||
{
|
||||
uint16_t item;
|
||||
|
||||
if (index == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
if (dev == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
/* Get a free slot */
|
||||
if (index->ddh_freeh == NULLINDEX)
|
||||
{
|
||||
/* nothing on the free list */
|
||||
return (ENOMEM);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the first element of the free list */
|
||||
item = index->ddh_freeh;
|
||||
/* Link the free list to the next element */
|
||||
index->ddh_freeh = index->ddh_map[item].ddm_next;
|
||||
|
||||
/* enforce empty condition on the other side of the list */
|
||||
if (index->ddh_freeh == NULLINDEX)
|
||||
index->ddh_freet = NULLINDEX;
|
||||
}
|
||||
|
||||
/* item is the index of the new slot */
|
||||
index->ddh_map[item].ddm_data = dev;
|
||||
index->ddh_map[item].ddm_refCount = 0;
|
||||
/* Make next point nowhere */
|
||||
index->ddh_map[item].ddm_next = NULLINDEX;
|
||||
/* generation stays the same - it is incremented on removal */
|
||||
|
||||
/* if result is NULL we're gonna lose this mapping */
|
||||
if (result)
|
||||
{
|
||||
/* Roll up the device_t */
|
||||
*result = (device_t)((item << 16) |
|
||||
index->ddh_map[item].ddm_generation);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* ddRemove - remove a mapping from device_t to struct device *
|
||||
*
|
||||
* This function must be called with the index mutex held.
|
||||
* This function only removes the mapping, it does not modify the contents of the
|
||||
* struct device.
|
||||
* If this function fails, it will leave the map unchanged.
|
||||
*
|
||||
* RETURNS: 0 on success or a value from errno.h on failure.
|
||||
*
|
||||
* \NOMANUAL
|
||||
*/
|
||||
|
||||
LOCAL int ddRemove
|
||||
(
|
||||
struct ddHeader *index,
|
||||
device_t dev
|
||||
)
|
||||
{
|
||||
uint16_t item;
|
||||
|
||||
if (!DEVICE_T_EXISTS(index, dev))
|
||||
return (EINVAL);
|
||||
|
||||
if (!DEVICE_T_VALID(index, dev))
|
||||
return (ENOENT);
|
||||
|
||||
/* If we got here, then dev refers to a valid mapping */
|
||||
item = DEVICE_T_ITEM(dev);
|
||||
|
||||
/* Cache the data so we can mark it when we're done */
|
||||
ITEM_MAP(index, item).ddm_cache = ITEM_MAP(index, item).ddm_data;
|
||||
|
||||
/* Set the data to NULL - this effects the unmapping */
|
||||
ITEM_MAP(index, item).ddm_data = NULL;
|
||||
|
||||
/*
|
||||
* Now we test to see whether or not we complete the removal here. If the
|
||||
* refCount is zero, the device_t is not in use, and we can undo it here.
|
||||
* If not, then we must wait and let ddUnmap() do the final removal.
|
||||
*/
|
||||
|
||||
if (ITEM_MAP(index, item).ddm_refCount == 0)
|
||||
{
|
||||
ddFinishRemoval(index, item);
|
||||
}
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* ddFinishRemoval -
|
||||
*
|
||||
* \NOMANUAL
|
||||
*/
|
||||
|
||||
LOCAL void ddFinishRemoval
|
||||
(
|
||||
struct ddHeader *index,
|
||||
uint16_t item
|
||||
)
|
||||
{
|
||||
uint16_t tail;
|
||||
struct device *dev;
|
||||
|
||||
/* Get the cached dev out so that we can mark it */
|
||||
dev = ITEM_MAP(index, item).ddm_cache;
|
||||
|
||||
/* We assume that ddh_mutex is held */
|
||||
ITEM_MAP(index, item).ddm_generation ++;
|
||||
|
||||
/* get the tail of the free list */
|
||||
tail = index->ddh_freet;
|
||||
|
||||
/* if its a valid item, link us into the free list */
|
||||
if (tail != NULLINDEX)
|
||||
{
|
||||
ITEM_MAP(index, tail).ddm_next = item;
|
||||
index->ddh_freet = item;
|
||||
}
|
||||
/* otherwise the list is empty - set head and tail */
|
||||
else
|
||||
{
|
||||
index->ddh_freeh = index->ddh_freet = item;
|
||||
}
|
||||
|
||||
/* terminate the list */
|
||||
ITEM_MAP(index, item).ddm_next = NULLINDEX;
|
||||
|
||||
/* mark the device as no longer mapped */
|
||||
if (dev)
|
||||
dev->dv_dev = NULLDEV;
|
||||
|
||||
/* We're done */
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* ddMap -
|
||||
*
|
||||
* \NOMANUAL
|
||||
*/
|
||||
|
||||
LOCAL struct device *ddMap
|
||||
(
|
||||
struct ddHeader *index,
|
||||
device_t dev
|
||||
)
|
||||
{
|
||||
uint16_t item;
|
||||
|
||||
if (!DEVICE_T_EXISTS(index, dev))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (!DEVICE_T_VALID(index, dev))
|
||||
{
|
||||
errno = ENOENT;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
item = DEVICE_T_ITEM(dev);
|
||||
|
||||
/* We have a good device_t, increment refCount */
|
||||
ITEM_MAP(index, item).ddm_refCount ++;
|
||||
|
||||
/* We're done */
|
||||
return (ITEM_MAP(index, item).ddm_data);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* ddUnmap -
|
||||
*
|
||||
* \NOMANUAL
|
||||
*/
|
||||
|
||||
LOCAL int ddUnmap
|
||||
(
|
||||
struct ddHeader *index,
|
||||
struct device *dev
|
||||
)
|
||||
{
|
||||
device_t d;
|
||||
uint16_t item;
|
||||
|
||||
if (dev == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
d = dev->dv_dev;
|
||||
|
||||
if (!DEVICE_T_EXISTS(index, d))
|
||||
return (EINVAL);
|
||||
|
||||
item = DEVICE_T_ITEM(d);
|
||||
|
||||
if (ITEM_MAP(index, item).ddm_generation != DEVICE_T_GEN(d))
|
||||
return (ENOENT);
|
||||
|
||||
/* Check the Count */
|
||||
if (ITEM_MAP(index, item).ddm_refCount == 0)
|
||||
return (EACCES);
|
||||
|
||||
/* Decrement the count */
|
||||
ITEM_MAP(index, item).ddm_refCount--;
|
||||
|
||||
/* Check to see if we have a pending delete */
|
||||
if (!ITEM_MAP(index, item).ddm_refCount && !ITEM_MAP(index, item).ddm_data)
|
||||
ddFinishRemoval(index, item);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* devInit - initialize the device manager
|
||||
*
|
||||
* This routine initializes the device manager for <ndevs> devices.
|
||||
*
|
||||
* RETURNS: OK upon success, ERROR otherwise
|
||||
*
|
||||
* ERRNO: EINVAL
|
||||
*/
|
||||
|
||||
STATUS devInit
|
||||
(
|
||||
uint16_t ndevs /* number of devices */
|
||||
)
|
||||
{
|
||||
/* Initialize the device index */
|
||||
dit_index = ddInit (ndevs);
|
||||
if (dit_index == NULL)
|
||||
return (ERROR);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* devAttach - attach a device
|
||||
*
|
||||
* RETURNS: 0 upon success, non-zero otherwise
|
||||
*/
|
||||
|
||||
int devAttach
|
||||
(
|
||||
struct device *dev,
|
||||
const char *name,
|
||||
int type,
|
||||
device_t *result
|
||||
)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/* Load dev with the appropriate values */
|
||||
strncpy (dev->dv_xname, name, MAX_DEVNAME);
|
||||
dev->dv_xname[MAX_DEVNAME] = '\0';
|
||||
dev->dv_type = type;
|
||||
|
||||
SPIN_LOCK_TASK_TAKE(&dit_index->ddh_lock);
|
||||
error = ddInsert (dit_index, dev, &dev->dv_dev);
|
||||
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
|
||||
|
||||
if (result != NULL)
|
||||
*result = dev->dv_dev;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* devDetach - detach a device
|
||||
*
|
||||
* RETURNS: 0 upon success, non-zero otherwise
|
||||
*/
|
||||
|
||||
STATUS devDetach
|
||||
(
|
||||
struct device *dev /* pointer to device to detach */
|
||||
)
|
||||
{
|
||||
int error;
|
||||
|
||||
SPIN_LOCK_TASK_TAKE(&dit_index->ddh_lock);
|
||||
error = ddRemove (dit_index, dev->dv_dev);
|
||||
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* devMap - map a device
|
||||
*
|
||||
* RETURNS: pointer to device upon success, NULL otherwise
|
||||
*/
|
||||
|
||||
struct device *devMap
|
||||
(
|
||||
device_t dev /* device to map */
|
||||
)
|
||||
{
|
||||
struct device *retVal;
|
||||
|
||||
SPIN_LOCK_TASK_TAKE(&dit_index->ddh_lock);
|
||||
retVal = ddMap (dit_index, dev);
|
||||
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
|
||||
|
||||
return (retVal);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* devMapUnsafe - map a device unconditionally
|
||||
*
|
||||
* RETURNS: pointer to device upon success, NULL otherwise
|
||||
*/
|
||||
|
||||
struct device *devMapUnsafe
|
||||
(
|
||||
device_t dev /* device to map */
|
||||
)
|
||||
{
|
||||
struct device *retVal;
|
||||
|
||||
retVal = ddMap (dit_index, dev);
|
||||
|
||||
return (retVal);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* devUnmap - unmap a device
|
||||
*
|
||||
* RETURNS: 0
|
||||
*/
|
||||
|
||||
int devUnmap
|
||||
(
|
||||
struct device *dev /* pointer to device to unmap */
|
||||
)
|
||||
{
|
||||
SPIN_LOCK_TASK_TAKE(&dit_index->ddh_lock);
|
||||
ddUnmap (dit_index, dev);
|
||||
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* devUnmapUnsafe - unmap a device unconditionally
|
||||
*
|
||||
* RETURNS: 0
|
||||
*/
|
||||
|
||||
int devUnmapUnsafe
|
||||
(
|
||||
struct device *dev /* pointer to device to unmap */
|
||||
)
|
||||
{
|
||||
ddUnmap (dit_index, dev);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* devName - name a device
|
||||
*
|
||||
* RETURNS: OK upon success, ERROR otherwise
|
||||
*/
|
||||
|
||||
STATUS devName
|
||||
(
|
||||
device_t dev, /* device to name */
|
||||
devname_t name /* name to assign */
|
||||
)
|
||||
{
|
||||
struct device *d;
|
||||
STATUS retVal;
|
||||
|
||||
d = devMap (dev);
|
||||
if (d != NULL)
|
||||
{
|
||||
strncpy (name, d->dv_xname, sizeof(devname_t));
|
||||
devUnmap (d);
|
||||
retVal = OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = ERROR;
|
||||
}
|
||||
|
||||
return (retVal);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* devGetByName - get a device handle by name
|
||||
*
|
||||
* RETURNS: device handle, NULLDEV otherwise
|
||||
*/
|
||||
|
||||
device_t devGetByName
|
||||
(
|
||||
char *deviceName
|
||||
)
|
||||
{
|
||||
int i;
|
||||
device_t index;
|
||||
struct device *pDev = NULL;
|
||||
|
||||
SPIN_LOCK_TASK_TAKE(&dit_index->ddh_lock);
|
||||
|
||||
for (i = 0; i < dit_index->ddh_size; i++)
|
||||
{
|
||||
index = (device_t)((i << 16) | dit_index->ddh_map[i].ddm_generation);
|
||||
|
||||
if ((pDev = ddMap (dit_index, index)) != NULL)
|
||||
{
|
||||
if (strcmp(deviceName, pDev->dv_xname) == 0)
|
||||
{
|
||||
|
||||
ddUnmap(dit_index, pDev);
|
||||
|
||||
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
ddUnmap(dit_index, pDev);
|
||||
}
|
||||
}
|
||||
|
||||
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
|
||||
|
||||
return NULLDEV;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user