GEC6818蜂鸣器驱动开发

发布于:2025-05-07 ⋅ 阅读:(17) ⋅ 点赞:(0)

相关知识:Linux设备驱动开发

insmod 编译好的.ko文件后再运行beep_app.c编译完成的可执行文件即可使板子蜂鸣。

beep_drv.c:

#include <linux/module.h> //包含了加载模块时需要使用的大量符号和函数声明
#include <linux/kernel.h> //包含了printk内核打印函数等函数声明
#include <linux/init.h>  //包含了模块加载函数和模块释放函数的宏定义
#include <linux/errno.h>
#include <linux/cdev.h>
#include<linux/fs.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/uaccess.h>

int devno_major=0;//beep的主设备号
int devno_minor=0;//beep的次设备号
struct class *beep_class;
struct device *beep_device;
struct resource *beep_resource;
void __iomem *gpioc_base_va;
void __iomem *gpiocout_va;    
void __iomem *gpiocoutenb_va; 
void __iomem *gpiocaltfn0_va; 
void __iomem *gpiocaltfn1_va; 
void __iomem *gpiocpad_va;    


module_param(devno_major,int,0660);
module_param(devno_minor,int,0660);

enum beep_state{BEEP_OFF,BEEP_ON};

int beep_state=BEEP_OFF;

/*1、定义一个字符设备 ---> struct cdev*/
struct cdev beep_cdev;

/*2、定义并初始化字符设备的文件操作集 ---> struct file_operations*/
int gec6818_beep_open(struct inode *inode, struct file *filp)
{
	printk("beep have been opened!\n");
	return 0;
}
ssize_t gec6818_beep_read (struct file *filp, char __user *user_buf,size_t size, loff_t *off)
{
	int r = copy_to_user(user_buf, (void*)&beep_state, size);
	if(r != 0)
		return EINVAL;
		
	return size;
}
ssize_t gec6818_beep_write (struct file *filp, const char __user *user_buf, size_t size, loff_t *off)
{
	int r = copy_from_user((void*)&beep_state, user_buf, size);
	if(r != 0)
		return EINVAL;

	if(beep_state == BEEP_ON)
		writel(readl(gpiocout_va)|(0x01<<14),gpiocout_va);
	else
		writel(readl(gpiocout_va)&(~(0x01<<14)),gpiocout_va);
	return size;
}
int gec6818_beep_release (struct inode *inode, struct file *filp)
{
	printk("beep have been closed!\n");
	return 0;
}

static const struct file_operations gec6818_beep_fops = {
	.owner = THIS_MODULE,
	.open = gec6818_beep_open,
	.read = gec6818_beep_read,
	.write = gec6818_beep_write,
	.release = gec6818_beep_release
};



