S3C2440内核蜂鸣器驱动解读

S3C2440内核函数

首先介绍需要的一些头文件的位置

linux-2.6.32.内核重要文件目录:
linux-2.6.32.2/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
linux-2.6.32.2/arch/arm/plat-s3c24xx/gpio.c
linux-2.6.32.2/linux/asm-generic/io.h
linux-2.6.32.2/include/linux/wait.h
asm -- linux-2.6.32.2/linux/asm-generic
mach -- linux-2.6.32.2/arch/arm/mach-s3c2410/include/mach
plat -- linux-2.6.32.2/arch/arm/plat-s3c24xx/include/plat
-- linux-2.6.32.2/arch/arm/plat/include/plat

1、2440蜂鸣器内核驱动

展示内核驱动

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>
	 
#include <mach/regs-gpio.h>
#include <linux/cdev.h>

static int beep_major = 0;
module_param(beep_major, int, 0);//传参函数,并在模块目录下会生成parameter目录及参数文件
/*
MODULE_AUTHOR ( 声明谁编写了模块 ),
MODULE_DESCRIPION( 一个人可读的关于模块做什么的声明 ),
MODULE_VERSION ( 一个代码修订版本号; 看 <linux/module.h> 的注释以便知道创建版本字串使用的惯例),
MODULE_ALIAS ( 模块为人所知的另一个名字 ), 以及 MODULE_DEVICE_TABLE ( 来告知用户空间, 模块支持那些设备 ). 
MODULE_LICENSE(“GPL”);
内核认识的特定许可有, “GPL”( 适用 GNU 通用公共许可的任何版本 ), “GPL v2”( 只适用 GPL 版本 2 ), “GPL and additional rights”, “Dual BSD/GPL”, “Dual MPL/GPL”, 和 “Proprietary”. 除非你的模块明确标识是在内核认识的一个自由许可下, 否则就假定它是私有的
*/
MODULE_AUTHOR("All");
MODULE_LICENSE("Dual BSD/GPL");

#define BEEP_MAGIC 'b'
#define BEEP_START_CMD _IO (BEEP_MAGIC, 1)//使用内核函数库提供的_IO函数,最后参考文献详细查看
#define BEEP_STOP_CMD _IO (BEEP_MAGIC, 2)

/*
 * Open the device; in fact, there's nothing to do here.
 */
int beep_open (struct inode *inode, struct file *filp)
{
	return 0;
}

ssize_t beep_read(struct file *file, char __user *buff, size_t count, loff_t *offp)
{
	return 0;
}

ssize_t beep_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)
{
	return 0;
}
//一般像read、write一般这些函数不会写什么内容,open有时候会放入初始化函数

/*
使用s3c2410_gpio_cfgpin函数初始化端口,设置为输出,s3c2410_gpio_setpin设置端口输出高低电压,对着开发手册进行设置自己所需要的输出电压。s3c2410_gpio_pullup控制上拉电阻。
*/
void beep_stop( void )
{
	//set GPB0 as output
	s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);
	s3c2410_gpio_setpin(S3C2410_GPB(0),0);
}

void beep_start( void )
{
	//set GPB0 as output
	s3c2410_gpio_pullup(S3C2410_GPB(0),1);
	s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);
	s3c2410_gpio_setpin(S3C2410_GPB(0),1);
}

/*函数调用,使用ioctl可以通过不同的cmd数,选择所调用的内核函数*/
static int beep_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	//add your src HERE!!!
	switch ( cmd ) {
		case BEEP_START_CMD: {
			beep_start(); 	break;
		}
		case BEEP_STOP_CMD: {
			beep_stop(); 	break;
		}
		default: {
			break;
		}
	}
	return 0;

}

static int beep_release(struct inode *node, struct file *file)
{
	return 0;
}

/*
 * Set up the cdev structure for a device.
 */
static void beep_setup_cdev(struct cdev *dev, int minor,
		struct file_operations *fops)
{
	int err, devno = MKDEV(beep_major, minor);
    
