全志按键驱动程序 标准输入方式

本文介绍了一种基于Allwinner平台的嵌入式GPIO控制模块实现细节,包括GPIO配置、中断处理、定时器使用及输入设备注册等核心功能。通过该模块可以实现对外部硬件的精确控制,并支持键盘输入功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 /*
 * drivers/char/arisc_test/arisc_test.c
 * (C) Copyright 2010-2015
 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
 * sunny <sunny@allwinnertech.com>
 *
 * sun6i arisc test driver
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 */


#include "sunxin_gpio.h"
#include <asm/div64.h>
#include <linux/math64.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/atmel_pdc.h>
#include <linux/init.h>
#include <linux/highmem.h>
#include <linux/slab.h>
#include <asm/system.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-sunxi.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <mach/sys_config.h>
#include <mach/platform.h>
#include <linux/timer.h>
#include <linux/sched.h>


#include <linux/input.h>




#include <linux/keyboard.h>
#include <linux/ioport.h>
#include <asm/irq.h>






#include <mach/sys_config.h>
#include <mach/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/pinconf-sunxi.h>
#include <linux/clk/sunxi.h>
#include <linux/err.h>






//usrlink.h
//Created on: 2014 Author: cr
#ifndef USRLINK_H_
#define USRLINK_H_


#define USER_NETLINK_CMD 25
#define MAXMSGLEN 1024


typedef enum error_e {
NET_ERROR,
NET_OK,
NET_PARAM,
NET_MEM,
NET_SOCK,
} netlink_err;


typedef enum module_e {
HELLO_CMD = 1,
} netlink_module;


typedef enum type_e {
HELLO_SET,
HELLO_GET,
} netlink_type;


#endif /* USRLINK_H_ */






#define gpio_MAJOR 225
#define DEVICE_NAME  "gpioctl"
#undef  DEBUG_GPIO








static u32 led_hdler[32];
static char *main_key1 = "maxim_rst_para";
static char *led_key1[32] = {
"rst_gpio",
"user3v3_en",
"in_2",
"in_3",
"uart_tx_io",
"uart_rx_io",
"uart_tx_r",
"uart_rx_r",
    "spi_din_io",
    "spi_dout_io",
    "spi_clk_io",
    "spi_cs0_io",
    "spi_din_r",
    "spi_dout_r",
    "spi_clk_r",
    "spi_cs0_r",
    "twi_scl",

};








static struct fasync_struct *fasync_queue;
static bool led_status;




static struct timer_list button_timer_in0;
static struct timer_list button_timer_in1;
static unsigned int timer_on_in0;
static unsigned int timer_on_in1;


static unsigned int g_input;






static struct timer_list gpioctl_timer;






static u32 hdler_in0,hdler_in1;
static u32 isr_num[2]={0,0};


static struct semaphore sem;




static void gpioctl_do_events (struct work_struct *work);


static struct workqueue_struct *gpioctl_wq;
static DECLARE_WORK(gpioctl_do_work, gpioctl_do_events);
static spinlock_t ioctrl_lock;


static int sunxi_gpio_req_ioctrl(struct gpio_config *gpio);


































/*
 * netlink.c
 *
 *  Created on: 2014 *      Author: cr
 */


#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/netlink.h>
#include <net/sock.h>
//#include "usrlink.h"


//MODULE_LICENSE("Dual BSD/GPL");
//MODULE_AUTHOR("MDAXIA");


struct sock *netlink_fd;






static struct pin_desc *irq_pd;  
static struct input_dev *sunxi_buttons_dev;  
static struct timer_list buttons_timer;  
//static int key_state[2];




static int key_repeat_report[2];


static unsigned long timeout_0 = 0x00;
static unsigned long timer_cnt_0 = 0x00;


static unsigned long timeout_1 = 0x00;
static unsigned long timer_cnt_1 = 0x00;








static void netlink_to_user(int dest, void *buf, int len)
{
struct nlmsghdr *nl;
struct sk_buff *skb;
int size;
    //printk( "dest = %d.\n", dest );
size = NLMSG_SPACE(len);
skb = alloc_skb(size, GFP_ATOMIC);
if(!skb || !buf)
{
printk(KERN_ALERT "netlink_to_user skb of buf null!\n");
return;
}
nl = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(len) - sizeof(struct nlmsghdr), 0);
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_group = 0;


memcpy(NLMSG_DATA(nl), buf, len);
nl->nlmsg_len = (len > 2) ? (len - 0):len;


netlink_unicast(netlink_fd, skb, dest, MSG_DONTWAIT);
//printk(KERN_ALERT "K send packet success\n");
}


static int process_hello_get(int dest, void *buf, int len)
{  
printk(KERN_ALERT "In process_hello get!\n");
memcpy(buf, "I known you !", 13);
netlink_to_user(dest, buf, 13);
return NET_OK;
}


static int process_hello_set(int dest, void *buf, int len)
{
//printk( "In process_hello set! %s\n", (char *)buf);
//memcpy(buf, "S known you !", 13);

netlink_to_user(dest, buf, len);
return NET_OK;
}




static void netlink_process_packet(struct nlmsghdr *nl)
{
int ret;


switch(nl->nlmsg_type)
{
case HELLO_GET:
printk( "process_hello_get.\n" );
ret = process_hello_get(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);
break;
case HELLO_SET:
printk( "process_hello_set.\n" );
ret = process_hello_set(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);
break;
default:break;
}
}


static void netlink_recv_packet(struct sk_buff *__skb)
{
struct sk_buff *skb;
struct nlmsghdr *nlhdr;


skb = skb_get(__skb);
if(skb->len >= sizeof(struct nlmsghdr))
{
nlhdr = (struct nlmsghdr *)skb->data;
if(nlhdr->nlmsg_len >= sizeof(struct nlmsghdr) &&
__skb->len >= nlhdr->nlmsg_len)
{
netlink_process_packet(nlhdr);
}
}
else
printk(KERN_ALERT "Kernel receive msg length error!\n");
}




