SylixOS嵌入式操作系统|论坛
标题:
使用内核模块创建字符设备,并实现按键控制led功能
[打印本页]
作者:
zhengyi
时间:
2017-8-11 15:39
标题:
使用内核模块创建字符设备,并实现按键控制led功能
内核模块程序:
/*
* btn_drv_module.c
*
* Created on: 2017年8月9日
* Author: zhengyi
*/
#define __SYLIXOS_KERNEL
#include <SylixOS.h>
#include <module.h>
#define __BTN_ON(pbtn) gpioSetValue(pbtn->BTN_uiGpio, pbtn->BTN_bIsOutPutHigh ? 1 : 0)
#define __BTN_OFF(pbtn) gpioSetValue(pbtn->BTN_uiGpio, pbtn->BTN_bIsOutPutHigh ? 0 : 1)
static INT BtnDrvNum = 0; /* BTN 主设备号 */
/*设备结构*/
typedef struct __btn_dev{
LW_DEV_HDR BTN_devhdr;//设备头
LW_LIST_LINE_HEADER BTN_fdNodeHeader;//线形表表头
LW_OBJECT_HANDLE BTN_hthread;//线程
LW_OBJECT_HANDLE BTN_hSemaphoreB;//信号量
UINT BTN_uigpio;//gpio
BOOL BTN_bIsOutPutHigh;//是否输出高电平为点亮
BOOL BTN_bQuit;//线程退出标志
time_t BTN_time;//设备创建时间
}__BTN_DEV;
typedef __BTN_DEV *__PBTN_DEV;
/*中断程序
*
* 对led取反操作
* */
void test_irq(void)
{
API_GpioClearIrq(50);
if(API_GpioGetValue(0)){
API_GpioSetValue(0, 0);
}
else{
API_GpioSetValue(0, 1);
}
return;
}
/*btn线程
*
* 实现btn等待功能
* */
static void __btnThread(__PBTN_DEV pbtn)
{
ULONG ulMsTime;
int i_error, i_irq;
i_error = API_GpioRequestOne(0, LW_GPIOF_OUT_INIT_LOW, "led");//设置GPIO输出并默认输出低电平
if(i_error != 0){
printk("led gpio request failed.\n");
return;
}
for(;;){
/*等待二进制型信号量*/
if(API_SemaphoreBPendEx(pbtn->BTN_hSemaphoreB, LW_OPTION_WAIT_INFINITE,
(PVOID)&ulMsTime) == 0){
if (pbtn->BTN_bQuit) {
break;
}
/*********************************待完成*****************************************/
i_irq = API_GpioSetupIrq(50, 0, 0);
if(i_irq == PX_ERROR){
printk("gpio setup irq failed.\n");
return;
}
i_error = API_InterVectorConnect(i_irq, (PINT_SVR_ROUTINE) test_irq, (PVOID) 50, "test_irq");
if(i_error != 0){
printk("connect irq failed.\n");
return;
}
API_InterVectorEnable(i_irq);
API_TimeSSleep(20);
/*解除系统指定向量中断服务*/
API_InterVectorDisconnect((ULONG)i_irq, (PINT_SVR_ROUTINE)test_irq, (PVOID)50);
API_GpioFree(0);
API_GpioFree(50);
}
}
}
/*BTN打开
*
* PLW_FD_NODE:文件节点
* */
static long __btnOpen(__PBTN_DEV pbtn, char *pcName, int iFlags, int iMode)
{
LW_CLASS_THREADATTR threadattr;
PLW_FD_NODE pfdnode;
BOOL bIsNew;
if(pcName == NULL){
_ErrorHandle(ERROR_IO_NO_DEVICE_NAME_IN_PATH);//没有设备名
return -1;
}else{
pfdnode = API_IosFdNodeAdd(&pbtn->BTN_fdNodeHeader, (dev_t) pbtn, 0, iFlags, iMode, 0, 0, 0, LW_NULL, &bIsNew);
if(pfdnode == NULL){
printk("__btnOpen(): failed to add fd node!\n");
return -1;
}
if(LW_DEV_INC_USE_COUNT(&pbtn->BTN_devhdr) == 1){
if(gpioRequestOne(pbtn->BTN_uigpio,
(LW_GPIOF_OUT_INIT_HIGH), "btn")){
LW_DEV_DEC_USE_COUNT(&pbtn->BTN_devhdr);
API_IosFdNodeDec(&pbtn->BTN_fdNodeHeader, pfdnode, NULL);
return PX_ERROR;
}
pbtn->BTN_bQuit = LW_FALSE;
threadattr = API_ThreadAttrGetDefault();
threadattr.THREADATTR_pvArg = (void *)pbtn;
threadattr.THREADATTR_ucPriority = LW_PRIO_HIGH;
threadattr.THREADATTR_ulOption |= LW_OPTION_OBJECT_GLOBAL;
pbtn->BTN_hSemaphoreB = API_SemaphoreBCreate("semaphore_btn", 0, 0, NULL);
pbtn->BTN_hthread = API_ThreadCreate("t_btn", (PTHREAD_START_ROUTINE) __btnThread,
&threadattr, NULL);
}
return ((long) pfdnode);
}
}
/*btn关闭
*
* PLW_FD_ENTRY:文件结构(文件表)
* */
static int __btnClose(PLW_FD_ENTRY pfdentry)
{
__PBTN_DEV pbtn = (__PBTN_DEV)pfdentry->FDENTRY_pdevhdrHdr;
PLW_FD_NODE pfdnode = (PLW_FD_NODE)pfdentry->FDENTRY_pfdnode;
if(pfdentry && pfdnode){//若文件结构和文件节点都存在
API_IosFdNodeDec(&pbtn->BTN_fdNodeHeader, pfdnode, NULL);//删除一个 fd_node
if(LW_DEV_DEC_USE_COUNT(&pbtn->BTN_devhdr) == 0){
pbtn->BTN_bQuit = 1;
API_SemaphoreBPostEx(pbtn->BTN_hSemaphoreB, NULL);//释放信号量
API_ThreadJoin(pbtn->BTN_hthread, NULL);//确保线程完全执行
pbtn->BTN_hthread = 0;//删除线程
API_SemaphoreBDelete(&pbtn->BTN_hSemaphoreB);
pbtn->BTN_hSemaphoreB = 0;//删除信号量
API_GpioFree(pbtn->BTN_uigpio);//释放gpio
}
}
return 0;
}
/*ioctl
*
* btn控制
* */
static int __btnIoctl(PLW_FD_ENTRY pfdentry, int iCmd, long lArg)
{
__PBTN_DEV pbtn = (__PBTN_DEV)pfdentry->FDENTRY_pdevhdrHdr;
switch(iCmd){
case 0:
API_SemaphoreBPostEx(pbtn->BTN_hSemaphoreB, (VOID *)lArg);
return 0;
case 1:
API_ThreadSetPriority(pbtn->BTN_hthread, (UINT8)lArg);
return 0;
}
return -1;
}
/*创建BTN驱动程序*/
int btnDrv(void)
{
struct file_operations fileop;
if(BtnDrvNum){
return ERROR_NONE;
}
lib_memset(&fileop, 0, sizeof(struct file_operations));
fileop.owner = LW_NULL;
fileop.fo_create = __btnOpen;
fileop.fo_open = __btnOpen;
fileop.fo_close = __btnClose;
fileop.fo_ioctl = __btnIoctl;
//fileop.fo_lstat = __btnLstat;
/*安装驱动程序,NEW_1型设备驱动程序*/
BtnDrvNum = API_IosDrvInstallEx2(&fileop, LW_DRV_TYPE_NEW_1);
API_IoSetDrvAuthor(BtnDrvNum, "Zheng.Yi");
API_IoSetDrvDescription(BtnDrvNum, "btn driver.");
API_IoSetDrvLicense(BtnDrvNum, "v1.00");
return (BtnDrvNum > 0) ? ERROR_NONE : PX_ERROR;
}
INT btnDevCreate(CPCHAR cpcName, UINT gpio, BOOL bIsOutPutHigh)
{
__PBTN_DEV pbtn;
/*从堆中申请字节池 (首次适应算法),返回分配的内存地址*/
pbtn = (__PBTN_DEV)__SHEAP_ALLOC(sizeof(__BTN_DEV));
if(!pbtn){
_DebugHandle(__ERRORMESSAGE_LEVEL, "system low memory.\n");
_ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);
return -1;
}
lib_memset(pbtn, 0, sizeof(__BTN_DEV));
pbtn->BTN_uigpio = gpio;
pbtn->BTN_bIsOutPutHigh = bIsOutPutHigh;
/*安装设备(指定设备 d_type),DT_CHR字符设备*/
if(API_IosDevAddEx(&pbtn->BTN_devhdr, cpcName, BtnDrvNum, DT_CHR) != 0){
__SHEAP_FREE(pbtn);
_ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);
return -1;
}
_ErrorHandle(ERROR_NONE);
return (ERROR_NONE);
}
void module_init(void)
{
btnDrv();
btnDevCreate("/dev/btn", 50, LW_FALSE);
}
void module_exit(void)
{
PLW_DEV_HDR pdevHdr;
pdevHdr = API_IosDevFind("/dev/btn", LW_NULL);
if (pdevHdr) {
API_IosDevDelete(pdevHdr);
}
}
复制代码
应用程序:
/*
* btn_drv_module.c
*
* Created on: 2017年8月9日
* Author: zhengyi
*
*********************************************************************************************************/
#include <stdio.h>
/*********************************************************************************************************
** 函数名称: main
** 功能描述: 程序主函数
** 输 入 : 无
** 输 出 : 无
** 全局变量:
** 调用模块:
*********************************************************************************************************/
int main (int argc, char *argv[])
{
int fb;
long time_ms;
fb = open("/dev/btn", O_RDWR, 0666);
if (fb < 0) {
printf("failed to open /dev/led\n");
return (-1);
}
/*
* LED 灯闪烁 10 次,每次亮 100ms,1s 后重新点亮。
*/
time_ms = 1000000;
ioctl(fb, 0, time_ms);
sleep(10);
close(fb);
return (0);
}
/*********************************************************************************************************
END
*********************************************************************************************************/
复制代码
作者:
databus
时间:
2017-8-12 10:12
666666666666666666666
欢迎光临 SylixOS嵌入式操作系统|论坛 (https://bbs.sylixos.com/)
Powered by Discuz! X3.2