文章目录
- 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}"