设备节点创建:
mknod /dev/ar9344_button c 10 189
可以通过查看文件
/proc # cat misc
189 ar9344_button
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);
}