这是一个较为完整的Linux驱动的例程
编译环境:
curtis@curtis-virtual-machine:~/Desktop/tdriver$ uname -r
5.4.0-42-generic
curtis@curtis-virtual-machine:~/Desktop/tdriver$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
chr_drv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
//静态的指定
int ret;
static unsigned int dev_major = 101;
static struct class *devcls;
static struct device *dev;
static int kernel_val = 555;
//read(fd,buff,size)
ssize_t chr_drv_read (struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
int ret;
printk("-----------%s--------------\n",__FUNCTION__);
ret = copy_to_user(buf, &kernel_val,count);
if(ret > 0)
{
printk("copy_to_user error!\n");
return -EFAULT;
}
return 0;
}
ssize_t chr_drv_write (struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{
int ret;
int value;
printk("-----------%s--------------\n",__FUNCTION__);
ret = copy_from_user(&value, buf ,count);
if(ret > 0)
{
printk("copy_from_user error!\n");
return -EFAULT;
}
printk("___KERNEL___ : %d \n",value);
return 0;
}
int chr_drv_open (struct inode *inode, struct file *filp)
{
printk("-----------%s--------------\n",__FUNCTION__);
return 0;
}
int chr_drv_close (struct inode *inode, struct file *filp)
{
printk("-----------%s--------------\n",__FUNCTION__);
return 0;
}
const struct file_operations my_fops =
{
.open = chr_drv_open,
.read = chr_drv_read,
.write = chr_drv_write,
.release = chr_drv_close,
};
static int __init chr_drv_init(void)
{
//一般申请设备资源
//申请设备号
register_chrdev(dev_major, "chr_dev_test", &my_fops);//cat/proc/devices
if(ret == 0)
{
printk("register ok\n");
}
else{
printk("register failed\n");
return -EINVAL;
}
devcls = class_create(THIS_MODULE, "chr_cls");
dev = device_create(devcls, NULL,
MKDEV(dev_major,0), NULL, "chr2");//dev/chr2
return 0;
}
static void __exit chr_drv_exit(void)
{
//一般是释放资源
device_destroy(devcls, MKDEV(dev_major,0));
class_destroy(devcls);
unregister_chrdev(dev_major, "chr_dev_test");
}
module_init(chr_drv_init);
module_exit(chr_drv_exit);
MODULE_LICENSE("GPL");
Makefile:
CONFIG_MODULE_SIG=n
ifeq ($(KERNELRELEASE),)
ROOTS_DIR = /root/
#内核源码路径,不同环境可能会不一样,内核源码一定要先编译
KERNEL_DIR = /lib/modules/$(shell uname -r)/build
CUR_DIR = $(shell pwd)
all:
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
clean :
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
install:
insmod chr_drv.ko
uninstall:
rmmod chr_drv
else
#用于指定到底编译的是哪个代码--hello.c
obj-m += chr_drv.o
#obj-m += math.o
endif
应用程序chr_test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int arvc, char *argv[])
{
//调用驱动
int fd;
int value = 0;
//返回文件描述符,设备从/dev/里读,和驱动所对应的设备节点一致
fd = open("/dev/chr2",O_RDWR);
if(fd < 0)
{
perror("open");
exit(1);
}
read(fd,&value,4);
printf("___USER____:%d\n",value );
//重新给value赋值
value = 666;
write(fd,&value,4);
close(fd);
return 0;
}