#if 0
static int __init netlink_init(void)
{
netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE);
if(NULL == netlink_fd)
{
printk(KERN_ALERT "Init netlink!\n");
return -1;
}
printk(KERN_ALERT "Init netlink success!\n");
return 0;
}


static void __exit netlink_exit(void)
{
netlink_kernel_release(netlink_fd);
printk(KERN_ALERT "Exit netlink!\n");
}
#endif










































static void demo_exit(void);




static struct tasklet_struct my_tasklet;  












static DECLARE_WAIT_QUEUE_HEAD(wq);
static int flag =0;




ssize_t sleepy_read( void )
{
    printk(KERN_DEBUG "process %i (%s) going to sleep\n",current->pid,current->comm);
    wait_event_interruptible(wq,flag!=0);
    flag = 0;
    printk(KERN_DEBUG "awoken %i (%s) \n",current->pid,current->comm);
    return 0;
}


 


ssize_t sleepy_write(void)
{    
    printk(KERN_DEBUG "process %i (%s) awakening the readers ...\n",current->pid,current->comm);
    flag = 1;
    wake_up_interruptible(&wq);
    return 0;  
//³É¹¦²¢±ÜÃâÖØÊÔ
}












//  tasklet´¦Àíº¯Êý  
static void tasklet_handler (unsigned long data)  
{  
       printk(KERN_ALERT "tasklet_handler is running.\n"); 
       
  sleepy_read();
    sleepy_write();

}    
static int  demo_init(void)  
{  
       //  ³õʼ»¯tasklet  
       tasklet_init(&my_tasklet, tasklet_handler, 0);  
       //  µ÷¶Ètasklet´¦Àí³ÌÐò     
       tasklet_schedule(&my_tasklet);  
       printk(KERN_ALERT "demo_init.\n");  
  //demo_exit();






  
       return 0;  
}    
 
static void demo_exit(void)  
{  
      //  Ïú»Ùtasklet  
      tasklet_kill(&my_tasklet);  
      printk(KERN_ALERT "demo_exit.\n");  
}  












static void timer_dowork(void)
{
    //printk( "add gpioctl_dowork\n");
    mod_timer(&gpioctl_timer, jiffies + HZ);
//printk( "pin_value = 0x%x.\n", pin_value ); 
    
demo_init();
}








static void gpioctl_do_events (struct work_struct *work)
{
int ret = 0;


    printk( "add gpioctl_do_events\n");
gpioctl_timer.expires = jiffies + HZ;
gpioctl_timer.data = 100;
gpioctl_timer.function = timer_dowork;
add_timer(&gpioctl_timer);

return;
}


























/


#if 1
static void set_gpio_status(int handler, bool status)
{
gpio_set_value(handler, status);
}


static int get_gpio_status(int handler)
{
    return gpio_get_value(handler);

}








static void set_led_status(unsigned long arg)
{
int i;
led_status = led_status ? false : true;
for( i = 0; i < 1; i++ ){
         set_gpio_status(led_hdler[i], arg);
}
}


//GPIO read
static ssize_t gpio_rd (struct file *file, char *buf, size_t count, loff_t *offset)
{
    int ret;
    int io_status;


    //led_status = led_status ? false : true;


    printk( KERN_NOTICE "count = %d.\r\n", count );

//printk( KERN_NOTICE "led_status = %x.\r\n", led_status );
//set_gpio_status(led_hdler[1], led_status);






struct regulator *ldo_dcdc1;


memset( buf, 0, count );
    
   
ldo_dcdc1 = regulator_get(NULL,"axp22_dcdc1"); 
if( IS_ERR(ldo_dcdc1) ){
printk("nand:some error happen, fail to get regulator axp22_dcdc1!");
return -1;
}
//set output voltage to 3.0V
//ret = regulator_set_voltage(regu1,3000000,3000000);
//dp_mcu
ret = regulator_set_voltage(ldo_dcdc1, 3100000, 3100000);
printk( KERN_NOTICE "ret = %d.\r\n", ret );
return count;
}
















//PB7_PCM0_DIN_EINT7_LS_INT RST sw_uart_check_baudset
//the 15 pin, ctrl the maxim
//GPIO Write
static ssize_t gpio_wr(struct file *file, const char *buf, size_t count, loff_t *offset)
{   
    if( buf[0]==0x00 || buf[0]==0x01 ){
        set_led_status(buf[0]);
    }
printk( KERN_NOTICE "buf[0] = %x.\r\n", buf[0] );
printk( KERN_NOTICE "count = %x.\r\n", count );
return count;
}




static void set_all_cfg_io( void )


{
    int io_status = 0;
int ret = 0;
unsigned long flags;
unsigned char buf[128];
unsigned char *sendstr = "12345";


script_item_u val;
script_item_value_type_e type;
struct gpio_config  *gpio_p = NULL;
int i;
    //ÅäÖÃËùÓÐgpioΪÆÕͨio¿Ú,²¢ÇÒÖÃΪµÍµçƽ
//printk( "cfg to io.\n" );
for( i = 4; i < 6; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);



for( i = 8; i < 12; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);



for( i = 16; i < 17; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}  

set_gpio_status(led_hdler[4], 0); 
set_gpio_status(led_hdler[5], 0);

set_gpio_status(led_hdler[8], 0); 
set_gpio_status(led_hdler[9], 0);
set_gpio_status(led_hdler[10], 0); 
set_gpio_status(led_hdler[11], 0);
set_gpio_status(led_hdler[16], 0);




}


