输入滤波,适合扩展低速的输入输出接口
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#define EXTIO_OUT_MAX 24
#define EXTIO_IN_MAX 24
typedef struct _input_t{
uint8_t buf[EXTIO_IN_MAX/8];
uint8_t save[EXTIO_IN_MAX/8];
uint8_t timer[EXTIO_IN_MAX];
}input_t;
typedef struct _output_t{
uint8_t byte[EXTIO_OUT_MAX/8];
}output_t;
typedef struct _extio_t{
input_t input;
output_t output;
}extio_t;
#define DEVICE_NAME "extio"
typedef struct
{
int data_out_pin;
int data_in_pin;
int clk_pin;
int le_pin;
int pe_pin;
}extio_handler;
extio_handler extio_define={
2*32+5,2*32+7,2*32+13,2*32+15,2*32+17
};
static struct timer_list extio_timer;
extio_t extio_buf;
#define data_in() gpio_get_value(extio_define.data_in_pin)
#define data_out_high() gpio_direction_output(extio_define.data_in_pin,1)
#define data_out_low() gpio_direction_output(extio_define.data_in_pin,0)
#define data_clk_high() gpio_direction_output(extio_define.clk_pin,1)
#define data_clk_low() gpio_direction_output(extio_define.clk_pin,0)
#define data_le_high() gpio_direction_output(extio_define.le_pin,1)
#define data_le_low() gpio_direction_output(extio_define.le_pin,0)
#define data_pe_high() gpio_direction_output(extio_define.pe_pin,1)
#define data_pe_low() gpio_direction_output(extio_define.pe_pin,0)
static void extio_write_bye(uint8_t byte)
{
uint8_t i;
for( i=0; i<8; i++ ){
if( byte&(0x80) )
data_out_high();
else
data_out_low();
data_clk_high();
data_clk_low();
byte<<=1;
}
}
static void extio_output(void)
{
uint8_t i;
for( i=0; i<EXTIO_OUT_MAX/8; i++ ){
extio_write_bye(extio_buf.output.byte[i]);
}
data_pe_high();
data_pe_low();
}
static void extio_read_byte(uint8_t *byte)
{
uint8_t i;
*byte = 0;
for( i=0; i<8; i++ ){
data_clk_high();
(*byte)<<=1;
if( data_in() )
(*byte) |= 0x01;
data_clk_low();
}
}
static void extio_input(void)
{
uint8_t *in_ptr =&extio_buf.input.buf[EXTIO_IN_MAX/8-1];
uint8_t i;
data_pe_low();
data_pe_high();
for( i=0; i<EXTIO_IN_MAX/8; i++ ){
if( i==0 )
extio_read_byte(in_ptr);
else
extio_read_byte(in_ptr);
in_ptr--;
}
}
static void extio_input_check( void )
{
uint8_t i,io,k,num;
for( num=0; num<EXTIO_IN_MAX/8; num++ )
{
if( extio_buf.input.buf[num]!=extio_buf.input.save[num] )
{
io = extio_buf.input.buf[num]^extio_buf.input.save[num];
for( i=0; i<8; i++ )
{
if( io&0x01 )
{
if( extio_buf.input.timer[num*8+i]<30 )
{
extio_buf.input.timer[num*8+i]++; //每一个IO口对应一个计时器
}
else
{
extio_buf.input.timer[num*8+i] = 0;
k = extio_buf.input.buf[num];
k >>= i;
if( k&0x01 )
{
extio_buf.input.save[num] |= (1<<i);
}
else
{
extio_buf.input.save[num] &= (~(1<<i));
}
}
}
else
{
extio_buf.input.timer[num*8+i] = 0;
}
io >>= 1;
}
}
}
}
static ssize_t extio_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
int ret = 0;
copy_from_user((char*)extio_buf.output.byte, buf, count);
extio_output();
return ret;
}
static ssize_t extio_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
int ret = 0;
copy_to_user(buf, (char*)extio_buf.input.save, EXTIO_IN_MAX/8);
return ret;
}
static int extio_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)
{
return 0;
}
static struct file_operations extio_fops={
.owner = THIS_MODULE,
.write = extio_write,
.read = extio_read,
.ioctl = extio_ioctl,
};
static struct miscdevice extio_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &extio_fops,
};
static void extio_timer_function(unsigned long data)
{
extio_input();
extio_input_check();
mod_timer(&extio_timer,jiffies+ HZ*100/1000 );
}
static int extio_init(void)
{
//GPIO
gpio_request(extio_define.data_in_pin, "data_in");
gpio_direction_input(extio_define.data_in_pin);
gpio_request(extio_define.data_out_pin, "data_out");
gpio_direction_output(extio_define.data_out_pin,0);
gpio_request(extio_define.clk_pin, "clk");
gpio_direction_output(extio_define.clk_pin,0);
gpio_request(extio_define.pe_pin, "pe");
gpio_direction_output(extio_define.pe_pin,0);
gpio_request(extio_define.pe_pin, "le");
gpio_direction_output(extio_define.le_pin,0);
int err = 0;
err = misc_register(&extio_miscdev);
init_timer(&extio_timer);
extio_timer.function=extio_timer_function;
extio_timer.expires=jiffies +HZ*100/1000;
add_timer(&extio_timer);
printk("extio driver up \n");
return 0;
}
static void extio_exit(void)
{
del_timer(&extio_timer);
misc_deregister(&extio_miscdev);
printk("extio driver remove \n");
}
module_init(extio_init);
module_exit(extio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("KENG DENG");