设备节点创建:
mknod /dev/ar9344_button c 10 189 
可以通过查看文件
/proc # cat misc 
189 ar9344_button

1 驱动程序分析

Watchdog程序只有一个文件,其在内核中的位置如下:

./src/linux/kernels/mips-linux-2.6.31/arch/mips/atheros/wdt.c

主要函数分析如下:

首先watchdog以混杂设备的方式编译为模块,混杂设备是字符设备的特殊情况。

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/signal.h>

#include <linux/interrupt.h>

#include <linux/irq.h>

#include <linux/init.h>

#include <linux/resource.h>

#include <linux/proc_fs.h>

#include <linux/miscdevice.h>

#include <asm/types.h>

#include <asm/irq.h>

#include <asm/delay.h>

#include <asm/system.h>

#include <asm/mach-atheros/atheros.h>

#define ATH_FACTORY_RESET             0x89ABCDEF

#define BUTTON_GPIO 15

#define UDELAY_COUNT 80000

#define BUTTON_MINOR 189

#define ATH_WDT_TEST_CODE

 

#ifdef ATH_WDT_TEST_CODE

#define btdbg printk

#else

#define btdbg(junk, ...)

#endif /* ATH_WDT_TEST_CODE 8 */

 

 

typedef enum

{

       INT_TYPE_EDGE,

       INT_TYPE_LEVEL,

} ath_gpio_int_type_t;

 

typedef enum

{

       INT_POL_ACTIVE_LOW,

       INT_POL_ACTIVE_HIGH,

} ath_gpio_int_pol_t;

 

 

extern int ath_gpio_in_val(int);

extern void ath_gpio_config_input(int gpio);

extern void ath_gpio_config_int(int gpio,ath_gpio_int_type_t type,ath_gpio_int_pol_t polarity);

extern void ath_restart(char *);

 

struct buttons_dev_t

{

       wait_queue_head_t buttons_waitqueue; /* 等待队列,当没有按键被按下时,如果有进程调用s3c24xx_buttons_read函数,它将休眠 */

       volatile int ev_press; /* 中断事件标志, 中断服务程序将它置1,s3c24xx_buttons_read将它清0 */

       volatile unsigned int press_cnt;    /* 4个按键被按下的次数(准确地说,是发生中断的次数) */

       struct timer_list button_timers; /* buttons delay timer */

       int ar9344_ButtonOpened;

};

 

static struct buttons_dev_t buttons_dev =

{

       .ev_press   = 0,

       .press_cnt  = 0,

};

 

static irqreturn_t ar9344buttons_interrupt(int irq, void *dev_id)

