[驱动开发]字符设备驱动应用——点灯

点亮开发板stm32mp157的三盏灯

//头文件
#ifndef __LED_H__
#define __LED_H__

//封装GPIO寄存器                                
typedef struct {                          
    volatile unsigned int MODER;   // 0x00
    volatile unsigned int OTYPER;  // 0x04
    volatile unsigned int OSPEEDR; // 0x08
    volatile unsigned int PUPDR;   // 0x0C
    volatile unsigned int IDR;     // 0x10
    volatile unsigned int ODR;     // 0x14
}gpio_t;

//宏定义基地址
#define PHY_LED1_ADDR 0x50006000
#define PHY_LED2_ADDR 0x50007000
#define PHY_LED3_ADDR 0x50006000
#define PHY_RCC 0x50000A28

#endif

//应用程序
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, const char *argv[])
{
	char buf[128]={0};
	int fd = open("/dev/mychrdev",O_RDWR);
	if(fd < 0)
	{
		printf("打开设备文件失败\n");
		exit(-1);
	}
	while(1)
	{
		bzero(buf,sizeof(buf));
		printf("选择LED:1 2 3>>>");
		fgets(buf,sizeof(buf),stdin);
		printf("输入控制命令:0熄灭 1开灯>>>");
		fgets(buf+1,sizeof(buf),stdin);
		buf[strlen(buf)-1]='\0';
		write(fd,buf,sizeof(buf));
	}
	close(fd);
	return 0;

}
//驱动程序
#include 
#include 
#include 
#include 
#include 
#include "led.h"

char kbuf[128]={0};
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;
int major; //保存主设备号
//封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
	int ret;
	if(sizeof(kbuf) < size)            //判断用户空间长度是否比内核空间大
		size=sizeof(kbuf);
	ret=copy_to_user(ubuf,kbuf,size);  //将内核数据拷贝到用户
	if(ret)
	{
		printk("copy_to_user filed\n");
		return -EIO;
	}
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
	int ret;
	if(sizeof(kbuf) < size)
		size=sizeof(kbuf);
	ret=copy_from_user(kbuf,ubuf,size);
	if(ret)
	{
		printk("copy_from_user filed\n");
		return -EIO;
	}

	if(kbuf[0]=='1')      //LED1
	{
		if(kbuf[1]=='1')  					//开灯
			vir_led1->ODR |= (0x1 << 10);
		else if(kbuf[1]=='0') 				//关灯
			vir_led1->ODR &= (~(0x1 << 10));
	}
	else if(kbuf[0]=='2')      //LED2
	{
		if(kbuf[1]=='1')  					//开灯
			vir_led2->ODR |= (0x1 << 10);
		else if(kbuf[1]=='0') 				//关灯
			vir_led2->ODR &= (~(0x1 << 10));
	}
	else if(kbuf[0]=='3')      //LED3
	{
		if(kbuf[1]=='1')  					//开灯
			vir_led3->ODR |= (0x1 << 8);
		else if(kbuf[1]=='0') 				//关灯
			vir_led3->ODR &= (~(0x1 << 8));
	}

    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

//定义一个操作方法结构体变量并初始化
struct file_operations fops =
{
	.open    =  mycdev_open,
	.read    =  mycdev_read,
	.write   =  mycdev_write,
	.release =  mycdev_close,
};

int led_init(void)
{
	//映射物理寄存器
	vir_led1=ioremap(PHY_LED1_ADDR,sizeof(gpio_t));
	if(vir_led1 == NULL)
	{
		printk("vir_led1寄存器地址映射表失败\n");
		return -EFAULT;
	}
	vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t));
	if(vir_led2 == NULL)
	{
		printk("vir_led2寄存器地址映射表失败\n");
		return -EFAULT;
	}
	vir_led3=ioremap(PHY_LED3_ADDR,sizeof(gpio_t));
	if(vir_led3 == NULL)
	{
		printk("vir_led1寄存器地址映射表失败\n");
		return -EFAULT;
	}
	
	vir_rcc=ioremap(PHY_RCC,4);
	if(vir_rcc==NULL)
	{
		printk("vir_rcc寄存器地址映射表失败\n");
		return -EFAULT;
	}
	
	printk("寄存器地址映射成功\n");
	
	//寄存器初始化
    (*vir_rcc) |= (0x3 << 4);//rcc使能
    vir_led1->MODER &= (~(0X3 << 20));//设置为输出
    vir_led1->MODER |= (0x1 << 20);
    vir_led1->ODR &= (~(0x1 << 10));//灭灯
    
	vir_led2->MODER &= (~(0X3 << 20));//设置为输出
    vir_led2->MODER |= (0x1 << 20);
    vir_led2->ODR &= (~(0x1 << 10));//灭灯
 
    vir_led3->MODER &= (~(0X3 << 16));//设置为输出
    vir_led3->MODER |= (0x1 << 16);
    vir_led3->ODR &= (~(0x1 << 8));//灭灯

	printk("硬件寄存器初始化成功\n");
	return 0;
}
static int __init mycdev_init(void)
{
	//字符设备驱动注册
	major = register_chrdev(0,"mychrdev",&fops);
	if(major < 0)
	{
		printk("字符设备驱动注册失败\n");
		return major;
	}
	printk("字符设备驱动注册成功major=%d\n",major);
	
	//初始化led
	led_init();
    
	return 0;
}

static void __exit mycdev_exit(void)
{
	//取消寄存器地址映射
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_led3);
    iounmap(vir_rcc);
	//字符设备驱动注销
	unregister_chrdev(major,"mychrdev");
	printk("字符设备驱动注销\n");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

结果

[驱动开发]字符设备驱动应用——点灯_第1张图片

你可能感兴趣的:(驱动开发,c#)