Linux嵌入式驱动开发01——第一个驱动Hello World(附源码)
Linux嵌入式驱动开发02——驱动编译到内核
Linux嵌入式驱动开发03——杂项设备驱动(附源码)
Linux嵌入式驱动开发04——应用层和内核层数据传输
Linux嵌入式驱动开发05——物理地址到虚拟地址映射
Linux嵌入式驱动开发06——第一个相对完整的驱动实践编写
Linux嵌入式驱动开发07——GPIO驱动过程记录(飞凌开发板)
Linux嵌入式驱动开发08——字符设备(步步为营)
Linux嵌入式驱动开发09——平台总线详解及实战
Linux嵌入式驱动开发10——设备树开发详解
Linux嵌入式驱动开发11——平台总线模型修改为设备树实例
Linux嵌入式驱动开发12——pinctl和gpio子系统实践操作
Linux嵌入式驱动开发13——ioctl接口(gpio控制使用)
Linux嵌入式驱动开发14——中断的原理以及按键中断的实现(tasklet中断下文)
Linux嵌入式驱动开发15——等待队列和工作队列
Linux嵌入式驱动开发16——按键消抖实验(内核定时器)
Linux嵌入式驱动开发17——输入子系统
Linux嵌入式驱动开发18——I2C通信
使用杂项设备完成一个蜂鸣器的驱动
完成一个上层测试应用
应用要求:在上层应用中传入参数1为打开蜂鸣器,传入参数0为关闭蜂鸣器
想要操作蜂鸣器,就要完成read函数 open函数,等等,我们做驱动,大部分情况下也都是使用这几个函数。
要完成上层应用的测试,就需要应用层和内核层传输数据,copy_to_user和copy_from_user
beep.c
#include
#include
#include
#include
#include
#include
#define GPIO5_DR 0x020AC000
unsigned int *vir_gpio5_dr;
int misc_open (struct inode *inode, struct file *file){
printk("hello misc_open!!!\n");
return 0;
}
int misc_release(struct inode *inode, struct file *file){
printk("bye bye misc_release!!!\n");
return 0;
}
ssize_t misc_read(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = "copy to user!!!\n";
if( copy_to_user(ubuf, kbuf, size) != 0 ){
printk("copy_to_user error!!!\n");
return -1;
}
printk("hello misc_read!!!\n");
return 0;
}
ssize_t misc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = "copy from user!!!\n";
printk("hello misc_write!!!\n");
if( copy_from_user(kbuf, ubuf, size) != 0 ){
printk("copy_from_user error!!!\n");
return -1;
}
printk("buf is:%s\n", kbuf);
if(kbuf[0] == 1){ //对蜂鸣器的控制,如果是1,控制gpio口
*vir_gpio5_dr |= (1 << 1); //因为是gpio5的01,所以左移一位就可以,给一个高电平,使蜂鸣器工作
}else if(kbuf[0] == 0){
*vir_gpio5_dr &= ~(1 << 1);
}
return 0;
}
struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.release = misc_release,
.read = misc_read,
.write = misc_write,
};
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "hello_misc",
.fops = &misc_fops
};
static int misc_init(void)
{
int ret;
ret = misc_register(&misc_dev);
if(ret < 0){
printk("misc_register failed!!!\n");
return -1;
}
printk("misc_register succeed!!!\n"); // 在内核中无法使用c语言库,所以不用printf
vir_gpio5_dr = ioremap(GPIO5_DR, 4); // 物理地址到虚拟地址的映射
if(vir_gpio5_dr == NULL){ //如果映射失败
printk("GPIO5_DR ioremap error!!!\n");
return -EBUSY; //EBUSY是Linux的预留参数,前面加个负号
}
return 0;
}
static void misc_exit(void)
{
misc_deregister(&misc_dev);
iounmap(vir_gpio5_dr); //取消虚拟地址的映射
printk("misc exit!!!\n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL"); //声明模块拥有开源许可
app.c
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int fd;
char buff[64] = {0};
fd = open("/dev/hello_misc", O_RDWR);
if(fd < 0){
perror("open error\n"); // perror在应用中打印
return fd;
}
buff[0] = atoi(argv[1]); //字符串转化成整形
// read(fd, buff, sizeof(buff));
write(fd, buff,sizeof(buff)); //在write中就传数据到底层,这样可以调用驱动的mis_write的操作了,直接操作 ./app 1或者./app 0
// printf("buf is:%s\n", buff);
close(fd);
return 0;
}