#include #include #include #include #include #include #include #include #include #include #include #include #include "gpioregs.h" #define DEVICE_NAME "ssegment" #define CLASS_NAME "ssegment_class" #define DRIVER_NAME "port80_seg7" #define BUFFER_SIZE 1024 // 可以通过模块参数指定主设备号和次设备号 static int major = 56; // 默认主设备号 static int minor = 40; // 默认次设备号 module_param(major, int, S_IRUGO); module_param(minor, int, S_IRUGO); MODULE_PARM_DESC(major, "Major device number"); MODULE_PARM_DESC(minor, "Minor device number"); static struct class *char_class = NULL; static struct device *char_device = NULL; static struct cdev my_cdev; static dev_t dev_num; // 设备结构体 struct ssegment_dev { char *buffer; size_t size; struct mutex lock; struct cdev cdev; struct delayed_work delay_work1; }; static struct ssegment_dev *dev = NULL; unsigned int readl_cust(unsigned int addr) { void __iomem *reg_base; reg_base = ioremap(addr, 0x1000); return readl(reg_base); } int writel_cust(unsigned int addr, unsigned int val) { void __iomem *reg_base; reg_base = ioremap(addr, 0x1000); writel(val, reg_base); return 0; } static void delay_work_func(struct work_struct *work) { int ret = 0; unsigned int val = 0; if(dev->size != 0) { // 写数据 outb(dev->buffer[0], PORT_80); if((dev->buffer[1] & 0x02)) { val = readl_cust(SSEGMENT_POINT); val = val | 0x01; ret = writel_cust(SSEGMENT_POINT, val); // 显示小数点 待提供接口 // 待实现 } else { val = readl_cust(SSEGMENT_POINT); val = val & 0xFFFFFFFE; ret = writel_cust(SSEGMENT_POINT, val); // 不显示小数点 } if((dev->buffer[1] & 0x80)) { // 闪烁 LED } else { // 不闪烁 LED } } printk(KERN_INFO "delay_work_func\n"); } // 文件打开操作 static int ssegment_open(struct inode *inode, struct file *filp) { struct ssegment_dev *dev; // if (!request_region(PORT_80, 1, DRIVER_NAME)) // { // pr_err("Port 80 I/O region busy\n"); // return -EBUSY; // } dev = container_of(inode->i_cdev, struct ssegment_dev, cdev); filp->private_data = dev; printk(KERN_INFO "ssegment: Device opened (major=%d, minor=%d)\n", imajor(inode), iminor(inode)); return 0; } // 文件释放操作 static int ssegment_release(struct inode *inode, struct file *filp) { // release_region(PORT_80, 1); printk(KERN_INFO "ssegment: Device closed\n"); return 0; } // 读操作 - 支持cat命令 static ssize_t ssegment_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct ssegment_dev *dev = filp->private_data; ssize_t retval = 0; size_t available; int read_count = 0; int ret = 0; if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS; // 这里read_count没有固定为4个字节,是为了便于后续扩展 if (count > dev->size) { read_count = dev->size; } else { read_count = count; } ret = copy_to_user(buf, dev->buffer, read_count); if (ret != 0) { printk(KERN_INFO "ssegment: copy_to_user failed\n"); goto out; } printk(KERN_INFO "ssegment: Read %zu bytes\n", count); out: mutex_unlock(&dev->lock); return ret; } // 写操作 static ssize_t ssegment_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { struct ssegment_dev *dev = filp->private_data; ssize_t retval = 0; size_t available; int ret = 0; // 加锁 if (mutex_lock_interruptible(&dev->lock)) { return -ERESTARTSYS; } // 计算可写数据量 if (count > BUFFER_SIZE) { count = BUFFER_SIZE; } // 拷贝数据 ret = copy_from_user(dev->buffer, buf, count); if (ret != 0) { printk(KERN_INFO "ssegment: copy_from_user failed\n"); goto out; } dev->size = count; printk(KERN_INFO "ssegment: Written %zu bytes\n", count); out: mutex_unlock(&dev->lock); // 调度延迟工作 if (ret == 0) { schedule_delayed_work(&dev->delay_work1, msecs_to_jiffies(10)); } return count; } // 文件操作结构体 static struct file_operations fops = { .owner = THIS_MODULE, .open = ssegment_open, .release = ssegment_release, .read = ssegment_read, .write = ssegment_write, }; // 模块初始化 int ssegment_init(void) { int result; printk(KERN_INFO "ssegment: Initializing driver with major=%d, minor=%d\n", major, minor); // 检查主设备号是否有效 if (major <= 0) { printk(KERN_ALERT "ssegment: Invalid major number %d\n", major); return -EINVAL; } // 构建设备号 dev_num = MKDEV(major, minor); // 注册设备号 - 使用指定的主设备号 result = register_chrdev_region(dev_num, 1, DEVICE_NAME); if (result < 0) { printk(KERN_ALERT "ssegment: Failed to register major number %d\n", major); printk(KERN_ALERT "ssegment: Try using a different major number\n"); return result; } printk(KERN_INFO "ssegment: Registered with major=%d, minor=%d\n", MAJOR(dev_num), MINOR(dev_num)); // 分配设备结构体 dev = kmalloc(sizeof(struct ssegment_dev), GFP_KERNEL); if (!dev) { result = -ENOMEM; goto fail_malloc; } memset(dev, 0, sizeof(struct ssegment_dev)); // 分配缓冲区 dev->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); if (!dev->buffer) { result = -ENOMEM; goto fail_buffer; } // 初始化互斥锁 mutex_init(&dev->lock); INIT_DELAYED_WORK(&dev->delay_work1, delay_work_func); // 初始化字符设备 cdev_init(&dev->cdev, &fops); dev->cdev.owner = THIS_MODULE; // 添加字符设备到系统 result = cdev_add(&dev->cdev, dev_num, 1); if (result) { printk(KERN_ALERT "ssegment: Failed to add cdev\n"); goto fail_cdev; } // 创建设备类 char_class = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(char_class)) { result = PTR_ERR(char_class); printk(KERN_ALERT "ssegment: Failed to create class\n"); goto fail_class; } // 创建设备 char_device = device_create(char_class, NULL, dev_num, NULL, DEVICE_NAME); if (IS_ERR(char_device)) { result = PTR_ERR(char_device); printk(KERN_ALERT "ssegment: Failed to create device\n"); goto fail_device; } printk(KERN_INFO "ssegment: Driver initialized successfully\n"); printk(KERN_INFO "ssegment: Device node: /dev/%s (major=%d, minor=%d)\n", DEVICE_NAME, major, minor); return 0; fail_device: class_destroy(char_class); fail_class: cdev_del(&dev->cdev); fail_cdev: kfree(dev->buffer); fail_buffer: kfree(dev); fail_malloc: unregister_chrdev_region(dev_num, 1); return result; } // 模块退出 void ssegment_exit(void) { cancel_delayed_work_sync(&dev->delay_work1); device_destroy(char_class, dev_num); class_destroy(char_class); if (dev) { cdev_del(&dev->cdev); if (dev->buffer) kfree(dev->buffer); kfree(dev); } unregister_chrdev_region(dev_num, 1); printk(KERN_INFO "ssegment: Driver removed (major=%d, minor=%d)\n", major, minor); }