书写驱动代码

如下要求
a.应用程序通过阻塞的io模型来读取number变量的值b.number是内核驱动中的一个变量
c.number的值随着按键按下而改变(按键中断)
例如number=O按下按键number=1 ,再次按下按键number=Od .在按下按键的时候需要同时将led1的状态取反
e .驱动中需要编写字符设备驱动
f.驱动中需要自动创建设备节点
g.这个驱动需要的所有设备信息放在设备树的同一个节点中

添加的设备树节点

myopt{
    led1=<&gpioe 10 0>;
    interrupts-extended=<&gpiof 9 0>;
};

驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>

int major; // 主设备号
struct class *cls;
struct device *dev;
// 定义一个等待队列头
wait_queue_head_t wq_head;
unsigned int condition = 0;
struct device_node *dnode;
unsigned int myirq;       // 中断号
struct gpio_desc *gpiono; // GPIO对象
char cbuf[128] = "";
int number;

// 中断处理函数
irqreturn_t myirq_handeler(int myirq, void *arg)
{
    int statue;
    condition = 1;
    wake_up_interruptible(&wq_head);
    // 获取当前LED1的状态
    statue = gpiod_get_value(gpiono);
    if (statue == 1) // 如果为亮灯,则熄灭
    {
        gpiod_set_value(gpiono, 0);
        number = 1;
    }
    else if (statue == 0) // 如果为灭灯,则点亮
    {
        gpiod_set_value(gpiono, 1);
        number = 0;
    }
    return IRQ_HANDLED;
}

// 封装操作方法
int my_open(struct inode *inode, struct file *file)
{
    return 0;
}

ssize_t my_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
    int ret;
    wait_event_interruptible(wq_head, condition);
    printk("从内核向用户拷贝内容\n");
    if(number == 1)
        cbuf[0] = '1';
    else if(number == 0)
        cbuf[0] = '0';
    ret = copy_to_user(ubuf, cbuf, sizeof(cbuf));
    if (ret < 0)
    {
        printk("copy_to_user failed\n");
        return -1;
    }
    condition = 0;
    return 0;
}

int my_close(struct inode *inode, struct file *file)
{
    return 0;
}
// 操作方法结构体定义并初始化
struct file_operations fops =
    {
        .open = my_open,
        .read = my_read,
        .release = my_close,
};

static int __init mycdev_init(void)
{
    int ret;
    // 初始化等待队列
    init_waitqueue_head(&wq_head);
    // 注册设备驱动
    major = register_chrdev(0, "myopt", &fops);
    if (major < 0)
    {
        printk("注册设备驱动失败\n");
        return -1;
    }
    printk("注册设备驱动成功\n");
    // 向上提交设备节点目录
    cls = class_create(THIS_MODULE, "myopt");
    if (IS_ERR(cls))
    {
        printk("向上提交设备节点目录失败\n");
        ret = -PTR_ERR(cls);
        goto out1;
    }
    printk("向上提交设备节点目录成功\n");
    // 向上提交设备节点信息
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "myopt0");
    if (IS_ERR(dev))
    {
        printk("向上提交设备节点信息失败\n");
        ret = -PTR_ERR(dev);
        goto out2;
    }
    printk("向上提交设备节点信息成功\n");

    // 解析设备树节点信息
    dnode = of_find_node_by_name(NULL, "myopt");
    if (dnode == NULL)
    {
        printk("解析相关设备树节点信息失败\n");
        ret = -1;
        goto out3;
    }
    printk("解析相关设备树节点信息成功\n");

    // 从设备树节点中解析出GPIO对象
    gpiono = gpiod_get_from_of_node(dnode, "led1", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono))
    {
        printk("从设备树节点中解析出GPIO对象失败\n");
        ret = -PTR_ERR(gpiono);
        goto out3;
    }
    printk("从设备树节点中解析出GPIO对象成功\n");

    // 获取中断号
    myirq = irq_of_parse_and_map(dnode, 0);
    if (!myirq)
    {
        printk("获取中断号失败\n");
        ret = -1;
        goto out4;
    }
    printk("获取中断号成功\n");
    // 注册中断号
    ret = request_irq(myirq, myirq_handeler, IRQF_TRIGGER_FALLING, "key", NULL);
    if (ret < 0)
    {
        printk("注册中断号失败\n");
        ret = -1;
        goto out4;
    }
    printk("注册中断号成功\n");
    return 0;

out4:
    gpiod_put(gpiono);
out3:
    device_destroy(cls, MKDEV(major, 0));
out2:
    class_destroy(cls);
