【C3】cpu_wtd_sysfs

news2025/1/11 1:19:39

文章目录

  • 2.cpu_wtd_sysfs:
    • switchboard.c (fpga下i2c访问Switch CPLD1,Switch CPLD2 :CPLD, FPGA , QSFP)
  • script
  • bmc_wtd:syscpld.c中wd_en和wd_kick节点对应寄存器,crontab,FUNCNAME
  • AST2500/2600 WDT切换主备:BMC用WDT2作为主备切换的watchdog控制器
    • AC后读取:bmc处于主primary flash(设完后:实际主,wtd1主,wtd2主)
    • 切换spi备:wtd2的2c寄存器设为0x93,换另一个flash后reboot后从备起(设完后:实际备,wtd1主,wtd2备)
    • 用WDT1切主:(设完后:实际备,wtd1备,wtd2备)
    • 用WDT2切主:(设完后:实际备,wtd1备,wtd2主)
    • 用WDT1切主:(设完后:实际主,wtd1主,wtd2主)
    • 关于清空寄存器:(设完后:WTD1主,WTD2主,实际主)
    • 结论:从主切到备,需要一个wdt的status是default也就是0的wdt,然后用0x93切换
  • BMC喂狗实现:sys/class/gpio/gpio1/value获取gpio1值
      • watch-dog.h
      • watch-dog.c
      • main.c
      • Makefile
      • run-watch-dog.sh
      • setup-watch-dog.sh
      • watch-dog_0.1.bb


2.cpu_wtd_sysfs:

switchboard.c (fpga下i2c访问Switch CPLD1,Switch CPLD2 :CPLD, FPGA , QSFP)

ONIE_ROOT=$(realpath $(dirname $0)/../../../)
MACHINE=$(basename $(dirname $(realpath $0)))
MACHINEROOT=$ONIE_ROOT/machine/huaqin
PARAMS=$*
PARAMS=${PARAMS:-help}
BUILD_IMAGE=$ONIE_ROOT/build/images

if [[ $PARAMS =~ .*rmbuild.* ]]; then
    echo "Delete all the build directories, which may require root permission"
    sudo rm -rf $ONIE_ROOT/build
    exit
fi

make -C $ONIE_ROOT/build-config -j64 MACHINEROOT=$MACHINEROOT MACHINE=$MACHINE $PARAMS

if [[ $PARAMS =~ .*help.* ]]; then
    echo "The following is the customized help of Huaqin : "
    echo
    echo "./build.sh clean   : Delete compiled image"
    echo "./build.sh rmbuild : Delete everything in the current build"
fi



if [[ $PARAMS =~ .*all.* ]] || [[ $PARAMS =~ .*demo.* ]]; then
    echo "Build images path: $BUILD_IMAGE"
    ls -l $BUILD_IMAGE/*${MACHINE}* | sed "s#$BUILD_IMAGE/##g"
fi

// cpld_h.c : lpc访问COMe/Baseboard CPLD : CPLD , LED , WatchDog
#include "common_hq.h"
#include <linux/kobject.h>
#define CPLD_DRIVER_NAME 	"sys_cpld"
#define CPLD_DRIVER_VER		"0.0.1"
/**
 * CPLD register address for read and write.
 */
/*
 * Base CPLD:0xA100 ~ 0xA1DF
 * COMe CPLD:0xA1E0 ~ 0xA1FF
 * */
#define BASE_CPLD_ADDR 		0xA100
#define COME_CPLD_ADDR		0xA1E0
#define VERSION_ADDR 		0xA100

#define BASE_PCB_VER_ADDR	0xA100
#define BASE_H_VER_ADDR		0xA101
#define BASE_M_VER_ADDR		0xA102
#define BASE_L_VER_ADDR		0xA103
#define BASE_SCRATCH_ADDR	0xA104

#define COME_PCB_VER_ADDR	0xA1E0
#define COME_H_VER_ADDR		0xA1E1
#define COME_M_VER_ADDR		0xA1E2
#define COME_L_VER_ADDR		0xA1E3
#define COME_SCRATCH_ADDR	0xA1E4

#define CPLD_REGISTER_SIZE 	0xFF
#define CPLD_TOTAL_NUMBER   4

/*watchdog*/
#define BASE_REG_ADDR_WD_EN         0xA190
#define BASE_REG_ADDR_WD_LTIME      0xA191
#define BASE_REG_ADDR_WD_HTIME      0xA192
#define BASE_REG_ADDR_WD_KICK       0xA193
#define BASE_REG_ADDR_WD_FOUN       0xA194
#define BASE_REG_ADDR_WD_STAE       0xA195  //status
#define BASE_REG_ADDR_WD_CLEAR      0xA196
#define BASE_REG_ADDR_WD_LTIMELEFT  0xA197
#define BASE_REG_ADDR_WD_HTIMELEFT  0xA198

/*sysled*/
#define PSU_LED_ADDR     0xA140
#define SYS_LED_ADDR     0xA141
#define Alarm_LED_ADDR   0xA142
#define Fan_LED_ADDR     0xA143
#define BMC_LED_ADDR     0xA144

enum
{
    DARK,
    GREEN,
    YELLOW,
    RED,
    BLUE,
    GREEN_LIGHT_FLASHING,
    YELLOW_LIGHT_FLASHING,
    RED_LIGHT_FLASHING,
    BLUE_LIGHT_FLASHING
};

int set_bit_value(int value,int bit,int status);
int get_bit_value(int value,int bit);

/******************************************************watchdog*******************************************************************/
ssize_t get_main_watchdog_identify(char *buf, size_t count)
{
    return sprintf(buf,"CPU_wdt\n");
}
EXPORT_SYMBOL(get_main_watchdog_identify);

ssize_t get_main_watchdog_state(char *buf, size_t count)
{
    int data=inb(BASE_REG_ADDR_WD_EN);
    // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",BASE_REG_ADDR_WD_EN,inb(BASE_REG_ADDR_WD_EN));
    data = get_bit_value(data,0);
    data=sprintf(buf,"%x\n",data);  //转为16进制
    return data;
}
EXPORT_SYMBOL(get_main_watchdog_state);

ssize_t get_main_watchdog_timeleft(char *buf, size_t count)
{
    int data_ligh = inb(BASE_REG_ADDR_WD_HTIMELEFT);
    // printk(KERN_INFO "Baseboard CPLD addr BASE_REG_ADDR_WD_HTIME :%.2x,value: %.2x \n",BASE_REG_ADDR_WD_HTIMELEFT,data_ligh);
    int data_low = inb(BASE_REG_ADDR_WD_LTIMELEFT);
    // printk(KERN_INFO "Baseboard CPLD addr BASE_REG_ADDR_WD_LTIME:%.2x,value: %.2x \n",BASE_REG_ADDR_WD_LTIMELEFT,data_low);
    int data=(data_ligh << 8 )+data_low;
    // printk(KERN_INFO "data :%.2x \n",data);
    data=data/1000;
    data=sprintf(buf,"%d\n",data);
    return data;
}
EXPORT_SYMBOL(get_main_watchdog_timeleft);

ssize_t get_main_watchdog_timeout(char *buf, size_t count)
{
    int data_ligh = inb(BASE_REG_ADDR_WD_HTIME);
    // printk(KERN_INFO "Baseboard CPLD addr BASE_REG_ADDR_WD_HTIME :%.2x,value: %.2x \n",BASE_REG_ADDR_WD_HTIME,data_ligh);
    int data_low = inb(BASE_REG_ADDR_WD_LTIME);
    // printk(KERN_INFO "Baseboard CPLD addr BASE_REG_ADDR_WD_LTIME:%.2x,value: %.2x \n",BASE_REG_ADDR_WD_LTIME,data_low);
    int data=(data_ligh << 8 )+data_low;    //拼接
    // printk(KERN_INFO "data :%.2x \n",data);
    data=data/1000;   //毫秒变成秒
    data=sprintf(buf,"%d\n",data);
    return data;
}
EXPORT_SYMBOL(get_main_watchdog_timeout);

int set_main_watchdog_timeout(int value)
{
    int value_ms = value * 1000 ;  //秒变成毫秒
    outb(value_ms&0xff ,BASE_REG_ADDR_WD_LTIME);  //outb写,取低八位
    outb((value_ms>>8)&0xff ,BASE_REG_ADDR_WD_HTIME);
    return;
}
EXPORT_SYMBOL(set_main_watchdog_timeout);

static void feed_watchdog(void)
{
        int addr,value;
        addr = BASE_REG_ADDR_WD_KICK;
        value = inb(addr);  // 读
        value = set_bit_value(value,0,0);  // 设 0x7c
        value = set_bit_value(value,1,0);
        value = set_bit_value(value,2,1);
        value = set_bit_value(value,3,1);
        value = set_bit_value(value,4,1);
        value = set_bit_value(value,5,1);
        value = set_bit_value(value,6,1);
        value = set_bit_value(value,7,0);
        outb(value,addr);  // 写
}

ssize_t get_main_watchdog_enable_status(char *buf, size_t count)
{
    int addr,value;
    addr = BASE_REG_ADDR_WD_EN;
    value=inb(addr);
    value = get_bit_value(value,0);   //看最后一位
    return sprintf(buf,"%02X\n", value);
}
EXPORT_SYMBOL(get_main_watchdog_enable_status);

int set_main_watchdog_enable_status(int status)
{
    int addr,value;
    addr = BASE_REG_ADDR_WD_EN;
    value = inb(addr);
    switch(status)
    {
        case 0:
            value = set_bit_value(value,0,0);
            outb(value,addr);
            break;
        case 1:
            value = set_bit_value(value,0,1);
            outb(value,addr);
            feed_watchdog();
            break;
        default:
            return -ENOSYS;
    }
    return status;
}
EXPORT_SYMBOL(set_main_watchdog_enable_status);


/******************************************************************************new enable node***********************************/
ssize_t get_watchdog_enable_status(struct device *dev, struct device_attribute *attr, char *buf)
{
    size_t count=0;
    return get_main_watchdog_enable_status(buf, count);
}
static ssize_t set_watchdog_enable_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    int value,rc = 0;
    rc = kstrtoint(buf,10,&value);
    if (rc != 0) {
        return size;
    }
    set_main_watchdog_enable_status(value);
    return size;
}
static struct device_attribute watchdog_enable_attr = __ATTR(enable, S_IRUGO | S_IWUSR,get_watchdog_enable_status,set_watchdog_enable_status);


/****************************************************************************new timeout node*******************************/
ssize_t get_watchdog_timeout(struct device *dev, struct device_attribute *attr, char *buf)
{
    return get_main_watchdog_timeout(buf,NULL);
}
static ssize_t set_watchdog_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    int value,rc = 0;
    rc = kstrtoint(buf,10,&value);
    if (rc != 0) {
        return size;
    }
    set_main_watchdog_timeout(value);
    return size;
}
static struct device_attribute watchdog_timeout_attr = __ATTR(timeout, S_IRUGO | S_IWUSR,get_watchdog_timeout,set_watchdog_timeout);


/******************************************************************************new feed node*******************************/
static ssize_t hq_set_watchdog_feed(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    int data,rc = 0;
    rc = kstrtoint(buf,16,&data);
    if (rc != 0) {
        return size;
    }
    // printk(KERN_INFO "Baseboard CPLD addr BASE_REG_ADDR_WD_KICK :%.2x,value: %.2x \n",BASE_REG_ADDR_WD_KICK,data);
    if(data==0x7c)
    {
        outb(data,BASE_REG_ADDR_WD_KICK);
        // printk(KERN_INFO "Baseboard CPLD feed dog getreg value : %.2x \n",inb(BASE_REG_ADDR_WD_KICK));
    }
    else
    {
        return -EINVAL;
    }
    return size;
}
static struct device_attribute watchdog_feed_attt = __ATTR(feed, S_IRUGO | S_IWUSR, NULL, hq_set_watchdog_feed);


/************************************************************************new strategy node*******************************/
ssize_t hq_get_watchdog_strategy(struct device *dev, struct device_attribute *attr, char *buf)
{
    return sprintf(buf,"%0.2x\n",inb(BASE_REG_ADDR_WD_FOUN));
}
static ssize_t hq_set_watchdog_strategy(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    int data,rc = 0;
    rc = kstrtoint(buf,16,&data);
    if (rc != 0) {
        return size;
    }
    if((data==0x01) || (data ==0x02))
    {
        outb(data,BASE_REG_ADDR_WD_FOUN);
        // printk(KERN_INFO " hq_set_watchdog_strategy addr value : %.2x \n",inb(BASE_REG_ADDR_WD_FOUN));
    }
    else
    {
        return -EINVAL;
    }
    return size;
}
static struct device_attribute watchdog_strategy_attr = __ATTR(strategy, S_IRUGO | S_IWUSR,hq_get_watchdog_strategy ,hq_set_watchdog_strategy);


/********************************************************************new timeout_counts node*******************************/
ssize_t hq_get_watchdog_timeout_times(struct device *dev, struct device_attribute *attr, char *buf)
{
    return sprintf(buf,"%d\n",inb(BASE_REG_ADDR_WD_STAE));
}
static struct device_attribute watchdog_timeout_counts_attr = __ATTR(timeout_counts, S_IWUSR|S_IRUGO,hq_get_watchdog_timeout_times, NULL);


/********************************************************************new timeout_reset node*******************************/
static ssize_t hq_set_watchdog_timeout_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    int data,rc = 0;
    rc = kstrtoint(buf,16,&data);
    if (rc != 0) {
        return size;
    }
    if(data==1)
    {
        outb(data,BASE_REG_ADDR_WD_KICK);
    }
    else
    {
        return -EINVAL;
    }
    return size;
}
static struct device_attribute watchdog_timeout_reset_attr = __ATTR(timeout_reset, S_IRUGO | S_IWUSR,NULL ,hq_set_watchdog_timeout_reset);

static struct attribute *watchdog_dir_attrs[] = {
    &watchdog_enable_attr.attr,
    &watchdog_timeout_attr.attr,
    &watchdog_feed_attt.attr,
    &watchdog_strategy_attr.attr,
    &watchdog_timeout_counts_attr.attr,
    &watchdog_timeout_reset_attr.attr,
    NULL
};

