Просмотр исходного кода

1、修复rmmod的bug。2、添加led heartbeat驱动功能

liu qidong [url ssh://qidong.liu@10.2.90.253:29418/] 1 месяц назад
Родитель
Сommit
18d489afb6
6 измененных файлов с 535 добавлено и 2 удалено
  1. 2 1
      Makefile
  2. 1 1
      fan.c
  3. 388 0
      led_heartbeat.c
  4. 7 0
      led_heartbeat.h
  5. 13 0
      main.c
  6. 124 0
      test_app/setled.c

+ 2 - 1
Makefile

@@ -3,7 +3,7 @@
 MODULE_NAME := opal
 obj-m := opal.o
 
-opal-objs := main.o led.o light_ring.o ssegment.o ec_version.o buzzer.o fan.o writeprotect.o myname.o cash_drawers.o batteryled.o watchdog.o power.o switches.o backlight.o gsensor.o lcd_2x20.o smart_battery.o voltage_sysfs.o
+opal-objs := main.o led.o light_ring.o ssegment.o ec_version.o buzzer.o fan.o writeprotect.o myname.o cash_drawers.o batteryled.o watchdog.o power.o switches.o backlight.o gsensor.o lcd_2x20.o smart_battery.o voltage_sysfs.o led_heartbeat.o
 
 PROJECT_NAME := POS
 KERNELDIR := ~/timesys/SDK64Bit-V6_02_00/kernel-source/linux-5.15/
@@ -17,6 +17,7 @@ all:
 	make CROSS_COMPILE=~/timesys/SDK64Bit-V6_02_00/toolchain/bin/x86_64-timesys-linux-gnu- -C $(KERNELDIR) M=$(PWD) modules
 	~/timesys/SDK64Bit-V6_02_00/toolchain/bin/x86_64-timesys-linux-gnu-gcc test_app/setss.c -DPROJECT=$(PROJECT_NAME) -o test_app/setss
 	~/timesys/SDK64Bit-V6_02_00/toolchain/bin/x86_64-timesys-linux-gnu-gcc test_app/test_beep.c -DPROJECT=$(PROJECT_NAME) -o test_app/beep
+	~/timesys/SDK64Bit-V6_02_00/toolchain/bin/x86_64-timesys-linux-gnu-gcc test_app/setled.c -DPROJECT=$(PROJECT_NAME) -o test_app/setled
 	~/timesys/SDK64Bit-V6_02_00/toolchain/bin/x86_64-timesys-linux-gnu-gcc test_app/cash_app.c -DPROJECT=$(PROJECT_NAME) -o test_app/cash_app -lpthread
 
 clean:

+ 1 - 1
fan.c

@@ -4339,7 +4339,7 @@ void fan_exit(void)
 	platform_device_unregister(it87_pdev[0]);
 	platform_driver_unregister(&it87_driver);
     sysfs_remove_group(hwmon_kobj, &fan_attr_group);
-    kobject_put(hwmon_kobj);
+    // kobject_put(hwmon_kobj);
 }
 
 module_param(update_vbat, bool, 0);

+ 388 - 0
led_heartbeat.c

