커 널 구동. - 커 널 타이머.
9046 단어 S5PV210
커 널 타이머 란 커 널 이 미래의 특정한 시간 대 (jiffies 현재 시간 기반) 에서 특정한 함 수 를 실행 하 는 메커니즘 을 제어 하 는 것 입 니 다. 배 치 된 함 수 는 비동기 로 실 행 됩 니 다. '소프트웨어 중단' 과 유사 하고 비 프로 세 스 의 문맥 에 있 습 니 다. 배 치 된 함 수 는 다음 과 같은 규칙 을 따라 야 합 니 다.
1) 없다 current 포인터, 사용자 공간 에 접근 할 수 없습니다.프로 세 스 컨 텍스트 가 없 기 때문에 관련 코드 는 중 단 된 프로 세 스 와 아무런 연락 이 없습니다.
2) 휴면 (또는 휴면 을 일 으 킬 수 있 는 함수) 과 스케줄 을 실행 할 수 없습니다.
3) 모든 방문 한 데이터 구 조 는 동시 방문 을 보호 하여 경쟁 조건 을 방지 해 야 한다.
커 널 타이머 의 스 케 쥴 러 함수 가 한 번 실 행 된 후 다 시 는 실행 되 지 않 습 니 다 (자동 로그아웃 에 해당 합 니 다). 그러나 스 케 쥴 러 함수 에서 자신 을 다시 스 케 쥴 러 주기 로 실행 할 수 있 습 니 다.
커 널 타이머 의 데이터 구조
struct timer_list {
struct list_head entry;
unsigned long expires; // jiffies , jiffies , function , data
void (*function)(unsigned long);
unsigned long data;
struct tvec_base *base;
/* ... */
};
2. 버튼 + 커 널 타이머 떨 기 코드 다운로드 클릭 하여 링크 열기
1. struct timer 정의list buttons_timer;2 、 init 초기 화timer(&buttons_timer);3, 등록 타이머 addtimer(&buttons_timer);4 、 타이머 mod 시작timer(&buttons_timer, jiffies + (HZ / 10)); /*시간 지연 1s / 10 = 100 ms * / 5, 타이머 취소 deltimer(&buttons_timer);
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GPH0CON 0xE0200C00
#define GPH0DAT 0xE0200C04
#define DEVICE_NAME "tqkey"
#define LEDCON 0xE0200060
#define LEDDAT 0xE0200064
volatile unsigned int *led_config;
volatile unsigned int *led_data;
volatile unsigned int *key_data;
//1、
struct work_struct *work;
//( )1、
struct timer_list buttons_timer;
void work_func(struct work_struct *work)
{
/* */ /* 1s/10=100ms */
mod_timer(&buttons_timer, jiffies + (HZ / 10));
}
//( )5、
static void buttons_timer_function(unsigned long data)
{
unsigned int key_val;
key_val = readw(key_data) & 0x1; //GPH0_0
if(key_val == 0) //
{
volatile unsigned short data;
data = readw(led_data);
if(data == 0)
{
data = 0xFF;
}
else
{
data = 0;
}
writel(data, led_data);
}
}
void timer_init(void)
{
//( )2、
init_timer(&buttons_timer);
buttons_timer.function = &buttons_timer_function;
//( )3、
add_timer(&buttons_timer);
}
static irqreturn_t key_int(int irq, void *dev_id)
{
//3、 keventd_wq
schedule_work(work);
return 0;
}
void key_hw_init(void)
{
volatile unsigned short data;
volatile unsigned int *gpio_config;
gpio_config = (volatile unsigned int *)ioremap(GPH0CON, 4);
data = readw(gpio_config); //
data &= ~0x0F;
data |= 0x0F;
writew(data, gpio_config);
printk("key_hw_init!
");
led_config = (volatile unsigned int *)ioremap(LEDCON, 4); //
writel(0x00011000, led_config);
led_data = (volatile unsigned int *)ioremap(LEDDAT, 4);
writel(0xFF, led_data);
key_data = (volatile unsigned int *)ioremap(GPH0DAT, 4);
}
/*static long key_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return -EINVAL;
}*/
static int key_open(struct inode *inode, struct file *file)
{
return 0;
}
static struct file_operations key_fops =
{
.owner = THIS_MODULE,
//.unlocked_ioctl = key_ioctl,
.open = key_open,
.release = NULL,
};
struct miscdevice key_miscdev =
{
.minor = 200,
.name = DEVICE_NAME,
.fops = &key_fops,
};
//
static int __init button_init(void)
{
int ret = 0;
misc_register(&key_miscdev);
//
ret = request_irq(IRQ_EINT0, key_int, IRQF_TRIGGER_FALLING, DEVICE_NAME, 0);
//
key_hw_init();
//2、
work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
//( :GFP_KERNEL , )
INIT_WORK(work, work_func); // ,
//
timer_init();
return 0;
}
//
static void __exit button_exit(void)
{
misc_deregister(&key_miscdev);
//
free_irq(IRQ_EINT0, 0);
//
del_timer(&buttons_timer);
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jerry.Gou");
MODULE_DESCRIPTION("TQ210 button driver");
다 중 버튼 인 터 럽 트
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GPH0CON 0xE0200C00
#define GPH0DAT 0xE0200C04
#define DEVICE_NAME "tqkey"
#define LEDCON 0xE0200060
#define LEDDAT 0xE0200064
volatile unsigned int *led_config;
volatile unsigned int *led_data;
volatile unsigned int *key_data;
//1、
struct work_struct *work;
//( )1、
struct timer_list buttons_timer;
void work_func(struct work_struct *work)
{
/* */ /* 1s/10=100ms */
mod_timer(&buttons_timer, jiffies + (HZ / 10));
}
//( )5、
static void buttons_timer_function(unsigned long data)
{
unsigned int key_val;
volatile unsigned short leddata;
key_val = readw(key_data) & 0x1; //GPH0_0 Key_1
if(key_val == 0) //
{
leddata = 0xFF; // LED
writel(leddata, led_data);
}
key_val = readw(key_data) & 0x02; //GPH0_0 Key_2
if(key_val == 0) //
{
leddata = 0x00; // LED
writel(leddata, led_data);
}
}
void timer_init(void)
{
//( )2、
init_timer(&buttons_timer);
buttons_timer.function = &buttons_timer_function;
//( )3、
add_timer(&buttons_timer);
}
static irqreturn_t key_int(int irq, void *dev_id)
{
//3、 keventd_wq
schedule_work(work);
return 0;
}
void key_hw_init(void)
{
volatile unsigned short data;
volatile unsigned int *gpio_config;
gpio_config = (volatile unsigned int *)ioremap(GPH0CON, 4);
data = readw(gpio_config); //
data &= ~0xFF;
data |= 0xFF;
writew(data, gpio_config);
printk("key_hw_init!
");
led_config = (volatile unsigned int *)ioremap(LEDCON, 4); //
writel(0x00011000, led_config);
led_data = (volatile unsigned int *)ioremap(LEDDAT, 4);
writel(0xFF, led_data);
key_data = (volatile unsigned int *)ioremap(GPH0DAT, 4);
}
/*static long key_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return -EINVAL;
}*/
static int key_open(struct inode *inode, struct file *file)
{
return 0;
}
static struct file_operations key_fops =
{
.owner = THIS_MODULE,
//.unlocked_ioctl = key_ioctl,
.open = key_open,
.release = NULL,
};
struct miscdevice key_miscdev =
{
.minor = 200,
.name = DEVICE_NAME,
.fops = &key_fops,
};
//
static int __init button_init(void)
{
int ret = 0;
misc_register(&key_miscdev);
//
ret = request_irq(IRQ_EINT0, key_int, IRQF_TRIGGER_FALLING, DEVICE_NAME, 0);
ret = request_irq(IRQ_EINT1, key_int, IRQF_TRIGGER_FALLING, DEVICE_NAME, 0);
//
key_hw_init();
//2、
work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
//( :GFP_KERNEL , )
INIT_WORK(work, work_func); // ,
//
timer_init();
return 0;
}
//
static void __exit button_exit(void)
{
misc_deregister(&key_miscdev);
//
free_irq(IRQ_EINT0, 0);
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jerry.Gou");
MODULE_DESCRIPTION("TQ210 button driver");
타이머 구현
/* log */
/*__func__ __TIME__ , “hh:mm:ss”*/
#include
#include
#include
#include
#include
static struct timer_list tm;
struct timeval oldtv;
void callback(unsigned long arg)
{
struct timeval tv;
char *strp = (char*)arg;
printk("%s: %lu, %s
", __func__, jiffies, strp);
do_gettimeofday(&tv);
printk("%s: %ld, %ld
", __func__,
tv.tv_sec - oldtv.tv_sec, // s
tv.tv_usec- oldtv.tv_usec); // ms
oldtv = tv;
tm.expires = jiffies+1*HZ;
add_timer(&tm); //
}
static int __init demo_init(void)
{
printk(KERN_INFO "%s : %s : %d - ok.
", __FILE__, __func__, __LINE__);
init_timer(&tm); //
do_gettimeofday(&oldtv); //
tm.function= callback; //
tm.data = (unsigned long)"hello world"; //
tm.expires = jiffies+1*HZ; //
add_timer(&tm); //
return 0;
}
static void __exit demo_exit(void)
{
printk(KERN_INFO "%s : %s : %d - ok.
", __FILE__, __func__, __LINE__);
del_timer(&tm); //
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jerry.Gou");
MODULE_DESCRIPTION("TQ210 button driver");