static struct attribute_group watchdog_attr_group = {   // 在下面cpld_hq_drv_probe函数里: kobject_create_and_add, sysfs_create_group
    .attrs = watchdog_dir_attrs,
};
/******************************************************watchdog end*********************************************************************************/

/******************************************************sysled begain*******************************************************************************/
int set_sysled_state(int status,char *names)
{
    int addr,value;
    if(strcmp(names,"PSU")==0)
    {
        addr=PSU_LED_ADDR;
    }
    else if(strcmp(names,"SYS")==0)
    {
        addr=SYS_LED_ADDR;
    }
    else if(strcmp(names,"Alarm")==0)
    {
       addr=Alarm_LED_ADDR;
    }
    else if(strcmp(names,"Fan")==0)
    {
        addr=Fan_LED_ADDR;
    }
    else if(strcmp(names,"BMC")==0)
    {
        addr=BMC_LED_ADDR;
    }
    else
    {
        return -ENOSYS;
    }
    value=inb(addr);
    switch(status)
    {
        case DARK:
                value=set_bit_value(value,6,1);
                value=set_bit_value(value,0,1);
                value=set_bit_value(value,1,0);
                outb(value,addr);
                // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",addr,inb(addr));
                break;
        case GREEN:
                value=set_bit_value(value,6,1);
                value=set_bit_value(value,4,0);
                value=set_bit_value(value,5,0);
                value=set_bit_value(value,1,0);
                value=set_bit_value(value,0,0);
                outb(value,addr);
                // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",addr,inb(addr));
                break;
        case YELLOW:
                value=set_bit_value(value,6,1);
                value=set_bit_value(value,4,1);
                value=set_bit_value(value,5,0);
                value=set_bit_value(value,1,0);
                value=set_bit_value(value,0,0);
                outb(value,addr);
                // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",addr,inb(addr));
                break; 
        case RED:
                return -ENOSYS;
        case BLUE:
                return -ENOSYS;
        case GREEN_LIGHT_FLASHING:
                value=set_bit_value(value,6,1);
                value=set_bit_value(value,4,0);
                value=set_bit_value(value,5,0);
                value=set_bit_value(value,1,1);
                value=set_bit_value(value,0,0);
                outb(value,addr);
                // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",addr,inb(addr));
                break;
        case YELLOW_LIGHT_FLASHING:
                value=set_bit_value(value,6,1);
                value=set_bit_value(value,4,1);
                value=set_bit_value(value,5,0);
                value=set_bit_value(value,1,1);
                value=set_bit_value(value,0,0);
                outb(value,addr);
                // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",addr,inb(addr));
                break;
        case RED_LIGHT_FLASHING:
                return -ENOSYS;
        case BLUE_LIGHT_FLASHING:
                return -ENOSYS;
        default:
            return -ENOSYS;
    }
    return 1;
}
EXPORT_SYMBOL(set_sysled_state);

ssize_t get_sysled_state(char *buf, size_t count,char *names)
{
    int addr,value;
    int len=-1;
    if(strcmp(names,"PSU")==0)
    {
        addr=PSU_LED_ADDR;
    }
    else if(strcmp(names,"SYS")==0)
    {
        addr=SYS_LED_ADDR;
    }
    else if(strcmp(names,"Alarm")==0)
    {
       addr=Alarm_LED_ADDR;
    }
    else if(strcmp(names,"Fan")==0)
    {
        addr=Fan_LED_ADDR;
    }
    else if(strcmp(names,"BMC")==0)
    {
        addr=BMC_LED_ADDR;
    }
    else
    {
        return -ENOSYS;
    }
    value=inb(addr);
    if(get_bit_value(value,0)==1 && get_bit_value(value,1)==0)
    {
        len=sprintf(buf,"dark\n");
        return len;
    }
    else if(get_bit_value(value,0)==0 && get_bit_value(value,1)==0)
    {
        //buf chang liang 常亮
        if(get_bit_value(value,4)==0 && get_bit_value(value,5)==0)
        {
            len=sprintf(buf,"green\n");
            return len;
        }
        else if(get_bit_value(value,4)==1 && get_bit_value(value,5)==0)
        {
            len=sprintf(buf,"yellow\n");
            return len;
        }
        else
        {
            ;
        }
    }
    else if(get_bit_value(value,0)==0 && get_bit_value(value,1)==1)
    {
        //buf 闪烁
        if(get_bit_value(value,4)==0 && get_bit_value(value,5)==0)
        {
            len=sprintf(buf,"green light flashing\n");
            return len;
        }
        else if(get_bit_value(value,4)==1 && get_bit_value(value,5)==0)
        {
            len=sprintf(buf,"yellow light flashing\n");
            return len;
        }
        else
        {
                ;
        }
    }
    else
    {
        return -ENOSYS;
    }
}
EXPORT_SYMBOL(get_sysled_state);

int get_bit_value(int value,int bit)
{
    if(value<0 || value>0xff || bit<0 || bit>7)
    {
        return -1;
    }
    int data ;
    data=value >> bit & 0x01;    // 右移bit位并取最后一位
    return data;
}

int set_bit_value(int value,int bit,int status)
{
    if(value<0 || value>0xff || bit<0 || bit>7|| status<0 || status>1)
    {
        return -1;
    }
    else
    {
        if(status==0)  //将1111 1111第二位(从0开始即第三位)置为0
        {
            value=(~(1<<bit)) & value;      //0000 0100 (1<<2)     1111 1011 & 1111 1111  =  1111 1011 (&:有0为0)
            return value;
        }
        else if(status==1)  //将0001 0001第二位(从0开始即第三位)置为1
        {
           value = (1<<bit) | value;       //0000 0100 (1<<2)      0000 0100 | 0001 0001  =  0001 0101 (|:有1为1)
           return value;
        }
        else
        {
            ;
        }
    }
}
/*****************************************************sysled end*************************************************************************************/

/***********************************************CPLD begain*******************************************************************************************/
int get_board_cpld_number(void)
{
    /* add vendor codes here */
    return CPLD_TOTAL_NUMBER;
}
EXPORT_SYMBOL(get_board_cpld_number);

/*
 * demo_get_main_board_cpld_alias - Used to identify the location of cpld,
 * @cpld_index: start with 1
 * @buf: Data receiving buffer
 * @count: length of buf
 *
 * This function returns the length of the filled buffer,
 * if not support this attributes filled "NA" to buf,
 * otherwise it returns a negative value on failed.
 */
ssize_t get_board_cpld_alias(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    int len = -1 ;
    switch(cpld_index)
    {
        case 1 :
            len=sprintf(buf,"Base board CPLD\n");
            break ;
        case 2 :
            len=sprintf(buf,"Come CPLD\n");
            break ;
        default:
            len = -1 ;
            break;
    }
    return len;
}
EXPORT_SYMBOL(get_board_cpld_alias);

/*
 * demo_get_main_board_cpld_type - Used to get cpld model name
 * @cpld_index: start with 1
 * @buf: Data receiving buffer
 * @count: length of buf
 *
 * This function returns the length of the filled buffer,
 * if not support this attributes filled "NA" to buf,
 * otherwise it returns a negative value on failed.
 */
ssize_t get_board_cpld_type(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    int len = -1 ;
    switch(cpld_index)
    {
        case 1 :
            len=sprintf(buf,"LCMXO3LF-4300C-5BG400C CPLD\n");
            break ;
        case 2 :
            len=sprintf(buf,"LCMXO3LF-2100C-5BG400C CPLD\n");
            break ;
        default:
            len = -1 ;
            break;
    }

    return len;
}
EXPORT_SYMBOL(get_board_cpld_type);

/*
 * demo_get_main_board_cpld_firmware_version - Used to get cpld firmware version,
 * @cpld_index: start with 1
 * @buf: Data receiving buffer
 * @count: length of buf
 *
 * This function returns the length of the filled buffer,
 * if not support this attributes filled "NA" to buf,
 * otherwise it returns a negative value on failed.
 */
ssize_t get_board_cpld_firmware_version(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    int len = -1; 
    switch(cpld_index){
        case 1:
            printk(KERN_INFO "BASE CPLD H version:0x%2.2x\n", inb(BASE_H_VER_ADDR));
            printk(KERN_INFO "BASE CPLD M version:0x%2.2x\n", inb(BASE_M_VER_ADDR));
            printk(KERN_INFO "BASE CPLD L version:0x%2.2x\n", inb(BASE_L_VER_ADDR));	
            len = sprintf(buf,"%x.%x.%x\n", inb(BASE_H_VER_ADDR),inb(BASE_M_VER_ADDR),inb(BASE_L_VER_ADDR));
            break;
        case 2:
            printk(KERN_INFO "COME CPLD H version:0x%2.2x\n", inb(COME_H_VER_ADDR));
            printk(KERN_INFO "COME CPLD M version:0x%2.2x\n", inb(COME_M_VER_ADDR));
            printk(KERN_INFO "COME CPLD L version:0x%2.2x\n", inb(COME_L_VER_ADDR));
            len = sprintf(buf,"%x.%x.%x\n", inb(COME_H_VER_ADDR),inb(COME_M_VER_ADDR),inb(COME_L_VER_ADDR));	
            break;
        default:
            len = -1;
            break;
    }

    return len;
}
EXPORT_SYMBOL(get_board_cpld_firmware_version);

/*
 * demo_get_main_board_cpld_board_version - Used to get cpld board version,
 * @cpld_index: start with 1
 * @buf: Data receiving buffer
 * @count: length of buf
 *
 * This function returns the length of the filled buffer,
 * if not support this attributes filled "NA" to buf,
 * otherwise it returns a negative value on failed.
 */
ssize_t get_board_cpld_board_version(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    int len = -1; 
    switch(cpld_index){
        case 1:
            len = sprintf(buf,"%02X\n", inb(BASE_PCB_VER_ADDR));
            break;
        case 2:
            len = sprintf(buf,"%02X\n", inb(COME_PCB_VER_ADDR));
            break;
        default:
            len = -1;
            break;
    }

    return len;
}
EXPORT_SYMBOL(get_board_cpld_board_version);

/*
 * demo_get_main_board_cpld_test_reg - Used to test cpld register read
 * filled the value to buf, value is hexadecimal, start with 0x
 * @cpld_index: start with 1
 * @buf: Data receiving buffer
 * @count: length of buf
 *
 * This function returns the length of the filled buffer,
 * if not support this attributes filled "NA" to buf,
 * otherwise it returns a negative value on failed.
 */
ssize_t get_board_cpld_test_reg(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    int len = -1 ;
    switch(cpld_index)
    {
        case 1 :
            len=sprintf(buf,"%02x\n",inb(BASE_SCRATCH_ADDR));
            break ;
        case 2 :
            len=sprintf(buf,"%02x\n",inb(COME_SCRATCH_ADDR));
            break ;
        default:
            len = -1 ;
            break;
    }

    return len;
}
EXPORT_SYMBOL(get_board_cpld_test_reg);

/*
 * demo_set_main_board_cpld_test_reg - Used to test cpld register write
 * @cpld_index: start with 1
 * @value: value write to cpld
 *
 * This function returns 0 on success,
 * otherwise it returns a negative value on failed.
 */
int set_board_cpld_test_reg(unsigned int cpld_index, unsigned int value)
{
    /* add vendor codes here */
    int ret = -1 ;
    switch(cpld_index)
    {
        case 1 :
            outb(value,BASE_SCRATCH_ADDR);
            ret = 1;
            break ;
        case 2 :
            outb(value,COME_SCRATCH_ADDR);
            ret = 1;
            break ;
        default: 
            ret = -1 ;
            break;
    }

    return ret;
}
EXPORT_SYMBOL(set_board_cpld_test_reg);
/********************************************************CPLD end***********************************************************************/

struct cpld_hq_data {
    struct mutex       cpld_lock;
    uint16_t           read_addr;
	uint16_t		   base_addr;
};

struct cpld_hq_data *cpld_data;

static ssize_t get_cpld_reg_address(struct device *dev, struct device_attribute *attr, char *buf)
{
    int len = 0;
    // CPLD register is one byte
    mutex_lock(&cpld_data->cpld_lock);
    len = sprintf(buf, "0x%2.2x\n",inb(cpld_data->read_addr));
    mutex_unlock(&cpld_data->cpld_lock);
    return len;
}

/**
 * Store the register address
 * @param  buf     address wanted to be read value of
 * @return         number of bytes stored, or an error code
 */
static ssize_t set_cpld_reg_address(struct device *dev, struct device_attribute *devattr,
                                    const char *buf, size_t count)
{
    uint32_t addr;
    char *last;

	mutex_lock(&cpld_data->cpld_lock);
    addr = (uint32_t)strtoul(buf, &last, 16);
    if (addr == 0 && buf == last) {
        return -EINVAL;
    }
	
    cpld_data->read_addr = cpld_data->base_addr + addr;
	mutex_unlock(&cpld_data->cpld_lock);
    return count;
}

static DEVICE_ATTR( getreg, 0600, get_cpld_reg_address, set_cpld_reg_address);

static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr,
                const char *buf, size_t count)
{
    // CPLD register is one byte
    uint16_t addr;
    uint8_t value;
    char *tok;
    char clone[count+1];
    char *pclone = clone;
    char *last;

    strcpy(clone, buf);

    mutex_lock(&cpld_data->cpld_lock);
    tok = strsep((char**)&pclone, " ");
    if(tok == NULL){
        mutex_unlock(&cpld_data->cpld_lock);
        return -EINVAL;
    }
    addr = (uint16_t)strtoul(tok, &last,16);
    if(addr == 0 && tok == last){
        mutex_unlock(&cpld_data->cpld_lock);
        return -EINVAL;
    }

    tok = strsep((char**)&pclone, " ");
    if(tok == NULL){
        mutex_unlock(&cpld_data->cpld_lock);
        return -EINVAL;
    }
    value = (uint8_t)strtoul(tok, &last,16);
    if(value == 0 && tok == last){
        mutex_unlock(&cpld_data->cpld_lock);
        return -EINVAL;
    }

    outb(value, cpld_data->base_addr + addr);
    mutex_unlock(&cpld_data->cpld_lock);
    return count;
}
//static DEVICE_ATTR_WO(setreg);
static DEVICE_ATTR( setreg, 0200, NULL , setreg_store);	
/**
 * Read all CPLD register in binary mode.
 * @return number of byte read.
 */
