kernel_test

#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio.h>
#include <linux/kthread.h>
#include <linux/delay.h>



/**
 * 全局变量:
 *      目录指针:AntennaSwitchDir    ------>    /proc/AntennaSwitch
 *      文件指针:AntennaSwitchFile   ------>    /proc/AntennaSwitch/antsw
 *
 */
struct proc_dir_entry *AntennaSwitchDir  = NULL;
struct proc_dir_entry *AntennaSwitchFile = NULL;


/**
 * 全局变量:
 *      打印宏开关: global_debug_flag  ------>  (默认关闭)
 *
 * 打开方式:
 *      echo "debug on" > /proc/AntennaSwitch/antsw
 *
 * 关闭方式:
 *      echo "debug off" > /proc/AntennaSwitch/antsw
 *
 */
static int global_debug_flag = 0;

#define PRINTF(fmt, ...)  if(global_debug_flag) \
do { \
    printk("7777777777777777 [kernel_test.c:%d] [%s]: "fmt"\n",__LINE__, __FUNCTION__, ##__VA_ARGS__); \
} while(0)


/**
 * GPIO基准值 128
 */
#define SPECIAL_GPIO_BASE_NUM 128

/**
 * 全局变量:
 *
 *      __ANT3_DETECT   ---->   ANT3_DETECT检测 GPIO97
 *      __ANT6_DETECT   ---->   ANT6_DETECT检测 GPIO98
 *
 *     -1   读取失败
 *      0   未插入
 *      1   插入
 *
 */
static int __ANT3_DETECT = -1;
static int __ANT6_DETECT = -1;


/**
 * 全局变量:
 *      __TASK   ---> 线程的结构体 , 作用与外置天线线程检测
 *
 */
static struct task_struct * __TASK = NULL;



/**
 * 说明:
 *      设置某个管脚为输入,相当于用户空间gpio的调用
 *
 * 例如:
 *      设置GPIO(46-basenum) 引脚为输入模式
 *      echo "46"  > /sys/class/gpio/export
 *      echo "in" > /sys/class/gpio/gpio46/direction
 *
 * 返回值:
 *      成功  0
 *      失败  -1
 */
int util_set_gpio_input( unsigned int gpio )
{
    if ( gpio < 0 ) {
        PRINTF("gpio num illegal!\n");
        return -1;
    }
    
    gpio += SPECIAL_GPIO_BASE_NUM;
    
    if( gpio_request( gpio , NULL ) != 0 )
    {
        PRINTF("gpio request error!\n");
        return -1;
    }
    
    gpio_direction_input(gpio);
    gpio_free(gpio);
    
    return 0;
}


/**
 * 说明:
 *      设置某个管脚为输出,且输出value(0,1),相当于用户空间gpio的调用
 *
 * 例如:
 *      设置GPIO(46-base) 引脚为输出模式,value值为1
 *      echo "46"  > /sys/class/gpio/export
 *      echo "out" > /sys/class/gpio/gpio46/direction
 *      echo "1" > /sys/class/gpio/gpio46/value
 *
 * 返回值:
 *      成功  0
 *      失败  -1
 */
int util_set_gpio_output( unsigned int gpio , int value )
{
    if ( gpio < 0  ) {
        PRINTF("gpio num illegal!\n");
        return -1;
    }
    
    if ( 0 != value && 1 != value  ) {
        PRINTF("set value illegal!\n");
        return -1;
    }
    
    gpio += SPECIAL_GPIO_BASE_NUM;
    
    if( gpio_request(gpio,NULL) != 0 ) {
        PRINTF("gpio request error!\n");
        return -1;
    }
    
    gpio_direction_output(gpio,value);
    gpio_free(gpio);
    
    return 0;
}

/**
 * 说明:
 *      获取某个GPIO的value, 且该GPIO必须是输入模式, 相当于用户空间gpio的调用
 *
 * 例如:
 *      获取GPIO(46-base)的value
 *      cat /sys/class/gpio/gpio46/value
 *
 * 返回值:
 *      成功  0
 *      失败  -1
 */
int util_get_gpio_value( unsigned int gpio )
{
    int value = -1;
    
    if ( gpio < 0 ) {
        PRINTF("gpio num illegal!\n");
        return -1;
    }
    
    gpio += SPECIAL_GPIO_BASE_NUM;
    
    if ( gpio_request( gpio, NULL ) != 0 ) {
        PRINTF("util_get_gpio_value err\n");
        return -1;
    }
    
    value = gpio_get_value(gpio);
    
    gpio_free(gpio);
 
    return value;
}



/**
 *
 * 说明:
 *      设置天线逻辑电平通用接口
 *
 * ATN3\ANT6逻辑电平所对应的引脚使能:
 *
 * ------------------------------------------------------------------------------------
 * |                 |  逻辑电平  |       功能        |              备注                |
 * ------------------------------------------------------------------------------------
 * |                 |    11     |   底层定向天线     |                                 |
 * |      ANT3       |    01     |   顶层定向天线     |   ANT3_DETECT检测:GPIO97高电平   |
 * |  GPIO20/GPIO18  |    10     |   顶层全向天线     |     需要将GPIO20/GPIO18切换到00   |
 * |                 |    00     |   接通断头        |                                 |
 * -------------------------------------------------—----------------------------------
 * |                 |    11     |   底层定向天线     |                                 |
 * |      ANT6       |    01     |   顶层定向天线     |  ANT6_DETECT检测:GPIO98高电平    |
 * |  GPIO31/GPIO51  |    10     |   顶层全向天线     |    需要将GPIO31/GPIO51切换到00    |
 * |                 |    00     |   接通断头        |                                 |
 * ---------------------------- -------------------------------------------------------
 *
 *
 * @param:
 *      antnum  ATN天线编号 ( 范围: Ant3 、 Ant4、 Ant5、 Ant6 )
 *      antval  逻辑电平    ( 范围: 00 、 01、 11、 10 )
 *
 * 返回值:
 *      成功  0
 *      失败  -1
 *
 */
static int Antenna_number_logic_value_setting( const char *AntNum , const char *AntVal )
{
    if ( !AntNum || !AntVal ) {
        PRINTF(" Param antnum or antval is NULL \n");
        return -1;
    }
    
    if ( strcmp( AntVal , "00" ) &&
        strcmp( AntVal , "01" ) &&
        strcmp( AntVal , "10" ) &&
        strcmp( AntVal , "11" ) ) {
        
        PRINTF(" Param antval illegal \n");
        return -1;
    }
    
    if ( !strcasecmp( AntNum , "Ant3" ) ) {
        if ( 0 == util_set_gpio_output( 20 , AntVal[0] - '0' ) ) {
            PRINTF("util_set_gpio_output  gpio20  val: %d success\n" , AntVal[0] - '0' );
        }
        else {
            PRINTF("util_set_gpio_output gpio20 failed\n");
            return -1;
        }
        if ( 0 == util_set_gpio_output( 18 , AntVal[1] - '0' ) ) {
            PRINTF("util_set_gpio_output  gpio18  val: %d success\n" , AntVal[1] - '0' );
        }
        else {
            PRINTF("util_set_gpio_output gpio18 failed\n");
            return -1;
        }
	}
	else if ( !strcasecmp( AntNum , "Ant6" ) ) {
	    if ( 0 == util_set_gpio_output( 31 , AntVal[0] - '0' ) ) {
            PRINTF("set  gpio31  val: %d success\n" , AntVal[0] - '0' );
        }
        else {
            PRINTF("set gpio31 failed\n");
            return -1;
        }
        if ( 0 == util_set_gpio_output( 51 , AntVal[1] - '0' ) ) {
            PRINTF("set  gpio51  val: %d success\n" , AntVal[1] - '0' );
        }
        else {
            PRINTF("set gpio51 failed\n");
            return -1;
        }
	}
	else if ( !strcasecmp( AntNum , "Ant4" ) ) {
	    // TODO:
	    PRINTF("set Ant4 Success TODO \n");
	}
	else if ( !strcasecmp( AntNum , "Ant5" ) ) {
	    // TODO:
	    PRINTF("set Ant5 Success TODO \n");
	}
	else {
	    PRINTF(" Param antnum illegal \n");
        return -1;
	}
	
	return 0;
}



/**
 * Usaeg_Help 使用帮助:
 *
 *      在切换之前,都会判断外置天线(ANT6_DETECT\ANT3_DETECT)是否插入,
 *      如果插入,内置定向天线的切换的动作都不会操作。
 *
 *      每次cat /proc/AntennaSwitch/antsw 都会读取下GPIO97、GPIO98状态:
 *
 *      ANT3_DETECT(GPIO97)检测:
 *                  1 (高电平,外置天线ANT3插入)   OR    0 (低电平,外置天线ANT3未插入)
 *
 *      ANT8_DETECT(GPIO98)检测:
 *                  1 (高电平,外置天线ANT6插入)   OR    0 (低电平,外置天线ANT6未插入)
 *
 *
 * 返回值:
 *      成功  0
 */
static int Usaeg_Help(struct seq_file *m, void *v)
{
    int ant3_detect = util_get_gpio_value( 97 );
    int ant6_detect = util_get_gpio_value( 98 );
    
    seq_printf(m, "Antenna Switch V1.0.0 Help page\n\n"\
	                "\tInstructions for use for directional antenna switching.\n"\
                    "\tBefore switching, it will judge whether the external antenna(ANT6、ANT3) is inserted.\n"\
                    "\tIf inserted, the switching action of the built-in directional antenna will not operate.\n\n"\
                    "\tif you want to print debug info or not :\n"\
                    "\t\techo \"debug on\" > /proc/AntennaSwitch/antsw\n"\
                    "\t\techo \"debug off\" > /proc/AntennaSwitch/antsw\n\n"\
                    "\tif you want to switch antenna :\n"\
                    "\t\techo \"<antnum> <antval>\" > /proc/AntennaSwitch/antsw\n\n"\
	                "\t\t<antnum>:\n"\
                    "\t\t\tAnt3 or Ant4 or Ant5 or Ant6\n\n"\
                    "\t\t<antval>:\n"\
                    "\t\t\t00 or 01 or 10 or 11\n\n"\
                    );
                    
    if ( -1 == __ANT3_DETECT ) {
        seq_printf(m, "\tANT3_DETECT: %d\t\t%s\n\n"
                        , ant3_detect , "Read Gpio97 value error !" );
	}
	else {
	    seq_printf(m, "\tANT3_DETECT: %d\t\t%s\n\n"
                        , ant3_detect
                        , ( ant3_detect == 0 ? \
                        "Low level, external antenna ANT3 is not inserted." : \
                        "High level, external antenna ANT3 is inserted." ) );
	}
    
    if ( -1 == __ANT6_DETECT ) {
        seq_printf(m, "\tANT6_DETECT: %d\t\t%s\n\n"
                        , ant6_detect , "Read Gpio98 value error !" );
	}
	else {
	    seq_printf(m, "\tANT6_DETECT: %d\t\t%s\n\n"
                        , ant6_detect
                        , ( ant6_detect == 0 ? \
                        "Low level, external antenna ANT6 is not inserted." : \
                        "High level, external antenna ANT6 is inserted." ) );
	}

    return 0;
}

/**
 * AtnSw_Open_Proc : 对应cat的操作
 *
 * 触发方式:
 *      cat /proc/AntennaSwitch/antsw
 *
 * 返回值:
 *      成功 0
 *      失败 -1
 */
static int AtnSw_Open_Proc(struct inode *inode, struct file *file)
{
    return single_open(file, Usaeg_Help, NULL);
}


/**
 * 外置天线ANT3_DETECT逻辑:
 *      高电平时是插入,优先级最高,需要外部循环检测!
 *      检测时长 ( 3 秒 )
 *      当 __ANT3_DETECT 与上次不同时才做动作
 *
 * ANT3_DETECT检测:(GPIO97)
 *      高电平,需要将GPIO20/GPIO18切换到00
 *
 *
 * 返回值:
 *      1   ANT3 天线插入
 *      0   ANT3 天线未插入
 *     -1   读取ANT3_DETECT 失败
 */
static int External_Antenna3_Detection( void )
{
    int value = -1;
    
    value = util_get_gpio_value( 97 );
    if ( -1 == value ) {
        PRINTF( "get_gpio_value 97 failed\n" );
        return -1;
    }
    
    if ( __ANT3_DETECT != value ) {
        __ANT3_DETECT = value;
        if ( 1 == __ANT3_DETECT ) {
             if ( 0 == Antenna_number_logic_value_setting( "Ant3" , "00" ) ) {
                PRINTF("Antenna_number_logic_value_setting  Ant3 00 success\n");
            }
            else {
                PRINTF("Antenna_number_logic_value_setting  Ant3 00 failed\n");
            }
        }
    }
    
    return __ANT3_DETECT;
    
}

/**
 * 外置天线ANT6_DETECT逻辑:
 *      高电平时是插入,优先级最高,需要外部循环检测!
 *      检测时长 ( 3 秒 )
 *      当 __ANT6_DETECT 与上次不同时才做动作
 *
 * ANT6_DETECT检测:(GPIO98)
 *      高电平,需要将GPIO31/GPIO51切换到00
 *
 *
 * 返回值:
 *      1   ANT6 天线插入
 *      0   ANT6 天线未插入
 *     -1   读取ANT6_DETECT 失败
 */
static int External_Antenna6_Detection( void )
{
    int value = -1;
    
    value = util_get_gpio_value( 98 );
    if ( -1 == value ) {
        PRINTF( "get_gpio_value 98 failed\n" );
        return -1;
    }
    
    if ( __ANT6_DETECT != value ) {
        __ANT6_DETECT = value;
        if ( 1 == __ANT6_DETECT ) {
            if ( 0 == Antenna_number_logic_value_setting( "Ant6" , "00" ) ) {
                PRINTF("Antenna_number_logic_value_setting  Ant6 00 success\n");
            }
            else {
                PRINTF("Antenna_number_logic_value_setting  Ant6 00 failed\n");
            }
        }
    }
    
    return value;
}


/**
 * 说明:
 *      因为外置天线的逻辑特定,需要创建个线程在内核里循环检测。
 *      累计读取ANT3_DETECT 、ANT6_DETECT失败 30次则线程退出
 *
 *      检测时长间隔 ( 3 秒 )
 *
 * 返回值:
 *      0
 */
static int  Antenna_Cycle_detection_thread( void *data )
{
    int err_num = 0;
    
    while ( !kthread_should_stop() )
    {
        if ( -1 == External_Antenna3_Detection() )
            err_num++;
        if ( -1 == External_Antenna6_Detection() )
            err_num++;
        
        if ( 30 == err_num ) {
            PRINTF("read ANT3_DETECT or ANT6_DETECT failed 10 times in total , exit ");
            __TASK = NULL;
            break;
        }
        msleep(3000);
    }
    
    return 0;
}





/**
 * AtnSw_Write_Proc :对应echo的操作
 *
 * DEBUG:
 *      打开: echo "debug on" > /proc/AntennaSwitch/antsw
 *      关闭:  echo "debug off" > /proc/AntennaSwitch/antsw
 *
 * 天线切换:
 *      echo "AntNum AntVal"  > /proc/AntennaSwitch/antsw
 *
 * 例如:
 *      echo "Ant3 00" > /proc/AntennaSwitch/antsw
 *      echo "Ant6 00" > /proc/AntennaSwitch/antsw
 *
 *
 * ATN3\ANT6逻辑电平所对应的引脚使能:
 *
 * ------------------------------------------------------------------------------------
 * |                 |  逻辑电平  |       功能        |              备注                |
 * ------------------------------------------------------------------------------------
 * |                 |    00     |   底层定向天线     |                                 |
 * |      ANT3       |    01     |   顶层定向天线     |   ANT3_DETECT检测:GPIO97高电平   |
 * |  GPIO20/GPIO18  |    10     |   顶层全向天线     |     需要将GPIO20/GPIO18切换到00   |
 * |                 |    11     |   接通断头        |                                 |
 * -------------------------------------------------—----------------------------------
 * |                 |    00     |   底层定向天线     |                                 |
 * |      ANT6       |    01     |   顶层定向天线     |  ANT6_DETECT检测:GPIO98高电平    |
 * |  GPIO31/GPIO51  |    10     |   顶层全向天线     |    需要将GPIO31/GPIO51切换到00    |
 * |                 |    11     |   接通断头        |                                 |
 * ---------------------------- -------------------------------------------------------
 *
 * 总则:
 *      正常使用时状态要求(切换过程不在同一面):
 *      ANT3跟ANT6永远在同一面,ANT4+ANT5永远在同一面
 *
 * 例如:
 *      组合1:ANT3(前)+ANT6(前)+ANT4(左)+ANT5(左)
 *      组合2:ANT3(前)+ANT6(前)+ANT4(右)+ANT5(右)
 *      组合3:ANT3(后)+ANT6(后)+ANT4(左)+ANT5(左)
 *      组合4:ANT3(后)+ANT6(后)+ANT4(左)+ANT5(左)
 *
 *
 * 返回值:
 *      count
 *
 */
static ssize_t AtnSw_Write_Proc(struct file *file, const char *buffer,
	size_t count, loff_t *data)
{
	char valstr[64] = "";
	char AntNum[8] = "";
	char AntVal[8] = "";
	
	if( count > sizeof(valstr) ) {
	    PRINTF(" The input data is too long, illegal \n");
	    goto __AtnSw_Write_Proc_exit;
	}
	
	memcpy(valstr, buffer, count);
	valstr[count-1] = '\0';
	
	PRINTF("Antenna input data : %s\n" , valstr );
	
	if ( !strcmp( valstr , "debug on" ) ) {
	    global_debug_flag = 1;
	    PRINTF("Debug is on \n" );
	    goto __AtnSw_Write_Proc_exit;
	}
	else if ( !strcmp( valstr , "debug off" ) ) {
	    PRINTF("Debug is off \n" );
	    global_debug_flag = 0;
	    goto __AtnSw_Write_Proc_exit;
	}
	
	if ( 2 != sscanf( valstr, "%s %s", AntNum, AntVal ) ) {
		PRINTF("usage: <AntNum> <AntVal> \n");
		goto __AtnSw_Write_Proc_exit;
	}
	
	if ( __ANT3_DETECT == 1 || __ANT6_DETECT == 1 ) {
	    PRINTF("ANT3_DETECT or ANT6_DETECT is inserted , do not operate \n");
	    goto __AtnSw_Write_Proc_exit;
	}
	
	if ( !strcmp( AntVal , "00" ) ) {
	    PRINTF("Shield operations 00 , cause this part in Antenna_Cycle_detection_thread\n");
	    goto __AtnSw_Write_Proc_exit;
	}
	
	if ( 0 == Antenna_number_logic_value_setting( AntNum , AntVal ) ) {
	    PRINTF("Antenna_number_logic_value_setting  %s %s success\n" , AntNum , AntVal );
	}
	else {
	    PRINTF("Antenna_number_logic_value_setting %s %s failed \n", AntNum , AntVal );
	}
	
__AtnSw_Write_Proc_exit:
    return count;
	
}


struct file_operations AntennaSwitchProcOps =
{
	.open       = AtnSw_Open_Proc,     //对应cat
	.read       = seq_read,
	.write      = AtnSw_Write_Proc,    //对应echo
	.llseek     = seq_lseek,
	.release    = single_release,
};


/**
 *
 * AntennaSwitch_init 初始化:
 *
 *      创建目录:/proc/AntennaSwitch
 *      创建文件:/proc/AntennaSwitch/antsw 属性:0600
 *      创建线程:Antenna_Cycle_detection_thread
 *
 *          top命令查看我们在此建立的内核线程名称为 Antenna_Cycle_Detection
 *
 *
 * 触发方式:
 *      insmod kernerl_test.ko
 *
 * 返回值:
 *      成功 0
 *      失败 -1
 */
int __init AntennaSwitch_init(void)
{
    int err = -1;
    
    printk("AntennaSwitch init\n");

    AntennaSwitchDir = proc_mkdir("AntennaSwitch", NULL);
    if (NULL == AntennaSwitchDir)
    {
        printk("\n Can't create /proc/AntennaSwitch\n");
        return -1;
    }
    if (NULL == (AntennaSwitchFile = proc_create("antsw", 0600, AntennaSwitchDir, &AntennaSwitchProcOps)))
    {
        remove_proc_entry("AntennaSwitch", NULL);
        AntennaSwitchDir = NULL;
        printk("\n Can't create /proc/AntennaSwitch/antsw file\n");
        return -1;
    }
    
    __TASK = kthread_create( Antenna_Cycle_detection_thread, NULL, "Antenna_Cycle_Detection" );
    if ( IS_ERR( __TASK ) ) {
        printk("Unable to start kernel thread \n");
        err = PTR_ERR(__TASK);
        __TASK = NULL;
        return err;
    }
    wake_up_process(__TASK);
    
    return 0;
}


/**
 * AntennaSwitch_exit :
 *
 *      释放资源:
 *          目录指针:AntennaSwitchDir
 *          文件指针:AntennaSwitchFile
 *
 * 触发方式:
 *      insmod kernerl_test.ko
 *
 * 返回值:
 *      成功 0
 *      失败 -1
 */
void __exit AntennaSwitch_exit(void)
{
    PRINTF("AntennaSwitch exit\n");
    if (AntennaSwitchFile)
	{
		remove_proc_entry("antsw", AntennaSwitchDir);
		AntennaSwitchFile = NULL;
	}

    if (AntennaSwitchDir)
    {
        remove_proc_entry("AntennaSwitch", NULL);
        AntennaSwitchDir = NULL;
    }
    
    if (__TASK)
    {
        kthread_stop(__TASK);
        __TASK = NULL;
        PRINTF("kthread_stop Antenna_Cycle_detection_thread\n");
    }
}

module_init(AntennaSwitch_init);
module_exit(AntennaSwitch_exit);

MODULE_LICENSE("Dual BSD/GPL");
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/jiffies.h>



/**
 * 全局变量:
 *      目录指针:AntennaSwitchDir    ------>    /proc/AntennaSwitch
 *      文件指针:AntennaSwitchFile   ------>    /proc/AntennaSwitch/antsw
 *
 */
struct proc_dir_entry *AntennaSwitchDir  = NULL;
struct proc_dir_entry *AntennaSwitchFile = NULL;


/**
 * 全局变量:
 *      打印宏开关: global_debug_flag  ------>  (默认关闭)
 *
 * 打开方式:
 *      echo "debug on" > /proc/AntennaSwitch/antsw
 *
 * 关闭方式:
 *      echo "debug off" > /proc/AntennaSwitch/antsw
 *
 */
static int global_debug_flag = 1;

#define PRINTF(fmt, ...)  if(global_debug_flag) \
do { \
    printk("7777777777777777 [kernel_test.c:%d] [%s]: "fmt"\n",__LINE__, __FUNCTION__, ##__VA_ARGS__); \
} while(0)


/**
 * GPIO基准值 128
 */
#define SPECIAL_GPIO_BASE_NUM 128

/**
 * 全局变量:
 *
 *      __ANT3_DETECT   ---->   ANT3_DETECT检测 GPIO97
 *      __ANT6_DETECT   ---->   ANT6_DETECT检测 GPIO98
 *
 *     -1   读取失败
 *      0   未插入
 *      1   插入
 *
 */
static int __ANT3_DETECT = -1;
static int __ANT6_DETECT = -1;


/**
 * 全局变量:
 *      mytimer             定时器
 *      ERROR_NUM           读取ANT3_DETECT、ANT6_DETECT 失败次数
 *      TIMING_INTERVAL     500ms
 *      MAXNUM_FAILURES     最大失败次数
 *
 */
struct timer_list mytimer;
static int ERROR_NUM = 0;
#define TIMING_INTERVAL     500
#define MAXNUM_FAILURES     100


/**
 * 说明:
 *      设置某个管脚为输入,相当于用户空间gpio的调用
 *
 * 例如:
 *      设置GPIO(46-basenum) 引脚为输入模式
 *      echo "46"  > /sys/class/gpio/export
 *      echo "in" > /sys/class/gpio/gpio46/direction
 *
 * 返回值:
 *      成功  0
 *      失败  -1
 */
int util_set_gpio_input( unsigned int gpio )
{
    if ( gpio < 0 ) {
        PRINTF("gpio num illegal!\n");
        return -1;
    }
    
    gpio += SPECIAL_GPIO_BASE_NUM;
    
    if( gpio_request( gpio , NULL ) != 0 )
    {
        PRINTF("gpio request error!\n");
        return -1;
    }
    
    gpio_direction_input(gpio);
    gpio_free(gpio);
    
    return 0;
}


/**
 * 说明:
 *      设置某个管脚为输出,且输出value(0,1),相当于用户空间gpio的调用
 *
 * 例如:
 *      设置GPIO(46-base) 引脚为输出模式,value值为1
 *      echo "46"  > /sys/class/gpio/export
 *      echo "out" > /sys/class/gpio/gpio46/direction
 *      echo "1" > /sys/class/gpio/gpio46/value
 *
 * 返回值:
 *      成功  0
 *      失败  -1
 */
int util_set_gpio_output( unsigned int gpio , int value )
{
    if ( gpio < 0  ) {
        PRINTF("gpio num illegal!\n");
        return -1;
    }
    
    if ( 0 != value && 1 != value  ) {
        PRINTF("set value illegal!\n");
        return -1;
    }
    
    gpio += SPECIAL_GPIO_BASE_NUM;
    
    if( gpio_request(gpio,NULL) != 0 ) {
        PRINTF("gpio request error!\n");
        return -1;
    }
    
    gpio_direction_output(gpio,value);
    gpio_free(gpio);
    
    return 0;
}

/**
 * 说明:
 *      获取某个GPIO的value, 且该GPIO必须是输入模式, 相当于用户空间gpio的调用
 *
 * 例如:
 *      获取GPIO(46-base)的value
 *      cat /sys/class/gpio/gpio46/value
 *
 * 返回值:
 *      成功  0
 *      失败  -1
 */
int util_get_gpio_value( unsigned int gpio )
{
    int value = -1;
    
    if ( gpio < 0 ) {
        PRINTF("gpio num illegal!\n");
        return -1;
    }
    
    gpio += SPECIAL_GPIO_BASE_NUM;
    
    if ( gpio_request( gpio, NULL ) != 0 ) {
        PRINTF("util_get_gpio_value err\n");
        return -1;
    }
    
    value = gpio_get_value(gpio);
    
    gpio_free(gpio);
 
    return value;
}



/**
 *
 * 说明:
 *      设置天线逻辑电平通用接口
 *
 * ATN3\ANT6逻辑电平所对应的引脚使能:
 *
 * ------------------------------------------------------------------------------------
 * |                 |  逻辑电平  |       功能        |              备注                |
 * ------------------------------------------------------------------------------------
 * |                 |    11     |   底层定向天线     |                                 |
 * |      ANT3       |    01     |   顶层定向天线     |   ANT3_DETECT检测:GPIO97高电平   |
 * |  GPIO20/GPIO18  |    10     |   顶层全向天线     |     需要将GPIO20/GPIO18切换到00   |
 * |                 |    00     |   接通断头        |                                 |
 * -------------------------------------------------—----------------------------------
 * |                 |    11     |   底层定向天线     |                                 |
 * |      ANT6       |    01     |   顶层定向天线     |  ANT6_DETECT检测:GPIO98高电平    |
 * |  GPIO31/GPIO51  |    10     |   顶层全向天线     |    需要将GPIO31/GPIO51切换到00    |
 * |                 |    00     |   接通断头        |                                 |
 * ---------------------------- -------------------------------------------------------
 *
 *
 * @param:
 *      antnum  ATN天线编号 ( 范围: Ant3 、 Ant4、 Ant5、 Ant6 )
 *      antval  逻辑电平    ( 范围: 00 、 01、 11、 10 )
 *
 * 返回值:
 *      成功  0
 *      失败  -1
 *
 */
static int Antenna_number_logic_value_setting( const char *AntNum , const char *AntVal )
{
    if ( !AntNum || !AntVal ) {
        PRINTF(" Param antnum or antval is NULL \n");
        return -1;
    }
    
    if ( strcmp( AntVal , "00" ) &&
        strcmp( AntVal , "01" ) &&
        strcmp( AntVal , "10" ) &&
        strcmp( AntVal , "11" ) ) {
        
        PRINTF(" Param antval illegal \n");
        return -1;
    }
    
    if ( !strcasecmp( AntNum , "Ant3" ) ) {
        if ( 0 == util_set_gpio_output( 20 , AntVal[0] - '0' ) ) {
            PRINTF("util_set_gpio_output  gpio20  val: %d success\n" , AntVal[0] - '0' );
        }
        else {
            PRINTF("util_set_gpio_output gpio20 failed\n");
            return -1;
        }
        if ( 0 == util_set_gpio_output( 18 , AntVal[1] - '0' ) ) {
            PRINTF("util_set_gpio_output  gpio18  val: %d success\n" , AntVal[1] - '0' );
        }
        else {
            PRINTF("util_set_gpio_output gpio18 failed\n");
            return -1;
        }
	}
	else if ( !strcasecmp( AntNum , "Ant6" ) ) {
	    if ( 0 == util_set_gpio_output( 31 , AntVal[0] - '0' ) ) {
            PRINTF("set  gpio31  val: %d success\n" , AntVal[0] - '0' );
        }
        else {
            PRINTF("set gpio31 failed\n");
            return -1;
        }
        if ( 0 == util_set_gpio_output( 51 , AntVal[1] - '0' ) ) {
            PRINTF("set  gpio51  val: %d success\n" , AntVal[1] - '0' );
        }
        else {
            PRINTF("set gpio51 failed\n");
            return -1;
        }
	}
	else if ( !strcasecmp( AntNum , "Ant4" ) ) {
	    // TODO:
	    PRINTF("set Ant4 Success TODO \n");
	}
	else if ( !strcasecmp( AntNum , "Ant5" ) ) {
	    // TODO:
	    PRINTF("set Ant5 Success TODO \n");
	}
	else {
	    PRINTF(" Param antnum illegal \n");
        return -1;
	}
	
	return 0;
}



/**
 * Usaeg_Help 使用帮助:
 *
 *      在切换之前,都会判断外置天线(ANT6_DETECT\ANT3_DETECT)是否插入,
 *      如果插入,内置定向天线的切换的动作都不会操作。
 *
 *      每次cat /proc/AntennaSwitch/antsw 都会读取下GPIO97、GPIO98状态:
 *
 *      ANT3_DETECT(GPIO97)检测:
 *                  1 (高电平,外置天线ANT3插入)   OR    0 (低电平,外置天线ANT3未插入)
 *
 *      ANT8_DETECT(GPIO98)检测:
 *                  1 (高电平,外置天线ANT6插入)   OR    0 (低电平,外置天线ANT6未插入)
 *
 *
 * 返回值:
 *      成功  0
 */
static int Usaeg_Help(struct seq_file *m, void *v)
{
    int ant3_detect = util_get_gpio_value( 97 );
    int ant6_detect = util_get_gpio_value( 98 );
    
    seq_printf(m, "Antenna Switch V1.0.0 Help page\n\n"\
	                "\tInstructions for use for directional antenna switching.\n"\
                    "\tBefore switching, it will judge whether the external antenna (ANT6 ANT3) is inserted.\n"\
                    "\tIf inserted, the switching action of the built-in directional antenna will not operate.\n\n"\
                    "\tif you want to print debug info or not :\n"\
                    "\t\techo \"debug on\" > /proc/AntennaSwitch/antsw\n"\
                    "\t\techo \"debug off\" > /proc/AntennaSwitch/antsw\n\n"\
                    "\tif you want to switch antenna :\n"\
                    "\t\techo \"<antnum> <antval>\" > /proc/AntennaSwitch/antsw\n\n"\
	                "\t\t<antnum>:\n"\
                    "\t\t\tAnt3 or Ant4 or Ant5 or Ant6\n\n"\
                    "\t\t<antval>:\n"\
                    "\t\t\t00 or 01 or 10 or 11\n\n"\
                    );
                    
    if ( -1 == ant3_detect ) {
        seq_printf(m, "\tANT3_DETECT: %d\t\t%s\n\n"
                        , ant3_detect , "Read Gpio97 value error !" );
	}
	else {
	    seq_printf(m, "\tANT3_DETECT: %d\t\t%s\n\n"
                        , ant3_detect
                        , ( ant3_detect == 0 ? \
                        "Low level, external antenna ANT3 is not inserted." : \
                        "High level, external antenna ANT3 is inserted." ) );
	}
    
    if ( -1 == ant6_detect ) {
        seq_printf(m, "\tANT6_DETECT: %d\t\t%s\n\n"
                        , ant6_detect , "Read Gpio98 value error !" );
	}
	else {
	    seq_printf(m, "\tANT6_DETECT: %d\t\t%s\n\n"
                        , ant6_detect
                        , ( ant6_detect == 0 ? \
                        "Low level, external antenna ANT6 is not inserted." : \
                        "High level, external antenna ANT6 is inserted." ) );
	}

    return 0;
}

/**
 * AtnSw_Open_Proc : 对应cat的操作
 *
 * 触发方式:
 *      cat /proc/AntennaSwitch/antsw
 *
 * 返回值:
 *      成功 0
 *      失败 -1
 */
static int AtnSw_Open_Proc(struct inode *inode, struct file *file)
{
    return single_open(file, Usaeg_Help, NULL);
}


/**
 * 外置天线ANT3_DETECT逻辑:
 *      高电平时是插入,优先级最高,需要外部循环检测!
 *      检测时长 ( 3 秒 )
 *      当 __ANT3_DETECT 与上次不同时才做动作
 *
 * ANT3_DETECT检测:(GPIO97)
 *      高电平,需要将GPIO20/GPIO18切换到00
 *
 *
 * 返回值:
 *      1   ANT3 天线插入
 *      0   ANT3 天线未插入
 *     -1   读取ANT3_DETECT 失败
 */
static int External_Antenna3_Detection( void )
{
    int value = -1;
    
    value = util_get_gpio_value( 97 );
    if ( -1 == value ) {
        PRINTF( "get_gpio_value 97 failed\n" );
        return -1;
    }
    
    if ( __ANT3_DETECT != value ) {
        __ANT3_DETECT = value;
        if ( 1 == __ANT3_DETECT ) {
             if ( 0 == Antenna_number_logic_value_setting( "Ant3" , "00" ) ) {
                PRINTF("Antenna_number_logic_value_setting  Ant3 00 success\n");
            }
            else {
                PRINTF("Antenna_number_logic_value_setting  Ant3 00 failed\n");
            }
        }
    }
    
    return __ANT3_DETECT;
    
}

/**
 * 外置天线ANT6_DETECT逻辑:
 *      高电平时是插入,优先级最高,需要外部循环检测!
 *      检测时长 ( 3 秒 )
 *      当 __ANT6_DETECT 与上次不同时才做动作
 *
 * ANT6_DETECT检测:(GPIO98)
 *      高电平,需要将GPIO31/GPIO51切换到00
 *
 *
 * 返回值:
 *      1   ANT6 天线插入
 *      0   ANT6 天线未插入
 *     -1   读取ANT6_DETECT 失败
 */
static int External_Antenna6_Detection( void )
{
    int value = -1;
    
    value = util_get_gpio_value( 98 );
    if ( -1 == value ) {
        PRINTF( "get_gpio_value 98 failed\n" );
        return -1;
    }
    
    if ( __ANT6_DETECT != value ) {
        __ANT6_DETECT = value;
        if ( 1 == __ANT6_DETECT ) {
            if ( 0 == Antenna_number_logic_value_setting( "Ant6" , "00" ) ) {
                PRINTF("Antenna_number_logic_value_setting  Ant6 00 success\n");
            }
            else {
                PRINTF("Antenna_number_logic_value_setting  Ant6 00 failed\n");
            }
        }
    }
    
    return value;
}


/**
 * 说明:
 *      因为外置天线的逻辑特定,需要创建个线程在内核里循环检测。
 *      累计读取ANT3_DETECT 、ANT6_DETECT失败 30次则线程退出
 *
 *      检测时长间隔 ( 500 ms )
 *
 * 返回值:
 *
 */
static void Antenna_Cycle_detection_thread( unsigned long data )
{
    
    if ( -1 == External_Antenna3_Detection() ) {
        ERROR_NUM++;
        PRINTF(" read ANT3_DETECT failed , times : %d \n" , ERROR_NUM);
    }
    
    if ( -1 == External_Antenna6_Detection() ) {
        ERROR_NUM++;
        PRINTF(" read ANT6_DETECT failed , times : %d \n" , ERROR_NUM);
    }
    
    if ( MAXNUM_FAILURES <= ERROR_NUM ) {
        PRINTF("read ANT3_DETECT or ANT6_DETECT failed %d times in total , exit \n" , MAXNUM_FAILURES );
        return;
    }
    
    mod_timer( &mytimer , jiffies + msecs_to_jiffies( TIMING_INTERVAL ) );
}




/**
 * AtnSw_Write_Proc :对应echo的操作
 *
 * DEBUG:
 *      打开: echo "debug on" > /proc/AntennaSwitch/antsw
 *      关闭:  echo "debug off" > /proc/AntennaSwitch/antsw
 *
 * 天线切换:
 *      echo "AntNum AntVal"  > /proc/AntennaSwitch/antsw
 *
 * 例如:
 *      echo "Ant3 00" > /proc/AntennaSwitch/antsw
 *      echo "Ant6 00" > /proc/AntennaSwitch/antsw
 *
 *
 * ATN3\ANT6逻辑电平所对应的引脚使能:
 *
 * ------------------------------------------------------------------------------------
 * |                 |  逻辑电平  |       功能        |              备注                |
 * ------------------------------------------------------------------------------------
 * |                 |    00     |   底层定向天线     |                                 |
 * |      ANT3       |    01     |   顶层定向天线     |   ANT3_DETECT检测:GPIO97高电平   |
 * |  GPIO20/GPIO18  |    10     |   顶层全向天线     |     需要将GPIO20/GPIO18切换到00   |
 * |                 |    11     |   接通断头        |                                 |
 * -------------------------------------------------—----------------------------------
 * |                 |    00     |   底层定向天线     |                                 |
 * |      ANT6       |    01     |   顶层定向天线     |  ANT6_DETECT检测:GPIO98高电平    |
 * |  GPIO31/GPIO51  |    10     |   顶层全向天线     |    需要将GPIO31/GPIO51切换到00    |
 * |                 |    11     |   接通断头        |                                 |
 * ---------------------------- -------------------------------------------------------
 *
 * 总则:
 *      正常使用时状态要求(切换过程不在同一面):
 *      ANT3跟ANT6永远在同一面,ANT4+ANT5永远在同一面
 *
 * 例如:
 *      组合1:ANT3(前)+ANT6(前)+ANT4(左)+ANT5(左)
 *      组合2:ANT3(前)+ANT6(前)+ANT4(右)+ANT5(右)
 *      组合3:ANT3(后)+ANT6(后)+ANT4(左)+ANT5(左)
 *      组合4:ANT3(后)+ANT6(后)+ANT4(左)+ANT5(左)
 *
 *
 * 返回值:
 *      count
 *
 */
static ssize_t AtnSw_Write_Proc(struct file *file, const char *buffer,
	size_t count, loff_t *data)
{
	char valstr[64] = "";
	char AntNum[8] = "";
	char AntVal[8] = "";
	
	if( count > sizeof(valstr) ) {
	    PRINTF(" The input data is too long, illegal \n");
	    goto __AtnSw_Write_Proc_exit;
	}
	
	memcpy(valstr, buffer, count);
	valstr[count-1] = '\0';
	
	PRINTF("Antenna input data : %s\n" , valstr );
	
	if ( !strcmp( valstr , "debug on" ) ) {
	    global_debug_flag = 1;
	    PRINTF("Debug is on \n" );
	    goto __AtnSw_Write_Proc_exit;
	}
	else if ( !strcmp( valstr , "debug off" ) ) {
	    PRINTF("Debug is off \n" );
	    global_debug_flag = 0;
	    goto __AtnSw_Write_Proc_exit;
	}
	
	if ( 2 != sscanf( valstr, "%s %s", AntNum, AntVal ) ) {
		PRINTF("usage: <AntNum> <AntVal> \n");
		goto __AtnSw_Write_Proc_exit;
	}
	
	if ( __ANT3_DETECT == 1 || __ANT6_DETECT == 1 ) {
	    PRINTF("ANT3_DETECT or ANT6_DETECT is inserted , do not operate \n");
	    goto __AtnSw_Write_Proc_exit;
	}
	
	if ( !strcmp( AntVal , "00" ) ) {
	    PRINTF("Shield operations 00 , cause this part in Antenna_Cycle_detection_thread\n");
	    goto __AtnSw_Write_Proc_exit;
	}
	
	if ( 0 == Antenna_number_logic_value_setting( AntNum , AntVal ) ) {
	    PRINTF("Antenna_number_logic_value_setting  %s %s success\n" , AntNum , AntVal );
	}
	else {
	    PRINTF("Antenna_number_logic_value_setting %s %s failed \n", AntNum , AntVal );
	}
	
__AtnSw_Write_Proc_exit:
    return count;
	
}


struct file_operations AntennaSwitchProcOps =
{
	.open       = AtnSw_Open_Proc,     //对应cat
	.read       = seq_read,
	.write      = AtnSw_Write_Proc,    //对应echo
	.llseek     = seq_lseek,
	.release    = single_release,
};


/**
 *
 * AntennaSwitch_init 初始化:
 *
 *      创建目录:/proc/AntennaSwitch
 *      创建文件:/proc/AntennaSwitch/antsw 属性:0600
 *
 *      定时执行:Antenna_Cycle_detection_thread ( 定时时间 500ms ; 读取ANTDETECT 出错次数累计达到 MAXNUM_FAILURES 次 注销定时器 )
 *
 *
 * 触发方式:
 *      insmod kernerl_test.ko
 *
 * 返回值:
 *      成功 0
 *      失败 -1
 */
int __init AntennaSwitch_init(void)
{
    
    printk("AntennaSwitch init\n");

    AntennaSwitchDir = proc_mkdir("AntennaSwitch", NULL);
    if (NULL == AntennaSwitchDir)
    {
        printk("\n Can't create /proc/AntennaSwitch\n");
        return -1;
    }
    if (NULL == (AntennaSwitchFile = proc_create("antsw", 0600, AntennaSwitchDir, &AntennaSwitchProcOps)))
    {
        remove_proc_entry("AntennaSwitch", NULL);
        AntennaSwitchDir = NULL;
        printk("\n Can't create /proc/AntennaSwitch/antsw file\n");
        return -1;
    }
    
    //初始化内核定时器
    init_timer( &mytimer );
	mytimer.function = Antenna_Cycle_detection_thread;
    mytimer.data = (unsigned long)ERROR_NUM;
    mytimer.expires = jiffies+msecs_to_jiffies( TIMING_INTERVAL );
	add_timer( &mytimer );
    
    return 0;
}


/**
 * AntennaSwitch_exit :
 *
 *      释放资源:
 *          目录指针:AntennaSwitchDir
 *          文件指针:AntennaSwitchFile
 *
 * 触发方式:
 *      insmod kernerl_test.ko
 *
 * 返回值:
 *      成功 0
 *      失败 -1
 */
void __exit AntennaSwitch_exit(void)
{
    PRINTF("AntennaSwitch exit\n");
    if (AntennaSwitchFile)
	{
		remove_proc_entry("antsw", AntennaSwitchDir);
		AntennaSwitchFile = NULL;
	}

    if (AntennaSwitchDir)
    {
        remove_proc_entry("AntennaSwitch", NULL);
        AntennaSwitchDir = NULL;
    }
    
    //注销内核定时器
    del_timer( &mytimer );
    
}

module_init(AntennaSwitch_init);
module_exit(AntennaSwitch_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("XN");
MODULE_DESCRIPTION("Demo for AntennaSwitch");
Logo

更多推荐