static long gpio_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
{
int io_status = 0;
int ret = 0;
unsigned long flags;
unsigned char buf[128];
unsigned char *sendstr = "12345";


script_item_u val;
script_item_value_type_e type;
struct gpio_config  *gpio_p = NULL;
int i;

//printk( "cmd = %d, arg = %d.\n", cmd, arg );
    switch ( cmd )
{  
 case 0:
  if( arg==0x00 || arg==0x01 ){
    set_gpio_status(led_hdler[0], arg);
         }
 break;


 case 1:
  if( arg==0x00 || arg==0x01 ){
    set_gpio_status(led_hdler[1], arg);
         }
 break;


 case 3:
  //printk( "cfg to io.\n" );
  for( i = 4; i < 6; i++ ){
    type = script_get_item(main_key1, led_key1[i], &val);
    if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
        printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
    }
    //printk( "type = %d.\n", type );
    gpio_p = &val.gpio;
    led_hdler[i] = gpio_p->gpio;
    if( led_hdler[i] == 0 ){
                 printk("gpio led_hdl[%d] failed.\n", i);
    }
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
    sunxi_gpio_req_ioctrl(gpio_p);
   } 


for( i = 8; i < 12; i++ ){
    type = script_get_item(main_key1, led_key1[i], &val);
    if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
        printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
    }
    //printk( "type = %d.\n", type );
    gpio_p = &val.gpio;
    led_hdler[i] = gpio_p->gpio;
    if( led_hdler[i] == 0 ){
                 printk("gpio led_hdl[%d] failed.\n", i);
    }
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
    sunxi_gpio_req_ioctrl(gpio_p);
   } 


for( i = 16; i < 17; i++ ){
    type = script_get_item(main_key1, led_key1[i], &val);
    if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
        printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
    }
    //printk( "type = %d.\n", type );
    gpio_p = &val.gpio;
    led_hdler[i] = gpio_p->gpio;
    if( led_hdler[i] == 0 ){
                 printk("gpio led_hdl[%d] failed.\n", i);
    }
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
    sunxi_gpio_req_ioctrl(gpio_p);
   }  

set_gpio_status(led_hdler[4], 0); 
set_gpio_status(led_hdler[5], 0);

set_gpio_status(led_hdler[8], 0); 
set_gpio_status(led_hdler[9], 0);
set_gpio_status(led_hdler[10], 0); 
set_gpio_status(led_hdler[11], 0);
set_gpio_status(led_hdler[16], 0);
 break;


      case 5:
  //printk( "cfg to spec.\n" );
  for( i = 6; i < 8; i++ ){
    type = script_get_item(main_key1, led_key1[i], &val);
    if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
        printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
    }
    //printk( "type = %d.\n", type );
    gpio_p = &val.gpio;
    led_hdler[i] = gpio_p->gpio;
    if( led_hdler[i] == 0 ){
                 printk("gpio led_hdl[%d] failed.\n", i);
    }
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
    sunxi_gpio_req_ioctrl(gpio_p);
   }


for( i = 12; i < 16; i++ ){
    type = script_get_item(main_key1, led_key1[i], &val);
    if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
        printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
    }
    //printk( "type = %d.\n", type );
    gpio_p = &val.gpio;
    led_hdler[i] = gpio_p->gpio;
    if( led_hdler[i] == 0 ){
                 printk("gpio led_hdl[%d] failed.\n", i);
    }
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
    sunxi_gpio_req_ioctrl(gpio_p);
   }
        //set_gpio_status(led_hdler[2], 0); 
//set_gpio_status(led_hdler[3], 0);    
 break;
      
 case 0x06:
  if( arg == 0x00 ){
//»ñÈ¡°´¼üÖµ 2¸ö
ret = g_input;
spin_lock_irqsave(&ioctrl_lock, flags);
g_input = 0x00;
spin_unlock_irqrestore(&ioctrl_lock, flags);
            return ret;
}else{
   //Çå³ý°´¼ü´¦Àí
   if( arg==1 || arg==2 || arg==3 ){
       spin_lock_irqsave(&ioctrl_lock, flags);
                g_input = g_input & (~arg);
   spin_unlock_irqrestore(&ioctrl_lock, flags);
   }
return 0x00;
}
 break;


 case 0x07:
  if( arg == 0x00 ){
//»ñÈ¡°´¼üÖµ 2¸ö
int pin_value,temp,temp1;
            temp = get_gpio_status(led_hdler[2]);
//printk( "pin_value2[%d].\n", temp );
//printk( "led_hdler[2][%d].\n", led_hdler[2] );
temp1 = get_gpio_status(led_hdler[3]);
//printk( "pin_value3[%d].\n", temp1 );
//printk( "led_hdler[3][%d].\n", led_hdler[3] );
pin_value = (temp<<1) | temp1;
            return pin_value;
}else{
return 0x00;
}
 break;




      case 0x08:
  //(int dest, void *buf, int len)

buf[0] = '1';
buf[1] = '2';
buf[2] = '3';
buf[3] = '4';
memcpy( buf, sendstr, strlen(sendstr) );
buf[strlen(sendstr)] = '\0';
//printk( "strlen(sendstr)[%d].\n", strlen(sendstr) );
        process_hello_set( 1, buf, strlen(sendstr) );
//ÄÚºËÖ÷¶¯·¢ËÍÏûÏ¢¸ø1ºÅÓ¦ÓóÌÐò
      break;

            
      //spi_gpio_cleanup 
      //uart_state


 
 default:
printk(KERN_NOTICE"The value of CMD = %d is err,must < 6\r\n",cmd);
   return -2;
 break;
}
return io_status;
}








static int sunxi_gpio_req_ioctrl(struct gpio_config *gpio)
{
int            ret = 0;
char           pin_name[8] = {0};
unsigned long  config;
sunxi_gpio_to_name(gpio->gpio, pin_name);
//printk( "pin_name = %s.\n", pin_name );
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, gpio->mul_sel);
ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
if( ret ){
   printk("set gpio %s mulsel failed.\n",pin_name);
   return -1;
    }
    
if( gpio->pull != GPIO_PULL_DEFAULT ){
        config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, gpio->pull);
        ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
        if( ret ){
            printk("set gpio %s pull mode failed.\n",pin_name);
            return -1;
        }
}
    
if( gpio->drv_level != GPIO_DRVLVL_DEFAULT ){
        config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, gpio->drv_level);
        ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
        if( ret ){
            printk("set gpio %s driver level failed.\n",pin_name);
            return -1;
        }
    }
                     
if( gpio->data != GPIO_DATA_DEFAULT ){
        config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, gpio->data);
        ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
        if( ret ){
            printk("set gpio %s initial val failed.\n",pin_name);
            return -1;
        }
    }
return 0;
}










