6.【linux驅動】字符設備

簡單輸出文字

需要注意的地方只有read中讀取數量和文件指針的移動問題

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");

static int data = 1;
module_param(data, int, 0644);  //聲明模塊參數
dev_t devid;
struct cdev char_dev;
struct class * char_class;
char * char_data = "hello char\n";

static int open(struct inode * node, struct file * fl){
	printk("char open\n");
	return 0;
}

static long ioctl(struct file * fl, unsigned int cmd, unsigned long arg){
	return 0;
}

static ssize_t read(struct file * fl, char __user * buf, size_t len, loff_t * offset){
	int ret = 0,copy_len,data_len;

	data_len = strlen(char_data)+1;
	if(fl->f_pos + len > data_len)
		copy_len = data_len - fl->f_pos; //超過長度,複製剩餘部分
	else
		copy_len = len;					 //沒超過

	ret = copy_to_user(buf,char_data+fl->f_pos,copy_len);
	ret = copy_len - ret;
	*offset += ret;						 //移動文件指針
	printk("char read len:%d\n",ret);
	return ret;
}

static ssize_t write(struct file * fl, const char __user * buf, size_t len, loff_t * offset){
	printk("char write\n");
	return 0;
}

struct file_operations my_opts = {
	.owner = THIS_MODULE,
	.open = open,
	.read = read,
	.write = write,
	.unlocked_ioctl = ioctl
};

static int __init char_init(void){
	int ret = 0;

    devid = MKDEV(241, 1);								//換算設備號
    ret = register_chrdev_region(devid, 1, "char_test");//註冊設備,在/proc/drivers下面可以看到
    if (ret < 0)
        goto err0;

    cdev_init(&char_dev,&my_opts);						//綁定opt結構體
    char_dev.owner = THIS_MODULE;
    ret = cdev_add(&char_dev,devid,1);					//註冊字符設備驅動
    if (ret < 0)
    	goto err1;

    char_class = class_create(THIS_MODULE,"char_test"); //在/sys/class中創建文件夾
    device_create(char_class,NULL,devid,NULL,"char_test_dev_%d",1);//在上一步文件夾中創建char_test_dev_1
	printk("char init\n");
    return 0;

	err1:
	    unregister_chrdev_region(devid, 1);
    err0:
        return ret;
}

static void __exit char_exit(void){
	unregister_chrdev_region(devid, 1);
	cdev_del(&char_dev);
	device_destroy(char_class,devid);
	class_destroy(char_class);
	printk("char exit\n");
}

module_init(char_init);
module_exit(char_exit);

完整讀寫操作

寫操作文件指針和讀操作基本相似

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");

static int data = 1;
module_param(data, int, 0644);  //聲明模塊參數
dev_t devid;
struct cdev char_dev;
struct class * char_class;
int buffer_size = 100;
char * char_data;

static int open(struct inode * node, struct file * fl){
	// printk("char open\n");
	return 0;
}

static long ioctl(struct file * fl, unsigned int cmd, unsigned long arg){
	return 0;
}

static ssize_t read(struct file * fl, char __user * buf, size_t len, loff_t * offset){
	int ret = 0,copy_len,data_len;

	data_len = strlen(char_data)+1;
	if(fl->f_pos + len > data_len)
		copy_len = data_len - fl->f_pos; //超過長度,複製剩餘部分
	else
		copy_len = len;					 //沒超過

	ret = copy_to_user(buf,char_data+fl->f_pos,copy_len);
	ret = copy_len - ret;
	*offset += ret;						 //移動文件指針
	// printk("char read len:%d\n",ret);
	return ret;
}

static ssize_t write(struct file * fl, const char __user * buf, size_t len, loff_t * offset){
	int ret = 0,copy_len,data_len = buffer_size;

	if(fl->f_pos + len > data_len)
		copy_len = data_len - fl->f_pos; //超過長度,複製剩餘部分
	else
		copy_len = len;					 //沒超過

	ret = copy_from_user(char_data+fl->f_pos,buf,copy_len);
	ret = copy_len - ret;
	*offset += ret;						 //移動文件指針
	// printk("char write:%d\n",ret);
	return ret;
}

struct file_operations my_opts = {
	.owner = THIS_MODULE,
	.open = open,
	.read = read,
	.write = write,
	.unlocked_ioctl = ioctl
};

static int __init char_init(void){
	int ret = 0;

    devid = MKDEV(241, 1);								//換算設備號
    ret = register_chrdev_region(devid, 1, "char_test");//註冊設備,在/proc/drivers下面可以看到
    if (ret < 0)
        goto err0;

    cdev_init(&char_dev,&my_opts);						//綁定opt結構體
    char_dev.owner = THIS_MODULE;
    ret = cdev_add(&char_dev,devid,1);					//註冊字符設備驅動
    if (ret < 0)
    	goto err1;

    char_class = class_create(THIS_MODULE,"char_test"); //在/sys/class中創建文件夾
    device_create(char_class,NULL,devid,NULL,"char_test_dev_%d",1);//在上一步文件夾中創建char_test_dev_1

    char_data = kzalloc(buffer_size,GFP_KERNEL);

	printk("char init\n");
    return 0;

	err1:
	    unregister_chrdev_region(devid, 1);
    err0:
        return ret;
}

static void __exit char_exit(void){
	unregister_chrdev_region(devid, 1);
	cdev_del(&char_dev);
	device_destroy(char_class,devid);
	class_destroy(char_class);
	printk("char exit\n");
}

module_init(char_init);
module_exit(char_exit);

運行下看看效果

[root@minicoco char]# insmod char.ko
[root@minicoco char]# echo "1234" > /dev/char_test_dev_1 
[root@minicoco char]# cat /dev/char_test_dev_1 
1234
[root@minicoco char]# 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章