도와주세요!!
글 수 15,339
2003.07.03 09:44:41 (*.239.95.67)
7783
제가 지금 하고자 하는 것은 이런 것입니다.
특정 GPIO를 버튼에 연결하여
버튼을 누르면 보드의 전원이 suspend되고
다시 누르면 resume되는 프로그램을 만들고 싶습니다.
현재 보드는 sa1100을 사용하지만 나중에는 pxa210을 이용할 것입니다.
현재 생각해낸 방법은 다음과 같습니다.
첫번째 인터넷을 돌다가 보니까? 다음과 같은 재미있는 문장이 있더군요.
그냥 커널 컴파일시 전원 관리를 체크하여 echo > /proc/sys/pm/suspend 을
수행하면 전원이 suspend되고 다시 GPIO0을 이용하여 wake up 시키면 된다고
하는거 같은데.. 제가 영어가 딸려서 맡는지 모르겠네요..
이게 맡는지 확인 좀 부탁드립니다.
# echo > /proc/sys/pm/suspend
1. the shell opens /proc/sys/pm/suspend for write
2. shell forks and runs the 'echo' program (be it built in or the
external
one) with stdout connected to /proc/sys/pm/suspend
3. echo writes "
" to stdout, and therefore /proc/sys/pm/suspend
4. when the kernel sees a write to this file, the proc filesystem
calls arch/arm/mach-sa1100/pm.c:sysctl_pm_do_suspend
5. sysctl_pm_do_suspend() sends PM_SUSPEND to all devices with an
argument
of (3) - corresponding to ACPI device state D3.
6. We then call pm_do_suspend()
7. pm_do_suspend saves the state of various registers to memory and
synchronises the RTC with the kernels idea of time.
8. We set PSPR to point at the physical address of some assembly for the
boot loader to run when we resume.
9. pm_do_suspend calls sa1100_cpu_suspend()
10. sa1100_cpu_suspend() saves enough registers onto the stack, and
saves the stack pointer to memory.
11. we eventually do the required stuff to make the CPU suspend, and
we hit this instruction:
20: b 20b @ loop waiting for sleep
We're now asleep.
12. When you hit GPIO0 and the CPU wakes up, the boot loader brings the
SDRAM out of self-refresh mode and the CPU enters the reset vector.
13. The boot loader checks to see if the reset reason indicates we're
coming out of sleep. NOTE! This is not the same as checking
PSPR != 0.
14. The boot loader re-initialises the SDRAM, and jumps to the address
given in PSPR. The CPU starts executing code from
arch/arm/mach-sa1100/sleep.S:sa1100_cpu_resume.
15. sa1100_cpu_resume is sets up the MMU so it's in the same state as it
was when we went to sleep.
16. We reload the stack pointer, and pull the registers off the stack
that
we saved in step 10.
17. Since we now have the CPU state restored to the point when
sa1100_cpu_suspend() was called, if we issue the return instruction,
the CPU will continue as if we were returning from sa1100_cpu_suspend
()
18. We restore various registers (see pm_do_suspend()) and continue as if
nothing happened.
다음으로 생각한 방법이 커널 내의 pm_do_suspend() 함수를 이용하는 방법입니
다.
커널 컴파일 할때 조금 수정하여서 심볼테이블에 이 함수를 등록하고 모듈 프
로그램을
작성하는 방법입니다. 대충 생각한 코드는 다음과 같습니다.
물론 cat ksyms | grep pm_do_suspend 심볼테이블에 등록된 함수가 확인됩니
다.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define IRQ_GPIO_BUTTON IRQ_GPIO4
#define GPIO_POWER_PIN GPIO_GPIO(4)
extern void pm_do_suspend();
static int power;
static void power_state()
{
if(power){
udelay(200);
pm_do_suspend();
power = 0;
} else{
power = 1;
}
}
static int __init pm_init(void)
{
int ret;
GPDR |= (GPIO_POWER_PIN); //GPIO_POWER_PIN(4)을 출력으로 설정
GPCR |= (GPIO_POWER_PIN); //GPIO_POWER_PIN(4)을 low로 설정
set_GPIO_IRQ_edge(GPIO_POWER_PIN, GPIO_RISING_EDGE);
ret = request_irq(IRQ_GPIO_BUTTON, power_state, SA_SHIRQ |
SA_INTERRUPT | SA_SAMPLE_RANDOM, "Power INT", NULL);
if(ret < 0){
printk(KERN_ERR "%s: Request for IRQ %d failed
", __FUNCTION__,
IRQ_GPIO_BUTTON);
return -EBUSY;
}
return 0;
}
static void __exit pm_exit(void)
{
printk("PM exit, IRQ %d
", IRQ_GPIO_BUTTON);
free_irq(IRQ_GPIO_BUTTON, NULL);
}
module_init(pm_init);
module_exit(pm_exit);
이상의 2가지 방법을 생각했습니다.
가능한 이야기인지 좀 알려주시고요.
다른 방법이 있으면 소개 부탁드립니다.
특정 GPIO를 버튼에 연결하여
버튼을 누르면 보드의 전원이 suspend되고
다시 누르면 resume되는 프로그램을 만들고 싶습니다.
현재 보드는 sa1100을 사용하지만 나중에는 pxa210을 이용할 것입니다.
현재 생각해낸 방법은 다음과 같습니다.
첫번째 인터넷을 돌다가 보니까? 다음과 같은 재미있는 문장이 있더군요.
그냥 커널 컴파일시 전원 관리를 체크하여 echo > /proc/sys/pm/suspend 을
수행하면 전원이 suspend되고 다시 GPIO0을 이용하여 wake up 시키면 된다고
하는거 같은데.. 제가 영어가 딸려서 맡는지 모르겠네요..
이게 맡는지 확인 좀 부탁드립니다.
# echo > /proc/sys/pm/suspend
1. the shell opens /proc/sys/pm/suspend for write
2. shell forks and runs the 'echo' program (be it built in or the
external
one) with stdout connected to /proc/sys/pm/suspend
3. echo writes "
" to stdout, and therefore /proc/sys/pm/suspend
4. when the kernel sees a write to this file, the proc filesystem
calls arch/arm/mach-sa1100/pm.c:sysctl_pm_do_suspend
5. sysctl_pm_do_suspend() sends PM_SUSPEND to all devices with an
argument
of (3) - corresponding to ACPI device state D3.
6. We then call pm_do_suspend()
7. pm_do_suspend saves the state of various registers to memory and
synchronises the RTC with the kernels idea of time.
8. We set PSPR to point at the physical address of some assembly for the
boot loader to run when we resume.
9. pm_do_suspend calls sa1100_cpu_suspend()
10. sa1100_cpu_suspend() saves enough registers onto the stack, and
saves the stack pointer to memory.
11. we eventually do the required stuff to make the CPU suspend, and
we hit this instruction:
20: b 20b @ loop waiting for sleep
We're now asleep.
12. When you hit GPIO0 and the CPU wakes up, the boot loader brings the
SDRAM out of self-refresh mode and the CPU enters the reset vector.
13. The boot loader checks to see if the reset reason indicates we're
coming out of sleep. NOTE! This is not the same as checking
PSPR != 0.
14. The boot loader re-initialises the SDRAM, and jumps to the address
given in PSPR. The CPU starts executing code from
arch/arm/mach-sa1100/sleep.S:sa1100_cpu_resume.
15. sa1100_cpu_resume is sets up the MMU so it's in the same state as it
was when we went to sleep.
16. We reload the stack pointer, and pull the registers off the stack
that
we saved in step 10.
17. Since we now have the CPU state restored to the point when
sa1100_cpu_suspend() was called, if we issue the return instruction,
the CPU will continue as if we were returning from sa1100_cpu_suspend
()
18. We restore various registers (see pm_do_suspend()) and continue as if
nothing happened.
다음으로 생각한 방법이 커널 내의 pm_do_suspend() 함수를 이용하는 방법입니
다.
커널 컴파일 할때 조금 수정하여서 심볼테이블에 이 함수를 등록하고 모듈 프
로그램을
작성하는 방법입니다. 대충 생각한 코드는 다음과 같습니다.
물론 cat ksyms | grep pm_do_suspend 심볼테이블에 등록된 함수가 확인됩니
다.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define IRQ_GPIO_BUTTON IRQ_GPIO4
#define GPIO_POWER_PIN GPIO_GPIO(4)
extern void pm_do_suspend();
static int power;
static void power_state()
{
if(power){
udelay(200);
pm_do_suspend();
power = 0;
} else{
power = 1;
}
}
static int __init pm_init(void)
{
int ret;
GPDR |= (GPIO_POWER_PIN); //GPIO_POWER_PIN(4)을 출력으로 설정
GPCR |= (GPIO_POWER_PIN); //GPIO_POWER_PIN(4)을 low로 설정
set_GPIO_IRQ_edge(GPIO_POWER_PIN, GPIO_RISING_EDGE);
ret = request_irq(IRQ_GPIO_BUTTON, power_state, SA_SHIRQ |
SA_INTERRUPT | SA_SAMPLE_RANDOM, "Power INT", NULL);
if(ret < 0){
printk(KERN_ERR "%s: Request for IRQ %d failed
", __FUNCTION__,
IRQ_GPIO_BUTTON);
return -EBUSY;
}
return 0;
}
static void __exit pm_exit(void)
{
printk("PM exit, IRQ %d
", IRQ_GPIO_BUTTON);
free_irq(IRQ_GPIO_BUTTON, NULL);
}
module_init(pm_init);
module_exit(pm_exit);
이상의 2가지 방법을 생각했습니다.
가능한 이야기인지 좀 알려주시고요.
다른 방법이 있으면 소개 부탁드립니다.