diff options
Diffstat (limited to 'linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch')
-rw-r--r-- | linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch | 561 |
1 files changed, 561 insertions, 0 deletions
diff --git a/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch b/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch index e69de29bb2..f8343f89e1 100644 --- a/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch +++ b/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch @@ -0,0 +1,561 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/apm.c~apm-hh-merge ++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/apm.c +@@ -86,6 +86,8 @@ + int magic; + struct apm_user * next; + int suser: 1; ++ int writer : 1; ++ int reader : 1; + int suspend_wait: 1; + int suspend_result; + int suspends_pending; +@@ -105,7 +107,7 @@ + /* + * Local variables + */ +-//static int suspends_pending; ++static int suspends_pending; + //static int standbys_pending; + //static int ignore_normal_resume; + +@@ -123,8 +125,6 @@ + #else + static int power_off = 1; + #endif +-static int exit_kapmd; +-static int kapmd_running; + + static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); + static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); +@@ -192,6 +192,41 @@ + return as->events[as->event_tail]; + } + ++static void queue_event(apm_event_t event, struct apm_user *sender) ++{ ++ struct apm_user * as; ++ if (user_list == NULL) ++ return; ++ for (as = user_list; as != NULL; as = as->next) { ++ if ((as == sender) || (!as->reader)) ++ continue; ++ as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; ++ if (as->event_head == as->event_tail) { ++ static int notified; ++ ++ if (notified++ == 0) ++ printk(KERN_ERR "apm: an event queue overflowed\n"); ++ as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; ++ } ++ as->events[as->event_head] = event; ++ if ((!as->suser) || (!as->writer)) ++ continue; ++ switch (event) { ++ case APM_SYS_SUSPEND: ++ case APM_USER_SUSPEND: ++ as->suspends_pending++; ++ suspends_pending++; ++ break; ++ ++ case APM_SYS_STANDBY: ++ case APM_USER_STANDBY: ++ as->standbys_pending++; ++ break; ++ } ++ } ++ wake_up_interruptible(&apm_waitqueue); ++} ++ + static int check_apm_user(struct apm_user *as, const char *func) + { + if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { +@@ -270,7 +305,6 @@ + return 0; + } + +-extern int pm_do_suspend(void); + + static int do_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +@@ -284,7 +318,17 @@ + return -EPERM; + switch (cmd) { + case APM_IOC_SUSPEND: +- pm_do_suspend(); ++ if (as->suspends_read > 0) { ++ as->suspends_read--; ++ as->suspends_pending--; ++ suspends_pending--; ++ } else { ++ queue_event(APM_USER_SUSPEND, as); ++ } ++ ++ if (suspends_pending <= 0) ++ wake_up(&apm_suspend_waitqueue); ++ + break; + default: + return -EINVAL; +@@ -301,6 +345,20 @@ + return 0; + filp->private_data = NULL; + lock_kernel(); ++ if (user_list == as) ++ user_list = as->next; ++ else { ++ struct apm_user * as1; ++ ++ for (as1 = user_list; ++ (as1 != NULL) && (as1->next != as); ++ as1 = as1->next) ++ ; ++ if (as1 == NULL) ++ printk(KERN_ERR "apm: filp not in user list\n"); ++ else ++ as1->next = as->next; ++ } + unlock_kernel(); + kfree(as); + return 0; +@@ -328,6 +386,8 @@ + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); ++ as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; ++ as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; + as->next = user_list; + user_list = as; + filp->private_data = as; +@@ -411,33 +471,7 @@ + return p - buf; + } + +-#ifndef MODULE +-static int __init apm_setup(char *str) +-{ +- int invert; +- +- while ((str != NULL) && (*str != '\0')) { +- if (strncmp(str, "off", 3) == 0) +- apm_disabled = 1; +- if (strncmp(str, "on", 2) == 0) +- apm_disabled = 0; +- invert = (strncmp(str, "no-", 3) == 0); +- if (invert) +- str += 3; +- if (strncmp(str, "debug", 5) == 0) +- debug = !invert; +- if ((strncmp(str, "power-off", 9) == 0) || +- (strncmp(str, "power_off", 9) == 0)) +- power_off = !invert; +- str = strchr(str, ','); +- if (str != NULL) +- str += strspn(str, ", \t"); +- } +- return 1; +-} + +-__setup("apm=", apm_setup); +-#endif + + static struct file_operations apm_bios_fops = { + owner: THIS_MODULE, +@@ -449,13 +483,55 @@ + }; + + static struct miscdevice apm_device = { +- APM_MINOR_DEV, +- "apm_bios", +- &apm_bios_fops ++ minor : APM_MINOR_DEV, ++ name : "apm_bios", ++ fops : &apm_bios_fops + }; + + #define APM_INIT_ERROR_RETURN return -1 + ++static pid_t apmd_pid; ++static DECLARE_COMPLETION(apmd_exited); ++ ++static int apm(void *unused) ++{ ++ unsigned short bx; ++ unsigned short cx; ++ unsigned short dx; ++ int error; ++ char * power_stat; ++ char * bat_stat; ++ DECLARE_WAITQUEUE(wait, current); ++ struct apm_user au, *as; ++ ++ lock_kernel(); ++ ++ daemonize(); ++ ++ strcpy(current->comm, "kapmd"); ++ ++ as = &au; ++ as->magic = APM_BIOS_MAGIC; ++ as->event_tail = as->event_head = 0; ++ as->suspends_pending = as->standbys_pending = 0; ++ as->suspends_read = as->standbys_read = 0; ++ as->suser = 1; ++ as->writer = 1; ++ as->reader = 0; ++ ++ while (!signal_pending (current)) { ++ interruptible_sleep_on(&apm_suspend_waitqueue); ++ ++ pm_suggest_suspend(); ++ ++ queue_event(APM_NORMAL_RESUME, as); ++ } ++ ++ unlock_kernel(); ++ ++ complete_and_exit(&apmd_exited, 0); ++} ++ + /* + * Just start the APM thread. We do NOT want to do APM BIOS + * calls from anything but the APM thread, if for no other reason +@@ -494,18 +570,19 @@ + + misc_register(&apm_device); + ++ apmd_pid = kernel_thread(apm, NULL, 0); ++ + return 0; + } + + static void __exit apm_exit(void) + { + misc_deregister(&apm_device); +- remove_proc_entry("apm", NULL); ++ remove_proc_entry("apm", NULL); ++ kill_proc (apmd_pid, SIGTERM, 1); ++ wait_for_completion(&apmd_exited); + if (power_off) + pm_power_off = NULL; +- exit_kapmd = 1; +- while (kapmd_running) +- schedule(); + pm_active = 0; + } + +@@ -514,6 +591,7 @@ + + MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell"); + MODULE_DESCRIPTION("A minimal emulation of APM"); ++MODULE_LICENSE("GPL"); + MODULE_PARM(debug, "i"); + MODULE_PARM_DESC(debug, "Enable debug mode"); + MODULE_PARM(power_off, "i"); +--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/pm.c~apm-hh-merge ++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/pm.c +@@ -53,6 +53,10 @@ + #include <asm/arch/assabet.h> + #endif + ++#define __KERNEL_SYSCALLS__ ++#include <linux/unistd.h> ++ ++ + /* + * ARGH! Stupid ACPI people. They should define this in linux/sysctl.h, + * NOT linux/acpi.h. +@@ -64,123 +68,6 @@ + #define CTL_ACPI 9999 + #define ACPI_S1_SLP_TYP 19 + +-#ifndef CONFIG_SA1100_BEAGLE +- +-extern void sa1100_cpu_suspend(void); +-extern void sa1100_cpu_resume(void); +- +-extern unsigned long *sleep_save; /* virtual address */ +-extern unsigned long sleep_save_p; /* physical address */ +- +-#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x +-#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] +- +-int sa1110_suspend(void) +-{ +- int retval; +- +- /* set up pointer to sleep parameters */ +- sleep_save = kmalloc (SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC); +- if (!sleep_save) +- return -ENOMEM; +- sleep_save_p = virt_to_phys(sleep_save); +- +- retval = pm_send_all(PM_SUSPEND, (void *)2); +- if (retval) { +- kfree(sleep_save); +- return retval; +- } +- +- cli(); +- +- /* preserve current time */ +- RCNR = xtime.tv_sec; +- +- /* save vital registers */ +- SAVE(OSCR); +- SAVE(OSMR0); +- SAVE(OSMR1); +- SAVE(OSMR2); +- SAVE(OSMR3); +- SAVE(OIER); +- +- SAVE(GPDR); +- SAVE(GRER); +- SAVE(GFER); +- SAVE(GAFR); +- +- SAVE(PPDR); +- SAVE(PPSR); +- SAVE(PPAR); +- SAVE(PSDR); +- +- SAVE(Ser1SDCR0); +- +- SAVE(ICMR); +- +- /* ... maybe a global variable initialized by arch code to set this? */ +- GRER = PWER; +- GFER = 0; +- GEDR = GEDR; +- +- /* Clear previous reset status */ +- RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR; +- +- /* set resume return address */ +- PSPR = virt_to_phys(sa1100_cpu_resume); +- +- /* go zzz */ +- sa1100_cpu_suspend(); +- +- /* ensure not to come back here if it wasn't intended */ +- PSPR = 0; +- +- DPRINTK("*** made it back from resume\n"); +- +- /* restore registers */ +- RESTORE(GPDR); +- RESTORE(GRER); +- RESTORE(GFER); +- RESTORE(GAFR); +- +- /* clear any edge detect bit */ +- GEDR = GEDR; +- +- RESTORE(PPDR); +- RESTORE(PPSR); +- RESTORE(PPAR); +- RESTORE(PSDR); +- +- RESTORE(Ser1SDCR0); +- +- PSSR = PSSR_PH; +- +- RESTORE(OSMR0); +- RESTORE(OSMR1); +- RESTORE(OSMR2); +- RESTORE(OSMR3); +- RESTORE(OSCR); +- RESTORE(OIER); +- +- ICLR = 0; +- ICCR = 1; +- RESTORE(ICMR); +- +- /* restore current time */ +- xtime.tv_sec = RCNR; +- +- sti(); +- +- kfree (sleep_save); +- +-#ifdef CONFIG_CPU_FREQ +- cpufreq_restore(); +-#endif +- +- return pm_send_all(PM_RESUME, (void *)0); +-} +- +-#else //CONFIG_SA1100_BEAGLE + + typedef struct _tag_SLEEP_SAVED_DATA { + uint wakeup_addr; +@@ -363,9 +250,6 @@ + " ); + } + +-extern void h3600_control_egpio( enum ipaq_egpio_type x, int setp ); +-extern unsigned long h3600_read_egpio( void ); +- + static int GPDR_saved; + static int GPLR_saved; + static int GRER_saved; +@@ -742,21 +626,37 @@ + Ser3UTSR1 = 0xff; + } + +-#endif //CONFIG_SA1100_BEAGLE +- ++/* ++ * If pm_suggest_suspend_hook is non-NULL, it is called by pm_suggest_suspend. ++ * ++ * If sysctl_pm_do_suspend_hook is non-NULL, it is called by sysctl_pm_do_suspend. ++ * If it returns a true value, then pm_suspend is not called. ++ * Use this to hook in apmd, for now. ++ * ++ * -not exported just so that the code compiles ++ */ ++int (*pm_suggest_suspend_hook)(int state); ++int (*pm_sysctl_suspend_hook)(int state); ++int pm_use_sbin_pm_helper = 1; + static char pm_helper_path[128] = "/sbin/pm_helper"; ++extern int exec_usermodehelper(char *path, char **argv, char **envp); ++int debug_pm = 0; ++static int pm_helper_veto = 0; + +-static void ++static int + run_sbin_pm_helper( pm_request_t action ) + { + int i; + char *argv[3], *envp[8]; + + if (!pm_helper_path[0]) +- return; ++ return 2; + + if ( action != PM_SUSPEND && action != PM_RESUME ) +- return; ++ return 1; ++ ++ /* Be root */ ++ current->uid = current->gid = 0; + + i = 0; + argv[i++] = pm_helper_path; +@@ -771,14 +671,15 @@ + envp[i] = 0; + + /* other stuff we want to pass to /sbin/hotplug */ +- call_usermodehelper (argv [0], argv, envp); ++ return exec_usermodehelper (argv [0], argv, envp); + } + ++int pm_force_suspend(void); ++ + int pm_do_suspend(void) + { +- DPRINTK("suggest\n"); +- run_sbin_pm_helper(PM_SUSPEND); +- return 0; ++ DPRINTK("suspend now\n"); ++ return pm_force_suspend(); + } + + #ifdef CONFIG_SA1100_BEAGLE +@@ -863,9 +764,91 @@ + } + #endif + ++int pm_suggest_suspend(void) ++{ ++ int retval; ++ ++ if (pm_suggest_suspend_hook) { ++ if (pm_suggest_suspend_hook(PM_SUSPEND)) ++ return 0; ++ } ++ ++ if (pm_use_sbin_pm_helper) { ++ pid_t pid; ++ int res; ++ int status = 0; ++ unsigned int old_fs; ++ ++ pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_SUSPEND, 0 ); ++ if ( pid < 0 ) ++ return pid; ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s:%d got pid=%d\n", __FUNCTION__, __LINE__, pid); ++ ++ old_fs = get_fs (); ++ set_fs (get_ds ()); ++ res = waitpid(pid, &status, __WCLONE); ++ set_fs (old_fs); ++ ++ if ( pid != res ) { ++ if (debug_pm) ++ printk(KERN_CRIT ": waitpid returned %d (exit_code=%d); not suspending\n", res, status ); ++ ++ return -1; ++ } ++ ++ /*if ( WIFEXITED(status) && ( WIFEXITSTATUS(status) != 0 )) {*/ ++ if (( status & 0xff7f ) != 0 ) { ++ if (pm_helper_veto) { ++ if (debug_pm) ++ printk(KERN_CRIT "%s: SUSPEND WAS CANCELLED BY pm_helper (exit status %d)\n", __FUNCTION__, status >> 8); ++ return -1; ++ } else { ++ if (debug_pm) ++ printk(KERN_CRIT "%s: pm_helper returned %d, but going ahead anyway\n", __FUNCTION__, status >> 8); ++ } ++ } ++ } ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s: REALLY SUSPENDING NOW\n", __FUNCTION__ ); ++ ++ if (pm_sysctl_suspend_hook) { ++ if (pm_sysctl_suspend_hook(PM_SUSPEND)) ++ return 0; ++ } ++ ++ retval = pm_do_suspend(); ++ if (retval) { ++ if (debug_pm) ++ printk(KERN_CRIT "pm_suspend returned %d\n", retval); ++ return retval; ++ } ++ ++ if (pm_use_sbin_pm_helper) { ++ pid_t pid; ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s: running pm_helper for wakeup\n", __FUNCTION__); ++ ++ pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_RESUME, 0 ); ++ if ( pid < 0 ) ++ return pid; ++ ++ if ( pid != waitpid ( pid, NULL, __WCLONE )) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(pm_suggest_suspend); ++ ++ + static struct ctl_table pm_table[] = + { +- {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0644, NULL, (proc_handler *)&pm_force_suspend}, ++/* {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0644, NULL, (proc_handler *)&pm_force_suspend}, */ + {2, "helper", pm_helper_path, sizeof(pm_helper_path), 0644, NULL, (proc_handler *)&proc_dostring}, + #ifdef CONFIG_SA1100_BEAGLE + {3, "wakeup_delayed_time", &wakeup_delayed_time, sizeof(wakeup_delayed_time), 0644, NULL, &proc_dointvec }, |