static ssize_t dump_read(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
{
    unsigned long i = 0;
    ssize_t status;

    mutex_lock(&cpld_data->cpld_lock);
    begin:
        if(i < count){
            buf[i++] = inb(VERSION_ADDR + off);
            off++;
            msleep(1);
            goto begin;
        }
        status = count;
    exit:
        mutex_unlock(&cpld_data->cpld_lock);
    return status;
}
				
static BIN_ATTR_RO(dump, CPLD_REGISTER_SIZE);

static struct attribute *cpld_hq_attrs[] = {
    &dev_attr_getreg.attr,
    &dev_attr_setreg.attr,
    NULL,
};

static struct bin_attribute *cpld_hq_bin_attrs[] = {
    &bin_attr_dump,
    NULL,
};

static struct attribute_group cpld_hq_attrs_group = {
    .attrs = cpld_hq_attrs,
    .bin_attrs = cpld_hq_bin_attrs,
};

static struct resource cpld_hq_resources[] = {
    {
        .start  = 0xA100,
        .end    = 0xA1FF,
        .flags  = IORESOURCE_IO,
    },
};

static void cpld_hq_dev_release( struct device * dev)
{
    return;
}

static struct platform_device cpld_hq_dev = {
    .name           = CPLD_DRIVER_NAME,
    .id             = -1,
    .num_resources  = ARRAY_SIZE(cpld_hq_resources),
    .resource       = cpld_hq_resources,
    .dev = {
        .release = cpld_hq_dev_release,
    }
};

static int cpld_hq_drv_remove(struct platform_device *pdev)
{
    sysfs_remove_group(&pdev->dev.kobj, &cpld_hq_attrs_group);
    return 0;
}

static struct kobject *watchdog = NULL;
static int cpld_hq_drv_probe(struct platform_device *pdev)
{
    struct resource *resource;
    int err = 0;
    
    cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct cpld_hq_data), GFP_KERNEL);
    if(!cpld_data)
        return -ENOMEM;
    
    mutex_init(&cpld_data->cpld_lock);
	
    cpld_data ->read_addr = VERSION_ADDR;
	cpld_data ->base_addr = BASE_CPLD_ADDR;
	
    resource = platform_get_resource(pdev, IORESOURCE_IO, 0);
    if(unlikely(!resource))
    {
        printk(KERN_ERR "Specified Resource Not Available...\n");
        return -ENODEV;
    }

    err = sysfs_create_group(&pdev->dev.kobj, &cpld_hq_attrs_group);
    if(err) {
        printk(KERN_ERR "Cannot create sysfs for system CPLD\n");
        return err;
    }

	printk(KERN_INFO "CPLD Probe driver");
    printk(KERN_INFO "BASE CPLD Address:ox%2.2x\n", BASE_CPLD_ADDR);
	printk(KERN_INFO "COMe CPLD Address:ox%2.2x\n", COME_CPLD_ADDR);
	
    printk(KERN_INFO "BASE CPLD PCB version:0x%2.2x\n", inb(BASE_PCB_VER_ADDR));
    printk(KERN_INFO "BASE CPLD H version:0x%2.2x\n", inb(BASE_H_VER_ADDR));
    printk(KERN_INFO "BASE CPLD M version:0x%2.2x\n", inb(BASE_M_VER_ADDR));
    printk(KERN_INFO "BASE CPLD L version:0x%2.2x\n", inb(BASE_L_VER_ADDR));

	printk(KERN_INFO "COME CPLD PCB version:0x%2.2x\n", inb(COME_PCB_VER_ADDR));
    printk(KERN_INFO "COME CPLD H version:0x%2.2x\n", inb(COME_H_VER_ADDR));
    printk(KERN_INFO "COME CPLD M version:0x%2.2x\n", inb(COME_M_VER_ADDR));
    printk(KERN_INFO "COME CPLD L version:0x%2.2x\n", inb(COME_L_VER_ADDR));	

    printk(KERN_INFO "GPIO base address:0x%x\n", inl(0x48));

    //watchdog
    watchdog = kobject_create_and_add("watchdog",&pdev->dev.kobj);
    if (!watchdog)
    {
        return -ENOMEM;
    }
    if(sysfs_create_group(watchdog,&watchdog_attr_group))
    {
        printk(KERN_INFO"watchdog_attr_group failed\n");
        return -1;
    }
    /*
    int ret;
    ret=watchdog_root_create();
    if (ret < 0) 
    {
        WDT_ERR("watchdog create error.\n");
        return ret;
    }
    */
    return 0;
    
}

static struct platform_driver cpld_hq_drv = {
    .probe = cpld_hq_drv_probe,
    .remove = __exit_p(cpld_hq_drv_remove),
    .driver = {
        .name = CPLD_DRIVER_NAME,
    },
};


static int __init cpld_hq_init(void)
{
    /*Register Platform device and Platform Driver*/
    platform_device_register(&cpld_hq_dev);
    platform_driver_register(&cpld_hq_drv);
	printk(KERN_INFO "%s: version %s loaded successfully\n", CPLD_DRIVER_NAME, CPLD_DRIVER_VER);
	return 0;
}

static void __exit cpld_hq_exit(void)
{
    /*Unregister Platform device and Platform Driver*/
    platform_driver_unregister(&cpld_hq_drv);
    platform_device_unregister(&cpld_hq_dev);
	printk(KERN_INFO "%s: unloaded successfully\n", CPLD_DRIVER_NAME);
}

module_init(cpld_hq_init);
module_exit(cpld_hq_exit);

MODULE_AUTHOR("Huaqin Technology Co.,Ltd.");
MODULE_DESCRIPTION("Hua Qin Common CPLD");
MODULE_VERSION(CPLD_DRIVER_VER);
MODULE_LICENSE("GPL");
#include "common_hq.h" //相当于复制进来

static int demo_get_main_board_cpld_number(void)
{
    /* add vendor codes here */
    return get_board_cpld_number();
}

static ssize_t demo_get_main_board_cpld_alias(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    if((cpld_index == 1) || (cpld_index == 2))
    {
        return get_board_cpld_alias(cpld_index, buf, count);
    }
    else if((cpld_index == 3) || (cpld_index == 4))
    {
        return get_switch_board_cpld_alias(cpld_index, buf, count);
    }
    else
    {
        return -EINVAL;
    }
}

在这里插入图片描述

# 外层Makefile
PWD		= $(shell pwd)
SYSFS_OUT_PUT := $(PWD)/build
sysfs_out_put_dir := $(SYSFS_OUT_PUT)/S3IP_sysfs/
export sysfs_out_put_dir
# KERNEL_SRC=/lib/modules/$(shell uname -r)
KERNEL_SRC=/home_a/yutao/sysfs/my/header/usr/src/linux-headers-4.9.0-14-2-amd64
export KERNEL_SRC

SYSFS_DRIVER_DIR = $(PWD)/s3ip_sysfs_frame
SWITCH_DRIVER_DIR = $(PWD)/demo_driver
HQ_DRIVER_DIR = $(PWD)/s3ip_hq_driver
KBUILD_EXTRA_SYMBOLS += $(HQ_DRIVER_DIR)/Module.symvers
KBUILD_EXTRA_SYMBOLS += $(SYSFS_DRIVER_DIR)/Module.symvers
KBUILD_EXTRA_SYMBOLS += $(SWITCH_DRIVER_DIR)/Module.symvers
export KBUILD_EXTRA_SYMBOLS

all :
	$(MAKE) -C $(HQ_DRIVER_DIR)
	$(MAKE) -C $(SYSFS_DRIVER_DIR)
	$(MAKE) -C $(SWITCH_DRIVER_DIR)
	
clean :
	-rm  -rf $(SYSFS_OUT_PUT)
	$(MAKE) -C $(HQ_DRIVER_DIR) clean
	$(MAKE) -C $(SYSFS_DRIVER_DIR) clean
	$(MAKE) -C $(SWITCH_DRIVER_DIR) clean
	
install:
	install -d $(DESTDIR)/lib/modules/s3ip/
	install -D $(sysfs_out_put_dir)/*.ko \
		$(DESTDIR)/lib/modules/s3ip/
	install -D scripts/s3ip_load.py \
		$(DESTDIR)/$(prefix)/bin/s3ip_load.py
	install -D scripts/s3ip_sysfs_conf.json \
		$(DESTDIR)/etc/s3ip/s3ip_sysfs_conf.json
	install -D scripts/s3ip_sysfs_tool.sh \
		$(DESTDIR)/$(prefix)/bin/s3ip_sysfs_tool.sh
	install -D scripts/s3ip-sysfs.service \
		$(DESTDIR)/etc/systemd/system/s3ip-sysfs.service

uninstall:
	-rm -f $(DESTDIR)$(prefix)/bin/s3ip_load.py
	-rm -f $(DESTDIR)/lib/modules/s3ip/
	-rm -f $(DESTDIR)/etc/s3ip
	-rm -f $(DESTDIR)/$(prefix)/bin/s3ip_sysfs_tool.sh
	-rm -f $(DESTDIR)/etc/systemd/system/s3ip-sysfs.service
# 里层Makefile
PWD		= $(shell pwd)
MAKEFILE_FILE_PATH = $(abspath $(lastword $(MAKEFILE_LIST)))
DEV_SYSFS_HEADER_DIR = $(abspath $(MAKEFILE_FILE_PATH)/../../s3ip_sysfs_frame/include)
SWITCH_DVR_HEADER_DIR = $(abspath $(MAKEFILE_FILE_PATH)/../../demo_driver/include)
HQ_DVR_HEADER_DIR = $(abspath $(MAKEFILE_FILE_PATH)/../../s3ip_hq_driver/include)
EXTRA_CFLAGS:= -I$(M)/include
EXTRA_CFLAGS+= -I$(DEV_SYSFS_HEADER_DIR)
EXTRA_CFLAGS+= -I$(SWITCH_DVR_HEADER_DIR)
EXTRA_CFLAGS+= -I$(HQ_DVR_HEADER_DIR)
EXTRA_CFLAGS+= -Wall

obj-m := cpld_hq.o
obj-m += fpga_i2c_adapter.o
obj-m += i2c-ocores.o
obj-m += mc24lc64t.o
obj-m += optoe.o
obj-m += switchboard.o

all:
		$(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules
		@if [ ! -d $(sysfs_out_put_dir) ]; then mkdir -p $(sysfs_out_put_dir) ;fi
		cp -p  $(PWD)/*.ko $(sysfs_out_put_dir)
clean:
		rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd 
		rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order 
		rm -rf $(PWD)/.tmp_versions
		rm -rf $(PWD)/.cache.mk
		rm -rf $(PWD)/*.mod
#ifndef _COMMON_HQ_H_
#define _COMMON_HQ_H_

#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/err.h>
#include <linux/kobject.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <uapi/linux/stat.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/jiffies.h>
#include <linux/moduleparam.h>
#include <linux/platform_data/pca954x.h>
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/log2.h>
#include <linux/spinlock.h>

extern int get_board_cpld_number(void);
extern ssize_t get_board_cpld_alias(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_board_cpld_type(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_board_cpld_firmware_version(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_board_cpld_board_version(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_board_cpld_test_reg(unsigned int cpld_index, char *buf, size_t count);
extern int set_board_cpld_test_reg(unsigned int cpld_index, unsigned int value);

extern int get_board_fpga_number(void);
extern ssize_t get_board_fpga_alias(unsigned int fpga_index, char *buf, size_t count);
extern ssize_t get_board_fpga_type(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_board_fpga_firmware_version(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_board_fpga_board_version(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_board_fpga_test_reg(unsigned int cpld_index, char *buf, size_t count);
extern int set_board_fpga_test_reg(unsigned int cpld_index, unsigned int value);

extern ssize_t get_switch_board_cpld_alias(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_switch_board_cpld_type(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_switch_board_cpld_firmware_version(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_switch_board_cpld_board_version(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t get_switch_board_cpld_test_reg(unsigned int cpld_index, char *buf, size_t count);
extern ssize_t set_switch_board_cpld_test_reg(unsigned int cpld_index, unsigned int value);

//QSFP
extern int get_main_eth_number(void);
extern ssize_t get_main_transceiver_power_on_status(char *buf, size_t count);
extern int set_main_transceiver_power_on_status(int status);
extern ssize_t get_main_eth_power_on_status(unsigned int eth_index, char *buf, size_t count);
extern int set_main_eth_power_on_status(unsigned int eth_index, int status);
extern ssize_t get_main_eth_tx_fault_status(unsigned int eth_index, char *buf, size_t count);
extern ssize_t get_main_eth_tx_disable_status(unsigned int eth_index, char *buf, size_t count);
extern int set_main_eth_tx_disable_status(unsigned int eth_index, int status);
extern ssize_t get_main_eth_present_status(unsigned int eth_index, char *buf, size_t count);
extern ssize_t get_main_eth_rx_los_status(unsigned int eth_index, char *buf, size_t count);
extern ssize_t get_main_eth_reset_status(unsigned int eth_index, char *buf, size_t count);
extern int set_main_eth_reset_status(unsigned int eth_index, int status);
extern ssize_t get_main_eth_low_power_mode_status(unsigned int eth_index, char *buf, size_t count);
extern ssize_t get_main_eth_interrupt_status(unsigned int eth_index, char *buf, size_t count);
extern int get_main_eth_eeprom_size(unsigned int eth_index);
extern ssize_t read_main_eth_eeprom_data(unsigned int eth_index, char *buf, loff_t offset, size_t count);
extern ssize_t write_main_eth_eeprom_data(unsigned int eth_index, char *buf, loff_t offset, size_t count);

//sysled
extern int set_sysled_state(int status,char *names);
extern ssize_t get_sysled_state(char *buf, size_t count,char *names);

//watchdog
extern ssize_t get_main_watchdog_identify(char *buf, size_t count);
extern ssize_t get_main_watchdog_state(char *buf, size_t count);
extern ssize_t get_main_watchdog_timeleft(char *buf, size_t count);
extern ssize_t get_main_watchdog_timeout(char *buf, size_t count);
extern int set_main_watchdog_timeout(int value);
extern ssize_t get_main_watchdog_enable_status(char *buf, size_t count);
extern int set_main_watchdog_enable_status(int value);

#endif

cpld_hq.c
// cpld_hq.c:         lpc访问COMe/Baseboard CPLD :                   CPLD ,  LED ,  WatchDog
// switchboard.c:    fpga下i2c访问Switch CPLD1,Switch CPLD2 :       CPLD,   FPGA ,  QSFP

#include "common_hq.h"
#include <linux/kobject.h>
#define CPLD_DRIVER_NAME 	"sys_cpld"
#define CPLD_DRIVER_VER		"0.0.1"
/**
 * CPLD register address for read and write.
 */