static int gpio_fasync(int fd, struct file *filp, int on)
{   
    int retval;   
retval = fasync_helper(fd, filp, on, &fasync_queue);   
if( retval < 0 ){      
return retval;
}
return 0;
}











//g_input = g_input | 0x04;
//kill_fasync(&fasync_queue, SIGIO, POLL_IN);
                
//ÉèÖüü´¦Àí  
static void button_jitter_in0( void )
{          
    int pin_value_0, pin_value_1;
    unsigned long flags;
    spin_lock_irqsave(&ioctrl_lock, flags);
    pin_value_0 = gpio_get_value(hdler_in0);
    //»ñÈ¡´Ë¿ÌµÄÉèÖüüÖµ
    if( pin_value_0 == 0x00 ){                                                             
        //°´ÏÂ״̬
        if( time_before(jiffies, timeout_0+200) ){
            //»¹Ã»Óг¬Ê±2S
        }else{
            //ÒѾ­³¬Ê±
            if( key_repeat_report[0] == 0x00 ){
 pin_value_1 = gpio_get_value(hdler_in1);
 //×éºÏ³¤°´ÅжÏ
 if( pin_value_1 == 0x00 ){   
input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,1);  
                    input_sync(sunxi_buttons_dev); 
     input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,0);  
                    input_sync(sunxi_buttons_dev); 
key_repeat_report[0]++;
key_repeat_report[1] = 0x01;
printk( "key0 zuhe.\n" );
 }else{
                    input_event(sunxi_buttons_dev,EV_KEY,KEY_F13,1);  
                    input_sync(sunxi_buttons_dev); 
     input_event(sunxi_buttons_dev,EV_KEY,KEY_F13,0);  
                    input_sync(sunxi_buttons_dev);
 key_repeat_report[0]++;
 printk( "key0 long.\n" );
     //printk( "pin_value_in03 = 0x%x.\n", pin_value );
 }
            }
            
        }
        timer_cnt_0++;
  //½øÈ붨ʱÆ÷´ÎÊý¼Ó1
        mod_timer( &button_timer_in0, jiffies + msecs_to_jiffies(100) );
}else{    
  if( timer_cnt_0 == 0 ){
            //Ïû¶¶ÎÞÓð´¼ü    
            //µÚÒ»¸ö100ms½øÀ´,°´¼ü¾ÍÊÍ·ÅÁË,˵Ã÷Êǰ´¼ü¶¶¶¯
  }else{
            //°´¼üÒѾ­ÊÍ·Å
            if( time_before(jiffies, timeout_0+200) ){
                //»¹Ã»Óг¬Ê±,¶Ì°´
                //ËÉ¿ª ×îºóÒ»¸ö²ÎÊý: 0-ËÉ¿ª, 1-°´Ï 
                if( key_repeat_report[0] == 0x00 ){
                    input_event(sunxi_buttons_dev,EV_KEY,KEY_F14,1);  
                    input_sync(sunxi_buttons_dev);  
                    input_event(sunxi_buttons_dev,EV_KEY,KEY_F14,0);  
                    input_sync(sunxi_buttons_dev);  
     printk( "key0 short.\n" );
                }
 //printk( "pin_value_in02 = 0x%x.\n", pin_value );
            }
       }
 key_repeat_report[0]=0x00;
 timer_on_in0 = 0;
 //¿ÉÒÔÔÙ´ÎÏìÓ¦ÖжÏÁË
    }
    spin_unlock_irqrestore(&ioctrl_lock, flags);
}
















//·µ»Ø¼ü´¦Àí
static void button_jitter_in1(void)
{       
    int pin_value_0, pin_value_1;
    unsigned long flags;
    spin_lock_irqsave( &ioctrl_lock, flags );
    pin_value_1 = gpio_get_value(hdler_in1);
    //»ñÈ¡´Ë¿ÌµÄ·µ»Ø¼üÖµ
    //printk( "pin_value_in1 = 0x%x.\n", pin_value );   
    if( pin_value_1 == 0x00 ){                                                             
        //°´ÏÂ״̬
        if( time_before(jiffies, timeout_1+200) ){
            //»¹Ã»Óг¬Ê±2S
        }else{
            //ÒѾ­³¬Ê±
            if( key_repeat_report[1] == 0x00 ){                       
                //ËÉ¿ª ×îºóÒ»¸ö²ÎÊý: 0-ËÉ¿ª, 1-°´Ï 
 pin_value_0 = gpio_get_value(hdler_in0);
 //×éºÏ³¤°´ÅжÏ
 if( pin_value_0 == 0x00 ){   
input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,1);  
                    input_sync(sunxi_buttons_dev); 
     input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,0);  
                    input_sync(sunxi_buttons_dev); 
key_repeat_report[0] = 0x01;
key_repeat_report[1]++;
printk( "key1 zuhe.\n" );
 }else{
                    input_event(sunxi_buttons_dev,EV_KEY,KEY_F16,1);  
                    input_sync(sunxi_buttons_dev); 
     input_event(sunxi_buttons_dev,EV_KEY,KEY_F16,0);  
                    input_sync(sunxi_buttons_dev); 
key_repeat_report[1]++;
printk( "key1 long.\n" );
     //printk( "pin_value_in03 = 0x%x.\n", pin_value );
 }
            }
            
        }
        timer_cnt_1++;
  //½øÈ붨ʱÆ÷´ÎÊý¼Ó1
        mod_timer( &button_timer_in1, jiffies + msecs_to_jiffies(100) );
}else{    
  if( timer_cnt_1 == 0 ){
            //Ïû¶¶ÎÞÓð´¼ü    
            //µÚÒ»¸ö100ms½øÀ´,°´¼ü¾ÍÊÍ·ÅÁË,˵Ã÷Êǰ´¼ü¶¶¶¯
  }else{
            //°´¼üÒѾ­ÊÍ·Å
            if( time_before(jiffies, timeout_1+200) ){
                //»¹Ã»Óг¬Ê±,¶Ì°´
                //ËÉ¿ª ×îºóÒ»¸ö²ÎÊý: 0-ËÉ¿ª, 1-°´Ï  
                if( key_repeat_report[1] == 0x00 ){
                    input_event(sunxi_buttons_dev,EV_KEY,KEY_F15,1);  
                    input_sync(sunxi_buttons_dev);  
                    input_event(sunxi_buttons_dev,EV_KEY,KEY_F15,0);  
                    input_sync(sunxi_buttons_dev);  
     printk( "key1 short.\n" );
                }
            }
       }
 key_repeat_report[1]=0x00;
 timer_on_in1 = 0;
 //¿ÉÒÔÔÙ´ÎÏìÓ¦ÖжÏÁË
    }
    spin_unlock_irqrestore(&ioctrl_lock, flags);
}




































