linux beep 实验

linux beep 实验

修改设备树

  • 添加 pinctrl 子节点
pinctrl_beep: beepgrp {
    /*  定义在arch/arm/boot/dts/imx6ull-pinfunc-snvs.h */
    fsl,pins = <
        MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01  0x10B0 /* LED0 */
        >;
};
  • 添加 beep 节点
beep {
    #address-cells = <1>; /* reg 属性中起始地址占用一个字长 */
    #size-cells = <1>;	  /* 地址长度占用一个字长 */
    pinctrl-names = "default";
    compatible = "gpio-beep"; /* 属性 compatbile 设置节点兼容性为“gpio-beep”*/
    pinctrl-0 = <&pinctrl_beep>; /* 设置蜂鸣器所使用的PIN对应的pinctrl节点 */
    gpio-led = <&gpio5 1 GPIO_ACTIVE_HIGH>; 
    status = "okay";	/* 属性 status 设置状态为“okay” */
};

驱动程序

beep的驱动程序起始和led等的是差不多一致的。几乎没有变化,只是修改对应的GPIO引脚

#include    // module_init、module_exit函数的头文件所在地
#include      //添加文件描述符,设备注册注销头文件
#include  // 添加module_XXX宏定义头文件
#include 
#include 
#include 
#include 
#include 
#include    // 包含readl等IO操作函数
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define NEW_CHAR_CNT 1   /*设备号数量*/
#define MY_NAME "gpio_beep" /*设备名字*/
#define BEEP_OFF     0   /* 关蜂鸣器 */
#define BEEP_ON      1   /* 开蜂鸣器 */


typedef struct my_dev{
    int major;  /*主设备号*/
	int minor;  /*次设备号*/
	dev_t dev;  /*设备号*/
	struct cdev cdev;  /* cdev */
	struct class *class; /*类*/
	struct device *device; /*设备*/
    struct device_node *nd; /* 设备树设备节点 */
    int beep_gpio; /* beep 所使用的 GPIO 编号 */
}my_dev_t;

my_dev_t my_new_dev;  /*新设备*/


/*打开设备*/
static int my_dev_open (struct inode *inode, struct file *file)
{
    file->private_data = &my_new_dev; /*设置私有数据*/
    return 0;
}
/*读设备*/
static ssize_t my_dev_read (struct file *file, char __user *buf, 
                            size_t cnt, loff_t * offt)
{
    return 0;
}
/*写设备*/
static ssize_t my_dev_write (struct file *file, const char __user *buf,
                         size_t cnt, loff_t *offt)
{
    int ret = 0;
    unsigned char data_buf[1];
    unsigned char beep_stat;
    my_dev_t *dev = file->private_data;  /* 获取私有数据 GPIO 编号 */
    /*接收用户空间的数据*/
    ret = copy_from_user(data_buf,buf,cnt);
    if(ret < 0)
    {
        printk(KERN_INFO "write fail ...\n");
        return -EFAULT; 
    }

    beep_stat = data_buf[0]; /* 获取状态值 */

    if(beep_stat == BEEP_ON)
    {
        gpio_set_value(dev->beep_gpio, 1); /* 关闭蜂鸣器 */
    }else if(beep_stat == BEEP_OFF)
    {
        gpio_set_value(dev->beep_gpio, 0); /* 打开蜂鸣器 */
    }

    return 0;
}
/*释放设备*/
static int my_dev_close (struct inode *inode, struct file *file)
{
    return 0;
}

static struct file_operations my_fops = {
    .owner		= THIS_MODULE,		// 惯例,直接写即可
	.open		= my_dev_open,		// 打开设备
    .read       = my_dev_read,		// 读设备
    .write		= my_dev_write,		// 写设备
	.release	= my_dev_close,		// 关闭设备
};

/*驱动入口函数 */
static int __init mydev_init(void)
{
    int ret;

    /* 获取设备树中的属性数据 */
    /* 1、获取设备节点:gpiobeep */
    my_new_dev.nd = of_find_node_by_path("/gpiobeep");

    if(my_new_dev.nd == NULL) {
        printk("gpiobeep node can not found!\r\n");
        return -EINVAL;
    } else {
        printk("gpiobeep node has been found!\r\n");
    }

    /* 2、 获取设备树中的 gpio 属性,得到 BEEP 所使用的 BEEP 编号 */
    my_new_dev.beep_gpio = of_get_named_gpio(my_new_dev.nd, "gpio-beep", 0);
    if(my_new_dev.beep_gpio < 0) {
        printk("can't get gpio-beep");
        return -EINVAL;
    }

    printk("gpio-beep num = %d\r\n", my_new_dev.beep_gpio);

    /* 3、设置 GPIO5_IO01 为输出,并且输出高电平,默认关闭 BEEP 灯 */
    ret = gpio_direction_output(my_new_dev.beep_gpio, 1);
    if(ret < 0) {
        printk("can't set gpio!\r\n");
    }

    /* 1、分配设备号 */
    if(my_new_dev.major) /*定义了主设备号*/
    {
        my_new_dev.dev = MKDEV(my_new_dev.major,0); /*次设备默认从0开始*/
        register_chrdev_region(my_new_dev.dev,NEW_CHAR_CNT,MY_NAME); /*静态申请设备号*/
    }else
    {
        alloc_chrdev_region(&my_new_dev.dev,0,NEW_CHAR_CNT,MY_NAME); /*动态申请设备号*/
        my_new_dev.major = MAJOR(my_new_dev.dev); /*主设备号*/
        my_new_dev.minor = MINOR(my_new_dev.dev); /*次设备号*/
    }
    /* 2、注册设备号 */
    my_new_dev.cdev.owner = THIS_MODULE;
    cdev_init(&my_new_dev.cdev,&my_fops); /*初始化cdev*/
    cdev_add(&my_new_dev.cdev,my_new_dev.dev,NEW_CHAR_CNT); /*添加一个dev*/
    /* 3、创建类 */
	my_new_dev.class = class_create(THIS_MODULE,MY_NAME);
    if(IS_ERR(my_new_dev.class))
    {
        return PTR_ERR(my_new_dev.class);
    }
    /* 4、创建设备 */
    my_new_dev.device = device_create(my_new_dev.class,NULL,my_new_dev.dev,NULL,MY_NAME);
    if(IS_ERR(my_new_dev.device))
    {
        return PTR_ERR(my_new_dev.device);
    }

    return 0;
}

/*驱动出口函数 */
static void __exit mydev_exit(void)
{
    /*注销字符设备*/
    cdev_del(&my_new_dev.cdev);
    unregister_chrdev_region(my_new_dev.dev, NEW_CHAR_CNT);

    /*注销掉类和设备*/
	device_destroy(my_new_dev.class,my_new_dev.dev);
    class_destroy(my_new_dev.class);
}

module_init(mydev_init); // 注册加载函数
module_exit(mydev_exit); // 注册卸载函数

// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL");             // 描述模块的许可证
MODULE_AUTHOR("dongfang");         // 描述模块的作者
MODULE_DESCRIPTION("module test"); // 描述模块的介绍信息
MODULE_ALIAS("------");            // 描述模块的别名信息

你可能感兴趣的:(Linux,RAM,linux,c语言,c++)