/*
 * Base CPLD:0xA100 ~ 0xA1DF
 * COMe CPLD:0xA1E0 ~ 0xA1FF
 * */
#define BASE_CPLD_ADDR 		0xA100
#define COME_CPLD_ADDR		0xA1E0
#define VERSION_ADDR 		0xA100

#define BASE_PCB_VER_ADDR	0xA100
#define BASE_H_VER_ADDR		0xA101
#define BASE_M_VER_ADDR		0xA102
#define BASE_L_VER_ADDR		0xA103
#define BASE_SCRATCH_ADDR	0xA104

#define COME_PCB_VER_ADDR	0xA1E0
#define COME_H_VER_ADDR		0xA1E1
#define COME_M_VER_ADDR		0xA1E2
#define COME_L_VER_ADDR		0xA1E3
#define COME_SCRATCH_ADDR	0xA1E4

#define CPLD_REGISTER_SIZE 	0xFF
#define CPLD_TOTAL_NUMBER   4

/*watchdog*/
#define BASE_REG_ADDR_WD_EN         0xA190
#define BASE_REG_ADDR_WD_LTIME      0xA191
#define BASE_REG_ADDR_WD_HTIME      0xA192
#define BASE_REG_ADDR_WD_KICK       0xA193
#define BASE_REG_ADDR_WD_FOUN       0xA194
#define BASE_REG_ADDR_WD_STAE       0xA195  //status
#define BASE_REG_ADDR_WD_CLEAR      0xA196
#define BASE_REG_ADDR_WD_LTIMELEFT  0xA197
#define BASE_REG_ADDR_WD_HTIMELEFT  0xA198

/*sysled*/
#define PSU_LED_ADDR     0xA140
#define SYS_LED_ADDR     0xA141
#define Alarm_LED_ADDR   0xA142
#define Fan_LED_ADDR     0xA143
#define BMC_LED_ADDR     0xA144

enum
{
    DARK,
    GREEN,
    YELLOW,
    RED,
    BLUE,
    GREEN_LIGHT_FLASHING,
    YELLOW_LIGHT_FLASHING,
    RED_LIGHT_FLASHING,
    BLUE_LIGHT_FLASHING
};

int set_bit_value(int value,int bit,int status);
int get_bit_value(int value,int bit);

/******************************************************watchdog*******************************************************************/
ssize_t get_main_watchdog_identify(char *buf, size_t count)
{
    return sprintf(buf,"CPU_wdt\n");
}
EXPORT_SYMBOL(get_main_watchdog_identify);

ssize_t get_main_watchdog_state(char *buf, size_t count)
{
    int data=inb(BASE_REG_ADDR_WD_EN);
    // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",BASE_REG_ADDR_WD_EN,inb(BASE_REG_ADDR_WD_EN));
    data = get_bit_value(data,0);
    data=sprintf(buf,"%x\n",data);  //转为16进制
    return data;
}
EXPORT_SYMBOL(get_main_watchdog_state);

ssize_t get_main_watchdog_timeleft(char *buf, size_t count)
{
    int data_ligh = inb(BASE_REG_ADDR_WD_HTIMELEFT);
    // printk(KERN_INFO "Baseboard CPLD addr BASE_REG_ADDR_WD_HTIME :%.2x,value: %.2x \n",BASE_REG_ADDR_WD_HTIMELEFT,data_ligh);
    int data_low = inb(BASE_REG_ADDR_WD_LTIMELEFT);
    // printk(KERN_INFO "Baseboard CPLD addr BASE_REG_ADDR_WD_LTIME:%.2x,value: %.2x \n",BASE_REG_ADDR_WD_LTIMELEFT,data_low);
    int data=(data_ligh << 8 )+data_low;
    // printk(KERN_INFO "data :%.2x \n",data);
    data=data/1000;
    data=sprintf(buf,"%d\n",data);
    return data;
}
EXPORT_SYMBOL(get_main_watchdog_timeleft);

ssize_t get_main_watchdog_timeout(char *buf, size_t count)
{
    int data_ligh = inb(BASE_REG_ADDR_WD_HTIME);
    // printk(KERN_INFO "Baseboard CPLD addr BASE_REG_ADDR_WD_HTIME :%.2x,value: %.2x \n",BASE_REG_ADDR_WD_HTIME,data_ligh);
    int data_low = inb(BASE_REG_ADDR_WD_LTIME);
    // printk(KERN_INFO "Baseboard CPLD addr BASE_REG_ADDR_WD_LTIME:%.2x,value: %.2x \n",BASE_REG_ADDR_WD_LTIME,data_low);
    int data=(data_ligh << 8 )+data_low;    //拼接
    // printk(KERN_INFO "data :%.2x \n",data);
    data=data/1000;   //毫秒变成秒
    data=sprintf(buf,"%d\n",data);
    return data;
}
EXPORT_SYMBOL(get_main_watchdog_timeout);

int set_main_watchdog_timeout(int value)
{
    int value_ms = value * 1000 ;  //秒变成毫秒
    outb(value_ms&0xff ,BASE_REG_ADDR_WD_LTIME);  //outb写,取低八位
    outb((value_ms>>8)&0xff ,BASE_REG_ADDR_WD_HTIME);
    return;
}
EXPORT_SYMBOL(set_main_watchdog_timeout);

static void feed_watchdog(void)
{
        int addr,value;
        addr = BASE_REG_ADDR_WD_KICK;
        value = inb(addr);  // 读
        value = set_bit_value(value,0,0);  // 设 0x7c
        value = set_bit_value(value,1,0);
        value = set_bit_value(value,2,1);
        value = set_bit_value(value,3,1);
        value = set_bit_value(value,4,1);
        value = set_bit_value(value,5,1);
        value = set_bit_value(value,6,1);
        value = set_bit_value(value,7,0);
        outb(value,addr);  // 写
}

ssize_t get_main_watchdog_enable_status(char *buf, size_t count)
{
    int addr,value;
    addr = BASE_REG_ADDR_WD_EN;
    value=inb(addr);
    value = get_bit_value(value,0);   //看最后一位
    return sprintf(buf,"%02X\n", value);
}
EXPORT_SYMBOL(get_main_watchdog_enable_status);

int set_main_watchdog_enable_status(int status)
{
    int addr,value;
    addr = BASE_REG_ADDR_WD_EN;
    value = inb(addr);
    switch(status)
    {
        case 0:
            value = set_bit_value(value,0,0);
            outb(value,addr);
            break;
        case 1:
            value = set_bit_value(value,0,1);
            outb(value,addr);
            feed_watchdog();
            break;
        default:
            return -ENOSYS;
    }
    return status;
}
EXPORT_SYMBOL(set_main_watchdog_enable_status);


/******************************************************************************new enable node***********************************/
ssize_t get_watchdog_enable_status(struct device *dev, struct device_attribute *attr, char *buf)
{
    size_t count=0;
    return get_main_watchdog_enable_status(buf, count);
}
static ssize_t set_watchdog_enable_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    int value,rc = 0;
    rc = kstrtoint(buf,10,&value);
    if (rc != 0) {
        return size;
    }
    set_main_watchdog_enable_status(value);
    return size;
}
static struct device_attribute watchdog_enable_attr = __ATTR(enable, S_IRUGO | S_IWUSR,get_watchdog_enable_status,set_watchdog_enable_status);


/****************************************************************************new timeout node*******************************/
ssize_t get_watchdog_timeout(struct device *dev, struct device_attribute *attr, char *buf)
{
    return get_main_watchdog_timeout(buf,NULL);
}
static ssize_t set_watchdog_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    int value,rc = 0;
    rc = kstrtoint(buf,10,&value);
    if (rc != 0) {
        return size;
    }
    set_main_watchdog_timeout(value);
    return size;
}
static struct device_attribute watchdog_timeout_attr = __ATTR(timeout, S_IRUGO | S_IWUSR,get_watchdog_timeout,set_watchdog_timeout);


/******************************************************************************new feed node*******************************/
static ssize_t hq_set_watchdog_feed(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    int data,rc = 0;
    rc = kstrtoint(buf,16,&data);
    if (rc != 0) {
        return size;
    }
    // printk(KERN_INFO "Baseboard CPLD addr BASE_REG_ADDR_WD_KICK :%.2x,value: %.2x \n",BASE_REG_ADDR_WD_KICK,data);
    if(data==0x7c)
    {
        outb(data,BASE_REG_ADDR_WD_KICK);
        // printk(KERN_INFO "Baseboard CPLD feed dog getreg value : %.2x \n",inb(BASE_REG_ADDR_WD_KICK));
    }
    else
    {
        return -EINVAL;
    }
    return size;
}
static struct device_attribute watchdog_feed_attt = __ATTR(feed, S_IRUGO | S_IWUSR, NULL, hq_set_watchdog_feed);


/************************************************************************new strategy node*******************************/
ssize_t hq_get_watchdog_strategy(struct device *dev, struct device_attribute *attr, char *buf)
{
    return sprintf(buf,"%0.2x\n",inb(BASE_REG_ADDR_WD_FOUN));
}
static ssize_t hq_set_watchdog_strategy(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    int data,rc = 0;
    rc = kstrtoint(buf,16,&data);
    if (rc != 0) {
        return size;
    }
    if((data==0x01) || (data ==0x02))
    {
        outb(data,BASE_REG_ADDR_WD_FOUN);
        // printk(KERN_INFO " hq_set_watchdog_strategy addr value : %.2x \n",inb(BASE_REG_ADDR_WD_FOUN));
    }
    else
    {
        return -EINVAL;
    }
    return size;
}
static struct device_attribute watchdog_strategy_attr = __ATTR(strategy, S_IRUGO | S_IWUSR,hq_get_watchdog_strategy ,hq_set_watchdog_strategy);


/********************************************************************new timeout_counts node*******************************/
ssize_t hq_get_watchdog_timeout_times(struct device *dev, struct device_attribute *attr, char *buf)
{
    return sprintf(buf,"%d\n",inb(BASE_REG_ADDR_WD_STAE));
}
static struct device_attribute watchdog_timeout_counts_attr = __ATTR(timeout_counts, S_IWUSR|S_IRUGO,hq_get_watchdog_timeout_times, NULL);


/********************************************************************new timeout_reset node*******************************/
static ssize_t hq_set_watchdog_timeout_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    int data,rc = 0;
    rc = kstrtoint(buf,16,&data);
    if (rc != 0) {
        return size;
    }
    if(data==1)
    {
        outb(data,BASE_REG_ADDR_WD_KICK);
    }
    else
    {
        return -EINVAL;
    }
    return size;
}
static struct device_attribute watchdog_timeout_reset_attr = __ATTR(timeout_reset, S_IRUGO | S_IWUSR,NULL ,hq_set_watchdog_timeout_reset);

static struct attribute *watchdog_dir_attrs[] = {
    &watchdog_enable_attr.attr,
    &watchdog_timeout_attr.attr,
    &watchdog_feed_attt.attr,
    &watchdog_strategy_attr.attr,
    &watchdog_timeout_counts_attr.attr,
    &watchdog_timeout_reset_attr.attr,
    NULL
};

static struct attribute_group watchdog_attr_group = {   // 在下面cpld_hq_drv_probe函数里: kobject_create_and_add, sysfs_create_group
    .attrs = watchdog_dir_attrs,
};
/******************************************************watchdog end*********************************************************************************/

/******************************************************sysled begain*******************************************************************************/
int set_sysled_state(int status,char *names)
{
    int addr,value;
    if(strcmp(names,"PSU")==0)
    {
        addr=PSU_LED_ADDR;
    }
    else if(strcmp(names,"SYS")==0)
    {
        addr=SYS_LED_ADDR;
    }
    else if(strcmp(names,"Alarm")==0)
    {
       addr=Alarm_LED_ADDR;
    }
    else if(strcmp(names,"Fan")==0)
    {
        addr=Fan_LED_ADDR;
    }
    else if(strcmp(names,"BMC")==0)
    {
        addr=BMC_LED_ADDR;
    }
    else
    {
        return -ENOSYS;
    }
    value=inb(addr);
    switch(status)
    {
        case DARK:
                value=set_bit_value(value,6,1);
                value=set_bit_value(value,0,1);
                value=set_bit_value(value,1,0);
                outb(value,addr);
                // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",addr,inb(addr));
                break;
        case GREEN:
                value=set_bit_value(value,6,1);
                value=set_bit_value(value,4,0);
                value=set_bit_value(value,5,0);
                value=set_bit_value(value,1,0);
                value=set_bit_value(value,0,0);
                outb(value,addr);
                // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",addr,inb(addr));
                break;
        case YELLOW:
                value=set_bit_value(value,6,1);
                value=set_bit_value(value,4,1);
                value=set_bit_value(value,5,0);
                value=set_bit_value(value,1,0);
                value=set_bit_value(value,0,0);
                outb(value,addr);
                // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",addr,inb(addr));
                break; 
        case RED:
                return -ENOSYS;
        case BLUE:
                return -ENOSYS;
        case GREEN_LIGHT_FLASHING:
                value=set_bit_value(value,6,1);
                value=set_bit_value(value,4,0);
                value=set_bit_value(value,5,0);
                value=set_bit_value(value,1,1);
                value=set_bit_value(value,0,0);
                outb(value,addr);
                // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",addr,inb(addr));
                break;
        case YELLOW_LIGHT_FLASHING:
                value=set_bit_value(value,6,1);
                value=set_bit_value(value,4,1);
                value=set_bit_value(value,5,0);
                value=set_bit_value(value,1,1);
                value=set_bit_value(value,0,0);
                outb(value,addr);
                // printk(KERN_INFO "Baseboard CPLD addr:%.2x ,value: %.2x \n",addr,inb(addr));
                break;
        case RED_LIGHT_FLASHING:
                return -ENOSYS;
        case BLUE_LIGHT_FLASHING:
                return -ENOSYS;
        default:
            return -ENOSYS;
    }
    return 1;
}
EXPORT_SYMBOL(set_sysled_state);