	cdev_init(dev, fops);
    //注册设备,或者应该说是初始化
	dev->owner = THIS_MODULE;
	dev->ops = fops;
	err = cdev_add (dev, devno, 1);
    //向内核添加设备失败,linux-2.6之后使用者两个函数进行注册和添加
	if (err)
		printk (KERN_NOTICE "Error %d adding beep%d", err, minor);
}

 /*
 file_operations结构体
 Linux使用file_operations结构访问驱动程序的函数,这个结构的每一个成员的名字都对应着一个函数调用。
	  用户进程利用在对设备文件进行诸如read/write操作的时候,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数,这是Linux的设备驱动程序工作的基本原理。
	  struct module *owner
	  第一个 file_operations 成员根本不是一个操作,它是一个指向拥有这个结构的模块的指针。这个成员用来在它的操作还在被使用时阻止模块被卸载. 几乎所有时间中, 它被简单初始化为 THIS_MODULE, 一个在 <linux/module.h> 中定义的宏.这个宏比较复杂,在进行简单学习操作的时候,一般初始化为THIS_MODULE。
https://blog.csdn.net/zqixiao_09/article/details/50850475
*/
static struct file_operations beep_remap_ops = {
	.owner   = THIS_MODULE,
	.open    = beep_open,
	.release = beep_release,
	.read    = beep_read,
	.write   = beep_write,
	.ioctl   = beep_ioctl,	
};

/*
 * There's no need for us to maintain any
 * special housekeeping info, so we just deal with raw cdevs.
 */
static struct cdev BeepDevs;

/*
 * Module housekeeping.
 */
/*beep_init函数主要用于获取设备号,用于内核识别*/
static int beep_init(void)
{
	int result;
	dev_t dev = MKDEV(beep_major, 0);
    //格式转换,beep_major是主设备号,这里是靠调用驱动时的传参,默认为0 
	char dev_name[]="beep";

	/* Figure out our device number. */
	if (beep_major)
		result = register_chrdev_region(dev, 1, dev_name);
    //手动分配注册设备号,如果之前没有分配设备号,beep_major为0因此调用动态分配设备号进行注册,但是内核分配后beep_major不为0,就会调用该函数,也就是说知道主设备号才来使用该函数
	else {
		result = alloc_chrdev_region(&dev, 0, 1, dev_name);
		beep_major = MAJOR(dev);
    //动态分配注册设备号,并更新主设备号,详细查看https://blog.csdn.net/welbell_uplooking/article/details/83654312
	}
	if (result < 0) {
		printk(KERN_WARNING "beep: unable to get major %d\n", beep_major);
		return result;
	}
	if (beep_major == 0)
		beep_major = result;

	/* Now set up cdev. */
	beep_setup_cdev(&BeepDevs, 0, &beep_remap_ops);
	printk("beep device installed, with major %d\n", beep_major);
	printk("The device name is: %s\n", dev_name);
	return 0;
}


static void beep_cleanup(void)
{
	cdev_del(&BeepDevs);
    //注销设备,删除一个cdev
	unregister_chrdev_region(MKDEV(beep_major, 0), 1);
    //释放注销的所占用的设备号
	printk("beep device uninstalled\n");
}


module_init(beep_init);
module_exit(beep_cleanup);
//驱动加载系统传参
EXPORT_SYMBOL(beep_major);


加载驱动模块

insmod beep_dev.ko

创建dev下面beep设备文件与我们的beep_dev驱动绑定

mknod /dev/beep c 251 0

原命令形式:mknod /dev/node_name c major minor

只有创建了beep文件用户才能通过open之类的操作访问或者调用内核驱动函数

2、2440蜂鸣器用户函数

其次是蜂鸣器内核外的应用层函数

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/ioctl.h>

#define BEEP_MAGIC 'b'
#define BEEP_START_CMD _IO (BEEP_MAGIC, 1)
#define BEEP_STOP_CMD _IO (BEEP_MAGIC, 2)



int main()
{
	int i = 0;
	int dev_fd;
	dev_fd = open("/dev/beep",O_RDWR | O_NONBLOCK);
	if ( dev_fd == -1 ) {
		printf("Cann't open file /dev/beep\n");
		exit(1);
	}
	printf("Start beep\n");
	ioctl (dev_fd, BEEP_START_CMD,0);
	getchar();
	ioctl (dev_fd, BEEP_STOP_CMD,0);
	printf("Stop beep and Close device\n");
	close(dev_fd);
	return 0;
}

关系大概如下:

image-20230613190752929

3、参考文献

1、#deinfne # ## #@用法: https://blog.csdn.net/bytxl/article/details/47423151

2、内核函数库_IO(): https://blog.csdn.net/hzn407487204/article/details/7995041

3、内核驱动开发: https://zhuanlan.zhihu.com/p/420194002

posted @ 2023-06-13 19:45  Prinz_Eugen  阅读(94)  评论(0)    收藏  举报