out1:
    unregister_chrdev(major, "myopt");
    return ret;
}
static void __exit mycdev_exit(void)
{
    // 释放中断号
    free_irq(myirq, NULL);
    // 释放gpio编号
    gpiod_put(gpiono);
    // 注销设备信息
    device_destroy(cls, MKDEV(major, 0));
    // 注销设备目录
    class_destroy(cls);
    // 注销设备驱动
    unregister_chrdev(major, "myopt");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

测试的应用程序代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

char buf[128] = "";

int main(int argc, const char *argv[])
{
    unsigned int number;
    int fd = open("/dev/myopt0",O_RDWR);
    if(fd < 0)
    {
        printf("打开设备文件失败\n");
        return -1;
    }
    printf("打开设备文件成功\n");
    while(1)
    {
        printf("准备读取\n");
        read(fd,buf,sizeof(buf));
        printf("读取完毕\n");
        printf("number = %c\n",buf[0]);
    }
    close(fd);
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Hall传感器驱动程序,用于在Linux系统上读取Hall传感器的值: ```c #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/gpio.h> #include <linux/interrupt.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Hall Sensor Driver"); #define DEVICE_NAME "hall_sensor" #define CLASS_NAME "hall" //GPIO pin for Hall sensor static unsigned int hall_gpio_pin = 17; static unsigned int irq_num; static int major_number; static struct class* hall_class = NULL; static struct device* hall_device = NULL; static irq_handler_t hall_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs) { printk(KERN_INFO "Hall Sensor: Interrupt occurred.\n"); return (irq_handler_t) IRQ_HANDLED; } static int hall_open(struct inode *inodep, struct file *filep) { printk(KERN_INFO "Hall Sensor: Device opened.\n"); return 0; } static ssize_t hall_read(struct file *filep, char *buffer, size_t len, loff_t *offset) { printk(KERN_INFO "Hall Sensor: Reading sensor value.\n"); //Read the value of the Hall sensor from GPIO pin int sensor_value = gpio_get_value(hall_gpio_pin); if (sensor_value == 0) { strcpy(buffer, "Magnetic field detected."); } else { strcpy(buffer, "No magnetic field detected."); } return strlen(buffer); } static int hall_release(struct inode *inodep, struct file *filep) { printk(KERN_INFO "Hall Sensor: Device closed.\n"); return 0; } static struct file_operations fops = { .open = hall_open, .read = hall_read, .release = hall_release, }; static int __init hall_init(void) { printk(KERN_INFO "Hall Sensor: Initializing driver.\n"); //Request GPIO pin for Hall sensor if (!gpio_is_valid(hall_gpio_pin)) { printk(KERN_ALERT "Hall Sensor: Invalid GPIO pin.\n"); return -ENODEV; } if (gpio_request(hall_gpio_pin, "hall_sensor")) { printk(KERN_ALERT "Hall Sensor: Failed to request GPIO pin.\n"); return -EINVAL; } gpio_direction_input(hall_gpio_pin); //Request IRQ for Hall sensor irq_num = gpio_to_irq(hall_gpio_pin); if (request_irq(irq_num, (irq_handler_t) hall_irq_handler, IRQF_TRIGGER_RISING, "hall_sensor", NULL)) { printk(KERN_ALERT "Hall Sensor: Failed to request IRQ.\n"); return -EINVAL; } //Register device major_number = register_chrdev(0, DEVICE_NAME, &fops); if (major_number < 0) { printk(KERN_ALERT "Hall Sensor: Failed to register device.\n"); return major_number; } hall_class = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(hall_class)) { unregister_chrdev(major_number, DEVICE_NAME); printk(KERN_ALERT "Hall Sensor: Failed to create device class.\n"); return PTR_ERR(hall_class); } hall_device = device_create(hall_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME); if (IS_ERR(hall_device)) { class_destroy(hall_class); unregister_chrdev(major_number, DEVICE_NAME); printk(KERN_ALERT "Hall Sensor: Failed to create device.\n"); return PTR_ERR(hall_device); } printk(KERN_INFO "Hall Sensor: Driver initialized.\n"); return 0; } static void __exit hall_exit(void) { printk(KERN_INFO "Hall Sensor: Exiting driver.\n"); //Destroy device device_destroy(hall_class, MKDEV(major_number, 0)); class_unregister(hall_class); class_destroy(hall_class); unregister_chrdev(major_number, DEVICE_NAME); //Free IRQ and GPIO pin free_irq(irq_num, NULL); gpio_free(hall_gpio_pin); printk(KERN_INFO "Hall Sensor: Driver exited.\n"); } module_init(hall_init); module_exit(hall_exit); ``` 在编译之前,您还需要在Makefile中添加以下内容: ```makefile obj-m += hall_sensor.o ``` 将以上两个文件保存到同一个目录下,然后在该目录下打开终端,执行以下命令进行编译: ```bash make -C /lib/modules/$(uname -r)/build M=$(pwd) modules ``` 如果编译成功,将生成名为hall_sensor.ko的内核模块文件。将此文件插入到Linux系统中,即可使用Hall传感器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值