ssize_t get_sysled_state(char *buf, size_t count,char *names)
{
    int addr,value;
    int len=-1;
    if(strcmp(names,"PSU")==0)
    {
        addr=PSU_LED_ADDR;
    }
    else if(strcmp(names,"SYS")==0)
    {
        addr=SYS_LED_ADDR;
    }
    else if(strcmp(names,"Alarm")==0)
    {
       addr=Alarm_LED_ADDR;
    }
    else if(strcmp(names,"Fan")==0)
    {
        addr=Fan_LED_ADDR;
    }
    else if(strcmp(names,"BMC")==0)
    {
        addr=BMC_LED_ADDR;
    }
    else
    {
        return -ENOSYS;
    }
    value=inb(addr);
    if(get_bit_value(value,0)==1 && get_bit_value(value,1)==0)
    {
        len=sprintf(buf,"dark\n");
        return len;
    }
    else if(get_bit_value(value,0)==0 && get_bit_value(value,1)==0)
    {
        //buf chang liang 常亮
        if(get_bit_value(value,4)==0 && get_bit_value(value,5)==0)
        {
            len=sprintf(buf,"green\n");
            return len;
        }
        else if(get_bit_value(value,4)==1 && get_bit_value(value,5)==0)
        {
            len=sprintf(buf,"yellow\n");
            return len;
        }
        else
        {
            ;
        }
    }
    else if(get_bit_value(value,0)==0 && get_bit_value(value,1)==1)
    {
        //buf 闪烁
        if(get_bit_value(value,4)==0 && get_bit_value(value,5)==0)
        {
            len=sprintf(buf,"green light flashing\n");
            return len;
        }
        else if(get_bit_value(value,4)==1 && get_bit_value(value,5)==0)
        {
            len=sprintf(buf,"yellow light flashing\n");
            return len;
        }
        else
        {
                ;
        }
    }
    else
    {
        return -ENOSYS;
    }
}
EXPORT_SYMBOL(get_sysled_state);

int get_bit_value(int value,int bit)
{
    if(value<0 || value>0xff || bit<0 || bit>7)
    {
        return -1;
    }
    int data ;
    data=value >> bit & 0x01;    // 右移bit位并取最后一位
    return data;
}

int set_bit_value(int value,int bit,int status)
{
    if(value<0 || value>0xff || bit<0 || bit>7|| status<0 || status>1)
    {
        return -1;
    }
    else
    {
        if(status==0)  //将1111 1111第二位(从0开始即第三位)置为0
        {
            value=(~(1<<bit)) & value;      //0000 0100 (1<<2)     1111 1011 & 1111 1111  =  1111 1011 (&:有0为0)
            return value;
        }
        else if(status==1)  //将0001 0001第二位(从0开始即第三位)置为1
        {
           value = (1<<bit) | value;       //0000 0100 (1<<2)      0000 0100 | 0001 0001  =  0001 0101 (|:有1为1)
           return value;
        }
        else
        {
            ;
        }
    }
}
/*****************************************************sysled end*************************************************************************************/

/***********************************************CPLD begain*******************************************************************************************/
int get_board_cpld_number(void)
{
    /* add vendor codes here */
    return CPLD_TOTAL_NUMBER;
}
EXPORT_SYMBOL(get_board_cpld_number);

/*
 * demo_get_main_board_cpld_alias - Used to identify the location of cpld,
 * @cpld_index: start with 1
 * @buf: Data receiving buffer
 * @count: length of buf
 *
 * This function returns the length of the filled buffer,
 * if not support this attributes filled "NA" to buf,
 * otherwise it returns a negative value on failed.
 */
ssize_t get_board_cpld_alias(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    int len = -1 ;
    switch(cpld_index)
    {
        case 1 :
            len=sprintf(buf,"Base board CPLD\n");
            break ;
        case 2 :
            len=sprintf(buf,"Come CPLD\n");
            break ;
        default:
            len = -1 ;
            break;
    }
    return len;
}
EXPORT_SYMBOL(get_board_cpld_alias);

/*
 * demo_get_main_board_cpld_type - Used to get cpld model name
 * @cpld_index: start with 1
 * @buf: Data receiving buffer
 * @count: length of buf
 *
 * This function returns the length of the filled buffer,
 * if not support this attributes filled "NA" to buf,
 * otherwise it returns a negative value on failed.
 */
ssize_t get_board_cpld_type(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    int len = -1 ;
    switch(cpld_index)
    {
        case 1 :
            len=sprintf(buf,"LCMXO3LF-4300C-5BG400C CPLD\n");
            break ;
        case 2 :
            len=sprintf(buf,"LCMXO3LF-2100C-5BG400C CPLD\n");
            break ;
        default:
            len = -1 ;
            break;
    }

    return len;
}
EXPORT_SYMBOL(get_board_cpld_type);

/*
 * demo_get_main_board_cpld_firmware_version - Used to get cpld firmware version,
 * @cpld_index: start with 1
 * @buf: Data receiving buffer
 * @count: length of buf
 *
 * This function returns the length of the filled buffer,
 * if not support this attributes filled "NA" to buf,
 * otherwise it returns a negative value on failed.
 */
ssize_t get_board_cpld_firmware_version(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    int len = -1; 
    switch(cpld_index){
        case 1:
            printk(KERN_INFO "BASE CPLD H version:0x%2.2x\n", inb(BASE_H_VER_ADDR));
            printk(KERN_INFO "BASE CPLD M version:0x%2.2x\n", inb(BASE_M_VER_ADDR));
            printk(KERN_INFO "BASE CPLD L version:0x%2.2x\n", inb(BASE_L_VER_ADDR));	
            len = sprintf(buf,"%x.%x.%x\n", inb(BASE_H_VER_ADDR),inb(BASE_M_VER_ADDR),inb(BASE_L_VER_ADDR));
            break;
        case 2:
            printk(KERN_INFO "COME CPLD H version:0x%2.2x\n", inb(COME_H_VER_ADDR));
            printk(KERN_INFO "COME CPLD M version:0x%2.2x\n", inb(COME_M_VER_ADDR));
            printk(KERN_INFO "COME CPLD L version:0x%2.2x\n", inb(COME_L_VER_ADDR));
            len = sprintf(buf,"%x.%x.%x\n", inb(COME_H_VER_ADDR),inb(COME_M_VER_ADDR),inb(COME_L_VER_ADDR));	
            break;
        default:
            len = -1;
            break;
    }

    return len;
}
EXPORT_SYMBOL(get_board_cpld_firmware_version);

/*
 * demo_get_main_board_cpld_board_version - Used to get cpld board version,
 * @cpld_index: start with 1
 * @buf: Data receiving buffer
 * @count: length of buf
 *
 * This function returns the length of the filled buffer,
 * if not support this attributes filled "NA" to buf,
 * otherwise it returns a negative value on failed.
 */
ssize_t get_board_cpld_board_version(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    int len = -1; 
    switch(cpld_index){
        case 1:
            len = sprintf(buf,"%02X\n", inb(BASE_PCB_VER_ADDR));
            break;
        case 2:
            len = sprintf(buf,"%02X\n", inb(COME_PCB_VER_ADDR));
            break;
        default:
            len = -1;
            break;
    }

    return len;
}
EXPORT_SYMBOL(get_board_cpld_board_version);

/*
 * demo_get_main_board_cpld_test_reg - Used to test cpld register read
 * filled the value to buf, value is hexadecimal, start with 0x
 * @cpld_index: start with 1
 * @buf: Data receiving buffer
 * @count: length of buf
 *
 * This function returns the length of the filled buffer,
 * if not support this attributes filled "NA" to buf,
 * otherwise it returns a negative value on failed.
 */
ssize_t get_board_cpld_test_reg(unsigned int cpld_index, char *buf, size_t count)
{
    /* add vendor codes here */
    int len = -1 ;
    switch(cpld_index)
    {
        case 1 :
            len=sprintf(buf,"%02x\n",inb(BASE_SCRATCH_ADDR));
            break ;
        case 2 :
            len=sprintf(buf,"%02x\n",inb(COME_SCRATCH_ADDR));
            break ;
        default:
            len = -1 ;
            break;
    }

    return len;
}
EXPORT_SYMBOL(get_board_cpld_test_reg);

/*
 * demo_set_main_board_cpld_test_reg - Used to test cpld register write
 * @cpld_index: start with 1
 * @value: value write to cpld
 *
 * This function returns 0 on success,
 * otherwise it returns a negative value on failed.
 */
int set_board_cpld_test_reg(unsigned int cpld_index, unsigned int value)
{
    /* add vendor codes here */
    int ret = -1 ;
    switch(cpld_index)
    {
        case 1 :
            outb(value,BASE_SCRATCH_ADDR);
            ret = 1;
            break ;
        case 2 :
            outb(value,COME_SCRATCH_ADDR);
            ret = 1;
            break ;
        default: 
            ret = -1 ;
            break;
    }

    return ret;
}
EXPORT_SYMBOL(set_board_cpld_test_reg);
/********************************************************CPLD end***********************************************************************/

struct cpld_hq_data {
    struct mutex       cpld_lock;
    uint16_t           read_addr;
	uint16_t		   base_addr;
};

struct cpld_hq_data *cpld_data;

static ssize_t get_cpld_reg_address(struct device *dev, struct device_attribute *attr, char *buf)
{
    int len = 0;
    // CPLD register is one byte
    mutex_lock(&cpld_data->cpld_lock);
    len = sprintf(buf, "0x%2.2x\n",inb(cpld_data->read_addr));
    mutex_unlock(&cpld_data->cpld_lock);
    return len;
}

/**
 * Store the register address
 * @param  buf     address wanted to be read value of
 * @return         number of bytes stored, or an error code
 */
static ssize_t set_cpld_reg_address(struct device *dev, struct device_attribute *devattr,
                                    const char *buf, size_t count)
{
    uint32_t addr;
    char *last;

	mutex_lock(&cpld_data->cpld_lock);
    addr = (uint32_t)strtoul(buf, &last, 16);
    if (addr == 0 && buf == last) {
        return -EINVAL;
    }
	
    cpld_data->read_addr = cpld_data->base_addr + addr;
	mutex_unlock(&cpld_data->cpld_lock);
    return count;
}

static DEVICE_ATTR( getreg, 0600, get_cpld_reg_address, set_cpld_reg_address);

static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr,
                const char *buf, size_t count)
{
    // CPLD register is one byte
    uint16_t addr;
    uint8_t value;
    char *tok;
    char clone[count+1];
    char *pclone = clone;
    char *last;

    strcpy(clone, buf);

    mutex_lock(&cpld_data->cpld_lock);
    tok = strsep((char**)&pclone, " ");
    if(tok == NULL){
        mutex_unlock(&cpld_data->cpld_lock);
        return -EINVAL;
    }
    addr = (uint16_t)strtoul(tok, &last,16);
    if(addr == 0 && tok == last){
        mutex_unlock(&cpld_data->cpld_lock);
        return -EINVAL;
    }

    tok = strsep((char**)&pclone, " ");
    if(tok == NULL){
        mutex_unlock(&cpld_data->cpld_lock);
        return -EINVAL;
    }
    value = (uint8_t)strtoul(tok, &last,16);
    if(value == 0 && tok == last){
        mutex_unlock(&cpld_data->cpld_lock);
        return -EINVAL;
    }

    outb(value, cpld_data->base_addr + addr);
    mutex_unlock(&cpld_data->cpld_lock);
    return count;
}
//static DEVICE_ATTR_WO(setreg);
static DEVICE_ATTR( setreg, 0200, NULL , setreg_store);	
/**
 * Read all CPLD register in binary mode.
 * @return number of byte read.
 */