static irqreturn_t test_sunxi_pinctrl_irq_handler_in0(int irq, void *dev_id)
{       
                
    unsigned long flags;
    //printk("[%s] handler for test pinctrl eint api.\n",__func__);
    //disable_irq_nosync(irq);
    spin_lock_irqsave(&ioctrl_lock, flags);  
    if( key_repeat_report[0] ){
        key_repeat_report[0] = 0x00;
  goto exit;
    }
         
    if( timer_on_in0 == 0x00 ){
        g_input = 0x00;
        //ÇåÁãËùÓÐ״̬
        key_repeat_report[0] = 0x00;
        //ÖØ¸´±¨¸æÇåÁã
        timeout_0 = jiffies;
        //»ñȡʱ¼ä´Á
        timer_cnt_0 = 0x00;
        //¶¨Ê±Æ÷½øÈë´ÎÊýÇåÁã
        button_timer_in0.expires = jiffies + 10;
  button_timer_in0.data = 100;
  button_timer_in0.function = button_jitter_in0;
  add_timer(&button_timer_in0);
  timer_on_in0 = 1;
    }
exit:
    spin_unlock_irqrestore(&ioctrl_lock, flags);
    return IRQ_HANDLED;
}




static irqreturn_t test_sunxi_pinctrl_irq_handler_in1(int irq, void *dev_id)
{   


    
    unsigned long flags;
    spin_lock_irqsave( &ioctrl_lock, flags );  
             
    if( key_repeat_report[1] ){
        key_repeat_report[1] = 0x00;
        goto exit;
    }
   
    if( timer_on_in1 == 0x00 ){
        g_input = 0x00;
        //ÇåÁãËùÓÐ״̬
        key_repeat_report[1] = 0x00;
        //ÖØ¸´±¨¸æÇåÁã
        timeout_1 = jiffies;
        //»ñȡʱ¼ä´Á
        timer_cnt_1 = 0x00;
        //¶¨Ê±Æ÷½øÈë´ÎÊýÇåÁã 
        button_timer_in1.expires = jiffies + 10;
        button_timer_in1.data = 100;
        button_timer_in1.function = button_jitter_in1;
        add_timer(&button_timer_in1);
        timer_on_in1 = 1;
    }
    exit:
    spin_unlock_irqrestore(&ioctrl_lock, flags);
    return IRQ_HANDLED;
}








static int sunxi_gpio_eint_test_ioctrl_in0( struct platform_device *pdev )
{
unsigned long arg;
    //test_pinctrl_eint_api
    //request_irq
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i, pin_index,ret;
int virq;
struct device *dev = &pdev->dev;


#if 0
printk("\n");
printk("\n");
printk("\n");
#endif

type = script_get_item(main_key1, "in_0", &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, "in_0" );
}


#if 0
printk( "type = %d.\n", type );
printk( "val.val = %d.\n", val.val );
printk( "val.str = %s.\n", val.str );
printk( "val.gpio.gpio = %d.\n", val.gpio.gpio );
printk( "val.gpio.mul_sel = %d.\n", val.gpio.mul_sel );
printk( "val.gpio.pull = %d.\n", val.gpio.pull );
#endif

gpio_p = &val.gpio;
pin_index = gpio_p->gpio;
//printk( "GPIOB(6) = %d.\n", GPIOB(6) );
//printk( "pin_index = %d.\n", pin_index );
if( pin_index == 0 ){
printk("gpio led_hdl[%d] failed.\n", pin_index);
}


//mdelay




sunxi_gpio_req_ioctrl(gpio_p);
//ÅäÖÃgpio¿ÚΪÖжÏÊäÈëģʽ
virq = gpio_to_irq(pin_index);
//»ñÈ¡¶ÔÓ¦¶Ë¿ÚµÄÖжϺÅ
//printk( "virq = %d.\n", virq );
//printk( "IS_ERR_VALUE(virq) = %d.\n", IS_ERR_VALUE(virq) );
if (IS_ERR_VALUE(virq)){
printk("map gpio [%d] to virq [%d] failed !\n ",pin_index,virq);
return -EINVAL;
}
    ret = request_irq(virq, test_sunxi_pinctrl_irq_handler_in0,IRQF_TRIGGER_FALLING, DEVICE_NAME, (void *)arg);
    //ÖжÏ×¢²á
//printk( "ret = %d.\n", ret );
hdler_in0 = gpio_p->gpio;
//¶Ë¿ÚµÄ²Ù×÷¾ä±ú
isr_num[0] = virq;
//¶Ë¿ÚµÄϵͳÖжϺű£´æ,ΪÁËÍ˳öÇý¶¯Ä£¿éµÄʱºòʹÓÃ
//printk( "hdler_in0 = %d.\n", hdler_in0 );
}




static int sunxi_gpio_eint_test_ioctrl_in1( struct platform_device *pdev )
{
unsigned long arg;
    //test_pinctrl_eint_api
    //request_irq
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i, pin_index,ret;
int virq;
struct device *dev = &pdev->dev;


#if 0
printk("\n");
printk("\n");
printk("\n");
#endif

type = script_get_item(main_key1, "in_1", &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, "in_1" );
}


#if 0
printk( "type = %d.\n", type );
printk( "val.val = %d.\n", val.val );
printk( "val.str = %s.\n", val.str );
printk( "val.gpio.gpio = %d.\n", val.gpio.gpio );
printk( "val.gpio.mul_sel = %d.\n", val.gpio.mul_sel );
printk( "val.gpio.pull = %d.\n", val.gpio.pull );
#endif

