#include #include #include #include #include #include #include #include #include #include #include #include #include #include "gpioregs.h" #define DEVICE_NAME "switches" #define CLASS_NAME "switches_class" #define BUFFER_SIZE 1024 /* 拨码 F12 0xFD6A0940 bit1 F16 0xFD6A0980 bit1 F17 0xFD6A0990 bit1 F18 0xFD6A09A0 bit1 跳帽 ID0-D0 0xFD6D0A40 bit1 ID1-D1 0xFD6D0A50 bit1 ID2-D14 0xFD6D0B20 bit1 ID3-D15 0xFD6D0B30 bit1 ID4-D16 0xFD6D0B40 bit1 */ #define SWITCH_F12 0xFD6A0940 #define SWITCH_F16 0xFD6A0980 #define SWITCH_F17 0xFD6A0990 #define SWITCH_F18 0xFD6A09A0 #define SWITCH_ID0 0xFD6D0A40 #define SWITCH_ID1 0xFD6D0A50 #define SWITCH_ID2 0xFD6D0B20 #define SWITCH_ID3 0xFD6D0B30 #define SWITCH_ID4 0xFD6D0B40 // 可以通过模块参数指定主设备号和次设备号 static int switches_major = 56; // 默认主设备号 static int switches_minor = 71; // 默认次设备号 module_param(switches_major, int, S_IRUGO); module_param(switches_minor, int, S_IRUGO); MODULE_PARM_DESC(switches_major, "Major device number"); MODULE_PARM_DESC(switches_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 switches_dev { char *buffer; size_t size; struct mutex lock; struct cdev cdev; wait_queue_head_t read_wait; struct delayed_work delay_work1; unsigned int switch_status[5]; }; static struct switches_dev *dev = NULL; unsigned int switch_readl(unsigned int addr) { void __iomem *reg_base = NULL; reg_base = ioremap(addr, 0x1000); return readl(reg_base); } int get_switch_gpio_status(void) { dev->switch_status[0] = 0; dev->switch_status[1] = 0; // 这里需要待完善,确认熊工提供的地址和API文档的对应关系 dev->switch_status[0] |= (switch_readl(SWITCH_F12)&0x02) >> 1; dev->switch_status[0] |= switch_readl(SWITCH_F16)&0x02; dev->switch_status[0] |= (switch_readl(SWITCH_F17)&0x02) << 1; dev->switch_status[0] |= (switch_readl(SWITCH_F18)%0x02) << 2; dev->switch_status[1] |= (switch_readl(SWITCH_ID0)&0x02) >> 1; dev->switch_status[1] |= switch_readl(SWITCH_ID1)&0x02; dev->switch_status[1] |= (switch_readl(SWITCH_ID2)&0x02) << 1; dev->switch_status[1] |= (switch_readl(SWITCH_ID3)%0x02) << 2; dev->switch_status[1] |= (switch_readl(SWITCH_ID4)%0x02) << 3; return 0; } static void delay_work_func(struct work_struct *work) { printk(KERN_INFO "delay_work_func\n"); } // 文件打开操作 static int switches_open(struct inode *inode, struct file *filp) { struct switches_dev *dev; dev = container_of(inode->i_cdev, struct switches_dev, cdev); filp->private_data = dev; printk(KERN_INFO "switches: Device opened (major=%d, minor=%d)\n", imajor(inode), iminor(inode)); return 0; } // 文件释放操作 static int switches_release(struct inode *inode, struct file *filp) { // release_region(PORT_80, 1); printk(KERN_INFO "switches: Device closed\n"); return 0; } // 读操作 - 支持cat命令 static ssize_t switches_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct switches_dev *dev = filp->private_data; ssize_t retval = 0; size_t available; int read_count = 0; int ret = 0; int i = 0; // ret = copy_to_user(buf, dev->switch_status, read_count); // if (ret != 0) // { // printk(KERN_INFO "switches: copy_to_user failed\n"); // goto out; // } printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); ret = get_switch_gpio_status(); for(i = 0; i < 5; i++) { printk("switch_status[%d]=%08x\n", i, dev->switch_status[i]); } // printk(KERN_INFO "switches: Read %zu bytes\n", count); return ret; } // 写操作 static ssize_t switches_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { return -1; } static unsigned int switches_poll(struct file *filp, poll_table *wait) { // poll_wait(filp, &dev->read_wait, wait); return 0; } // 文件操作结构体 static struct file_operations fops = { .owner = THIS_MODULE, .open = switches_open, .release = switches_release, .read = switches_read, .write = switches_write, .poll = switches_poll, }; // 模块初始化 int switches_init(void) { int result; printk(KERN_INFO "switches: Initializing driver with major=%d, minor=%d\n", switches_major, switches_minor); // 检查主设备号是否有效 if (switches_major <= 0) { printk(KERN_ALERT "switches: Invalid major number %d\n", switches_major); return -EINVAL; } // 构建设备号 dev_num = MKDEV(switches_major, switches_minor); // 注册设备号 - 使用指定的主设备号 result = register_chrdev_region(dev_num, 1, DEVICE_NAME); if (result < 0) { printk(KERN_ALERT "switches: Failed to register major number %d\n", switches_major); printk(KERN_ALERT "switches: Try using a different major number\n"); return result; } printk(KERN_INFO "switches: Registered with major=%d, minor=%d\n", MAJOR(dev_num), MINOR(dev_num)); // 分配设备结构体 dev = kmalloc(sizeof(struct switches_dev), GFP_KERNEL); if (!dev) { result = -ENOMEM; goto fail_malloc; } memset(dev, 0, sizeof(struct switches_dev)); init_waitqueue_head(&dev->read_wait); // 分配缓冲区 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 "switches: 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 "switches: 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 "switches: Failed to create device\n"); goto fail_device; } printk(KERN_INFO "switches: Driver initialized successfully\n"); printk(KERN_INFO "switches: Device node: /dev/%s (major=%d, minor=%d)\n", DEVICE_NAME, switches_major, switches_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 switches_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 "switches: Driver removed (major=%d, minor=%d)\n", switches_major, switches_minor); }