static ssize_t dump_read(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
{
    unsigned long i = 0;
    ssize_t status;

    mutex_lock(&cpld_data->cpld_lock);
    begin:
        if(i < count){
            buf[i++] = inb(VERSION_ADDR + off);
            off++;
            msleep(1);
            goto begin;
        }
        status = count;
    exit:
        mutex_unlock(&cpld_data->cpld_lock);
    return status;
}
				
static BIN_ATTR_RO(dump, CPLD_REGISTER_SIZE);

static struct attribute *cpld_hq_attrs[] = {
    &dev_attr_getreg.attr,
    &dev_attr_setreg.attr,
    NULL,
};

static struct bin_attribute *cpld_hq_bin_attrs[] = {
    &bin_attr_dump,
    NULL,
};

static struct attribute_group cpld_hq_attrs_group = {
    .attrs = cpld_hq_attrs,
    .bin_attrs = cpld_hq_bin_attrs,
};

static struct resource cpld_hq_resources[] = {
    {
        .start  = 0xA100,
        .end    = 0xA1FF,
        .flags  = IORESOURCE_IO,
    },
};

static void cpld_hq_dev_release( struct device * dev)
{
    return;
}

static struct platform_device cpld_hq_dev = {
    .name           = CPLD_DRIVER_NAME,
    .id             = -1,
    .num_resources  = ARRAY_SIZE(cpld_hq_resources),
    .resource       = cpld_hq_resources,
    .dev = {
        .release = cpld_hq_dev_release,
    }
};

static int cpld_hq_drv_remove(struct platform_device *pdev)
{
    sysfs_remove_group(&pdev->dev.kobj, &cpld_hq_attrs_group);
    return 0;
}

static struct kobject *watchdog = NULL;
static int cpld_hq_drv_probe(struct platform_device *pdev)
{
    struct resource *resource;
    int err = 0;
    
    cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct cpld_hq_data), GFP_KERNEL);
    if(!cpld_data)
        return -ENOMEM;
    
    mutex_init(&cpld_data->cpld_lock);
	
    cpld_data ->read_addr = VERSION_ADDR;
	cpld_data ->base_addr = BASE_CPLD_ADDR;
	
    resource = platform_get_resource(pdev, IORESOURCE_IO, 0);
    if(unlikely(!resource))
    {
        printk(KERN_ERR "Specified Resource Not Available...\n");
        return -ENODEV;
    }

    err = sysfs_create_group(&pdev->dev.kobj, &cpld_hq_attrs_group);
    if(err) {
        printk(KERN_ERR "Cannot create sysfs for system CPLD\n");
        return err;
    }

	printk(KERN_INFO "CPLD Probe driver");
    printk(KERN_INFO "BASE CPLD Address:ox%2.2x\n", BASE_CPLD_ADDR);
	printk(KERN_INFO "COMe CPLD Address:ox%2.2x\n", COME_CPLD_ADDR);
	
    printk(KERN_INFO "BASE CPLD PCB version:0x%2.2x\n", inb(BASE_PCB_VER_ADDR));
    printk(KERN_INFO "BASE CPLD H version:0x%2.2x\n", inb(BASE_H_VER_ADDR));
    printk(KERN_INFO "BASE CPLD M version:0x%2.2x\n", inb(BASE_M_VER_ADDR));
    printk(KERN_INFO "BASE CPLD L version:0x%2.2x\n", inb(BASE_L_VER_ADDR));

	printk(KERN_INFO "COME CPLD PCB version:0x%2.2x\n", inb(COME_PCB_VER_ADDR));
    printk(KERN_INFO "COME CPLD H version:0x%2.2x\n", inb(COME_H_VER_ADDR));
    printk(KERN_INFO "COME CPLD M version:0x%2.2x\n", inb(COME_M_VER_ADDR));
    printk(KERN_INFO "COME CPLD L version:0x%2.2x\n", inb(COME_L_VER_ADDR));	

    printk(KERN_INFO "GPIO base address:0x%x\n", inl(0x48));

    //watchdog
    watchdog = kobject_create_and_add("watchdog",&pdev->dev.kobj);
    if (!watchdog)
    {
        return -ENOMEM;
    }
    if(sysfs_create_group(watchdog,&watchdog_attr_group))
    {
        printk(KERN_INFO"watchdog_attr_group failed\n");
        return -1;
    }
    /*
    int ret;
    ret=watchdog_root_create();
    if (ret < 0) 
    {
        WDT_ERR("watchdog create error.\n");
        return ret;
    }
    */
    return 0;
    
}

static struct platform_driver cpld_hq_drv = {
    .probe = cpld_hq_drv_probe,
    .remove = __exit_p(cpld_hq_drv_remove),
    .driver = {
        .name = CPLD_DRIVER_NAME,
    },
};


static int __init cpld_hq_init(void)
{
    /*Register Platform device and Platform Driver*/
    platform_device_register(&cpld_hq_dev);
    platform_driver_register(&cpld_hq_drv);
	printk(KERN_INFO "%s: version %s loaded successfully\n", CPLD_DRIVER_NAME, CPLD_DRIVER_VER);
	return 0;
}

static void __exit cpld_hq_exit(void)
{
    /*Unregister Platform device and Platform Driver*/
    platform_driver_unregister(&cpld_hq_drv);
    platform_device_unregister(&cpld_hq_dev);
	printk(KERN_INFO "%s: unloaded successfully\n", CPLD_DRIVER_NAME);
}

module_init(cpld_hq_init);
module_exit(cpld_hq_exit);

MODULE_AUTHOR("Huaqin Technology Co.,Ltd.");
MODULE_DESCRIPTION("Hua Qin Common CPLD");
MODULE_VERSION(CPLD_DRIVER_VER);
MODULE_LICENSE("GPL");

// i2c-ocores.c
struct ocores_i2c {
	int prescale; //属性
};

static ssize_t i2c_clk_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct ocores_i2c *i2c_test = dev_get_drvdata(dev);
	if(i2c_test->prescale==0xe0)
	{
		return sprintf(buf,"100\n");
	}
	else if(i2c_test->prescale==0x71)
	{
		return sprintf(buf,"200\n");
	}
	else if(i2c_test->prescale==0x36)
	{
		return sprintf(buf,"400\n");
	}
	else
	{
		return sprintf(buf,"please echo 100/200/400 hz bus clk \n");
	}
}

static ssize_t i2c_clk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
	ssize_t status;
	int value;
    struct ocores_i2c *i2c_test = dev_get_drvdata(dev);
	i2c_test->prescale=0xe6;
	u8 ctrl = oc_getreg(i2c_test, OCI2C_CONTROL);

	// printk(KERN_INFO "into set                            \n");
	status = kstrtoint(buf,10,&value);
	if(value==100)
	{
		i2c_test->prescale=0xe0;
		// dev_info(dev, "----------------------------100-------------------------\n");
	}
	else if(value==200)
	{
		i2c_test->prescale=0x71;
		// dev_info(dev, "----------------------------200-------------------------\n");
	}
	else if(value==400)
	{
		i2c_test->prescale=0x36;
		// dev_info(dev, "----------------------------400-------------------------\n");
	}
	else
	{
		dev_info(dev, "This I2C bus frequency cannot be provided\n");
		return -EINVAL;
	}
	
	//printk(KERN_INFO "out   if   code                          \n");
	oc_setreg(i2c_test, OCI2C_PRELOW, i2c_test->prescale & 0xff);
	oc_setreg(i2c_test, OCI2C_PREHIGH, i2c_test->prescale >> 8);
	oc_setreg(i2c_test, OCI2C_CMD, OCI2C_CMD_IACK);  /* Init the device */
	oc_setreg(i2c_test, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN);

	u8 data = oc_getreg(i2c_test,OCI2C_PRELOW);
	printk(KERN_INFO "OCI2C_PRELOW:  %x\n",data);
	u8 data1 =oc_getreg(i2c_test,OCI2C_PREHIGH);
	printk(KERN_INFO "OCI2C_PREHIGH:  %x\n",data1);
	u8 data2 = oc_getreg(i2c_test,OCI2C_CMD);
	printk(KERN_INFO "OCI2C_CMD:  %x\n",data2);
	u8 data3 =oc_getreg(i2c_test,OCI2C_CONTROL);
	printk(KERN_INFO "OCI2C_CONTROL:  %x\n",data3);

	// dev_info(dev, "Address: %lx\n", i2c_test->base);
	// dev_info(dev, "Prescale: %d\n", i2c_test->prescale);
	// printk(KERN_INFO "                   end                          \n");
	return size;
}
struct device_attribute i2c_ocores_test = __ATTR(i2c_bus_freq, 0600, i2c_clk_show,i2c_clk_store);

static struct attribute *i2c_ocores_dttrs[] = {
    &i2c_ocores_test.attr,
    NULL,
};

static struct attribute_group ocores_attr_test = {  // ocores_attr_test 在ocores_i2c_probe函数里即845行添加节点
    .attrs = i2c_ocores_dttrs ,
};

static void i2c_ocores_dev_release(struct device * dev)
{
	return;
}

/******************create /sys/bus/platform/device/ocores-i2c-hq.1***********************/
static struct platform_device i2c_ocores_dev = {
    .name           = "ocores-i2c-hq",
    .id             = -1,
    .num_resources  = 0,
    .dev = {
        .release = i2c_ocores_dev_release,
    }
};

static int ocores_i2c_probe(struct platform_device *pdev)
{
	struct ocores_i2c_platform_data *pdata;
	struct resource *res;
	struct ocores_i2c *i2c_test;
	int irq;
	int ret;
	int i;

	i2c_test = devm_kzalloc(&pdev->dev, sizeof(*i2c_test), GFP_KERNEL);
	if (!i2c_test)
		return -ENOMEM;

	dev_set_drvdata(&pdev->dev, i2c_test); //
	spin_lock_init(&i2c_test->process_lock);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res) {
		i2c_test->base = devm_ioremap_resource(&pdev->dev, res);
		printk(KERN_INFO "---------------------------------------------ocore Address-------------------------------: %lx\n", i2c_test->base);
		// dev_info(pdev,"ocore Address: %lx\n", i2c_test->base);
		if (IS_ERR(i2c_test->base))
			return PTR_ERR(i2c_test->base);

	/*******************************************create i2c_bus_freq****************************************/
	int err = 0;
	err = sysfs_create_group(&pdev->dev.kobj,&ocores_attr_test); 
	if(err)
	{
		printk(KERN_ERR "Cannot create sysfs for system I2C\n");
		return err;
	}
	return 0;

err_clk:
	clk_disable_unprepare(i2c_test->clk);
	return ret;
}

script

s3ip_sysfs_tool.sh

#! /bin/bash
s3ip_link_hq(){
    sudo rm -rf /usr/local/s3ip/
    sudo mkdir /usr/local/s3ip
    ln -s /sys/bus/i2c/devices/i2c-0/0-0056/eeprom /usr/local/s3ip/syseeprom
    mkdir /usr/local/s3ip/transceiver
    for((i=1;i<=32;i++));
    do
      mkdir /usr/local/s3ip/transceiver/eth$i
      # /sys_switch (s3ip_load.py和.json) 软连接到 /usr/local 再软连接到 /sys/s3ip
      ln -s /sys/bus/i2c/devices/$((36+i))-0050/eeprom /usr/local/s3ip/transceiver/eth$i/eeprom
      ln -s /sys/s3ip/transceiver/eth$i/interrupt /usr/local/s3ip/transceiver/eth$i/interrupt
      ln -s /sys/s3ip/transceiver/eth$i/power_on /usr/local/s3ip/transceiver/eth$i/power_on
      ln -s /sys/s3ip/transceiver/eth$i/reset /usr/local/s3ip/transceiver/eth$i/reset
      ln -s /sys/s3ip/transceiver/eth$i/tx_disable /usr/local/s3ip/transceiver/eth$i/tx_disable
      ln -s /sys/s3ip/transceiver/eth$i/low_power_mode /usr/local/s3ip/transceiver/eth$i/low_power_mode
      ln -s /sys/s3ip/transceiver/eth$i/present /usr/local/s3ip/transceiver/eth$i/present
      ln -s /sys/s3ip/transceiver/eth$i/rx_los /usr/local/s3ip/transceiver/eth$i/rx_los
      ln -s /sys/s3ip/transceiver/eth$i/tx_fault //usr/local/s3ip/transceiver/eth$i/tx_fault
    done
}

s3ip_start(){
        sudo insmod /lib/modules/s3ip/s3ip_sysfs.ko
        sudo insmod /lib/modules/s3ip/syseeprom_device_driver.ko
        sudo insmod /lib/modules/s3ip/fan_device_driver.ko
        sudo insmod /lib/modules/s3ip/cpld_device_driver.ko
        sudo insmod /lib/modules/s3ip/sysled_device_driver.ko
        sudo insmod /lib/modules/s3ip/psu_device_driver.ko
        sudo insmod /lib/modules/s3ip/transceiver_device_driver.ko
        sudo insmod /lib/modules/s3ip/temp_sensor_device_driver.ko
        sudo insmod /lib/modules/s3ip/vol_sensor_device_driver.ko
        sudo insmod /lib/modules/s3ip/fpga_device_driver.ko
        sudo insmod /lib/modules/s3ip/watchdog_device_driver.ko
        sudo insmod /lib/modules/s3ip/curr_sensor_device_driver.ko
        sudo insmod /lib/modules/s3ip/slot_device_driver.ko
        s3ip_link_hq
        sudo rm -rf /sys_switch
        sudo /usr/bin/s3ip_load.py
        echo "s3ip service start"
}
s3ip_stop(){
        sudo rmmod slot_device_driver
        sudo rmmod curr_sensor_device_driver
        sudo rmmod watchdog_device_driver
        sudo rmmod fpga_device_driver
        sudo rmmod vol_sensor_device_driver
        sudo rmmod temp_sensor_device_driver
        sudo rmmod transceiver_device_driver
        sudo rmmod psu_device_driver
        sudo rmmod sysled_device_driver
        sudo rmmod cpld_device_driver
        sudo rmmod fan_device_driver
        sudo rmmod syseeprom_device_driver
        sudo rmmod s3ip_sysfs
        sudo rm -rf /sys_switch
	echo "s3ip service stop"

}

case "$1" in
    start)
	s3ip_start
        ;;
    stop)
	s3ip_stop
	;;
    status)
        sudo tree -l /sys_switch
	;;
    restart)
	s3ip_stop
	s3ip_start
	;;	
    *)
        echo "Usage: $0 {start|stop|status|restart}"
	exit 1
esac
exit 


bmc_wtd:syscpld.c中wd_en和wd_kick节点对应寄存器,crontab,FUNCNAME

在这里插入图片描述

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

WATCHDOG_LOG="/tmp/watchdog.log"

usage(){
    program=$(basename "$0")
    echo "Usage:"
    echo "$program <operation>"
    echo "  <operation>  : start stop kick query restart"
    echo "Examples:"
    echo "  $program start"
    echo ""
}

kick()
{
    ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)
    if [ "$ret" = "0x1" ];then
        echo "0x7c" > /sys/bus/i2c/devices/0-000d/wd_kick
    else
        usage
        exit
    fi
    ret=$(date)
    echo "$ret ${FUNCNAME[0]}" >> $WATCHDOG_LOG
}

enable()
{
    ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)
    if [ "$ret" != "0x1" ];then
        echo "0x1" > /sys/bus/i2c/devices/0-000d/wd_en
    else
        usage
        exit
    fi
    ret=$(date)
    echo "$ret ${FUNCNAME[0]}" > $WATCHDOG_LOG
}

disable()
{
    ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)
    if [ "$ret" = "0x1" ];then
        echo "0x0" > /sys/bus/i2c/devices/0-000d/wd_en
        echo "0x7c" > /sys/bus/i2c/devices/0-000d/wd_kick
    else
        usage
        exit
    fi
    ret=$(date)
    echo "$ret ${FUNCNAME[0]}" >> $WATCHDOG_LOG
}

