其实这篇博客就是上篇博客https://blog.csdn.net/qq_41495871/article/details/100378690的一个具体例子
先在总线上注册LED这个设备 ,这里我的设备名命名为 MyLED_device
#include
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("HQU_Orange");
#define DEVICE_NAME "MyLED_device"
void MyLED_device_release(struct device *dev);
struct platform_device MyLED_device =
{
.name = DEVICE_NAME ,
.id = -1 , //-1代表设备数量为1
.dev =
{
.release= MyLED_device_release ,
}
};
static int Mini_Linux_Device_Module_Init (void)
{
int Device_Status;
printk(KERN_EMERG "Mini Liunx Device Module Enter ! \r\n");
Device_Status=platform_device_register(&MyLED_device);
printk(KERN_EMERG "Module Device Status is %d \n",Device_Status);
return 0;
}
static void Mini_Linux_Device_Module_Exit (void)
{
platform_device_unregister(&MyLED_device);
printk(KERN_EMERG "Mini Linux Device Module Exit ! \r\n");
}
void MyLED_device_release(struct device *dev)
{
printk(KERN_EMERG DEVICE_NAME "\tdevice release wolk!\r\n");
}
module_init(Mini_Linux_Device_Module_Init);
module_exit(Mini_Linux_Device_Module_Exit);
下面是最重要的部分,LED的驱动编写,我先将代码贴出来
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("HQU_Orange");
#define DEVICE_NAME "MyLED_device"
#define DEVICENODE_NAME "MyLED"
int MyLED_driver_probe(struct platform_device* MyLED_device);
int MyLED_driver_remove(struct platform_device* MyLED_device);
void MyLED_driver_shutdown(struct platform_device* MyLED_device);
int MyLED_driver_suspend(struct platform_device* MyLED_device,pm_message_t state);
int MyLED_driver_resume(struct platform_device* MyLED_device);
int MyLED_driver_fops_open(struct inode* p_inode,struct file* p_file);
int MyLED_driver_fops_release(struct inode* p_inode,struct file* p_file);
long MyLED_driver_fops_unlocked_ioctl(struct file* p_file ,unsigned int ID ,unsigned long cmd);
struct platform_driver MyLED_driver =
{
.probe = MyLED_driver_probe ,
.remove = MyLED_driver_remove ,
.shutdown= MyLED_driver_shutdown ,
.suspend= MyLED_driver_suspend ,
.resume = MyLED_driver_resume ,
.driver =
{
.name = DEVICE_NAME ,
.owner = THIS_MODULE ,
}
};
struct file_operations MyLED_driver_fops =
{
.owner = THIS_MODULE ,
.open = MyLED_driver_fops_open ,
.release = MyLED_driver_fops_release ,
.unlocked_ioctl = MyLED_driver_fops_unlocked_ioctl,
};
struct miscdevice MyLED_misc_device=
{
.minor = MISC_DYNAMIC_MINOR ,
.name = DEVICENODE_NAME ,
.fops = &MyLED_driver_fops ,
};
static int Mini_Linux_Driver_Init (void)
{
int Driver_Status;
printk(KERN_EMERG "Mini Liunx Module Enter ! \r\n");
Driver_Status=platform_driver_register(&MyLED_driver);
printk(KERN_EMERG "Driver Status is %d \n",Driver_Status);
return 0;
}
static void Mini_Linux_Driver_Exit (void)
{
platform_driver_unregister(&MyLED_driver);
printk(KERN_EMERG "Mini Linux Module Exit ! \r\n");
}
int MyLED_driver_probe(struct platform_device* MyLED_device)
{
int res;
printk(KERN_EMERG "device-> name = %s device -> id = %d probe !\r\n",MyLED_device->name,MyLED_device->id);
gpio_free(EXYNOS4_GPL2(0));
gpio_free(EXYNOS4_GPK1(1));
res=gpio_request(EXYNOS4_GPL2(0),"MyLED_1");
if(res==-1)
{printk(KERN_EMERG "%s L2(0) gpio request fail !\r\n",MyLED_device->name);return res ;}
res=gpio_request(EXYNOS4_GPK1(1),"MyLED_2");
if(res==-1)
{printk(KERN_EMERG "%s K1(1) gpio request fail !\r\n",MyLED_device->name);return res ;}
s3c_gpio_cfgpin(EXYNOS4_GPL2(0),S3C_GPIO_OUTPUT);
gpio_set_value(EXYNOS4_GPL2(0),0);
s3c_gpio_cfgpin(EXYNOS4_GPK1(1),S3C_GPIO_OUTPUT);
gpio_set_value(EXYNOS4_GPK1(1),0);
misc_register(&MyLED_misc_device);
return 0;
}
int MyLED_driver_remove(struct platform_device* MyLED_device)
{
printk(KERN_EMERG "device-> name = %s device -> id = %d remove!\r\n",MyLED_device->name,MyLED_device->id);
misc_deregister(&MyLED_misc_device);
return 0;
}
void MyLED_driver_shutdown(struct platform_device* MyLED_device)
{
printk(KERN_EMERG "device-> name = %s device -> id = %d shutdown!\r\n",MyLED_device->name,MyLED_device->id);
}
int MyLED_driver_suspend(struct platform_device* MyLED_device,pm_message_t state)
{
printk(KERN_EMERG "device-> name = %s device -> id = %d suspend!\r\n",MyLED_device->name,MyLED_device->id);
return 0;
}
int MyLED_driver_resume(struct platform_device* MyLED_device)
{
printk(KERN_EMERG "device-> name = %s device -> id = %d resume!\r\n",MyLED_device->name,MyLED_device->id);
return 0;
}
int MyLED_driver_fops_open(struct inode* p_inode,struct file* p_file)
{
printk(KERN_EMERG "MyLED_file_open \r\n");
return 0;
}
int MyLED_driver_fops_release(struct inode* p_inode,struct file* p_file)
{
printk(KERN_EMERG "MyLED_file_release \r\n");
return 0;
}
long MyLED_driver_fops_unlocked_ioctl(struct file* p_file ,unsigned int ID ,unsigned long cmd)
{
printk(KERN_EMERG "ID is %d cmd is %d \r\n" ,ID , cmd);
if(ID>2||cmd>2)
{
printk(KERN_EMERG "ID and cmd must are 0 or 1\r\n");
return 1;
}
if(ID)
gpio_set_value(EXYNOS4_GPL2(0),cmd);
else
gpio_set_value(EXYNOS4_GPK1(1),cmd);
return 0;
}
module_init(Mini_Linux_Driver_Init);
module_exit(Mini_Linux_Driver_Exit);
熟悉单片机的应该知道其实驱动LED其实就是控制一个引脚的电平。
gpio_free() 其实不是必要的,因为 我之前烧进去的内核已经将这个两个引脚资源先占用了,而现在为了方便调试用了模块加载的方法,故要先释放这两个引脚的资源,才能用我们自己的驱动控制这两个引脚。
gpio_request() 请求 引脚资源
s3c_gpio_cfgpin() 引脚模式设置
gpio_set_value()引脚输出电平设置
ioctl的实现,下面应用会调用到这个函数。
编写应用程序
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc ,char* argv[])
{
int fd ;
int res;
char* file_node = argv[1];
char id = atoi(argv[2]);
char cmd = atoi(argv[3]);
fd=open(file_node,O_RDWR|O_NOCTTY|O_NDELAY);
if(fd==-1)
{
perror(file_node);
exit(EXIT_FAILURE);
}
res=ioctl(fd,id,cmd);
if(res==-1)
{
perror("ioctl");
close(fd);
exit(EXIT_FAILURE);
}
close(fd);
exit(EXIT_SUCCESS);
}
编写Makeflie
obj-m +=MyLED_Device.o
obj-m +=MyLED_Driver.o
KDIR := /home/topeet/zImage/iTop4412_Kernel_3.0
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.order *.symvers
make编译
再编译 应用程序 arm-none-linux-gnueabi-gcc -o linux_file_ioctl linux_file_ioctl.c -static
将这个三个文件传输到板子上。
先加载设备在加载驱动
此时两个LED灭了,说明在probe函数里面将gpio电平拉低的程序起作用了
查看/dev目录 生成了我们的设备节点
调用应用程序试试看
输入命令 ./linux_file_ioctl /dev/MyLED 0 1
发现板子上的靠近蜂鸣器的led亮了
再输入命令 ./linux_file_ioctl /dev/MyLED 1 1
结合ioctl程序
说明LED驱动工作正常。
其实熟悉了Linux框架后,就是调用厂家提供的库函数进行开发驱动,相信熟悉单片机的都知道,这套流程下来除去与Linux内核
打交道的代码外,其实就是一个gpio模式设置和一个gpio电平变化。