@@ -0,0 +1,388 @@
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "gpioregs.h"
+
+#define DEVICE_NAME "led"
+#define CLASS_NAME "led_heartbeat_class"
+#define led_heartbeat_MAJOR 56
+#define led_heartbeat_MINOR 60
+
+
+typedef enum
+{
+    LED_GREEN = 0,
+    LED_RED = 1
+} led_color_t;
+
+static struct class *led_heartbeat_class = NULL;
+static struct device *led_heartbeat_device = NULL;
+static struct cdev led_heartbeat_cdev;
+
+static int led_color  = 0;
+static int led_blink_flag  = 0;
+static int led_blink_speed = 0;
+static unsigned char blink_count = 0;
+static struct delayed_work delay_work1;
+
+static int wait_ibf(void)
+{
+    int i = 0;
+    while (inb(EC_CMD_PORT) & EC_IBF)
+    {
+        if (++i > TIMEOUT_LOOPS)
+        {
+            return -1;
+        }
+        udelay(1);
+    }
+    return 0;
+}
+
+static int wait_obf(void)
+{
+    int i = 0;
+    while (!(inb(EC_CMD_PORT) & EC_OBF))
+    {
+        if (++i > TIMEOUT_LOOPS)
+        {
+            return -1;
+        }
+        udelay(1);
+    }
+    return 0;
+}
+
+static int ec_read_ram(uint8_t offset, uint8_t *data)
+{
+    if (wait_ibf() < 0)
+        return -1;
+    outb(CMD_READ_RAM, EC_CMD_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(offset, EC_DATA_PORT);
+
+    if (wait_obf() < 0)
+        return -1;
+    *data = inb(EC_DATA_PORT);
+
+    return 0;
+}
+
+static int ec_write_ram(uint8_t offset, uint8_t data)
+{
+    if (wait_ibf() < 0)
+        return -1;
+    outb(CMD_WRITE_RAM, EC_CMD_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(offset, EC_DATA_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(data, EC_DATA_PORT);
+
+    return 0;
+}
+
+static int oem_ec_read_ram(uint8_t page, uint8_t offset, uint8_t *data)
+{
+    unsigned char WEC, REC;
+    switch(page)
+    {
+        case 0:
+        {
+            WEC = 0x96;
+            REC = 0x95;
+            break;
+        }
+        
+        case 1:
+        {
+            WEC = 0x98;
+            REC = 0x97;
+            break;
+        }
+        
+        default:
+        {
+            WEC = 0x81;
+            REC = 0x80;
+            break;
+        }
+    }    
+    if (wait_ibf() < 0)
+        return -1;
+    outb(REC, EC_CMD_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(offset, EC_DATA_PORT);
+
+    if (wait_obf() < 0)
+        return -1;
+    *data = inb(EC_DATA_PORT);
+
+    return 0;
+}
+
+static int oem_ec_write_ram(uint8_t page, uint8_t offset, uint8_t data)
+{
+    unsigned char WEC, REC;
+    switch(page)
+    {
+        case 0:
+        {
+            WEC = 0x96;
+            REC = 0x95;
+            break;
+        }
+        
+        case 1:
+        {
+            WEC = 0x98;
+            REC = 0x97;
+            break;
+        }
+        
+        default:
+        {
+            WEC = 0x81;
+            REC = 0x80;
+            break;
+        }
+    }
+    if (wait_ibf() < 0)
+        return -1;
+    outb(WEC, EC_CMD_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(offset, EC_DATA_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(data, EC_DATA_PORT);
+
+    return 0;
+}
+
+static void heart_led_turn_on(void)
+{
+    oem_ec_write_ram(1, OFFSET_TURNOFF_CTL, 0x00);
+    printk("%s %s %d.\n", __FILE__, __FUNCTION__, __LINE__);
+}
+
+static void heart_led_turn_off(void)
+{
+    oem_ec_write_ram(1, OFFSET_TURNOFF_CTL, 0x01);
+    printk("%s %s %d.\n", __FILE__, __FUNCTION__, __LINE__);
+}
+
+static int led_set_color(led_color_t color)
+{
+    uint8_t val;
+    if (ec_read_ram(OFFSET_COLOR_CTL, &val) < 0)
+        return -1;
+
+    if (color == LED_RED)
+        val |= BIT0;
+    else
+        val &= ~BIT0;
+
+    heart_led_turn_on();
+    return ec_write_ram(OFFSET_COLOR_CTL, val);
+}
+
+static int led_set_blink(int enable, uint8_t interval_unit)
+{
+    uint8_t ctl;
+
+    if (enable)
+    {
+        if (ec_write_ram(OFFSET_BLINK_TIME, interval_unit) < 0)
+            return -1;
+    }
+
+    if (ec_read_ram(OFFSET_BLINK_CTL, &ctl) < 0)
+        return -1;
+
+    if (enable)
+        ctl |= BIT0;
+    else
+        ctl &= ~BIT0;
+
+    heart_led_turn_on();
+    return ec_write_ram(OFFSET_BLINK_CTL, ctl);
+}
+
+static int led_heartbeat_open(struct inode *inode, struct file *filp)
+{
+    return 0;
+}
+
+static int led_heartbeat_release(struct inode *inode, struct file *filp)
+{
+    return 0;
+}
+
+static ssize_t led_heartbeat_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+    int ret = 0;
+    return ret;
+}
+
+static ssize_t led_heartbeat_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
+{
+    unsigned char kbuff[3] = {0};
+    if(count > sizeof(kbuff))
+    {
+        count = sizeof(kbuff);
+    }
+    if (copy_from_user(kbuff, buf, count) != 0)
+    {
+        return -EFAULT;
+    }
+
+    led_color = kbuff[0];
+    led_blink_flag = kbuff[1];
+    led_blink_speed = kbuff[2];
+    printk("%02x %02x %02x\n", kbuff[0], kbuff[1], kbuff[2]);
+
+    if(led_color == 0x00)
+    {
+        // off
+        heart_led_turn_off();
+        return count;
+    }
+    else if(led_color == 0x40)
+    {
+        // set color to red
+        led_set_color(LED_RED);
+    }
+    else if(led_color == 0x80)
+    {
+        // set color to green
+        led_set_color(LED_GREEN);
+    }
+
+    led_set_blink(led_blink_flag, kbuff[2]);
+    return count;
+
+    if(led_blink_flag)
+    {
+        led_set_blink(1, led_blink_speed);
+        // blink_count = 0;
+        // schedule_delayed_work(&delay_work1, msecs_to_jiffies(1000*led_blink_speed));        
+    }
+    return count;
+}
+
+static struct file_operations led_heartbeat_fops = {
+    .owner = THIS_MODULE,
+    .open = led_heartbeat_open,
+    .release = led_heartbeat_release,
+    .read = led_heartbeat_read,
+    .write = led_heartbeat_write,
+};
+
+static void led_heartbeat_work_func(struct work_struct *work)
+{
+
+    if(led_blink_flag)
+    {
+        if(blink_count%2 == 0)
+        {
+            if(led_color == 0x40)
+            {
+                // set color to red
+                led_set_color(LED_RED);
+            }
+            else if(led_color == 0x80)
+            {
+                // set color to green
+                led_set_color(LED_GREEN);
+            }
+        }
+        else
+        {
+            printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
+            heart_led_turn_off();
+        }
+        blink_count++;
+        schedule_delayed_work(&delay_work1, msecs_to_jiffies(1000*led_blink_speed));
+    }
+}
+
+int led_heartbeat_init(void)
+{
+    dev_t dev_num;
+    int ret;
+
+    // 使用指定的主设备号和次设备号
+    dev_num = MKDEV(led_heartbeat_MAJOR, led_heartbeat_MINOR);
+    
+    // 注册设备号
+    ret = register_chrdev_region(dev_num, 1, DEVICE_NAME);
+    if (ret < 0) {
+        pr_err("Failed_heartbeat to register device number %d:%d\n", led_heartbeat_MAJOR, led_heartbeat_MINOR);
+        return ret;
+    }
+    pr_info("led_heartbeat driver loaded, device number = %d:%d\n", led_heartbeat_MAJOR, led_heartbeat_MINOR);
+
+    // 初始化 cdev 并添加到系统
+    cdev_init(&led_heartbeat_cdev, &led_heartbeat_fops);
+    led_heartbeat_cdev.owner = THIS_MODULE;
+    ret = cdev_add(&led_heartbeat_cdev, dev_num, 1);
+    if (ret < 0) {
+        pr_err("Failed_heartbeat to add cdev\n");
+        unregister_chrdev_region(dev_num, 1);
+        return ret;
+    }
+
+    // 创建设备类
+    led_heartbeat_class = class_create(THIS_MODULE, CLASS_NAME);
+    if (IS_ERR(led_heartbeat_class)) {
+        pr_err("Failed_heartbeat to create class\n");
+        cdev_del(&led_heartbeat_cdev);
+        unregister_chrdev_region(dev_num, 1);
+        return PTR_ERR(led_heartbeat_class);
+    }
+
+    // 创建设备节点
+    led_heartbeat_device = device_create(led_heartbeat_class, NULL, dev_num, NULL, DEVICE_NAME);
+    if (IS_ERR(led_heartbeat_device)) {
+        pr_err("Failed_heartbeat to create device\n");
+        class_destroy(led_heartbeat_class);
+        cdev_del(&led_heartbeat_cdev);
+        unregister_chrdev_region(dev_num, 1);
+        return PTR_ERR(led_heartbeat_device);
+    }
+
+    INIT_DELAYED_WORK(&delay_work1, led_heartbeat_work_func);
+
+    pr_info("led_heartbeat driver initialized successfully\n");
+    return 0;
+}
+
+void led_heartbeat_exit(void)
+{
+    dev_t dev_num = MKDEV(led_heartbeat_MAJOR, led_heartbeat_MINOR);
+
+    device_destroy(led_heartbeat_class, dev_num);
+    class_destroy(led_heartbeat_class);
+    cdev_del(&led_heartbeat_cdev);
+    unregister_chrdev_region(dev_num, 1);
+    pr_info("led_heartbeat driver unloaded\n");
+}

+ 7 - 0
led_heartbeat.h

@@ -0,0 +1,7 @@
+#ifndef __LED_HEARTBEAT_H__
+#define __LED_HEARTBEAT_H__
+
+int led_heartbeat_init(void);
+void led_heartbeat_exit(void);
+
+#endif

+ 13 - 0
main.c

@@ -34,6 +34,7 @@
 #include "lcd_2x20.h"
 #include "smart_battery.h"
 #include "voltage_sysfs.h"
+#include "led_heartbeat.h"
 
 struct kobject *vfiec_kobj = NULL;
 struct kobject *hwmon_kobj = NULL;
@@ -168,8 +169,17 @@ static int __init all_driver_init(void)
         goto out_battery_acpi;
     }
 
+    ret = led_heartbeat_init();
+    if(ret != 0)
+    {
+        printk(KERN_ERR "led_heartbeat_init failed\n");
+        goto out_voltage_sysfs;
+    }
+
     printk(KERN_INFO "all_driver_init\n");
     return ret;
+out_led_heartbeat:
+    led_heartbeat_exit();
 out_voltage_sysfs:
     voltage_sysfs_exit();
 out_battery_acpi:
@@ -207,6 +217,7 @@ out_switches:
 out_backlight:
     backlight_exit();
 out_kobject_put:
+    kobject_put(hwmon_kobj);
     kobject_put(vfiec_kobj);
     return ret;
 }
@@ -231,6 +242,8 @@ static void __exit all_driver_exit(void)
     lcd2x20_exit();
     battery_acpi_driver_exit();
     voltage_sysfs_exit();
+    led_heartbeat_exit();
+    kobject_put(hwmon_kobj);
     kobject_put(vfiec_kobj);
 }
 

+ 124 - 0
test_app/setled.c

@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define DEVICE_PATH "/dev/led"
+
+
+
+void usage()
+{
+    printf("Usage: [command] [param1] [param2] [param2]\n");
+    printf("Commands:\n");
+    printf("  setled off\n");
+    printf("  setled red off\n");
+    printf("  setled green off\n");
+    printf("  setled red on 1\n");
+    printf("  setled green on 255\n");
+}
+
+int main(int argc, char *argv[])
+{
+    int fd = 0;
+    int ret = 0;
+    int blink_value = 0;
+    char buff[3];
+    if (argc == 2)
+    {
+        printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
+        if(strcmp(argv[1], "off") == 0)
+        {
+            buff[0] = 0x00;
+            buff[1] = 0x01;
+            buff[2] = 0x01;
+        }
+    }
+    else if (argc == 3)
+    {
+        printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
+        if(strcmp(argv[1], "red") == 0)
+        {
+            buff[0] = 0x40;
+        }
+        else if(strcmp(argv[1], "green") == 0)
+        {
+            buff[0] = 0x80;
+        }
+        else
+        {
+            usage();
+            return -1;
+        }
+
+        if(strcmp(argv[2], "off") == 0)
+        {
+            buff[1] = 0x00;
+            buff[2] = 0x01;
+        }
+        else
+        {
+            usage();
+            return -1;
+        }
+    }
+    else if (argc == 4)
+    {
+        printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
+        if(strcmp(argv[1], "red") == 0)
+        {
+            buff[0] = 0x40;
+        }
+        else if(strcmp(argv[1], "green") == 0)
+        {
+            buff[0] = 0x80;
+        }
+        else
+        {
+            usage();
+            return -1;
+        }
+
+        if(strcmp(argv[2], "on") == 0)
+        {
+            buff[1] = 0x01;
+        }
+        else
+        {
+            usage();
+            return -1;
+        }
+
+        blink_value = atoi(argv[3]);
+        buff[2] = blink_value&0xff;
+    }
+    else
+    {
+        printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
+        usage();
+        return -1;
+    }
+
+        printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
+    fd = open(DEVICE_PATH, O_RDWR);
+    if (fd < 0)
+    {
+        perror("open failed");
+        return -1;
+    }
+
+        printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
+    ret = write(fd, buff, sizeof(buff));
+    if (ret < 0)
+    {
+        perror("write failed");
+        close(fd);
+        return -1;
+    }
+
+        printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
+    close(fd);
+    return 0;
+}