check_parameter()
{
    if [ $# -ne 1 ];then
        usage
        exit
    fi

    case ${1} in
        "start" | "stop" | "kick" |"query" |"restart")
            ;;
        *)      #除上面的其他的
            usage
            exit
            ;;
    esac
}

check_parameter "$@"

case ${1} in
    "start")
        ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)
        if [ "$ret" = "0x1" ];then
            usage
            exit
        fi
        enable
        kick
        ;;
    "stop")
        disable
        exit
        ;;
    "kick")
        kick
        exit
        ;;
    "restart")
        ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)
        if [ "$ret" = "0x1" ];then
            usage
            exit
        fi
        enable
        kick
        exit
        ;;
    "query")
        ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)
        if [ "$ret" = "0x1" ];then
            echo "ENABLE"
        else
            echo "DISABLE"
        fi
        exit
        ;;
esac

while true
do
    ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)
    if [ "$ret" = "0x1" ];then
        kick
    fi
    sleep 30
done
root@bmc-oob:~# ps | grep wd
  588 root      2904 S    runsv /etc/sv/wd
  591 root      3036 S    {wd} /bin/bash /usr/local/bin/wd start
  779 root      3036 S    grep wd
root@bmc-oob:~# wd query
ENABLE
root@bmc-oob:~# wd stop
root@bmc-oob:~# wd query
DISABLE
root@bmc-oob:~# wd restart
root@bmc-oob:~# wd kick
root@bmc-oob:~# wd query
ENABLE
init()
{
    ret=$(ps |grep crond|grep -v grep)
    if [ "x$ret" = "x" ];then
        echo "No found crond process"
        exit
    fi
    if [ ! -d /crontabs ];then
        mkdir /crontabs
        touch /crontabs/root
    fi
    crontab -c /etc/cron/crontabs/ /etc/cron/crontabs/root
    cp /var/log/watchdog.sh /usr/local/bin/watchdog.sh
}

add_task()
{
    echo "* * * * * /usr/local/bin/watchdog.sh kick" >> /etc/cron/crontabs/root
    echo "* * * * * date >> /var/log/date.log" >> /etc/cron/crontabs/root
}

del_task()
{
    sed -i "/\* \* \* \* \* \/usr\/local\/bin\/watchdog.sh kick/d" /etc/cron/crontabs/root
}

AST2500/2600 WDT切换主备:BMC用WDT2作为主备切换的watchdog控制器

AC后读取:bmc处于主primary flash(设完后:实际主,wtd1主,wtd2主)

在这里插入图片描述
如下0x100代表default flash。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

切换spi备:wtd2的2c寄存器设为0x93,换另一个flash后reboot后从备起(设完后:实际备,wtd1主,wtd2备)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下202第1位(不是第0位)和第9位置为1,发现这时确实WDT2可控,当前在备flash启动。
在这里插入图片描述

用WDT1切主:(设完后:实际备,wtd1备,wtd2备)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

用WDT2切主:(设完后:实际备,wtd1备,wtd2主)

在这里插入图片描述
在这里插入图片描述

用WDT1切主:(设完后:实际主,wtd1主,wtd2主)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

关于清空寄存器:(设完后:WTD1主,WTD2主,实际主)

在这里插入图片描述
在这里插入图片描述
wdt1和wdt2都切到备flash。
在这里插入图片描述
如下clear寄存器清除wdt1的status,保留了reset次数,但是将code source(主备)清除为0(主)。
在这里插入图片描述
再用wdt2切换主。
在这里插入图片描述
这次切到了主。
在这里插入图片描述
用wdt1切换到备。
在这里插入图片描述
清空wdt1的status。这时如果用我们的测试脚本bootsource会判断是在主,其实是在备。
在这里插入图片描述
尝试wdt1用0x13切换主,成功切到主。
在这里插入图片描述
在这里插入图片描述

结论:从主切到备,需要一个wdt的status是default也就是0的wdt,然后用0x93切换

从备切到主,需要满足两(三)个wdt中都从备切到主。比如wdt1是备,wdt2是备,那要对wdt1,wdt2都下一次0x93。如果wdt1,wdt2中一个是备,那对对应的wdt下0x93。

还有因为清空寄存器造成的虽然在备,但是wdt都是显示在主,这时候用0x13就可以切到主。用wdt2进行切换主备。避免使用清空寄存器0x14/0x34。

a=0x00000100 #256
b=$(( ((a & 0xff00) >> 8 ) ))
c=$((a & 0xff00))
d=$((a >> 8))
echo $b
echo $c
echo $d
# yutao@obmc-server:~/bak$ ./a.sh 
# 1
# 256
# 1


# 检查当前BMC是在主还是备启动的检查函数boot_source实现如下:
check_boot_source()
{
    # Please refer to reg WDT1/WDT2 Control Register definition to
    # understand this code block, WDT1 is on page 646 of ast2500v16.pdf
    # and WDT2 is on page 649 of ast2500v16.pdf

    # get watch dog1 timeout status register
    wdt1=$(devmem 0x1e785010)

    # get watch dog2 timeout status register
    wdt2=$(devmem 0x1e785030)

    wdt1_timeout_cnt=$(( ((wdt1 & 0xff00) >> 8) ))  #取出高8位,自动转为十进制
    wdt2_timeout_cnt=$(( ((wdt2 & 0xff00) >> 8) ))
    wdt1_boot_code_source=$(( ((wdt1 & 0x2) >> 1) )) #取出第1位(不是第0)
    wdt2_boot_code_source=$(( ((wdt2 & 0x2) >> 1) ))
    boot_code_source=0

    # Check both WDT1 and WDT2 to indicate the boot source
    if [ $wdt1_timeout_cnt -ge 1 ] && [ $wdt1_boot_code_source -eq 1 ]; then
        boot_code_source=1
    elif [ $wdt2_timeout_cnt -ge 1 ] && [ $wdt2_boot_code_source -eq 1 ]; then
        boot_code_source=1
    fi

    echo $boot_code_source
}

bmc_boot_info() {
    wdt1=$(devmem 0x1e785010)
    wdt2=$(devmem 0x1e785030)

    wdt1_timeout_cnt=$(( ((wdt1 & 0xff00) >> 8) ))
    wdt2_timeout_cnt=$(( ((wdt2 & 0xff00) >> 8) ))

    boot_code_source=$(check_boot_source)

    boot_source="Master Flash"
    if [ $((boot_code_source)) -eq 1 ]; then
      boot_source="Slave Flash"
    fi

    echo "WDT1 Timeout Count: " $wdt1_timeout_cnt
    echo "WDT2 Timeout Count: " $wdt2_timeout_cnt
    echo "Current BMC Boot Code Source: $boot_source"
}

bmc_boot_from() {
    # Enable watchdog reset_system_after_timeout bit and WDT_enable_signal bit.
    # Refer to ast2500v16.pdf page 650th.
    boot_source=0x00000013
    boot_code_source=$(check_boot_source)
    if [ "$1" = "master" ]; then
        if [ $((boot_code_source)) -eq 0 ]; then
            echo "Current boot source is master, no need to switch."
            return 0
        fi
        # Set bit_7 to 0 : Use default boot code whenever WDT reset.
        boot_source=0x00000033
    elif [ "$1" = "slave" ]; then
        if [ $((boot_code_source)) -eq 1 ]; then
            echo "Current boot source is slave, no need to switch."
            return 0
        fi
        # No matter BMC boot from any one of master and slave.
        # Set bit_7 to 1 : Use second boot code whenever WDT reset.
        # And the sencond boot code stands for the other boot source.
        boot_source=0x000000b3
    fi
    echo "BMC will switch to $1 after 10 seconds..."
    /usr/local/bin/watch-dog stop
    # Clear WDT1 counter and boot code source status
    devmem 0x1e785014 w 0x77
    # Clear WDT2 counter and boot code source status
    devmem 0x1e785034 w 0x77
    # Set WDT time out 10s, 0x00989680 = 10,000,000 us
    devmem 0x1e785024 32 0x00989680
    # WDT magic number to restart WDT counter to decrease.
    devmem 0x1e785028 32 0x4755
    devmem 0x1e78502c 32 $boot_source
}

BMC喂狗实现:sys/class/gpio/gpio1/value获取gpio1值

bmc喂狗gpio硬件管脚:
在这里插入图片描述
在这里插入图片描述
bmc监听gpio中断硬件管脚:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

导出GPIO:
    echo $gpio_num > /sys/class/gpio/export
    eg: echo 1 > /sys/class/gpio/export
    执行完以上命令后,如果该gpio接口存在且未被占用则会出现如下目录:/sys/class/gpio/gpio1

设置方向:
    gpio的方向分为两类:in和out
    in:表示该gpio用于输入。(如该gpio连接一个按钮)
    out:表示该gpio用于输出。(如该gpio连接一个led灯)
    指定为in模式的命令:echo in > /sys/class/gpio/gpio1/direction
    指定为out模式的命令如下:
        echo out > /sys/class/gpio/gpio1/direction //默认value为0
        echo low > /sys/class/gpio/gpio1/direction //指定方向为out且value为0
        echo high > /sys/class/gpio/gpio1/direction //指定方向为out且value为1

设置高低:
    只用当方向为out模式时才能指定gpio接口的电压的高低。这个很容易理解,因为如果是in模式的话,它的电平高低取决于所连接外设的电平高低,我们只能读取它的值,不能更改它的值
    echo 1 > /sys/class/gpio/gpio1/value //指定gpio1为高电平
    echo 0 > /sys/class/gpio/gpio1/value //指定gpio1为低电平    

在这里插入图片描述
在这里插入图片描述

watch-dog.h

在这里插入图片描述

#ifndef SENSOR_MON__h
#define SENSOR_MON__h

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h> 
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <dirent.h>
#include <stdarg.h>
#include <syslog.h>
#include <openbmc/libgpio.h>
#include <fcntl.h>
#include <stdbool.h>
#include <poll.h>
#include <ctype.h>
#include <assert.h>
#include <libgen.h>
#include <linux/limits.h>

//#define GPIO_KICK_NUM    885
//#define GPIO_KICK_NAME   "GPIOL5"
#define WDT_MASK_PATH "/sys/bus/i2c/devices/82-000d/bmc_wdt_mask"
#define GPIO_KICK_SHADOW "BMC_CPLD_GPIO69_WDO"

typedef enum {
  WD_FUNC_START,  //0
  WD_FUNC_STOP,
  WD_FUNC_KICK,
  WD_FUNC_UNKNOWN,
} wd_func;

typedef enum {
  MASK_ENABLE = 1,
  MASK_DISABLE = 0,
} wd_mask;

// 如下LOG替换syslog , syslog像printf定义在<syslog.h>, 打印在/var/log/message
#define LOG(mode,format, ...)   syslog(mode, format, __VA_ARGS__)

int bmc_wd_set(wd_mask value);
void feed_dog_func();

#endif

watch-dog.c

#include "watch-dog.h"

int bmc_wd_set(wd_mask value){   // bmc设置cpld寄存器控制wtd芯片(是外置芯片,不是bmc芯片内置的)开关
    FILE* pFile = fopen(WDT_MASK_PATH, "w");
    char regvalue[4]= {0};
    int ret = 0;
    if(value == MASK_DISABLE){ // 0
        sprintf(regvalue,"0x0");
    }else if(value == MASK_ENABLE){
        sprintf(regvalue,"0x1");
    }
    ret = fwrite(regvalue, sizeof(regvalue) , 1, pFile );  //ret为次数即fwrite中的1
    if(ret==1){
        fflush(pFile);
        ret = 0;
    }else{
        ret = -1;
    }
    fclose(pFile);
    return ret;
}

void feed_dog_func()   // bmc通过gpio的0.5s高低电平来喂狗
{
    int ret = 0;
    struct timespec n_sleep;
    n_sleep.tv_sec = 0; //secondes, integer part sleep duration    // 整数
    n_sleep.tv_nsec = 5e8L; //nanoseconds, decimal part sleep duration   // 小数  0.5s(上行整数0,这行小数5)

    gpio_desc_t* desc = gpio_open_by_shadow(GPIO_KICK_SHADOW);  // libgpio-ctrl.so中的接口
    if (!desc) {
        syslog(LOG_INFO ,"gpio_open_by_shadow fail\n");
        return ;
    }
    ret = gpio_set_direction(desc, GPIO_DIRECTION_OUT);
    if (ret == -1){
        syslog(LOG_ERR ,"gpio_change_direction err \n");
        gpio_close(desc);
        return ;
    }
    ret = gpio_set_edge(desc, GPIO_EDGE_NONE);
    if (ret == -1){
        syslog(LOG_ERR ,"gpio_change_edge err \n");
        gpio_close(desc);
        return ;
    }
//BMC启动时,喂狗(硬件gpio管脚,每隔500ms翻转一次高低电平),并关闭中断MASK如下:
//cmm cpld 0X71 地址 bit0 是中断MASK (为1时MASK使能即看门狗关闭;为0时MASK失效即看门狗打开)
//i2cset -f -y 82 0xd 0x71 0xfe 做成bmc_wdt_mask节点
    ret=bmc_wd_set(MASK_DISABLE);  // 0开wtd
    if(ret == 0){
        syslog(LOG_INFO ,"bmc_wd_set OK\n");
    }else{
        syslog(LOG_ERR ,"bmc_wd_set Fail\n");
        gpio_close(desc);
        return;
    }
    while(1)
    {
        gpio_set_value(desc,GPIO_VALUE_HIGH);
        nanosleep(&n_sleep, NULL);  // 0.5s 高电平
        gpio_set_value(desc,GPIO_VALUE_LOW);
        nanosleep(&n_sleep, NULL);   // 0.5s 低电平
    }
    gpio_close(desc);
    return ;
}

main.c

#include "watch-dog.h"

int func_start()
{
    int ret = 0;
    ret=bmc_wd_set(MASK_DISABLE);  //mask和disable都是否定
    if(ret == 0){
        syslog(LOG_INFO ,"func_start OK\n");
    }else{
        syslog(LOG_ERR ,"func_start Fail\n");
        return -1;
    }
    return 0;
}

