#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/device.h>
struct cdev cdev;
dev_t devno;
static struct class *cls;
static struct device *test_device;
/* We suppose this is the two device's registers */
int dev1_registers[5];
int dev2_registers[5];
/*文件打开函数*/
int hello_open(struct inode *inode, struct file *filp)
{
/*获取次设备号*/
int num = MINOR(inode->i_rdev);
if (num == 0)
filp->private_data = dev1_registers;
else if(num == 1)
filp->private_data = dev2_registers;
else
return -ENODEV; //无效的次设备号
return 0;
}
/*文件释放函数*/
int hello_release(struct inode *inode, struct file *filp)
{
return 0;
}
/*读函数*/
static ssize_t hello_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
int *register_addr = filp->private_data; /*获取设备的寄存器基地址*/
/*判断读位置是否有效*/
if (p >= 5 * sizeof(int))
return 0;
if (count > 5 * sizeof(int) - p)
count = 5 * sizeof(int) - p;
/*读数据到用户空间*/
if (copy_to_user(buf, register_addr + p, count))
{
ret = -EFAULT;
}
else
{
*ppos += count;
ret = count;
}
return ret;
}
/*写函数*/
static ssize_t hello_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
int *register_addr = filp->private_data; /*获取设备的寄存器地址*/
/*分析和获取有效的写长度*/
if (p >= 5*sizeof(int))
return 0;
if (count > 5 * sizeof(int) - p)
count = 5 * sizeof(int) - p;
/*从用户空间写入数据*/
if (copy_from_user(register_addr + p, buf, count))
ret = -EFAULT;
else
{
*ppos += count;
ret = count;
}
return ret;
}
/* seek文件定位函数 */
static loff_t hello_llseek(struct file *filp, loff_t offset, int whence)
{
loff_t newpos;
switch(whence) {
case SEEK_SET:
newpos = offset;
break;
case SEEK_CUR:
newpos = filp->f_pos + offset;
break;
case SEEK_END:
newpos = 5 * sizeof(int) - 1 + offset;
break;
default:
return -EINVAL;
}
if ((newpos < 0) || (newpos > 5 * sizeof(int)))
return -EINVAL;
filp->f_pos = newpos;
return newpos;
}
/*文件操作结构体*/
static const struct file_operations hello_fops =
{
.open = hello_open,
.read = hello_read,
.write = hello_write,
.llseek = hello_llseek,
.release = hello_release,
};
static int hello_init()
{
printk(KERN_EMERG "hello module has been mount!\n");
/*初始化cdev结构*/
cdev_init(&cdev, &hello_fops);
/* 注册字符设备 */
alloc_chrdev_region(&devno, 0, 2, "hello");
cdev_add(&cdev, devno, 2); // cat proc/devices 可以查看hello
cls = class_create(THIS_MODULE, "helloclass"); //生成/sys/class/helloclass/
test_device = device_create(cls,NULL,devno,NULL,"hello"); //生成dev/hello
if(IS_ERR(test_device))
{
class_destroy(cls);
unregister_chrdev_region(devno, 2);
return -EBUSY;
}
return 0;
}
static void hello_exit()
{
device_destroy(cls,devno);
class_destroy(cls);
cdev_del(&cdev); /*注销设备*/
unregister_chrdev_region(devno, 2); /*释放设备号*/
printk(KERN_EMERG "hello module has been remove!\n");
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);
Linux 字符设备操作-hello
最新推荐文章于 2024-08-19 15:21:15 发布