简单输出文字
需要注意的地方只有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]#