首页 > 编程学习 > 22071班(11月18日)

22071班(11月18日)

发布时间:2022/11/19 6:46:42

1.在串口工具进行输入:   
    echo 1 > /dev/myled0 ---->led1灯点亮
    echo 0 > /dev/myled0 ---->led1灯熄灭
    echo 1 > /dev/myled1 ---->led1灯点亮
    echo 0 > /dev/myled1 ---->led1灯熄灭
    echo 1 > /dev/myled2 ---->led1灯点亮
    echo 0 > /dev/myled2 ---->led1灯熄灭
要求:
    1)分部实现注册字符设备驱动
    2)自动创建设备节点
    3)通过结构体对led灯地址进行映射
    4)次设备号完成私有数据传参

driver.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "myled.h"

#define CNAME "myled"

struct cdev* cdev;
dev_t devnum;
struct device* dev;
struct class* cls;

#if 0
unsigned int major = 0;
#else
unsigned int major = 500;
#endif

int minor=1;
const int count=3;


int k_open(struct inode *inode, struct file *file)
{
    //终端在传参时会打开对应的驱动文件,相当于调用了open和write函数,
    //inode结构体中存放着该驱动的设备号,次设备号不同,通过私有数据传参到write函数中进行判断
    file->private_data=(void*)MINOR(inode->i_rdev);
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t k_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t K_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
    char ch;
    int ret;
    int kminjor;
    //接收终端传入的字符(控制led的亮灭)
    ret=copy_from_user(&ch,ubuf,sizeof(char));
    if(ret)
    {
        printk("copy from user is error\n");
        return -EIO;
    }
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    //接收k_open函数传递的私有数据(次设备号)
    kminjor=(int)file->private_data;
    if(ch=='1')
    {
        if(kminjor==1)
        {
            gpioe->ODR |= (0x1 << 10);
        }
        if(kminjor==2)
        {
            gpiof->ODR |= (0x1 << 10);
        }
        if(kminjor==3)
        {
            gpioe->ODR |= (0x1 << 8);
        }
    }
    else
    {
        if(kminjor==1)
        {
            gpioe->ODR &= (~(0x1 << 10));
        }
        if(kminjor==2)
        {
            gpiof->ODR &= (~(0x1 << 10));
        }
        if(kminjor==3)
        {
            gpioe->ODR &= (~(0x1 << 8));
        }
    }
    return size;
}
int  k_close (struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
//初始化操作方法结构体
const struct file_operations fops=
{
    .open=k_open,
    .read=k_read,
    .write=K_write,
    .release=k_close,
};
//入口,安装驱动时执行
static int __init k_init(void)
{
    int ret,i;
    //分配字符设备驱动
    cdev=cdev_alloc();
    if(cdev==NULL)
    {
        printk("cdev_alloc is error\n");
        ret=-EIO;
        goto ERR1;
    }
    //初始化设备驱动
    cdev_init(cdev,&fops);
    //申请设备号
    if(major>0)
    {
        ret=register_chrdev_region(MKDEV(major,minor),count,CNAME);
        if(ret)
        {
            printk("register_chrdev_region is error\n");
            ret=-ENOMEM;
            goto ERR2;
        }  
    }
    else
    {
        ret=alloc_chrdev_region(&devnum,1,count,CNAME);
        if(ret)
        {
            printk("alloc_chrdev_region is error\n");
            ret=-ENOMEM;
            goto ERR2;
        }
        major=MAJOR(devnum);
        minor=MINOR(devnum);
    }
    //驱动的注册
    ret=cdev_add(cdev,MKDEV(major,minor),count);
    if(ret)
    {
        printk("cdev add is error\n");
        ret = -EIO;
        goto ERR3;
    }

    //自动创建设备节点
    cls = class_create(THIS_MODULE,CNAME);
    if(IS_ERR(cls)) 
    {
        printk("class create is error\n");
        ret = PTR_ERR(cls); 
        goto ERR4;
    }
    for(i=1;i<=count;i++)
    {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
        if(IS_ERR(dev))
        {
           printk("device create is error\n");
           ret = PTR_ERR(dev);
           goto ERR5;
        }
    }
    //RCC寄存器地址映射
    rcc=ioremap(RCC,4);
    if(NULL == rcc)
    {
        printk("rcc ioremap is error\n");
        return -ENOMEM;
    }
    //GPIOE寄存器地址映射
    gpioe=ioremap(GPIOE,sizeof(gpio_t));
    if(NULL == gpioe)
    {
        printk("gpioe ioremap is error\n");
        return -ENOMEM;
    }
    //GPIOF寄存器地址映射
    gpiof=ioremap(GPIOF,sizeof(gpio_t));
    if(NULL == gpiof)
    {
        printk("gpiof ioremap is error\n");
        return -ENOMEM;
    }
   
    //LED1--->PE10引脚初始化
    *rcc|= (0x1 << 4);
    gpioe->MODER &= (~(0x3 << 20));
    gpioe->MODER |= (0x1 << 20);
    gpioe->ODR &= (~(0x1 << 10));
    // LED2--->PF10初始化
    *rcc|= (0x1 << 5);
    gpiof->MODER &= (~(0x3 << 20));
    gpiof->MODER |= (0x1 << 20);
    gpiof->ODR &= (~(0x1 << 10));
    //LED3--->PE8初始化
    *rcc|= (0x1 << 4);
    gpioe->MODER &= (~(0x3 << 16));
    gpioe->MODER |= (0x1 << 16);
    gpioe->ODR &= (~(0x1 << 8));

    return 0;
ERR5:  
    for(--i;i>=0;i--)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    class_destroy(cls);
ERR4:
    cdev_del(cdev);
ERR3:
    unregister_chrdev_region(MKDEV(major,minor),count);
ERR2:
    kfree(cdev);
ERR1:
    return -EIO;
}
//出口,卸载驱动时执行
static void __exit k_exit(void)
{
     int i;
    //销毁设备节点信息
    for(i=1;i<=count;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //销毁目录信息
    class_destroy(cls);
    //驱动的注销
    cdev_del(cdev);
    //销毁设备号
    unregister_chrdev_region(MKDEV(major,minor),count);
    //释放cdev结构体
    kfree(cdev);
    //取消地址映射
    iounmap(rcc);
    iounmap(gpioe);
    iounmap(gpiof);
}

module_init(k_init);
module_exit(k_exit);
MODULE_LICENSE("GPL");

myled.h:

#ifndef __MYLED__H__
#define __MYLED__H__

typedef struct{
    volatile unsigned int MODER;
    volatile unsigned int OTYPER;
    volatile unsigned int OSPEEDR;
    volatile unsigned int PUPDR;
    volatile unsigned int IDR;
    volatile unsigned int ODR;
}gpio_t;
#define GPIOE 0x50006000
#define GPIOF 0x50007000
#define RCC 0x50000A28
volatile unsigned int* rcc;
gpio_t* gpioe;
gpio_t* gpiof;

#endif

实验现象:

 串口工具如图:

 

Copyright © 2010-2022 dgrt.cn 版权所有 |关于我们| 联系方式