【LINUX驱动】第二篇—基于MIPS设备字符驱动之LED驱动控制实现

铺垫:
这俩天写了一个控制LED灯的驱动,真的是哭死我这个小白了,因为之前ARM上弄过相似的,以为很简单,哪知道,还是有点麻烦的,现在的的程序是基于MIPS平台编写的。什么都得纯手工。

正题:

LED灯驱动

在mips平台上,制作一个简易的LED驱动来练习char字符驱动

  • Step1:查看对应硬件寄存器配置需求

首先查看,当前LED对应的端口是PB03,查找数据手册,GPIO部分,看看需要如何设置,可以看到下面2个主要的寄存器,一个控制方向(输入or输出),一个数据寄存器(写入0 or 1–对应拉高或拉低
【LINUX驱动】第二篇—基于MIPS设备字符驱动之LED驱动控制实现_第1张图片
在这里插入图片描述
【LINUX驱动】第二篇—基于MIPS设备字符驱动之LED驱动控制实现_第2张图片
【LINUX驱动】第二篇—基于MIPS设备字符驱动之LED驱动控制实现_第3张图片
知道了LED对应的端口寄存器的配置需求,接下来,就可以编写驱动源文件了

  • Step2:myled.c编写
#include
#include
#include
#include
#include
#include
#include
#include
#include


MODULE_LICENSE("GPL");

static struct class *my_led_class;
static struct device *my_led_device;

volatile unsigned long *my_led_pbpat=NULL;
volatile unsigned long *my_led_pbdata=NULL;

static int led_open(struct inode *inode,struct file *file);
static int led_read(struct file *filp,char __user *buff,size_t count,loff_t *offp);
static int led_write(struct file *file,const char __user*buf,size_t count,loff_t *ppos);
struct file_operations led_drv_ops={
        .open=led_open,
        .read=led_read,
        .write=led_write,
        .owner=THIS_MODULE,
};

int dev_num=0;
static int led_open(struct inode *inode,struct file *file)
{
        printk("led open\n");
        *my_led_pbpat &=~(0x1<<3);//PBPAT103 0: out,1: input
//        *my_led_pbpat |= (0x1<<3);

        *my_led_pbdata |=(1<<3);
        return 0;
}

static int led_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos)
{
        int val;
        printk("led write\n");

        copy_from_user(&val,buf,count);
        if(val == '0')
        {
                //to set 0
                *my_led_pbdata &=~(1<<3);
        }
        else
        {
                //to set 1
                *my_led_pbdata |=(1<<3);
        }

        return 0;
}

static int led_read(struct file *filp,char __user *buff,size_t cunt,loff_t *offp)
{
        printk("led read\n");
        return 0;
}


static int led_init(void)
{
        dev_num=register_chrdev(0,"led_drv",&led_drv_ops);
        if(dev_num<0)
        {
                printk("sorry,register char device failed!\n");
                return -1;
        }

        my_led_class=class_create(THIS_MODULE,"leddrv");
        my_led_device=device_create(my_led_class,NULL,MKDEV(dev_num,0),NULL,"shlled");




        printk("init ok\n");

        my_led_pbpat=(volatile unsigned long *)ioremap(0x10010130,16);

        my_led_pbdata=(volatile unsigned long *)ioremap(0x10010140,16);//0x10010140


        return 0;
}

static void led_exit(void)
{
        unregister_chrdev(dev_num,"led_drv");
        device_unregister(my_led_device);
        class_destroy(my_led_class);
        iounmap(my_led_pbpat);
        iounmap(my_led_pbdata);


        printk("led driver exit\n");

}
module_init(led_init);
module_exit(led_exit);

- Step3: Makefile的编写

obj-m:=myled.o
KERNELDIR :=/home/shl/work/x1500/kernel/
#KERNELDIR :=/usr/src/linux-headers-4.15.0-47-generic/

PWD :=$(shell pwd)
all:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

.PHONEY:clean
clean:
        rm -f *.o *.ko *.order *.symvers *.mod*

当然,在编译makefile需要注意的是,当前编译需要使用交叉编译器
因为linux下默认的是gcc,编译出来的文件在x1500核心板上是无法运行的,(我因为这个问题困住了2天),将环境变量中的ARCH和CROSS_COMPILE都修改一下
命令行输入:
export ARCH=mips
export CROSS_COMPILE=mips-linux-gnu-

执行make ,生成myled.ko文件
【LINUX驱动】第二篇—基于MIPS设备字符驱动之LED驱动控制实现_第4张图片
编写测试文件来测试当前驱动的功能

  • Step4:test.c编写
#include
#include
#include



int main(int argc,char *argv[])
{
        char buf[2]={'0','1'};

        int cmd;
        int fd=open("/dev/shlled",O_RDWR);
        if(fd<0)
        {
                printf("open dev/shlled fail!\n");
                return -1;
        }

        cmd=atoi(argv[1]);
        if(cmd==0)
        {
                write(fd,&buf[0],sizeof(char));
        }
        else if(cmd==1)
        {
                write(fd,&buf[1],sizeof(char));
        }
        else
        {
                printf("please input 0 or 1");
        }

        printf("\n");
        return 0;
}

编译生成可执行文件
mips-linux-gnu-gcc test.c -muclibc -o test
(为何多了一个 -muclibc,这是因为系统的依赖库和板子上的依赖库的版本不一样,板子是老板给的,系统是我自己装的,老板又不让我重新刷系统,我能咋办)
详情可以参照动态库不匹配(超链接日后再补)

  • step5: 加载驱动,并测试
    (执行代码摘录,test,myled.ko当前存放在/tmp目录下)
    /tmp # chmod 777 test

    /tmp # insmod myled.ko
    [ 736.732691] init ok
    /tmp # ls /dev/shlled
    /dev/shlled (这里可以看到,我自己编写的shlled已经成功显示在dev下面了)
    /tmp # ./test 0
    [ 813.653481] led open
    [ 813.655778] led write

    /tmp # ./test 1
    [ 817.871106] led open
    [ 817.873552] led write

    /tmp # ./test 0
    [ 893.370064] led open
    [ 893.372463] led write

对应的LED灯亮灭(0 亮,1灭)
【LINUX驱动】第二篇—基于MIPS设备字符驱动之LED驱动控制实现_第5张图片
【LINUX驱动】第二篇—基于MIPS设备字符驱动之LED驱动控制实现_第6张图片

你可能感兴趣的:(Linux相关)