驱动层: mychrdev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
unsigned int major;
char kbuf[128] = {0};
gpio_t* vir_led1;
gpio_t* vir_led2;
gpio_t* vir_led3;
gpio_t* vir_fan; //风扇 gpioe9
gpio_t* vir_beep;//蜂鸣器 gpiob6
gpio_t* vir_motor;//马达 gpiof6
rcc_t* vir_rcc;
struct class *cls;
struct device *dev;
int mychrdev_open (struct inode *inode, struct file *file)
{
printk ("%s:%s:%d\n",__FILE__, __func__, __LINE__);
return 0;
}
ssize_t mychrdev_read (struct file *file, char *ubuf, size_t size, loff_t *lof)
{
printk ("%s:%s:%d\n",__FILE__, __func__, __LINE__);
unsigned long ret;
//向内核空间拷贝数据
if(size > sizeof(kbuf)) //
{
size = sizeof(kbuf);
}
ret = copy_to_user(ubuf,kbuf,size);
if(ret)
{
printk ("copy to user failed\n");
return ret;
}
return 0;
}
ssize_t mychrdev_write (struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
unsigned long ret;
//从用户空间读取数据
if(size > sizeof(kbuf)) //
{
size = sizeof(kbuf);
}
ret = copy_from_user(kbuf,ubuf,size);
if(ret)
{
printk ("copy from user failed\n");
return ret;
}
printk ("%s:%s:%d\n",__FILE__, __func__, __LINE__);
switch(kbuf[0])
{
case '1':
if ('1' == kbuf[1])
{
//(*vir_odr) &= (0x1<<10);
(vir_led1->ODR) |= (1<<10);
printk("%s\n","LED1 on by kernel");
} else if ('0' == kbuf[1])
{
//(*vir_odr) &= (~(0x1<<10));
(vir_led1->ODR) &= (~(1<<10));
printk("%s\n","LED1 off by kernel");
}
break;
case '2':
if ('1' == kbuf[1])
{
//(*vir_odr) &= (0x1<<10);
(vir_led2->ODR) |= (1<<10);
printk("%s\n","LED2 on by kernel");
} else if ('0' == kbuf[1])
{
//(*vir_odr) &= (~(0x1<<10));
(vir_led2->ODR) &= (~(1<<10));
printk("%s\n","LED2 off by kernel");
}
break;
case '3':
if ('1' == kbuf[1])
{
//(*vir_odr) &= (0x1<<10);
(vir_led1->ODR) |= (1<<8);
printk("%s\n","LED3 on by kernel");
} else if ('0' == kbuf[1])
{
//(*vir_odr) &= (~(0x1<<10));
(vir_led1->ODR) &= (~(1<<8));
printk("%s\n","LED3 off by kernel");
}
break;
case '4':
if ('1' == kbuf[1])
{
(vir_fan->ODR) |= (1<<9);
printk("%s\n","fan on by kernel");
} else if ('0' == kbuf[1])
{
(vir_fan->ODR) &= (~(1<<9));
printk("%s\n","fan off by kernel");
}
break;
case '5':
if ('1' == kbuf[1])
{
(vir_beep->ODR) |= (1<<6);
printk("%s\n","beep on by kernel");
} else if ('0' == kbuf[1])
{
(vir_beep->ODR) &= (~(1<<6));
printk("%s\n","beep off by kernel");
}
break;
case '6':
if ('1' == kbuf[1])
{
(vir_motor->ODR) |= (1<<6);
printk("%s\n","motor on by kernel");
} else if ('0' == kbuf[1])
{
(vir_motor->ODR) &= (~(1<<6));
printk("%s\n","motor off by kernel");
}
break;
default:
break;
}
return 0;
}
int mychrdev_close (struct inode *inode, struct file *file)
{
printk ("%s:%s:%d\n",__FILE__, __func__, __LINE__);
return 0;
}
const struct file_operations fops =
{
.open = mychrdev_open,
.read =mychrdev_read,
.write =mychrdev_write,
.release =mychrdev_close,
};
int led_init(void)
{
//寄存器地址映射
//LED1
vir_led1 = ioremap(GPIOE,sizeof(gpio_t));
if (vir_led1 == NULL)
{
printk("ioremap failed:%d\n",__LINE__);
return -ENOMEM;
}
vir_led2 = ioremap(GPIOF,sizeof(gpio_t));
if (vir_led2 == NULL)
{
printk("ioremap failed:%d\n",__LINE__);
return -ENOMEM;
}
vir_beep = ioremap(GPIOB,sizeof(gpio_t));
if (vir_beep == NULL)
{
printk("ioremap failed:%d\n",__LINE__);
return -ENOMEM;
}
vir_led3 = vir_led1;
vir_fan = vir_led1;
vir_motor = vir_led2;
vir_rcc = ioremap(RCC,sizeof(rcc_t));
if (vir_rcc == NULL)
{
printk("ioremap failed:%d\n",__LINE__);
return -ENOMEM;
}
printk("physical address mapping succeeded\n");
//寄存器初始化
// (*vir_rcc) |= (0x1<<4);
// (*vir_moder) &= (~(0x3<<20));
// (*vir_moder) |= (~(0x1<<20));
//GPIOE使能
(vir_rcc->MP_AHB4ENSETR) |= (1<<4);
//GPIOF使能
(vir_rcc->MP_AHB4ENSETR) |= (1<<5);
//GPIOB使能
(vir_rcc->MP_AHB4ENSETR) |= (1<<1);
//LED1 moder
(vir_led1->MODER) &= (~(3<<20));
(vir_led1->MODER) |= (1<<20);
//LED2 moder
(vir_led2->MODER) &= (~(3<<20));
(vir_led2->MODER) |= (1<<20);
//LED3 moder
(vir_led3->MODER) &= (~(3<<16));
(vir_led3->MODER) |= (1<<16);
//LED1 odr输出低电平
//(*vir_odr) &= (~(0x1<<10));
(vir_led1->ODR) &= (~(1<<10));
//LED2 odr输出低电平
(vir_led2->ODR) &= (~(1<<10));
//LED3 odr输出低电平
(vir_led3->ODR) &= (~(1<<8));
/*****风扇 蜂鸣器 马达 部分*****/
//风扇 gpioe9
vir_fan->MODER &= (~(3<<18));
vir_fan->MODER |= (1<<18);
vir_fan->ODR &= (~(1<<9));
//蜂鸣器 gpiob6
vir_beep->MODER &= (~(3<<12));
vir_beep->MODER |= (1<<12);
vir_beep->ODR &= (~(1<<6));
//马达 gpiof6
vir_motor->MODER &= (~(3<<12));
vir_motor->MODER |= (1<<12);
vir_motor->ODR &= (~(1<<6));
printk("register init succeeded\n");
return 0;
}
static int __init mychrdev_init(void)
{
//字符设备驱动注册
major = register_chrdev(0,"mychrdev",&fops);
if (major < 0)
{
printk(" register_chrdev failed\n");
return major;
}
printk("register_chrdev succeeded:major=%d\n",major);
//向上提交目录
cls = class_create(THIS_MODULE,"mychrdev");
if (IS_ERR(cls))
{
printk(" 向上提交目录失败\n");
return PTR_ERR(cls);
}
printk(" 向上提交目录成功\n");
//向上提交设备信息
dev = device_create(cls,NULL,MKDEV(major,0),NULL,"mychrdev");
if (IS_ERR(dev))
{
printk(" 向上提交设备信息失败\n");
return PTR_ERR(dev);
}
printk(" 向上提交设备信息成功\n");
led_init();
return 0;
}
static void __exit mychrdev_exit(void)
{
//取消地址映射
iounmap(vir_led1);
iounmap(vir_led2);
iounmap(vir_led3);
iounmap(vir_rcc);
//销毁设备信息
device_destroy(cls,MKDEV(major,0));
//销毁目录
class_destroy(cls);
//注销字符设备驱动
unregister_chrdev(major,"mychrdev");
}
module_init(mychrdev_init);
module_exit(mychrdev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Satoshi Nakamoto");
应用层: test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
char buf[128] = {0};
void horse_led(int fd);
void telegram_beep(int fd);
int main(int argc, char *argv[])
{
int fd = open("/dev/mychrdev",O_RDWR);
if (fd < 0)
{
printf("open failed\n");
return -1;
}
while (1)
{
printf("请输入两个字符:\n");
printf("第一个字符:1(LED1),2(LED2),3(LED3),4(风扇),5(蜂鸣器),6(马达)\n");
printf("第二个字符:0(关),1(开)\n");
printf("输入horse实现跑马灯\n");
printf("输入quit退出\n");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = '\0'; //替换\n
if (!strcmp(buf,"quit"))
{
break;
}
if (!strcmp(buf,"horse"))
{
horse_led(fd);
}
if (!strcmp(buf,"telegram"))
{
telegram_beep(fd);
}
//向设备中写
write(fd,buf,sizeof(buf));
//从设备文件中读取
memset(buf,0,sizeof(buf));
read(fd,buf,sizeof(buf));
printf("buf returned from kernel==>%s\n",buf);
}
return 0;
}
void horse_led(int fd)
{
while (1)
{
strcpy(buf,"11");
write(fd,buf,sizeof(buf));
sleep(1);
strcpy(buf,"10");
write(fd,buf,sizeof(buf));
sleep(1);
strcpy(buf,"21");
write(fd,buf,sizeof(buf));
sleep(1);
strcpy(buf,"20");
write(fd,buf,sizeof(buf));
sleep(1);
strcpy(buf,"31");
write(fd,buf,sizeof(buf));
sleep(1);
strcpy(buf,"30");
write(fd,buf,sizeof(buf));
sleep(1);
}
}
void telegram_beep(int fd)
{
while (1)
{
strcpy(buf,"51");
write(fd,buf,sizeof(buf));
sleep(0.5);
strcpy(buf,"51");
write(fd,buf,sizeof(buf));
sleep(0.5);
strcpy(buf,"51");
write(fd,buf,sizeof(buf));
sleep(0.5);
strcpy(buf,"50");
write(fd,buf,sizeof(buf));
sleep(0.5);
strcpy(buf,"50");
write(fd,buf,sizeof(buf));
sleep(0.5);
strcpy(buf,"50");
write(fd,buf,sizeof(buf));
sleep(0.5);
}
}
现象: