Bläddra i källkod

添加C181 FAN功能

qidong.liu 1 vecka sedan
förälder
incheckning
f0631adee5
1 ändrade filer med 168 tillägg och 11 borttagningar
  1. 168 11
      fan.c

+ 168 - 11
fan.c

@@ -463,11 +463,121 @@ static void set_auto_mode(int nr)
 	data->fan_main_ctrl |= BIT(nr);
 	ec_write_reg(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
 }
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#define DEVICE_NAME "fan"           // 设备节点名称
+#define CLASS_NAME  "fan_class"     // 类名
+#define MAJOR_NUM   56
+#define MINOR_NUM   110
+
+static int major = MAJOR_NUM;
+static int minor = MINOR_NUM;
+static struct class *fan_class = NULL;
+static struct device *fan_device = NULL;
+static struct cdev fan_cdev;
+static struct delayed_work delay_work1;
+static wait_queue_head_t read_wait;
+static unsigned int condition = 0;
+static char fan_buff[3] = {0};
+
+static void read_fan_delay_work_func(struct work_struct *work)
+{
+	int i = 0;
+	int val[3] = {0};
+	u16 reg;
+	struct vfiec_data *data = g_data;
+	mutex_lock(&data->lock);
+	reg = ec_read_reg(data, IT87_REG_FAN[0]);
+	reg |= (ec_read_reg(data, IT87_REG_FANX[0]) << 8);
+	val[0] = FAN16_FROM_REG(reg);
+	if(val[0] > 0)
+	{
+	    fan_buff[0] = 'A';
+	}
+	else
+	{
+	    fan_buff[0] = 'a';
+	}
+	
+	reg = ec_read_reg(data, IT87_REG_FAN[1]);
+	reg |= (ec_read_reg(data, IT87_REG_FANX[1]) << 8);
+	val[1] = FAN16_FROM_REG(reg);
+	if(val[1] > 0)
+	{
+	    fan_buff[1] = 'B';
+	}
+	else
+	{
+	    fan_buff[1] = 'b';
+	}
+	mutex_unlock(&data->lock);
+
+	condition = 1;
+	wake_up_interruptible(&read_wait);
+	schedule_delayed_work(&delay_work1, msecs_to_jiffies(5000));
+}
+
+// 打开设备
+static int fan_open(struct inode *inodep, struct file *filep)
+{
+	schedule_delayed_work(&delay_work1, msecs_to_jiffies(100));
+    return 0;
+}
+
+// 释放设备
+static int fan_release(struct inode *inodep, struct file *filep)
+{
+    printk(KERN_INFO "fan: device closed\n");
+    return 0;
+}
+
+// 读设备
+static ssize_t fan_read(struct file *filep, char __user *buf, size_t len, loff_t *offset)
+{
+    int ret;
+	if(len < 2)
+		return -EINVAL;
+	if (wait_event_interruptible(read_wait, condition))
+    {
+            // 被信号中断
+            printk(KERN_INFO "gpio_monitor: wait interrupted by signal\n");
+            return -ERESTARTSYS;
+    }
+	ret = copy_to_user(buf, fan_buff, 2);
+	if (ret)
+	{
+		return -EFAULT;
+	}
+	condition = 0;
+    return 2;
+}
+
+static struct file_operations fan_fops = {
+    .owner = THIS_MODULE,
+    .open = fan_open,
+    .release = fan_release,
+    .read = fan_read,
+};
+
+static char *my_devnode(struct device *dev, umode_t *mode) {
+    if (mode) {
+        *mode = 0666;
+    }
+    return NULL;
+}
+
 int fan_init(void)
 {
 	int err;
 	unsigned short address = 0;
 	struct vfiec_data *data;
+    dev_t dev_num;
+    int ret;
 
 	/* 探测SuperIO */
 	err = vfiec_find(REG_2E, &address);
@@ -513,19 +623,60 @@ int fan_init(void)
 
 	g_data = data;
 
-	/* 注册属性组 */
-	err = sysfs_create_group(hwmon_kobj, &fan_attr_group);
-	if (err)
-	{
-		pr_err("Failed to create sysfs attributes\n");
-		goto err_release;
-	}
-
-	set_auto_mode(0);
-	set_auto_mode(1);
+	dev_num = MKDEV(major, minor);
+	
+    ret = register_chrdev_region(dev_num, 1, DEVICE_NAME);
+    if (ret < 0) {
+        printk(KERN_ERR "fan: register_chrdev_region failed, ret=%d\n", ret);
+        goto err_release;
+    }
+	cdev_init(&fan_cdev, &fan_fops);
+    fan_cdev.owner = THIS_MODULE;
+    ret = cdev_add(&fan_cdev, dev_num, 1);
+    if (ret < 0) {
+        printk(KERN_ERR "fan: cdev_add failed, ret=%d\n", ret);
+        goto err_unregister;
+    }
+
+    // 创建类
+    fan_class = class_create(THIS_MODULE, CLASS_NAME);
+    if (IS_ERR(fan_class)) {
+        printk(KERN_ERR "fan: class_create failed\n");
+        ret = PTR_ERR(fan_class);
+        goto err_cdev_del;
+    }
+    fan_class->devnode = my_devnode;
+
+    fan_device = device_create(fan_class, NULL, dev_num, NULL, DEVICE_NAME);
+    if (IS_ERR(fan_device))
+    {
+        ret = PTR_ERR(fan_device);
+        printk(KERN_ALERT "fan: Failed to create device\n");
+        goto err_class_destroy;
+    }
+
+	INIT_DELAYED_WORK(&delay_work1, read_fan_delay_work_func);
+	init_waitqueue_head(&read_wait);
+
+	// /* 注册属性组 */
+	// err = sysfs_create_group(hwmon_kobj, &fan_attr_group);
+	// if (err)
+	// {
+	// 	pr_err("Failed to create sysfs attributes\n");
+	// 	goto err_release;
+	// }
+
+	// set_auto_mode(0);
+	// set_auto_mode(1);
 	pr_info("VFIEC hwmon driver loaded, path: /sys/kernel/vfiec/hwmon/\n");
 	return 0;
 
+err_class_destroy:
+    class_destroy(fan_class);
+err_cdev_del:
+    cdev_del(&fan_cdev);
+err_unregister:
+    unregister_chrdev_region(dev_num, 1);
 err_release:
 	release_region(data->addr, 2);
 	kfree(data);
@@ -537,10 +688,16 @@ void fan_exit(void)
 {
 	if (g_data)
 	{
-		sysfs_remove_group(hwmon_kobj, &fan_attr_group);
+		// sysfs_remove_group(hwmon_kobj, &fan_attr_group);
 		release_region(g_data->addr, 2);
 		kfree(g_data);
 		g_data = NULL;
 	}
+
+	cancel_delayed_work_sync(&delay_work1);
+	device_destroy(fan_class, MKDEV(major, minor));
+	cdev_del(&fan_cdev);
+	class_destroy(fan_class);
+	unregister_chrdev_region(MKDEV(major, minor), 1);
 	pr_info("VFIEC hwmon driver unloaded\n");
 }