|
|
@@ -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");
|
|
|
}
|