linux 字符设备驱动

这是一个简单的字符驱动程序,有open, close, read, write 功能,还有 ioctl() 功能

0. 准备

   新建 /opt/driver/char2文件夹,在里面创建4个文件: char2.c,  test_char2.c,  driver_ioctl.h, Makefile 

1. char2.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <asm/uaccess.h>

#include "driver_ioctl.h"

MODULE_LICENSE("GPL");

static char ker_buf[100];
static int  a;

static int     dev_open(struct inode* inode, struct file* filep);
static ssize_t dev_read(struct file *filep, char *buf, size_t len, loff_t *off);
static ssize_t dev_write(struct file* filep, const char *buff, size_t len, loff_t *off);
static int     dev_release(struct inode* inode, struct file* filep);
static long    my_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);

static struct file_operations fops = 
{
	.read           = dev_read,
	.write          = dev_write,
	.open           = dev_open,
	.release        = dev_release,
	.unlocked_ioctl = my_ioctl,
};


static int char2_init(void)
{
	int t = register_chrdev(91, "mydev2", &fops);
	
	if(t < 0)
	{
		printk(KERN_ALERT "2.=> DEVICE REGISTRATION FAILED.\n");
	}
	else
	{
		printk(KERN_ALERT "2.=> DEVICE REGISTERED\n");
	}

	return 0;
}


static void char2_exit(void)
{
	unregister_chrdev(91, "mydev2");
	printk(KERN_ALERT "2.=> EXITED.\n");
}

static int dev_open(struct inode* inode, struct file* filep)
{
	printk(KERN_ALERT "2.=> DEVICE OPENED\n");
	return 0;
}


static ssize_t dev_read(struct file* filep, char *buf, size_t len, loff_t *off)
{
	copy_to_user(buf, ker_buf, len);
	return len;
}

static ssize_t dev_write(struct file* filep, const char *buf, size_t len, loff_t *off)
{
	copy_from_user(ker_buf, buf, len);
	ker_buf[len] = 0;
	
	return len;
}

static int dev_release(struct inode *inode, struct file *filep)
{
	printk(KERN_ALERT "2.=> DEVICE CLOSED.\n");
	return 0;
}

static long my_ioctl(struct file* filep, unsigned int cmd, unsigned long arg)
{
	switch(cmd)
	{
		case QUERY_GET_VALUE:
			copy_to_user((int*)arg, &a, sizeof(int));
			break;
		case QUERY_SET_VALUE:
			copy_from_user(&a, (int*)arg, sizeof(int));
			break;
		case QUERY_CLEAR_VALUE:
			break;
	}
	
	return 0;
}


module_init(char2_init);
module_exit(char2_exit);

 2. driver_ioctl.h

#include <linux/ioctl.h>

#define QUERY_GET_VALUE   _IOR('q', 1, int *)
#define QUERY_CLEAR_VALUE _IO('q', 2)
#define QUERY_SET_VALUE   _IOW('q', 3, int*)

 3. Makefile

obj-m := char2.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
#	make -C /usr/src/kernels/2.6.32-431.el6.i686 M=`pwd` modules 

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

 4. test_char2.c

#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include <sys/ioctl.h>
#include "driver_ioctl.h"


// compile: gcc -o test_char2 test_char2.c

int main()
{
	char buf[100] = "hello";
        char rbuf[7]  = {0};
	int  a        = 10;
	int  fd;

	fd = open("/dev/mydev2", O_RDWR);

	// test read, write
	 write(fd, buf, strlen(buf));

        printf("writing into device\n");
        read(fd, rbuf, 6);
        printf("read: %s\n", rbuf);


	// test ioctl
	ioctl(fd, QUERY_SET_VALUE, &a);
	printf("value written is: %d\n", a);

	a = 0;

	printf("let's read value from device\n");
	ioctl(fd, QUERY_GET_VALUE, &a);
	
	printf("value of a is: %d\n", a);

	return 0;	
}

 5. 编译

编译 .ko:
# make

编译测试程序 test_char2.c :
# gcc -o test_char2 test_char2.c

 

 6. 创建字符设备文件

# mknod /dev/mydev2 c 91 1
# chmod a+w /dev/mydev2

mkdod创建设备文件, c 表示字符设备,91是主设备号, 1是次设备号
chmod为设备文件添加写权限, 否则不能向设备写数据。

 7. 测试结果:

向内核插入模块:
# insmod char2.ko
# dmesg
# cat /proc/devices
  ...
  91 mydev2
  ...

测试设备驱动:
[root@centos6 char2]# ./test_char2
writing into device
read: hello
value written is: 10
let's read value from device
value of a is: 10

 

posted @ 2023-02-08 23:14  北极熊129  阅读(45)  评论(0编辑  收藏  举报