基於UNIX一切皆文件的哲學,SylixOS中也會把GPIO抽象爲設備文件,即/dev/gpiofd
目錄下的數字編號的文件,應用層通過訪問設備文件的方式即可操作GPIO。
實現這些函數要用到的主要接口有:
設備文件驅動接口
GPIO Drv接口
select接口
中斷系統接口
註冊驅動和設備
/*********************************************************************************************************
驅動程序全局變量
*********************************************************************************************************/
static INT _G_iGpiofdDrvNum = PX_ERROR;
static LW_GPIOFD_DEV _G_gpiofddev;
static LW_OBJECT_HANDLE _G_hGpiofdSelMutex;
/*********************************************************************************************************
** 函數名稱: API_GpiofdDrvInstall
** 功能描述: 安裝 gpiofd 設備驅動程序
** 輸 入 : NONE
** 輸 出 : 驅動是否安裝成功
*********************************************************************************************************/
LW_API
INT API_GpiofdDrvInstall (VOID)
{
if (_G_iGpiofdDrvNum <= 0) {
_G_iGpiofdDrvNum = iosDrvInstall(LW_NULL,
LW_NULL,
_gpiofdOpen,
_gpiofdClose,
_gpiofdRead,
_gpiofdWrite,
_gpiofdIoctl);
DRIVER_LICENSE(_G_iGpiofdDrvNum, "GPL->Ver 2.0");
DRIVER_AUTHOR(_G_iGpiofdDrvNum, "Han.hui");
DRIVER_DESCRIPTION(_G_iGpiofdDrvNum, "gpiofd driver.");
}
if (_G_hGpiofdSelMutex == LW_OBJECT_HANDLE_INVALID) {
_G_hGpiofdSelMutex = API_SemaphoreMCreate("gpiofdsel_lock",
LW_PRIO_DEF_CEILING,
LW_OPTION_WAIT_PRIORITY | LW_OPTION_DELETE_SAFE |
LW_OPTION_INHERIT_PRIORITY | LW_OPTION_OBJECT_GLOBAL,
LW_NULL);
}
return ((_G_iGpiofdDrvNum == (PX_ERROR)) ? (PX_ERROR) : (ERROR_NONE));
}
/*********************************************************************************************************
** 函數名稱: API_GpiofdDevCreate
** 功能描述: 安裝 gpiofd 設備
** 輸 入 : NONE
** 輸 出 : 設備是否創建成功
*********************************************************************************************************/
LW_API
INT API_GpiofdDevCreate (VOID)
{
if (_G_iGpiofdDrvNum <= 0) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "no driver.\r\n");
_ErrorHandle(ERROR_IO_NO_DRIVER);
return (PX_ERROR);
}
if (iosDevAddEx(&_G_gpiofddev.GD_devhdrHdr,
LW_GPIOFD_DEV_PATH,
_G_iGpiofdDrvNum,
DT_DIR) != ERROR_NONE) {
return (PX_ERROR);
}
return (ERROR_NONE);
}
- API_GpiofdDrvInstall 函數會註冊一個
gpiofd driver
驅動,驅動中需要實現5個底層的標準文件操作函數。 - API_GpiofdDevCreate 函數會註冊一個
/dev/gpiofd
設備文件夾,訪問該文件夾時會調用gpiofd driver
驅動。 - 系統會自動調用上面兩個函數,此時文件系統中就已經具備
/dev/gpiofd
設備文件夾,但要訪問這個文件夾還是要必須實現驅動中回調的那5個底層的標準文件操作函數。
實現標準回調函數
_gpiofdOpen, _gpiofdClose, _gpiofdRead,_gpiofdWrite, _gpiofdIoctl
這5個回調函數是實現虛擬文件系統驅動所必須的,其接口參數也是標準的。
/*********************************************************************************************************
** 函數名稱: _gpiofdOpen
** 功能描述: 打開 gpiofd 設備
** 輸 入 : pgpiofddev gpiofd 設備
** pcName 名稱
** iFlags 方式
** iMode 方法
** 輸 出 : ERROR
*********************************************************************************************************/
static LONG _gpiofdOpen (PLW_GPIOFD_DEV pgpiofddev,
PCHAR pcName,
INT iFlags,
INT iMode)
{
#define GPIO_IS_ROOT(gpio) ((gpio) == __ARCH_UINT_MAX)
PLW_GPIOFD_FILE pgpiofdfil;
UINT uiGpio;
PCHAR pcTemp;
ULONG ulGpioLibFlags;
if (pcName == LW_NULL) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "device name invalidate.\r\n");
_ErrorHandle(ERROR_IO_NO_DEVICE_NAME_IN_PATH);
return (PX_ERROR);
} else {
if (iFlags & O_CREAT) {
_ErrorHandle(ERROR_IO_FILE_EXIST);
return (PX_ERROR);
}
if (*pcName == PX_DIVIDER) {
pcName++;
}
for (pcTemp = pcName; *pcTemp != PX_EOS; pcTemp++) {
if (!lib_isdigit(*pcTemp)) {
_ErrorHandle(ENOENT);
return (PX_ERROR);
}
}
if (pcName[0] == PX_EOS) {
uiGpio = __ARCH_UINT_MAX;
} else {
uiGpio = lib_atoi(pcName);
if (API_GpioRequest(uiGpio, "gpiofd")) {
return (PX_ERROR);
}
}
pgpiofdfil = (PLW_GPIOFD_FILE)__SHEAP_ALLOC(sizeof(LW_GPIOFD_FILE));
if (!pgpiofdfil) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "system low memory.\r\n");
_ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);
return (PX_ERROR);
}
pgpiofdfil->GF_iFlag = iFlags;
pgpiofdfil->GF_uiGpio = uiGpio;
pgpiofdfil->GF_ulIrq = LW_VECTOR_INVALID;
API_GpioGetFlags(pgpiofdfil->GF_uiGpio, &ulGpioLibFlags);
if (ulGpioLibFlags & LW_GPIODF_IS_OUT) {
pgpiofdfil->GF_iGpioFlags = GPIO_FLAG_DIR_OUT;
} else {
pgpiofdfil->GF_iGpioFlags = GPIO_FLAG_DIR_IN;
}
if (ulGpioLibFlags & LW_GPIODF_TRIG_FALL) {
pgpiofdfil->GF_iGpioFlags |= GPIO_FLAG_TRIG_FALL;
}
if (ulGpioLibFlags & LW_GPIODF_TRIG_RISE) {
pgpiofdfil->GF_iGpioFlags |= GPIO_FLAG_TRIG_RISE;
}
if (ulGpioLibFlags & LW_GPIODF_TRIG_LEVEL) {
pgpiofdfil->GF_iGpioFlags |= GPIO_FLAG_TRIG_LEVEL;
}
if (ulGpioLibFlags & LW_GPIODF_OPEN_DRAIN) {
pgpiofdfil->GF_iGpioFlags |= GPIO_FLAG_OPEN_DRAIN;
}
if (ulGpioLibFlags & LW_GPIODF_OPEN_SOURCE) {
pgpiofdfil->GF_iGpioFlags |= GPIO_FLAG_OPEN_SOURCE;
}
lib_bzero(&pgpiofdfil->GF_selwulist, sizeof(LW_SEL_WAKEUPLIST));
pgpiofdfil->GF_selwulist.SELWUL_hListLock = _G_hGpiofdSelMutex;
LW_DEV_INC_USE_COUNT(&_G_gpiofddev.GD_devhdrHdr);
return ((LONG)pgpiofdfil);
}
}
/*********************************************************************************************************
** 函數名稱: _gpiofdClose
** 功能描述: 關閉 gpiofd 文件
** 輸 入 : pgpiofdfil gpiofd 文件
** 輸 出 : ERROR
*********************************************************************************************************/
static INT _gpiofdClose (PLW_GPIOFD_FILE pgpiofdfil)
{
if (pgpiofdfil) {
SEL_WAKE_UP_TERM(&pgpiofdfil->GF_selwulist);
LW_DEV_DEC_USE_COUNT(&_G_gpiofddev.GD_devhdrHdr);
if (!GPIO_IS_ROOT(pgpiofdfil->GF_uiGpio)) {
API_GpioFree(pgpiofdfil->GF_uiGpio);
if (pgpiofdfil->GF_ulIrq != LW_VECTOR_INVALID) {
API_InterVectorDisableEx(pgpiofdfil->GF_ulIrq, 1);
API_InterVectorDisconnect(pgpiofdfil->GF_ulIrq, (PINT_SVR_ROUTINE)_gpiofdIsr,
(PVOID)pgpiofdfil);
}
}
__SHEAP_FREE(pgpiofdfil);
return (ERROR_NONE);
} else {
return (PX_ERROR);
}
}
/*********************************************************************************************************
** 函數名稱: _gpiofdRead
** 功能描述: 讀 gpiofd 設備
** 輸 入 : pgpiofdfil gpiofd 文件
** pcBuffer 接收緩衝區
** stMaxBytes 接收緩衝區大小
** 輸 出 : 讀取字節數
*********************************************************************************************************/
static ssize_t _gpiofdRead (PLW_GPIOFD_FILE pgpiofdfil,
PCHAR pcBuffer,
size_t stMaxBytes)
{
INT iValue;
if (!pcBuffer) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
if (!stMaxBytes) {
return (0);
}
if (GPIO_IS_ROOT(pgpiofdfil->GF_uiGpio)) {
_ErrorHandle(EISDIR);
return (PX_ERROR);
}
iValue = API_GpioGetValue(pgpiofdfil->GF_uiGpio);
if (iValue < 0) {
return (iValue);
}
*pcBuffer = (CHAR)iValue;
return (1);
}
/*********************************************************************************************************
** 函數名稱: _gpiofdWrite
** 功能描述: 寫 gpiofd 設備
** 輸 入 : pgpiofdfil gpiofd 文件
** pcBuffer 將要寫入的數據指針
** stNBytes 寫入數據大小
** 輸 出 : 寫入字節數
*********************************************************************************************************/
static ssize_t _gpiofdWrite (PLW_GPIOFD_FILE pgpiofdfil,
PCHAR pcBuffer,
size_t stNBytes)
{
if (!pcBuffer) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
if (!stNBytes) {
return (0);
}
if (GPIO_IS_ROOT(pgpiofdfil->GF_uiGpio)) {
_ErrorHandle(EISDIR);
return (PX_ERROR);
}
API_GpioSetValue(pgpiofdfil->GF_uiGpio, *pcBuffer);
return (1);
}
/*********************************************************************************************************
** 函數名稱: _gpiofdIoctl
** 功能描述: 控制 gpiofd 文件
** 輸 入 : pgpiofdfil gpiofd 文件
** iRequest 功能
** lArg 參數
** 輸 出 : ERROR
*********************************************************************************************************/
static INT _gpiofdIoctl (PLW_GPIOFD_FILE pgpiofdfil,
INT iRequest,
LONG lArg)
{
struct stat *pstatGet;
struct statfs *pstatfsGet;
PLW_SEL_WAKEUPNODE pselwunNode;
switch (iRequest) {
case FIONBIO:
if (*(INT *)lArg) {
pgpiofdfil->GF_iFlag |= O_NONBLOCK;
} else {
pgpiofdfil->GF_iFlag &= ~O_NONBLOCK;
}
break;
case FIOFSTATGET:
pstatGet = (struct stat *)lArg;
if (pstatGet) {
pstatGet->st_dev = LW_DEV_MAKE_STDEV(&_G_gpiofddev.GD_devhdrHdr);
if (GPIO_IS_ROOT(pgpiofdfil->GF_uiGpio)) {
pstatGet->st_ino = (ino_t)0;
pstatGet->st_mode = 0666 | S_IFDIR;
pstatGet->st_size = 0;
pstatGet->st_blksize = 1;
pstatGet->st_blocks = 0;
} else {
pstatGet->st_ino = (ino_t)pgpiofdfil->GF_uiGpio;
pstatGet->st_mode = 0666 | S_IFCHR;
pstatGet->st_size = 1;
pstatGet->st_blksize = 1;
pstatGet->st_blocks = 1;
}
pstatGet->st_nlink = 1;
pstatGet->st_uid = 0;
pstatGet->st_gid = 0;
pstatGet->st_rdev = 1;
pstatGet->st_atime = API_RootFsTime(LW_NULL);
pstatGet->st_mtime = API_RootFsTime(LW_NULL);
pstatGet->st_ctime = API_RootFsTime(LW_NULL);
} else {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
break;
case FIOFSTATFSGET:
pstatfsGet = (struct statfs *)lArg;
if (pstatfsGet) {
pstatfsGet->f_type = 0;
pstatfsGet->f_bsize = 0;
pstatfsGet->f_blocks = 1;
pstatfsGet->f_bfree = 0;
pstatfsGet->f_bavail = 1;
pstatfsGet->f_files = LW_CFG_MAX_GPIOS;
pstatfsGet->f_ffree = 0;
#if LW_CFG_CPU_WORD_LENGHT == 64
pstatfsGet->f_fsid.val[0] = (int32_t)((addr_t)&_G_gpiofddev >> 32);
pstatfsGet->f_fsid.val[1] = (int32_t)((addr_t)&_G_gpiofddev & 0xffffffff);
#else
pstatfsGet->f_fsid.val[0] = (int32_t)&_G_gpiofddev;
pstatfsGet->f_fsid.val[1] = 0;
#endif
pstatfsGet->f_flag = 0;
pstatfsGet->f_namelen = PATH_MAX;
} else {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
break;
case FIOREADDIR:
return (_gpiofdReadDir(pgpiofdfil, (DIR *)lArg));
case GPIO_CMD_SET_FLAGS:
return (_gpiofdSetFlags(pgpiofdfil, (INT)lArg));
case GPIO_CMD_GET_FLAGS:
return (_gpiofdGetFlags(pgpiofdfil, (INT *)lArg));
case FIOSELECT:
pselwunNode = (PLW_SEL_WAKEUPNODE)lArg;
return (_gpiofdSelect(pgpiofdfil, pselwunNode));
case FIOUNSELECT:
pselwunNode = (PLW_SEL_WAKEUPNODE)lArg;
return (_gpiofdUnselect(pgpiofdfil, pselwunNode));
case FIOFSTYPE:
*(PCHAR *)lArg = "GPIO FileSystem";
return (ERROR_NONE);
default:
_ErrorHandle(ERROR_IO_UNKNOWN_REQUEST);
return (PX_ERROR);
}
return (ERROR_NONE);
}
實現支撐函數
實現上面的標準回調函數時,還會調用一些支撐函數。
/*********************************************************************************************************
** 函數名稱: _gpiofdReadDir
** 功能描述: 讀 gpiofd 目錄
** 輸 入 : pgpiofdfil gpiofd 文件
** pdir 當前偏移量上的文件信息
** 輸 出 : ERROR
*********************************************************************************************************/
static INT _gpiofdReadDir (PLW_GPIOFD_FILE pgpiofdfil, DIR *pdir)
{
if (!pdir) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
if (!GPIO_IS_ROOT(pgpiofdfil->GF_uiGpio)) {
_ErrorHandle(ENOTDIR);
return (PX_ERROR);
}
while (pdir->dir_pos < LW_CFG_MAX_GPIOS) {
if (API_GpioHasDrv((UINT)pdir->dir_pos)) {
snprintf(pdir->dir_dirent.d_name, NAME_MAX + 1, "%ld", pdir->dir_pos);
lib_strlcpy(pdir->dir_dirent.d_shortname,
pdir->dir_dirent.d_name,
sizeof(pdir->dir_dirent.d_shortname));
pdir->dir_dirent.d_type = DT_CHR;
pdir->dir_pos++;
return (ERROR_NONE);
} else {
pdir->dir_pos++;
}
}
_ErrorHandle(ENOENT);
return (PX_ERROR);
}
/*********************************************************************************************************
** 函數名稱: _gpiofdIsr
** 功能描述: gpiofd 文件中斷服務程序
** 輸 入 : pgpiofdfil gpiofd 文件
** iFlags gpiofd 屬性標誌
** 輸 出 : ERROR
*********************************************************************************************************/
static irqreturn_t _gpiofdIsr (PLW_GPIOFD_FILE pgpiofdfil)
{
irqreturn_t irqret;
irqret = API_GpioSvrIrq(pgpiofdfil->GF_uiGpio);
if (LW_IRQ_RETVAL(irqret)) {
SEL_WAKE_UP_ALL(&pgpiofdfil->GF_selwulist, SELREAD);
API_GpioClearIrq(pgpiofdfil->GF_uiGpio);
}
return (irqret);
}
/*********************************************************************************************************
** 函數名稱: _gpiofdSetFlagsIrq
** 功能描述: 設置 gpiofd 文件中斷屬性標誌
** 輸 入 : pgpiofdfil gpiofd 文件
** iFlags gpiofd 屬性標誌
** 輸 出 : ERROR
*********************************************************************************************************/
static INT _gpiofdSetFlagsIrq (PLW_GPIOFD_FILE pgpiofdfil, INT iFlags)
{
BOOL bIsLevel;
UINT uiType;
ULONG ulIrq;
if (iFlags & GPIO_FLAG_TRIG_LEVEL) {
bIsLevel = LW_TRUE;
} else {
bIsLevel = LW_FALSE;
}
if ((iFlags & GPIO_FLAG_IRQ_T2) == GPIO_FLAG_IRQ_T2) {
uiType = 2;
} else if ((iFlags & GPIO_FLAG_IRQ_T0) == GPIO_FLAG_IRQ_T0) {
uiType = 0;
} else if ((iFlags & GPIO_FLAG_IRQ_T1) == GPIO_FLAG_IRQ_T1) {
uiType = 1;
} else {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
ulIrq = API_GpioGetIrq(pgpiofdfil->GF_uiGpio, bIsLevel, uiType);
if (ulIrq == LW_VECTOR_INVALID) {
return (PX_ERROR);
}
API_InterVectorConnect(ulIrq, (PINT_SVR_ROUTINE)_gpiofdIsr,
(PVOID)pgpiofdfil, "gpiofd_isr");
pgpiofdfil->GF_ulIrq = API_GpioSetupIrq(pgpiofdfil->GF_uiGpio, bIsLevel, uiType);
if (pgpiofdfil->GF_ulIrq == LW_VECTOR_INVALID) {
API_InterVectorDisconnect(pgpiofdfil->GF_ulIrq,
(PINT_SVR_ROUTINE)_gpiofdIsr, (PVOID)pgpiofdfil);
return (PX_ERROR);
}
API_InterVectorEnable(pgpiofdfil->GF_ulIrq);
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: _gpiofdSetFlagsOrg
** 功能描述: 設置 gpiofd 文件普通屬性標誌
** 輸 入 : pgpiofdfil gpiofd 文件
** iFlags gpiofd 屬性標誌
** 輸 出 : ERROR
*********************************************************************************************************/
static INT _gpiofdSetFlagsOrg (PLW_GPIOFD_FILE pgpiofdfil, INT iFlags)
{
if (iFlags & GPIO_FLAG_DIR_IN) {
if (API_GpioDirectionInput(pgpiofdfil->GF_uiGpio) < 0) {
return (PX_ERROR);
}
} else {
if (API_GpioDirectionOutput(pgpiofdfil->GF_uiGpio,
((iFlags & GPIO_FLAG_INIT_HIGH) ? 1 : 0)) < 0) {
return (PX_ERROR);
}
}
if (iFlags & GPIO_FLAG_OPEN_DRAIN) {
API_GpioOpenDrain(pgpiofdfil->GF_uiGpio, LW_TRUE);
} else {
API_GpioOpenDrain(pgpiofdfil->GF_uiGpio, LW_FALSE);
}
if (iFlags & GPIO_FLAG_OPEN_SOURCE) {
API_GpioOpenSource(pgpiofdfil->GF_uiGpio, LW_TRUE);
} else {
API_GpioOpenSource(pgpiofdfil->GF_uiGpio, LW_FALSE);
}
if (pgpiofdfil->GF_ulIrq != LW_VECTOR_INVALID) {
API_InterVectorDisableEx(pgpiofdfil->GF_ulIrq, 1);
API_InterVectorDisconnect(pgpiofdfil->GF_ulIrq, (PINT_SVR_ROUTINE)_gpiofdIsr, (PVOID)pgpiofdfil);
pgpiofdfil->GF_ulIrq = LW_VECTOR_INVALID;
}
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: _gpiofdSetFlags
** 功能描述: 設置 gpiofd 文件屬性標誌
** 輸 入 : pgpiofdfil gpiofd 文件
** iFlags gpiofd 屬性標誌
** 輸 出 : ERROR
*********************************************************************************************************/
static INT _gpiofdSetFlags (PLW_GPIOFD_FILE pgpiofdfil, INT iFlags)
{
INT iError = ERROR_NONE;
if (GPIO_IS_ROOT(pgpiofdfil->GF_uiGpio)) {
_ErrorHandle(EISDIR);
return (PX_ERROR);
}
if (iFlags & GPIO_FLAG_PULL_UP) {
iError = API_GpioSetPull(pgpiofdfil->GF_uiGpio, 1);
} else if (iFlags & GPIO_FLAG_PULL_DOWN) {
iError = API_GpioSetPull(pgpiofdfil->GF_uiGpio, 2);
} else if (iFlags & GPIO_FLAG_PULL_DISABLE) {
iError = API_GpioSetPull(pgpiofdfil->GF_uiGpio, 0);
}
if (iError < ERROR_NONE) {
return (PX_ERROR);
}
if (iFlags & GPIO_FLAG_IRQ) {
iError = _gpiofdSetFlagsIrq(pgpiofdfil, iFlags);
} else {
iError = _gpiofdSetFlagsOrg(pgpiofdfil, iFlags);
}
if (iError == ERROR_NONE) {
pgpiofdfil->GF_iGpioFlags = iFlags;
}
return (iError);
}
/*********************************************************************************************************
** 函數名稱: _gpiofdGetFlags
** 功能描述: 獲取 gpiofd 文件屬性標誌
** 輸 入 : pgpiofdfil gpiofd 文件
** piFlags gpiofd 屬性標誌
** 輸 出 : ERROR
*********************************************************************************************************/
static INT _gpiofdGetFlags (PLW_GPIOFD_FILE pgpiofdfil, INT *piFlags)
{
if (GPIO_IS_ROOT(pgpiofdfil->GF_uiGpio)) {
_ErrorHandle(EISDIR);
return (PX_ERROR);
}
if (piFlags) {
*piFlags = pgpiofdfil->GF_iGpioFlags;
}
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: _gpiofdSelect
** 功能描述: gpiofd FIOSELECT
** 輸 入 : pgpiofdfil gpiofd 文件
** pselwunNode select 節點
** 輸 出 : ERROR
*********************************************************************************************************/
static INT _gpiofdSelect (PLW_GPIOFD_FILE pgpiofdfil, PLW_SEL_WAKEUPNODE pselwunNode)
{
if (GPIO_IS_ROOT(pgpiofdfil->GF_uiGpio)) {
_ErrorHandle(EISDIR);
return (PX_ERROR);
}
SEL_WAKE_NODE_ADD(&pgpiofdfil->GF_selwulist, pselwunNode);
switch (pselwunNode->SELWUN_seltypType) {
case SELREAD:
if (!(pgpiofdfil->GF_iGpioFlags & GPIO_FLAG_IRQ)) {
SEL_WAKE_UP(pselwunNode);
}
break;
case SELWRITE:
SEL_WAKE_UP(pselwunNode);
break;
case SELEXCEPT:
break;
}
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: _gpiofdUnselect
** 功能描述: gpiofd FIOUNSELECT
** 輸 入 : pgpiofdfil gpiofd 文件
** pselwunNode select 節點
** 輸 出 : ERROR
*********************************************************************************************************/
static INT _gpiofdUnselect (PLW_GPIOFD_FILE pgpiofdfil, PLW_SEL_WAKEUPNODE pselwunNode)
{
if (GPIO_IS_ROOT(pgpiofdfil->GF_uiGpio)) {
_ErrorHandle(EISDIR);
return (PX_ERROR);
}
SEL_WAKE_NODE_DELETE(&pgpiofdfil->GF_selwulist, pselwunNode);
return (ERROR_NONE);
}