gpio_p = &val.gpio;
pin_index = gpio_p->gpio;
//printk( "GPIOB(6) = %d.\n", GPIOB(6) );
//printk( "pin_index = %d.\n", pin_index );
if( pin_index == 0 ){
printk("gpio led_hdl[%d] failed.\n", pin_index);
}


//mdelay




sunxi_gpio_req_ioctrl(gpio_p);
virq = gpio_to_irq(pin_index);
//printk( "virq = %d.\n", virq );
//printk( "IS_ERR_VALUE(virq) = %d.\n", IS_ERR_VALUE(virq) );
    if( IS_ERR_VALUE(virq)){
        printk("map gpio [%d] to virq [%d] failed !\n ",pin_index,virq);
        return -EINVAL;
    }
    ret = request_irq(virq, test_sunxi_pinctrl_irq_handler_in1,IRQF_TRIGGER_FALLING, DEVICE_NAME, (void *)arg);
//printk( "ret = %d.\n", ret );
hdler_in1 = gpio_p->gpio;
isr_num[1] = virq;
//printk( "hdler_in1 = %d.\n", hdler_in1 );
}




static int __init io_ctl_probe(struct platform_device *pdev)
{
script_item_u val;
script_item_value_type_e type;
struct gpio_config  *gpio_p = NULL;
int i;





for( i = 0; i < 4; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
    printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
             printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
set_gpio_status(led_hdler[0], 1); 
    set_gpio_status(led_hdler[1], 1); 
//ÇжÏmaxim°å×ӵĵçÔ´
    //¸ßµçƽ1,µÍµçƽ0    
    set_gpio_status(led_hdler[2], 1);
set_gpio_status(led_hdler[3], 1);
    //printk("gpio hander ok.\n");



sunxi_gpio_eint_test_ioctrl_in0(pdev);
sunxi_gpio_eint_test_ioctrl_in1(pdev);
return 0;
}


















static int __exit io_ctl_remove(struct platform_device *pdev)
{
//del_timer(&led_timer);
return 0;
}


static struct platform_driver io_ctrl_driver = {
.driver = {
.name = "io_ctrl",
.owner = THIS_MODULE,
},
.remove = __exit_p(io_ctl_remove),
};








static int gpio_close(struct inode *inode, struct file *file)
{
    //printk("gpio_close!\n");
    gpio_fasync(-1, file, 0);
return 0;
}










//led-gpio-ctl.c
static struct file_operations gpio_fops = {
.owner = THIS_MODULE,
.read = gpio_rd,
.write = gpio_wr,
.unlocked_ioctl = gpio_ioctl,
.fasync = gpio_fasync,
.release = gpio_close,
};


          
//Install the gpio dev interface driver                          
static int __init sunxin_gpio_init( void )                
{   
    int ret;
init_timer(&button_timer_in0);
//ÉèÖüüÏû¶¶¶¨Ê±Æ÷
init_timer(&button_timer_in1);
//·µ»Ø¼üÏû¶¶¶¨Ê±Æ÷
timer_on_in0 = 0x00;
//ÉèÖüü½ûÖ¹ÖØ¸´±¨¸æ
timer_on_in1 = 0x00;
     //·µ»Ø¼ü½ûÖ¹ÖØ¸´±¨¸æ
    key_repeat_report[0] = 0x00;
    key_repeat_report[1] = 0x00;
g_input = 0x00;
//È«¾Ö°´¼ü״̬

//³õʼ»¯ÐźÅÁ¿ºÍ¼Ä´æÆ÷valµÄÖµ
//init_MUTEX(&(dev->sem));
//sema_init( &sem, 1 );                           
    spin_lock_init(&ioctrl_lock);   
//×ÔÐýËø






#if 0
gpioctl_wq = create_singlethread_workqueue("gpioctl.do.work");
if( gpioctl_wq == NULL ){
printk("create gpioctl_wq fail!\n");
return -ENOMEM;
}
    #endif



    //init_timer(&gpioctl_timer);
    //queue_work(gpioctl_wq, &gpioctl_do_work);
    


    //printk("\n");
//printk( KERN_ERR "in sunxin_gpio_init.\n" );                                      
if( register_chrdev(gpio_MAJOR, "gpioctl", &gpio_fops) ) {                                             
printk(KERN_ERR "sunxin_gpio: Unable to get major %d for gpio\n", gpio_MAJOR);                 
return -EIO;                  
}                       
//led_ctl_probe();
//set_led_status(1);
ret = platform_driver_probe(&io_ctrl_driver, io_ctl_probe);
//printk( KERN_ERR "[io_ctrl] ret = %d.\n", ret );     
    //printk(KERN_INFO "sunxin GPIO io-ctrl loaded ok!\n");


    //set_all_cfg_io();
#if 0
    netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE);
if(NULL == netlink_fd)
{
printk(KERN_ALERT "Init netlink!\n");
return -1;
}
printk(KERN_ALERT "Init netlink success!\n");
    #endif
  
    #define INPUT_DEV_NAME          ("sunxi-keyboard_selfdef_io")  
    //1.·ÖÅäÒ»¸öinput_dev½á¹¹Ìå  
    sunxi_buttons_dev = input_allocate_device();
sunxi_buttons_dev->name = INPUT_DEV_NAME;  
//sunxi_buttons_dev->phys = "sunxikbd/input0"; 
//sunxi_buttons_dev->id.bustype = BUS_HOST;      
//sunxi_buttons_dev->id.vendor = 0x0001;
//sunxi_buttons_dev->id.product = 0x0001;
//sunxi_buttons_dev->id.version = 0x0100;



    //2.ÉèÖÃ  
    //2.1 ÉèÖð´¼üÄܲúÉúÄÄÀàʼþ  
    set_bit(EV_KEY,sunxi_buttons_dev->evbit);  
    set_bit(EV_REP,sunxi_buttons_dev->evbit);  
  
    //2.2 ÉèÖÃÄÄЩʼþÄܲúÉúÕâÀà²Ù×÷  
    set_bit(KEY_F13,sunxi_buttons_dev->keybit);  
    set_bit(KEY_F14,sunxi_buttons_dev->keybit);  
    set_bit(KEY_F15,sunxi_buttons_dev->keybit);  
      
    //3.×¢²á  
    ret = input_register_device(sunxi_buttons_dev);  
    //printk( KERN_ALERT "input_register_device success! = %d\n", ret );
    return 0;
}




































