gpio驅動重構版,未優化,附上測試demo

最近應師傅要求重構了A64上的gpio驅動接口,由於明天就要離職了,還有一些bug來不及優化了,也沒整理,先記錄一下大體邏輯吧,有空再優化一下。

目前已知的問題:

1.核心問題也是最需要解決的問題,中斷消抖,這塊還是很不理想,無奈沒時間調了,暫時也想不出更好的方案了。

2.卸載驅動時時會有段錯誤,還未找到根源,不過這個好解決,有空先把消抖搞定吧。


驅動代碼:


#include <linux/interrupt.h>
#include <linux/input/matrix_keypad.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/sched.h> 
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/async.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/init-input.h>
#include <linux/gpio.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/list.h>
#include <linux/kthread.h> 


#define DEVICE_NAME "gpio_ctrl"
static DECLARE_WAIT_QUEUE_HEAD(state_waitq);
struct gp_pack {
unsigned long gp;
int current_state;
};
struct package {
struct gp_pack gp2user;
int old_state;
int init_state;
int irq;
struct timer_list timer;
struct list_head list;
};
static struct package *p_cueernt;
#define GP_HIGH 1
#define GP_LOW 0
#define GP_UNCERTAIN -1
static current_state = 0;
static int state_changed = 0;
static int change_count = 0;
static int flag = 1;
static int high_state = 0;
static int low_state = 0;
#define PACKAGE_LEN sizeof(struct package)
static LIST_HEAD(inputgpio_list);
#define KEY_TIMER_DELAY1    (HZ/25)             //gp去抖延時20毫秒   
#define KEY_TIMER_DELAY2    (HZ/10)
struct package *datatouser;   
static struct task_struct *tsk; 

static struct package*
xx_irq2listp(int irq){
struct package *p=NULL;
struct package *p1=NULL;
unsigned long gp = -1;


list_for_each_entry(p,&inputgpio_list,list){
if(p->irq == irq){
p1 = container_of(&p->irq, struct package,irq);
if(p1 == NULL){
printk("container_of faild! \n");
return NULL;
}
return p1;
}
}
 
printk("%s:faild!  irq = %d\n",__FUNCTION__,irq);
return NULL;
}


static int thread_gpioctrl(void *data){
int i=0,state = -1;
printk("thread startting !\n");
do{
if(!flag){
state = __gpio_get_value(p_cueernt->gp2user.gp);
if(state == GP_LOW){
low_state++;
//high_state = 0;
}else{
high_state++;
//low_state = 0;
}

schedule_timeout_uninterruptible(1);
}
}while(!kthread_should_stop());


printk("thread was stop!\n");
return 0;
}
static irqreturn_t
xx_irq_handler(int irq, void *dev_id){
unsigned long gp = (unsigned long)dev_id;
struct package *p = ococci_irq2listp(irq);
if(p == NULL){
printk("ococci_irq2listp faild!\n");
return IRQ_NONE;
}
printk("$$$$$$$$$$$$$$$$$$1 flag  = %d    current_state =%d\n",flag,current_state);

if(flag && current_state != GP_UNCERTAIN){
flag=0;
current_state = GP_UNCERTAIN;
p_cueernt = p;
p->timer.expires = jiffies + KEY_TIMER_DELAY1;
        add_timer(&p->timer);
}

return IRQ_HANDLED;
}




static void
xx_timer_handler(unsigned long data){
int next_tate = -1,report = 0;
struct package *p = (struct package*)data;



if(current_state == GP_UNCERTAIN){
if(low_state >=3){
//printk("#1");
//if( GP_LOW == __gpio_get_value(p->gp2user.gp)){
//printk("#2");
report = 1;
current_state = GP_LOW;
//}
}else if(high_state >=3){
//printk("#1");
//if(GP_HIGH == __gpio_get_value(p->gp2user.gp)){
printk("#2");
report = 1;
current_state = GP_HIGH;
//}
}else
printk("1>>>!!!!!!!!!!!!!!!!\n");
}
low_state = 0;
high_state = 0;

if((current_state != p->old_state) && (report == 1) && (current_state != GP_UNCERTAIN)){
printk("interrupt done!!  current_state = %d!!\n",current_state);
datatouser = &p->gp2user;
p->gp2user.current_state = current_state;
p->old_state = current_state;
state_changed = 1;
wake_up_interruptible(&state_waitq);
}
if(current_state == GP_UNCERTAIN){
current_state = p->init_state;
}
flag = 1;


}




