Linux内核驱动

1.设备号

Linux的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,称为设备文件。应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。为了管理这些设备,系统为设备编了号,每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。对于常用设备,Linux有约定俗成的编号,如硬盘的主设备号是3。

     一个字符设备或者块设备都有一个主设备号和次设备号。主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。例如一个嵌入式系统,有两个LED指示灯,LED灯需要独立的打开或者关闭。那么,可以写一个LED灯的字符设备驱动程序,可以将其主设备号注册成5号设备,次设备号分别为1和2。这里,次设备号就分别表示两个LED灯。

2.驱动代码的编写

1.驱动代码编写:pin4test.c    pin4driver.c

2.内核驱动编译

cd  /home/duyong/SYSTEM/linux-rpi-4.14.y/drivers/char

驱动代码pin4driver.c 拷贝到  /home/duyong/SYSTEM/linux-rpi-4.14.y/drivers/char

修改 目录下的 Makefile

cd ../../

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-  KERNEL=kernel7 make modules

生成 /drivers/char/pin4driver.ko

交叉编译:arm-linux-gnueabihf-gcc  pin4test.c  -o pin4test

拷贝: scp ./drivers/char/pin4driver.ko pi@192.168.1.11:/home/pi/Driver

 scp pin4test pi@192.168.1.11:/home/pi/Driver

8.测试驱动:

sudo insmod pin4driver.ko 内核驱动装载    lsmod  查看内核模块

sudo rmmod pin4drive 内核驱动卸载

sudo chmod 666 /dev/pin4   ls /dev/pin4 -l

执行 ./pin4test

手动生成设备:sudo mknod chenlichen c 8 1 (设备类型 主设备号,次设备号)

pin4driver.c:

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/types.h>
#include <asm/io.h>

volatile unsigned int* GPFSEL0 = NULL;
volatile unsigned int* GPSET0  = NULL;
volatile unsigned int* GPCLR0  = NULL;

static struct class *pin4_class;
static struct device *pin4_class_dev;

static dev_t devno;
static int major = 231;
static int minor = 0;
static char *module_name = "pin4";

static ssize_t pin4_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{	
	int userCmd;
	//获取上层write值
	copy_from_user(&userCmd,buf,count);
	printk("get value:%d\n",userCmd);
	//根据值操作io口
	if(userCmd == 1){
		*GPSET0 |= 0x1<<4;
		printk("set 1\n");
	}else if(userCmd == 0){
		*GPCLR0 |= 0x1<<4;
		printk("set 0\n");
	}else{
		printk("undo\n");
	}
	return 0;
}
static ssize_t pin4_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    printk("pin4_read\n");
    return 0;
}

static int pin4_open(struct inode * inode, struct file * filp)
{
	*GPFSEL0 &= ~(0x6<<12);//配置pin4引脚为输出引脚
	*GPFSEL0 |= 0x1<<12;
    printk("pin4_open\n");//内核的打印函数
    return 0;
}

//在内核源码查找struct file_operations看结构体成员,添加用到的函数
static const struct file_operations pin4_fops = {
    .owner = THIS_MODULE,
    .write = pin4_write,//函数指针
    .open  = pin4_open,
    .read  = pin4_read,
};


static int __init pin4_init(void)//驱动入口
{
	int ret;
	printk("insmod driver pin4 success\n");
	devno = MKDEV(major,minor);//创建设备号
	ret = register_chrdev(major,module_name,&pin4_fops);//注册驱动,把这个驱动加入到内核链表
	pin4_class = class_create(THIS_MODULE,"myfirstdemo");//代码自动生成设备
	pin4_class_dev = device_create(pin4_class,NULL,devno,NULL,module_name);//创建设备文件

	GPFSEL0 = (volatile unsigned int *)ioremap(0x3f200000,4);//物理地址转换为虚拟地址,io口寄存器映射成普通内存单元进行访问
	GPSET0  = (volatile unsigned int *)ioremap(0x3f20001C,4);
	GPCLR0  = (volatile unsigned int *)ioremap(0x3f200028,4);
	return 0;
}

static void __exit  pin4_exit(void)
{
	iounmap(GPFSEL0);//先解除虚拟地址映射,在销毁设备
    iounmap(GPSET0);
	iounmap(GPCLR0);
	device_destroy(pin4_class,devno);//销毁设备
	class_destroy(pin4_class);//销毁类
	unregister_chrdev(major,module_name);//卸载设备
}

module_init(pin4_init);//入口,是个宏
module_exit(pin4_exit);
MODULE_LICENSE("GPL v2");

pin4test.c

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

int main()
{
        int fd;
        int cmd;
     

        fd = open("/dev/pin4",O_RDWR);
        if(fd < 0){
                printf("open failed\n");
                perror("reson:");
                exit(-1);
        }else{
                printf("open success\n");
        }
        printf("input commnd :1/0  \n1:set pin4 high \n0:set pin4 low\n");
        scanf("%d",&cmd);

        printf("cmd= %d\n",cmd);
        write(fd,&cmd,1);
        close(fd);
        return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值