//入口函数 -->安装驱动
static int  __init gec6818_beep_init(void)
{
	dev_t devno;//beep的设备号
	int ret=0;
	/*3、给字符设备申请一个设备号 ---> 设备号=主设备号<<20 + 次设备号*/
	if(devno_major != 0)
	{
		devno = MKDEV(devno_major,devno_minor);
		if(register_chrdev_region(devno, 1, "gec6818_beep"))
		{
			printk("register_chrdev_region error!\n");
			if(alloc_chrdev_region(&devno, devno_minor, 1, "gec6818_beep"))
			{
				printk("alloc_chrdev_region error!\n");
				ret = EINVAL;
				goto alloc_chrdev_region_err;
			}
		}
		
	}
	else
	{
		if(alloc_chrdev_region(&devno, devno_minor, 1, "gec6818_beep"))
		{
			printk("alloc_chrdev_region error!\n");
			ret = EINVAL;
			goto alloc_chrdev_region_err;
		}
	}
	devno_major = MAJOR(devno);
	devno_minor = MINOR(devno);
	
	/*4、初始化字符设备*/
	cdev_init(&beep_cdev, &gec6818_beep_fops);
	
	/*5、将字符设备加入内核*/
	if(cdev_add(&beep_cdev, devno, 1)<0)
	{
		ret = EINVAL;
		goto cdev_add_err;	
	}
	
	/*6、创建class*/
	beep_class = class_create(THIS_MODULE, "gec6818_beep");
	if(beep_class == NULL)
	{
		ret = EBUSY;
		goto class_create_err;
		
	}
	/*7、创建device*/
	beep_device = device_create(beep_class, NULL,devno, NULL, "gec6818_beep");
	if(beep_device == NULL)
	{
		ret = EBUSY;
		goto device_create_err;
	}
    /*8、申请物理内存区*/
	beep_resource = request_mem_region(0xC001C000, 0x1000, "GPIOC_MEM");
	if(beep_resource == NULL)
	{
		ret = EBUSY;
		goto request_mem_region_err;
	}

	/*9、IO内存动态映射,得到虚拟地址*/
	gpioc_base_va = ioremap(0xC001C000, 0x1000);
	if(gpioc_base_va == NULL)
	{
		ret = EBUSY;
		goto ioremap_err;
	}
	
	/*10、使用虚拟地址,把beep进行初始化*/
	
	gpiocout_va    = gpioc_base_va + 0x00;
	gpiocoutenb_va = gpioc_base_va + 0x04;
	gpiocaltfn0_va = gpioc_base_va + 0x20;
	gpiocaltfn1_va = gpioc_base_va + 0x24;
	gpiocpad_va    = gpioc_base_va + 0x18;

	//GPIOCALTFN0 &= ~(0x03<<28);//把GPIOC14设置为GPIO功能
	writel(readl(gpiocaltfn0_va)&(~(0x03<<28)),gpiocaltfn0_va);
	//GPIOCALTFN0 |= (0x01<<28);
	writel(readl(gpiocaltfn0_va)|((0x01<<28)),gpiocaltfn0_va);
	//GPIOCOUTENB |= 1<<14;//把GPIOC14设置为输出模式
	writel(readl(gpiocoutenb_va)|((0x01<<14)),gpiocoutenb_va);
	//GPIOCOUT &= ~(1<<14);//把GPIOC14输出低电平,默认beep不响
	writel(readl(gpiocout_va)&(~(0x01<<14)),gpiocout_va);
	
	printk("gec6818 beep init success!\n");
	return 0;
ioremap_err:
	release_mem_region(0xC001C000, 0x1000);
request_mem_region_err:
	device_destroy(beep_class, devno);
device_create_err:
	class_destroy(beep_class);
class_create_err:
cdev_add_err:
	unregister_chrdev_region(devno, 1);//注销设备号
alloc_chrdev_region_err:
	return ret;
}

//出口函数 -->卸载驱动
static void __exit gec6818_beep_exit(void)
{
	iounmap(gpioc_base_va);
	release_mem_region(0xC001C000, 0x1000);
	device_destroy(beep_class, MKDEV(devno_major,devno_minor));
	class_destroy(beep_class);
	unregister_chrdev_region(MKDEV(devno_major,devno_minor), 1);//注销设备号
	printk("6818gec beep exit\n ");
}

//驱动程序的入口: #insmod hello.ko ==> module_init() ==> gec6868_hello_init();
module_init(gec6818_beep_init);
//驱动程序的出口: #rmmod hello.ko ==> module_exit() ==> gec6818_hello_exit();
module_exit(gec6818_beep_exit);
//module的描述: #modinfo  hello.ko
MODULE_AUTHOR("GEC_Liudehua@163.com");
MODULE_DESCRIPTION("beep driver for GEC6818");
MODULE_LICENSE("GPL");
MODULE_VERSION("V1.0");

 beep_app.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int beep_state;
int readbuf;

int main()
{
	int fd = open("/dev/gec6818_beep",O_RDWR);
	if(fd == -1)
	{
		printf("open failed!\n");
		return -1;
	}

	while(1)
	{
		beep_state=1;
		int r = write(fd,&beep_state,4);
		if(r !=4 )
		{
			printf("write error!\n");
		}
		read(fd,&readbuf,4);
		printf("read buf is %d\n",readbuf);
		sleep(2);
		beep_state=0;
		write(fd,&beep_state,4);
		read(fd,&readbuf,4);
		printf("read buf is %d\n",readbuf);
		sleep(2);
	}
}

makefile:


#KERNELRELEASE这个变量,在内核源码的根目录下面的Makefile会初初始化的

ifeq ($(KERNELRELEASE),)

KERN_DIR := /home/china/6818GEC/kernel

#在Makefile中可以调用shell的命令,调用方法如下:
# $(shell  shell命令) -> 整个这个表达式,表示调用该shell命令的输出结果
PWD := $(shell pwd)

CROSS_COMPILE := /home/china/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-

modules:
	make -C $(KERN_DIR)  M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE)  modules
clean:
	rm -rf *.o
	rm -rf  modules.order  .tmp_versions *.ko  Module.symvers
	rm -f  *.cmd .*.cmd  *.mod.c

else
	
	obj-m += beep_drv.o

endif


网站公告

今日签到

点亮在社区的每一天
去签到