Files
m241Neelima/vxworks-6.9/target/src/drv/manager/device.c
T
2026-07-30 11:19:44 +05:30

628 lines
14 KiB
C

/* 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;
}