{

              unsigned int delay;

              disable_irq(irq);     

      

              for (delay = UDELAY_COUNT; delay; delay--)

              {

                     if(ath_gpio_in_val(BUTTON_GPIO))

                     {

                            btdbg("\n

break: ath_gpio_in_val(BUTTON_GPIO):0x%x\n",ath_gpio_in_val(BUTTON_GPIO));  

                            break;

                     }

                     btdbg("\n

delay:%d \t ath_gpio_in_val(BUTTON_GPIO):0x%x\n",delay,ath_gpio_in_val(BUTTON_GPIO));

                     udelay(100);

              }

 

              if (!delay)

              {

                     printk("\n you press button a long time,do'not response the interrupt .....!\n");    

              }

              else

              {

                     btdbg("\nbuttons_interrupt comming  \n");

                     buttons_dev.press_cnt = buttons_dev.press_cnt+ 1; /* 按键计数加1 */

                     buttons_dev.ev_press = 1;                /* 表示中断发生了 */

                     wake_up_interruptible(&(buttons_dev.buttons_waitqueue));   /* 唤醒休眠的进程*/

                     btdbg("\n buttons_dev.press_cnt: %d:buttons_dev.ev_press:%d\n",

buttons_dev.press_cnt ,buttons_dev.ev_press);  

                     if(buttons_dev.press_cnt > 10)

                     {

                            printk("\n%s: systerm reboot.........\n", __func__);

                            ath_restart(NULL);                             

                     }

              }

              enable_irq(irq);

       return IRQ_HANDLED;

}

 

 

static int ar9344Button_open(struct inode *inode, struct file *file)

{

       int ret =0;

       if (MINOR(inode->i_rdev) != BUTTON_MINOR)

       {

              return -ENODEV;

       }

       if (buttons_dev.ar9344_ButtonOpened)

       {

              return -EBUSY;

       }

       buttons_dev.ar9344_ButtonOpened = 1;

       ret = request_irq(ATH_GPIO_IRQn(BUTTON_GPIO), ar9344buttons_interrupt, 0,"ar9344 button", NULL);

       if (ret != 0)

       {

              printk("request_irq for button  (error %d)\n", ret);

       }     

       return ret;

}

 

static int ar9344Button_close(struct inode *inode, struct file *file)

{

       if (MINOR(inode->i_rdev) != BUTTON_MINOR)

       {

              return -ENODEV;

       }

       buttons_dev.ar9344_ButtonOpened = 0;

       free_irq(ATH_GPIO_IRQn(BUTTON_GPIO), NULL);

       return 0;

}

 

static ssize_t ar9344Button_read(struct file *file, char *buff, size_t count, loff_t * ppos)

{

       unsigned long err;

       int retval = 0;

       /* 如果ev_press等于0,休眠 */

       wait_event_interruptible(buttons_dev.buttons_waitqueue, (buttons_dev.ev_press != 0));

       /* 执行到这里时,ev_press等于1,将它清0 */

       buttons_dev.ev_press = 0;

       /* 将按键状态复制给用户,并清0 */

       err =copy_to_user(buff,(const void *)&buttons_dev.press_cnt,sizeof(buttons_dev.press_cnt));

       if (err < 0)

       {

              printk("\ncopy_to_user error ret: %d\n",err);     

              retval = -EFAULT;

       }

       else

       {

              retval = sizeof(buttons_dev.press_cnt);

       }

 // buttons_dev.press_cnt =0;

       //printk("\nretval:%d  buttons_dev.press_cnt: %d: buttons_dev.ev_press:%d\n",

retval,buttons_dev.press_cnt ,buttons_dev.ev_press);

       return retval;

}

 

static ssize_t ar9344Button_write(struct file *file, const char *buf, size_t count, loff_t * ppos)

{

       unsigned  int cnt =0;

       int ret ;

       int __user *ptr = (int __user *)buf;

       ret = get_user(cnt, ptr);

       if(ret)

       {

              ret= -EFAULT;

       }

       else

       {

              ret = count;

              buttons_dev.press_cnt = cnt;

       }

       printk("\rret: %d  buttons_dev.press_cnt: %d:

cnt:%d  count;%d\n",ret,buttons_dev.press_cnt ,cnt,count);    

       return ret;

}

 

static int ar9344Button_ioctl(struct inode *inode, struct file *file, unsigned int cmd,unsigned long arg)

{

       int ret = 0;

       return ret;

}

 

static struct file_operations ar9344Button_fops = {

       read:                     ar9344Button_read,

       write:             ar9344Button_write,

       ioctl:              ar9344Button_ioctl,

       open:                    ar9344Button_open,

       release:   ar9344Button_close

};

 

static struct miscdevice athfr_miscdev = {

       BUTTON_MINOR,

       "ar9344_button",

       &ar9344Button_fops

};

static int __init ar9344_button_init(void)

{

       int ret;

      

       ret = misc_register(&athfr_miscdev);

       if (ret < 0) {

              printk("*** ath misc_register failed %d *** \n", ret);

              return -1;

       }

       init_waitqueue_head(&(buttons_dev.buttons_waitqueue));

      

       ath_gpio_config_input(BUTTON_GPIO);

       ath_gpio_config_int(BUTTON_GPIO, INT_TYPE_LEVEL,INT_POL_ACTIVE_LOW);

       printk("%s (%s) BUTTON_GPIO: %d\t gpioValue:0x%x\n", __FILE__, __func__,BUTTON_GPIO,ath_gpio_in_val(BUTTON_GPIO));

       return ret;

}     

static void __exit ar9344_buttons_exit(void)

{      

              misc_deregister(&athfr_miscdev);

       //     ath_gpio_intr_shutdown(ATH_GPIO_IRQn(BUTTON_GPIO));

         printk("%s (%s) line: %d\n", __FILE__, __func__,__LINE__);               

}            

module_init(ar9344_button_init);

module_exit(ar9344_buttons_exit);

MODULE_AUTHOR("suiyuan from comba");             // 驱动程序的作者

MODULE_DESCRIPTION("ar9344 BUTTON Driver");   // 一些描述信息

MODULE_LICENSE("GPL");                              // 遵循的协议

测试结果如下:

~ # button

ar9344buttons_interrupt: ath_restart.........
Button press_cnt:1

ar9344buttons_interrupt: ath_restart.........
Button press_cnt:2

ar9344buttons_interrupt: ath_restart.........
Button press_cnt:3

ar9344buttons_interrupt: ath_restart.........
Button press_cnt:4

ar9344buttons_interrupt: ath_restart.........
Button press_cnt:5

ar9344buttons_interrupt: ath_restart.........
Button press_cnt:6

ar9344buttons_interrupt: ath_restart.........
Button press_cnt:7

ar9344buttons_interrupt: ath_restart.........
Button press_cnt:8

 

测试代码如下:

#include <stdio.h>

#include <fcntl.h>

#include <signal.h>

int press_cnt =0;

int main(int argc, char * argv[])

{

       int fd =0;

       int ret =0;

       int wcnt =0;

       if ((fd = open("/dev/ar9344_button", O_RDWR)) == -1) {

              perror("open");

              return ;

       }

       while(1)

       {

              if(argv[1] != NULL)

              {

                     wcnt = atoi(argv[1]);

                     ret = write(fd, (void*)&wcnt, sizeof(wcnt));

                     printf("Set Button press_cnt to zero:%d\n",wcnt);

                     return 0;

              }

              ret = read(fd, (void*)&press_cnt, sizeof(press_cnt));

              printf("\rButton press_cnt:%d\n",press_cnt);

             

       /*    if(press_cnt >5)

              {

                     wcnt = 0;

                     ret = write(fd, (void*)&wcnt, sizeof(wcnt));

                     printf("Set Button press_cnt to zero:%d\n",wcnt);

              }

              */

       }

       close(fd);

}

Logo

更多推荐