int func_stop()
{
    int ret = 0;
    ret=bmc_wd_set(MASK_ENABLE);
    if(ret == 0){
        syslog(LOG_INFO ,"func_stop OK\n");
    }else{
        syslog(LOG_ERR ,"func_stop Fail\n");
        return -1;
    }
    return 0;
}

void usage(void)
{
    fprintf(stderr, "usage: watch-dog <start/stop/kick> \n");
    exit (1);
}

int func_kick()
{
    int rc,ret,pid_file;
    int pid_value;
    char piddata[12];
    char file_path[60];
    pthread_t tid_feed;
    ret = snprintf(file_path, sizeof(file_path), "/var/run/watch_dog.pid");  // /var/run/a 也可以,记录当前进程pid号
    if ((ret < 0) || (ret >= sizeof(file_path))) {
        syslog(LOG_ERR ,"watch_dog:too long for lockfile\n");
        return -1;
    }
    pid_file = open(file_path, O_CREAT | O_RDWR, 0666);
    if (pid_file < 0) {
        syslog(LOG_ERR ,"watch_dog: failed to acquire lock\n");
        exit(1);
    }else{
        pid_value=getpid();
        snprintf(piddata, sizeof(piddata), "%d\n", pid_value);
        ret=write(pid_file, piddata, sizeof(piddata));  //先open再write
        if(ret < 0) {
            syslog(LOG_ERR ,"watch_dog: write pid err\n");
        }
    }
    rc = flock(pid_file, LOCK_EX | LOCK_NB); // Linux文件锁flock: 检测进程是否已经存在
    if(rc)
    {
        if(EWOULDBLOCK == errno)
        {
            syslog(LOG_ERR ,"Another watch_dog instance is running...\n");
            exit(1);
        }
    }
    
    syslog(LOG_INFO ,"watch_dog: daemon started\n");
    pthread_create(&tid_feed,NULL,(void *)feed_dog_func,NULL);  //一个pthread_create只创建一个线程
    pthread_join(tid_feed,NULL);

    if (pid_file >= 0) {
        unlink(file_path);  //#include<unistd.h> , unlink删除文件
    }

    syslog(LOG_INFO ,"watch_dog: daemon end\n");
    return 0;
}

wd_func wd_func_judge(char * desc)
{
    if (!strcmp(desc, "start")){   // strcmp相同返回0,if(1)执行,shell中if(0)执行
        return WD_FUNC_START;
    }else if (!strcmp(desc, "stop")){
        return WD_FUNC_STOP;
    }else if (!strcmp(desc, "kick")){
        return WD_FUNC_KICK;
    }
    return WD_FUNC_UNKNOWN;
}


int main(int argc, char* argv[])
{
    wd_func wd_func_sel = WD_FUNC_UNKNOWN;
    if (argc != 2) {
        usage();
    }
    wd_func_sel = wd_func_judge(argv[1]);
    if ( wd_func_sel == WD_FUNC_UNKNOWN ){
        usage();
    }
    switch (wd_func_sel)
    {
        case WD_FUNC_START :
            func_start();
            break;
        case WD_FUNC_STOP :
            func_stop();
            break;
        case WD_FUNC_KICK :
            func_kick();
            break;
        default :
            break;
    }
    return 0;
}

Makefile

#
all: watch-dog
SRC = $(wildcard ./*.c)
CFLAGS += -Wall -Werror -D _XOPEN_SOURCE -pthread -lm -std=c99

watch-dog: $(SRC)
	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)

.PHONY: clean

clean:
	rm -rf *.o watch-dog

run-watch-dog.sh

exec /usr/local/bin/watch-dog kick

setup-watch-dog.sh

WDTFUNC=/usr/local/bin/watch-dog
# /etc/init.d/setup-watch-dog.sh: start and stop the watch-dog
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin:/usr/local/bin"
case "$1" in
    start)
        echo -n "Starting watch dog kick daemon..."
        runsv /etc/sv/watch-dog > /dev/null 2>&1 &  # runsv找/etc/sv/watch-dog/run文件运行
        echo "done."
        ;;
    stop)
        echo -n "Stopping watch dog daemon..."
        $WDTFUNC stop > /dev/null 2>&1 &
        echo "done."
        ;;
    *)
        echo "Usage: /etc/init.d/setup-watch-dog.sh {start|stop}"
        exit 1
        ;;
esac
exit 0

watch-dog_0.1.bb

SUMMARY = "watch dog Daemon"
DESCRIPTION = "Daemon for watch dog"
SECTION = "base"
PR = "r1"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=eb723b61539feef013de476e68b5c50a"
SRC_URI = "file://COPYING \
           file://main.c \
           file://watch-dog.c \
           file://watch-dog.h \
           file://Makefile \
           file://setup-watch-dog.sh \
           file://run-watch-dog.sh \
          "
S = "${WORKDIR}"
binfiles = "watch-dog \
           "
pkgdir = "watch-dog"
LDFLAGS = "-lgpio-ctrl"
DEPENDS += "libgpio-ctrl update-rc.d-native"
RDEPENDS_${PN} += "libgpio-ctrl bash"

install_sysv() {
  install -d ${D}${sysconfdir}/init.d
  install -d ${D}${sysconfdir}/rcS.d
  install -d ${D}${sysconfdir}/sv
  install -d ${D}${sysconfdir}/sv/watch-dog
  install -d ${D}${sysconfdir}/watch-dog
  install -m 755 setup-watch-dog.sh ${D}${sysconfdir}/init.d/setup-watch-dog.sh
  install -m 755 run-watch-dog.sh ${D}${sysconfdir}/sv/watch-dog/run  #将run-watch-dog.sh复制到/etc/sv/watch-dog/run文件里
  update-rc.d -r ${D} setup-watch-dog.sh defaults 93 5  #defaults :开机自动执行setup-watch-dog.sh start ,reboot自动执行setup-watch-dog.sh stop
}

do_install() {
  dst="${D}/usr/local/fbpackages/${pkgdir}"
  bin="${D}/usr/local/bin"
  install -d $dst
  install -d $bin
  for f in ${binfiles}; do
    install -m 755 $f ${dst}/$f
    ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f
  done
  install_sysv
}

FBPACKAGEDIR = "${prefix}/local/fbpackages"
FILES_${PN} = "${FBPACKAGEDIR}/watch-dog ${prefix}/local/bin ${sysconfdir}"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/373999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring事务的隔离级别

事务的特性: 隔离性:多个事务在并发执行的时候&#xff0c;多个事务执行的一个行为模式&#xff0c;当一个事务执行的时候&#xff0c;另一个事务执行的一个行为模式是什么&#xff1f; 1)A&#xff0c;原子性&#xff0c;一个事务中的所有操作&#xff0c;要么全部执行成功&am…

I2C误码了怎么处理

我相信不少人有遇到I2C设备识别不到&#xff0c;或者概率性误码。 我相信大部分工程师的做法如下&#xff1a; 1.调整上拉电阻的大小&#xff0c;然后重新老化测试&#xff1b; 2.降低I2C速率&#xff0c;然后老化测试&#xff1b; 3.软件加入一定判断条件&#xff0c;将能…

Ncvicat 打开sql文件方法

Nacicat打开sql文件时&#xff0c;有比较多的文章介绍可以直接打开&#xff0c;方法介绍的比较多&#xff0c;但是我遇到了一个坑&#xff0c;就是如何配置环境都无法打开。 本机环境&#xff1a; windows10 mysql 5.7.40 Navicat12.1 一、遇到问题情况 1.1、通过navicat…

Kubernetes向集群外部暴露服务的方式你知道吗?

Kubernetes向进群外暴露服务的方式有三种&#xff1a;Ingress、LoadBlancer类型的Service、NodePort类型的Service。IngressIngress相当于service的service&#xff0c;可以将外部请求通过按照不同规则转发到对应的service。实际上&#xff0c;ingress相当于一个7层的负载均衡器…

面了一个月,终于让我总结出了这份最详细的接口测试面试题

目录 1、你们公司是如何做接口测试的&#xff1f; 2、什么时候开展接⼝测试&#xff1f; 3、接⼝测试和UI测试的工作是否重复&#xff1f; 4、接口测试框架怎么搭建&#xff1f; 5、接⼝之间有依赖时怎么处理&#xff1f; 6、如何判断接⼝测试的结果&#xff08;成功或失败&a…

【C进阶】指针的高级话题

文章目录:star:1. 字符指针:star:2. 指针数组2.1 指针数组的定义2.2 指针数组的使用:star:3. 数组指针3.1 数组的地址3.2 数组指针的使用:star:4. 数组参数和指针参数:star:5. 函数指针5.1 函数名和函数的地址5.2 练习:star:6. 函数指针数组6.1 转移表:star:7. 指向函数指针数组…

昌德科技冲刺上市:计划募资约12亿元,蒋卫和为实控人

近日&#xff0c;深圳市昌德新材科技股份有限公司&#xff08;下称“昌德科技”&#xff09;递交招股书&#xff0c;准备在真真证券交易所主板上市。本次冲刺上市&#xff0c;昌德科技计划募资11.69亿元&#xff0c;中信建投证券为其保荐机构。 据招股书介绍&#xff0c;昌德科…

西电编译原理期末核心考点汇总(期末真题+相关知识点)

文章目录前言一、正规式1.1 相关知识点1.1.1 正规式定义1.1.2 辅助定义1.2 历年真题二、二义文法2.1 相关知识点2.1.1 二义性概念2.2 历年考题三、全部短语、直接短语和句柄3.1 相关知识点3.1.1 短语&#xff0c;直接短语和句柄定义3.1.2 短语&#xff0c;直接短语和句柄例题3.…

【企业管理】研发部视角提出对外支撑业务自助门户构思和实现

导读&#xff1a;公司是由不同部门组成&#xff0c;各个部门之间必然有协同才能使得公司各项职能正常运行。可以说公司的竞争力越强往往会得出公司内部之间工作协同就越高效&#xff0c;可以看出公司各部门之间协同对公司营运是十分重要的。高效协同前提必然是实现便利的信息共…

数据库设计表与表之间的关系详细介绍

文章目录数据库设计数据库设计简介表关系之一对多表关系之多对多表关系之一对一数据库设计 数据库设计简介 软件研发的步骤如下: 设计数据库还是很重要的 数据库设计概念: 数据库设计就是根据业务系统的具体需求&#xff0c;结合我们所选用的DBMS&#xff0c;为这个业务系统构…

Synology搭建Gitea(Docker)

Synology搭建Gitea(Docker) 文章目录Synology搭建Gitea(Docker)参考增加用户与用户组增加映像安装配置反向代理路由器端口转发参考 Nas轻量git方案&#xff1a;Docker安装Gitea;群晖(Synology) NAS 如何安装 gitea 增加用户与用户组 为所有Docer创建一个组docker&#xff1b; 权…

行测-判断推理-图形推理-样式规律-黑白运算

黑白元素个数不同&#xff0c;优先考虑黑白运算白白白黑黑白黑白黑选A考试时&#xff0c;这种题不要先把规律全部推出来&#xff0c;再去做题&#xff0c;太慢了直接看要推的图&#xff0c;通过排除法选答案黑白元素个数不同&#xff0c;优先考虑黑白运算白白白黑黑白黑白黑选B…

【5G RRC】5G系统消息SIB3介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

[python入门(52)] - python中的OS模块(包) - 1

目录 ❤ OS模块和path模块(函数) ❤ 当前路径及路径下的文件 ❤ 绝对路径 ❤ 查看指定文件路径的文件夹路径部分和文件名部分 ❤ 路径拼接 ❤ 获取路径的文件夹路径部分 ❤ 获取路径的文件名 ❤ 查看文件时间 ❤ 查看文件大小 ❤ 查看文件是否存在 ❤ OS模…

【原创】java+swing+mysql设备预约管理系统设计与实现

我们在办公室或者学校实验室的&#xff0c;经常需要使用一些设备&#xff0c;因此需要提前租借。今天我们主要介绍如何使用javaswing和mysql数据库去完成一个设备预约管理系统&#xff0c;方便用户进行设备管理和预约。 功能分析&#xff1a; 设备预约管理系统主要是为了方便…

医疗床头卡(基站方案)

一、产品特色 低功耗&#xff0c;常规使用3-5年电池寿命支持空中唤醒点阵电子纸屏幕安装简单&#xff0c;快速布置远程智能化管理低碳环保&#xff0c;无纸化安全可靠ESL_BWR7.5_V2二、系统结构 三、多基站组织架构 四、电子床头卡 接收路由器发送的数据信息并解析&#xff0…

深度学习之卷积神经网络学习笔记一

1. 引言深度学习是一系列算法的统称&#xff0c;包括卷积神经网络&#xff08;CNN&#xff09;&#xff0c;循环神经网络&#xff08;RNN&#xff09;&#xff0c;自编码器&#xff08;AE&#xff09;&#xff0c;深度置信网络&#xff08;DBN&#xff09;&#xff0c;生成对抗…

FreeRTOS优先级翻转

优先级翻转优先级翻转&#xff1a;高优先级的任务反而慢执行&#xff0c;低优先级的任务反而优先执行优先级翻转在抢占式内核中是非常常见的&#xff0c;但是在实时操作系统中是不允许出现优先级翻转的&#xff0c;因为优先级翻转会破坏任务的预期顺序&#xff0c;可能会导致未…

16- TensorFlow实现线性回归和逻辑回归 (TensorFlow系列) (深度学习)

知识要点 线性回归要点: 生成线性数据: x np.linspace(0, 10, 20) np.random.rand(20)画点图: plt.scatter(x, y)TensorFlow定义变量: w tf.Variable(np.random.randn() * 0.02)tensor 转换为 numpy数组: b.numpy()定义优化器: optimizer tf.optimizers.SGD()定义损失: …

利用Redis一步步实现优惠券的最终秒杀方案

订单ID不能采用自增长的原因&#xff1a; 1、规律变化太明显。两天下单的ID的差值&#xff0c;能够计算出商城的订单量&#xff1b; 2、如果采用自增长&#xff0c;订单数据是会不断产生的&#xff0c;到时候要分表&#xff0c;但是每个表的ID都是从0开始增长的&#xff0c;这…