//Remove the gpio dev interface driver
static void __exit sunxin_gpio_exit( void )
{  




    if( isr_num[0] ){
        free_irq(isr_num[0], NULL);
}


if( isr_num[1] ){
        free_irq(isr_num[1], NULL);
}
    input_unregister_device(sunxi_buttons_dev);

    platform_driver_unregister(&io_ctrl_driver);
unregister_chrdev( gpio_MAJOR, "gpioctl" );
printk(KERN_INFO "sunxin GPIO driver unloaded\n");


netlink_kernel_release(netlink_fd);
printk(KERN_ALERT "Exit netlink!\n");




}


module_init(sunxin_gpio_init);
module_exit(sunxin_gpio_exit);








MODULE_LICENSE("GPL");
MODULE_AUTHOR("dp_mcu");
MODULE_DESCRIPTION("GPIO dev interface for MID");
MODULE_VERSION("Ver 1.0");
#endif






//


#if 0
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>


//#include "hello.h"




#include <linux/cdev.h>  
#include <linux/semaphore.h>  
  
#define HELLO_DEVICE_NODE_NAME  "hello"  
#define HELLO_DEVICE_FILE_NAME  "hello"  
#define HELLO_DEVICE_PROC_NAME  "hello"  
#define HELLO_DEVICE_CLASS_NAME "hello"  
  
struct hello_android_dev {  
    int val;  
    struct semaphore sem;  
    struct cdev dev;  
};  








/*Ö÷É豸ºÍ´ÓÉ豸ºÅ±äÁ¿*/
static int hello_major = 0;
static int hello_minor = 0;


/*É豸Àà±ðºÍÉ豸±äÁ¿*/
static struct class* hello_class = NULL;
static struct hello_android_dev* hello_dev = NULL;


/*´«Í³µÄÉ豸Îļþ²Ù×÷·½·¨*/
static int hello_open(struct inode* inode, struct file* filp);
static int hello_release(struct inode* inode, struct file* filp);
static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);
static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);


/*É豸Îļþ²Ù×÷·½·¨±í*/
static struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.read = hello_read,
.write = hello_write, 
};


/*·ÃÎÊÉèÖÃÊôÐÔ·½·¨*/
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr,  char* buf);
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);


/*¶¨ÒåÉ豸ÊôÐÔ*/
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);






/*´ò¿ªÉ豸·½·¨*/
static int hello_open(struct inode* inode, struct file* filp) {
struct hello_android_dev* dev;        

/*½«×Ô¶¨ÒåÉ豸½á¹¹Ìå±£´æÔÚÎļþÖ¸ÕëµÄ˽ÓÐÊý¾ÝÓòÖУ¬ÒÔ±ã·ÃÎÊÉ豸ʱÄÃÀ´ÓÃ*/
dev = container_of(inode->i_cdev, struct hello_android_dev, dev);
filp->private_data = dev;

return 0;
}


/*É豸ÎļþÊÍ·Åʱµ÷Ó㬿ÕʵÏÖ*/
static int hello_release(struct inode* inode, struct file* filp) {
return 0;
}


/*¶ÁÈ¡É豸µÄ¼Ä´æÆ÷valµÄÖµ*/
static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {
ssize_t err = 0;
struct hello_android_dev* dev = filp->private_data;        


/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {
return -ERESTARTSYS;
}


if(count < sizeof(dev->val)) {
goto out;
}        


/*½«¼Ä´æÆ÷valµÄÖµ¿½±´µ½Óû§ÌṩµÄ»º³åÇø*/
if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) {
err = -EFAULT;
goto out;
}


err = sizeof(dev->val);


out:
up(&(dev->sem));
return err;
}


/*дÉ豸µÄ¼Ä´æÆ÷Öµval*/
static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {
struct hello_android_dev* dev = filp->private_data;
ssize_t err = 0;        


/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {
return -ERESTARTSYS;        
}        


if(count != sizeof(dev->val)) {
goto out;        
}        


/*½«Óû§ÌṩµÄ»º³åÇøµÄֵдµ½É豸¼Ä´æÆ÷È¥*/
if(copy_from_user(&(dev->val), buf, count)) {
err = -EFAULT;
goto out;
}


err = sizeof(dev->val);


out:
up(&(dev->sem));
return err;
}




/*¶ÁÈ¡¼Ä´æÆ÷valµÄÖµµ½»º³åÇøbufÖУ¬ÄÚ²¿Ê¹ÓÃ*/
static ssize_t __hello_get_val(struct hello_android_dev* dev, char* buf) {
int val = 0;        


/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {                
return -ERESTARTSYS;        
}        


val = dev->val;        
up(&(dev->sem));        


return snprintf(buf, PAGE_SIZE, "%d\n", val);
}


/*°Ñ»º³åÇøbufµÄֵдµ½É豸¼Ä´æÆ÷valÖÐÈ¥£¬ÄÚ²¿Ê¹ÓÃ*/
static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) {
int val = 0;        


/*½«×Ö·û´®×ª»»³ÉÊý×Ö*/        
val = simple_strtol(buf, NULL, 10);        


/*ͬ²½·ÃÎÊ*/        
if(down_interruptible(&(dev->sem))) {                
return -ERESTARTSYS;        
}        


dev->val = val;        
up(&(dev->sem));


return count;
}


/*¶ÁÈ¡É豸ÊôÐÔval*/
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {
struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);        


return __hello_get_val(hdev, buf);
}


/*дÉ豸ÊôÐÔval*/
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) { 
struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);  

return __hello_set_val(hdev, buf, count);
}