static int setinput_gpio(unsigned long gp){
int irq=-1;
struct package *p = NULL;
if (0 != gpio_direction_input(gp))
printk("gpio_direction_output fail !\n");
irq = gpio_to_irq(gp);
printk("gpio_req_irq : %d\n",irq);
if(irq<0){
printk("gpio2irq faild!\n");
return -1;
}
if(request_irq(irq, ococci_irq_handler,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "gpio_irq",NULL) <0 ){
printk("gpio_req_irq faild!\n");
return -1;
}

p = kmalloc(PACKAGE_LEN,GFP_KERNEL);
if(NULL == p){
printk("kmalloc faild !\n");
return -1;
}
p->gp2user.gp = gp;
p->gp2user.current_state = __gpio_get_value(gp);
p->old_state = p->gp2user.current_state;
p->init_state = p->gp2user.current_state;
p->irq = irq;

setup_timer(&p->timer, ococci_timer_handler,p);

list_add(&p->list,&inputgpio_list);
//printk("%s:gp = %d, irq = %d\n",__FUNCTION__,gp,irq);
return irq;
}
static long
xx_gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long gp)
{
int data = -1;


//printk("cmd = %d  gp=%d \n",cmd,gp);

if(0 != gpio_request(gp, NULL)) {
printk("gpio_request fail ! %d\n",gp);
return -1;
}



//printk("end !!cmd = %d  gp=%d \n",cmd,gp);
switch(cmd){
case 1 :
setinput_gpio(gp);
break;
case 3:
if (0 != gpio_direction_output(gp, 0))
printk("gpio_direction_output fail !\n");
break;
case 4 :
if (0 != gpio_direction_output(gp, 1))
printk("gpio_direction_output fail !\n");
break;
case 5 :
/*data = __gpio_get_value(gp);
gpio_free(gp);
return data;*/
gpio_free(gp);
default:
printk("cmd is wrong \n");
break;
}
return 0;
}
static unsigned int
xx_gpio_poll(struct file *file, poll_table *wait){
unsigned int mask = 0;
poll_wait(file, &state_waitq, wait);

if(state_changed)  
    {  
        mask |= (POLLIN | POLLRDNORM);  /* 表示有數據可讀 */  
    }  

return mask;
}
static ssize_t
xx_gpio_read(struct file *file, char __user *user, size_t size, loff_t *ppos){
if(size != sizeof(struct gp_pack))return -EINVAL;
if(datatouser == NULL){
printk("%s:faild!\n",__FUNCTION__);
return -1;
}
copy_to_user(user, datatouser, sizeof(struct gp_pack));
state_changed = 0;


return 0;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,  
    .read       =
xx_gpio_read,  
.unlocked_ioctl =
xx_gpio_ioctl,
.compat_ioctl =
xx_gpio_ioctl,
.poll       =
xx_gpio_poll, 
};


static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};


static int __init dev_init(void)
{
int ret;
  printk("-------------------->dev_init--------------------->\n");
ret = misc_register(&misc);
tsk = kthread_run(thread_gpioctrl, NULL, "gpioctrl_thread");
if(tsk==NULL){
printk("線程創建失敗....\n");
return -1;
}
printk (DEVICE_NAME"\tinitialized\n");


return ret;
}


static void __exit dev_exit(void){
struct package *p = NULL;

if (tsk) {
kthread_stop(tsk);
schedule_timeout_uninterruptible(10);
tsk = NULL;
}
printk("will free gpio_list\n");
while(!list_empty(&inputgpio_list)){
list_for_each_entry(p,&inputgpio_list,list){
printk("will free gp=%d\n",p->gp2user.gp);
free_irq(p->irq,NULL);
gpio_free(p->gp2user.gp);
kfree(p);
}
}
misc_deregister(&misc);
}


module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("
MRZHANG
");



上層demo:


#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>


#define PATH "/dev/gpio_ctrl"
#define CMD 3
#define PIN 35
struct package {
unsigned long gp;
int current_state;
};
void main(){
int ret,timeout=100,i=0;
struct package gp_pack;
fd_set rfds;
struct timeval tv;
int fd = open(PATH, O_RDWR);
if (fd<=0) {
printf("Error on opening the device file\n");
return -1;
}
printf(">>>>>>>>>>>>>>>1\n");
/*for(i=0;i<2;i++){
printf(">>>>>>>>>>>>>>>2\n");
if(i>0)ret = ioctl(fd, 1, 359);
else
    ret = ioctl(fd, 1, PIN);




if (ret < 0) {
printf("ioctl err: %s\n",strerror(errno));
close(fd);
return -1;
}
}*/
ret = ioctl(fd, 1, PIN);
if (ret < 0) {
printf("ioctl err: %s\n",strerror(errno));
close(fd);
return -1;
}

ret = ioctl(fd, 1, 359);
if (ret < 0) {
printf("ioctl err: %s\n",strerror(errno));
close(fd);
return -1;
}
while(1){
FD_ZERO(&rfds);
FD_SET(fd,&rfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
switch (select(fd+1,&rfds,NULL,NULL,NULL))//最後一個參數設爲NULL,將會永遠等待,即阻塞!
{
case 0:
break;
case -1:
break;
default :
if(FD_ISSET(fd,&rfds)){ 
ret =read(fd,&gp_pack,sizeof(struct package));  
printf("ret = %d   gp = %d  state = %d\n",ret,gp_pack.gp,gp_pack.current_state); 
}else{
printf("No data within 5s,please wait.. \n",&tv.tv_sec);
}
break;
}
}


printf(">>>>>>>>>>>>>>>3\n");
return 0;
close(fd);
}



mk文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE :=gpio_test
LOCAL_SRC_FILES :=$(call all-subdir-c-files)
include $(BUILD_EXECUTABLE)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章