summaryrefslogtreecommitdiff
path: root/packages/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch')
-rw-r--r--packages/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch561
1 files changed, 561 insertions, 0 deletions
diff --git a/packages/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch b/packages/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch
index e69de29bb2..f8343f89e1 100644
--- a/packages/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch
+++ b/packages/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 },