/*¶ÁÈ¡É豸¼Ä´æÆ÷valµÄÖµ£¬±£´æÔÚpage»º³åÇøÖÐ*/
static ssize_t hello_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) {
if(off > 0) {
*eof = 1;
return 0;
}


return __hello_get_val(hello_dev, page);
}


/*°Ñ»º³åÇøµÄÖµbuff±£´æµ½É豸¼Ä´æÆ÷valÖÐÈ¥*/
static ssize_t hello_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) {
int err = 0;
char* page = NULL;


if(len > PAGE_SIZE) {
printk(KERN_ALERT"The buff is too large: %lu.\n", len);
return -EFAULT;
}


page = (char*)__get_free_page(GFP_KERNEL);
if(!page) {                
printk(KERN_ALERT"Failed to alloc page.\n");
return -ENOMEM;
}        


/*ÏȰÑÓû§ÌṩµÄ»º³åÇøÖµ¿½±´µ½Äں˻º³åÇøÖÐÈ¥*/
if(copy_from_user(page, buff, len)) {
printk(KERN_ALERT"Failed to copy buff from user.\n");                
err = -EFAULT;
goto out;
}


err = __hello_set_val(hello_dev, page, len);


out:
free_page((unsigned long)page);
return err;
}


/*´´½¨/proc/helloÎļþ*/
static void hello_create_proc(void) {
struct proc_dir_entry* entry;

entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL);
if(entry) {
//entry->owner = THIS_MODULE;
entry->read_proc = hello_proc_read;
entry->write_proc = hello_proc_write;
}
}


/*ɾ³ý/proc/helloÎļþ*/
static void hello_remove_proc(void) {
remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL);
}




/*³õʼ»¯É豸*/
static int  __hello_setup_dev(struct hello_android_dev* dev) {
int err;
dev_t devno = MKDEV(hello_major, hello_minor);


memset(dev, 0, sizeof(struct hello_android_dev));


cdev_init(&(dev->dev), &hello_fops);
dev->dev.owner = THIS_MODULE;
dev->dev.ops = &hello_fops;        


/*×¢²á×Ö·ûÉ豸*/
err = cdev_add(&(dev->dev),devno, 1);
if(err) {
return err;
}        


/*³õʼ»¯ÐźÅÁ¿ºÍ¼Ä´æÆ÷valµÄÖµ*/
//init_MUTEX(&(dev->sem));
sema_init (&(dev->sem), 1); 
dev->val = 0;


return 0;
}


/*Ä£¿é¼ÓÔØ·½·¨*/
static int __init hello_init(void){ 
int err = -1;
dev_t dev = 0;
struct device* temp = NULL;


printk(KERN_ALERT"Initializing hello device.\n");        


/*¶¯Ì¬·ÖÅäÖ÷É豸ºÍ´ÓÉ豸ºÅ*/
err = alloc_chrdev_region(&dev, 0, 1, HELLO_DEVICE_NODE_NAME);
if(err < 0) {
printk(KERN_ALERT"Failed to alloc char dev region.\n");
goto fail;
}


hello_major = MAJOR(dev);
hello_minor = MINOR(dev);        
printk( KERN_ALERT "hello_major = %x.\n", hello_major );
printk( KERN_ALERT "hello_minor = %x.\n", hello_minor );


/*·ÖÅäheloÉ豸½á¹¹Ìå±äÁ¿*/
hello_dev = kmalloc(sizeof(struct hello_android_dev), GFP_KERNEL);
if(!hello_dev) {
err = -ENOMEM;
printk(KERN_ALERT"Failed to alloc hello_dev.\n");
goto unregister;
}        


/*³õʼ»¯É豸*/
err = __hello_setup_dev(hello_dev);
if(err) {
printk(KERN_ALERT"Failed to setup dev: %d.\n", err);
goto cleanup;
}        


/*ÔÚ/sys/class/Ŀ¼Ï´´½¨É豸Àà±ðĿ¼hello*/
hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME);
if(IS_ERR(hello_class)) {
err = PTR_ERR(hello_class);
printk(KERN_ALERT"Failed to create hello class.\n");
goto destroy_cdev;
}        


/*ÔÚ/dev/Ŀ¼ºÍ/sys/class/helloĿ¼Ï·ֱ𴴽¨É豸Îļþhello*/
temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);
if(IS_ERR(temp)) {
err = PTR_ERR(temp);
printk(KERN_ALERT"Failed to create hello device.");
goto destroy_class;
}        


/*ÔÚ/sys/class/hello/helloĿ¼Ï´´½¨ÊôÐÔÎļþval*/
err = device_create_file(temp, &dev_attr_val);
if(err < 0) {
printk(KERN_ALERT"Failed to create attribute val.");                
goto destroy_device;
}


dev_set_drvdata(temp, hello_dev);        


/*´´½¨/proc/helloÎļþ*/
hello_create_proc();


printk(KERN_ALERT"Succedded to initialize hello device.\n");
return 0;


destroy_device:
device_destroy(hello_class, dev);


destroy_class:
class_destroy(hello_class);


destroy_cdev:
cdev_del(&(hello_dev->dev));


cleanup:
kfree(hello_dev);


unregister:
unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1);


fail:
return err;
}


/*Ä£¿éÐ¶ÔØ·½·¨*/
static void __exit hello_exit(void) {
dev_t devno = MKDEV(hello_major, hello_minor);


printk(KERN_ALERT"Destroy hello device.\n");        


/*ɾ³ý/proc/helloÎļþ*/
hello_remove_proc();        


/*Ïú»ÙÉ豸Àà±ðºÍÉ豸*/
if(hello_class) {
device_destroy(hello_class, MKDEV(hello_major, hello_minor));
class_destroy(hello_class);
}        


/*ɾ³ý×Ö·ûÉ豸ºÍÊÍ·ÅÉ豸ÄÚ´æ*/
if(hello_dev) {
cdev_del(&(hello_dev->dev));
kfree(hello_dev);
}        


/*ÊÍ·ÅÉ豸ºÅ*/
unregister_chrdev_region(devno, 1);
}


MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("First Android Driver");


module_init(hello_init);
module_exit(hello_exit);
#endif
//









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值