diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/arch/i386/kernel/apm.c linux-2.4.4-boxevent/arch/i386/kernel/apm.c --- linux-2.4.4-orig/arch/i386/kernel/apm.c Tue May 1 14:33:34 2001 +++ linux-2.4.4-boxevent/arch/i386/kernel/apm.c Mon May 7 15:36:53 2001 @@ -148,6 +148,9 @@ * 1.14: Make connection version persist across module unload/load. * Enable and engage power management earlier. * Disengage power management on module unload. + * 1.15: Move most of the /dev/apm_bios stuff to drivers/char/boxevent.c + * Reject all events by default + * (John Fremlin ) * * APM 1.1 Reference: * @@ -186,6 +189,7 @@ #include #include #include +#include #include #include @@ -301,10 +305,6 @@ int suser: 1; int suspend_wait: 1; int suspend_result; - int suspends_pending; - int standbys_pending; - int suspends_read; - int standbys_read; int event_head; int event_tail; apm_event_t events[APM_MAX_EVENTS]; @@ -325,8 +325,7 @@ #ifdef CONFIG_APM_CPU_IDLE static int clock_slowed; #endif -static int suspends_pending; -static int standbys_pending; +static int suspend_launched; static int waiting_for_resume; static int ignore_normal_resume; static int bounce_interval = DEFAULT_BOUNCE_INTERVAL; @@ -352,7 +351,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); static struct apm_user * user_list; -static char driver_version[] = "1.14"; /* no spaces */ +static char driver_version[] = "1.15"; /* no spaces */ static char * apm_event_name[] = { "system standby", @@ -579,56 +578,6 @@ clock_slowed = 0; } } - -#if 0 -extern int hlt_counter; - -/* - * If no process has been interested in this - * CPU for some time, we want to wake up the - * power management thread - we probably want - * to conserve power. - */ -#define HARD_IDLE_TIMEOUT (HZ/3) - -/* This should wake up kapmd and ask it to slow the CPU */ -#define powermanagement_idle() do { } while (0) - -/* - * This is the idle thing. - */ -static void apm_cpu_idle(void) -{ - unsigned int start_idle; - - start_idle = jiffies; - while (1) { - if (!current->need_resched) { - if (jiffies - start_idle < HARD_IDLE_TIMEOUT) { - if (!current_cpu_data.hlt_works_ok) - continue; - if (hlt_counter) - continue; - __cli(); - if (!current->need_resched) - safe_halt(); - else - __sti(); - continue; - } - - /* - * Ok, do some power management - we've been idle for too long - */ - powermanagement_idle(); - } - - schedule(); - check_pgt_cache(); - start_idle = jiffies; - } -} -#endif #endif #ifdef CONFIG_SMP @@ -791,54 +740,6 @@ } #endif -static int queue_empty(struct apm_user *as) -{ - return as->event_head == as->event_tail; -} - -static apm_event_t get_queued_event(struct apm_user *as) -{ - as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; - 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) - 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) - 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++; - standbys_pending++; - break; - } - } - wake_up_interruptible(&apm_waitqueue); -} - static void set_time(void) { unsigned long flags; @@ -898,8 +799,6 @@ printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armageddon\n" ); return 0; } - if (apm_info.connection_version > 0x100) - apm_set_power_state(APM_STATE_REJECT); return 0; } break; @@ -913,6 +812,44 @@ return 1; } +static void announce_event(apm_event_t event) +{ + char*type = BOXEVENT_NOTIFY; + char*name; + + if (event <= NR_APM_EVENT_NAME) + name = apm_event_name[event - 1]; + else name = "unknown event"; + + switch(event){ + case APM_SYS_STANDBY: + case APM_USER_STANDBY: + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + case APM_CRITICAL_SUSPEND: + type = BOXEVENT_SLEEP; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + case APM_STANDBY_RESUME: + type = BOXEVENT_WAKE; + break; + case APM_CAPABILITY_CHANGE: + type = BOXEVENT_WAKE; + break; + case APM_LOW_BATTERY: + type = BOXEVENT_EMERGENCY; + break; + case APM_POWER_STATUS_CHANGE: + type = BOXEVENT_POWERCHANGE; + break; + default: + type = BOXEVENT_NOTIFY; + } + boxevent(type,"APM",name); +} + + static int suspend(void) { int err; @@ -929,12 +866,13 @@ apm_error("suspend", err); send_event(APM_NORMAL_RESUME); sti(); - queue_event(APM_NORMAL_RESUME, NULL); + announce_event(APM_NORMAL_RESUME); for (as = user_list; as != NULL; as = as->next) { as->suspend_wait = 0; as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO); } ignore_normal_resume = 1; + suspend_launched = 0; wake_up_interruptible(&apm_suspend_waitqueue); return err; } @@ -989,46 +927,16 @@ if (ignore_normal_resume && (event != APM_NORMAL_RESUME)) ignore_normal_resume = 0; + announce_event(event); + switch (event) { case APM_SYS_STANDBY: case APM_USER_STANDBY: - if (send_event(event)) { - queue_event(event, NULL); - if (standbys_pending <= 0) - standby(); - } - break; - case APM_USER_SUSPEND: -#ifdef CONFIG_APM_IGNORE_USER_SUSPEND + case APM_SYS_SUSPEND: if (apm_info.connection_version > 0x100) apm_set_power_state(APM_STATE_REJECT); break; -#endif - case APM_SYS_SUSPEND: - if (ignore_bounce) { - if (apm_info.connection_version > 0x100) - apm_set_power_state(APM_STATE_REJECT); - break; - } - /* - * If we are already processing a SUSPEND, - * then further SUSPEND events from the BIOS - * will be ignored. We also return here to - * cope with the fact that the Thinkpads keep - * sending a SUSPEND event until something else - * happens! - */ - if (waiting_for_resume) - return; - if (send_event(event)) { - queue_event(event, NULL); - waiting_for_resume = 1; - if (suspends_pending <= 0) - (void) suspend(); - } - break; - case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: case APM_STANDBY_RESUME: @@ -1039,7 +947,6 @@ || (ignore_normal_resume == 0)) { set_time(); send_event(event); - queue_event(event, NULL); } break; @@ -1047,7 +954,6 @@ case APM_LOW_BATTERY: case APM_POWER_STATUS_CHANGE: send_event(event); - queue_event(event, NULL); break; case APM_UPDATE_TIME: @@ -1055,7 +961,9 @@ break; case APM_CRITICAL_SUSPEND: + suspend_launched = 1; send_event(event); + /* * We can only hope it worked - we are not allowed * to reject a critical suspend. @@ -1068,20 +976,6 @@ static void apm_event_handler(void) { - static int pending_count = 4; - int err; - - if ((standbys_pending > 0) || (suspends_pending > 0)) { - if ((apm_info.connection_version > 0x100) && (pending_count-- <= 0)) { - pending_count = 4; - if (debug) - printk(KERN_DEBUG "apm: setting state busy\n"); - err = apm_set_power_state(APM_STATE_BUSY); - if (err) - apm_error("busy", err); - } - } else - pending_count = 4; check_events(); } @@ -1146,78 +1040,10 @@ return 0; } -static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos) -{ - struct apm_user * as; - int i; - apm_event_t event; - DECLARE_WAITQUEUE(wait, current); - - as = fp->private_data; - if (check_apm_user(as, "read")) - return -EIO; - if (count < sizeof(apm_event_t)) - return -EINVAL; - if (queue_empty(as)) { - if (fp->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&apm_waitqueue, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (queue_empty(as) && !signal_pending(current)) { - schedule(); - goto repeat; - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&apm_waitqueue, &wait); - } - i = count; - while ((i >= sizeof(event)) && !queue_empty(as)) { - event = get_queued_event(as); - if (copy_to_user(buf, &event, sizeof(event))) { - if (i < count) - break; - return -EFAULT; - } - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - as->suspends_read++; - break; - - case APM_SYS_STANDBY: - case APM_USER_STANDBY: - as->standbys_read++; - break; - } - buf += sizeof(event); - i -= sizeof(event); - } - if (i < count) - return count - i; - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -static unsigned int do_poll(struct file *fp, poll_table * wait) -{ - struct apm_user * as; - - as = fp->private_data; - if (check_apm_user(as, "poll")) - return 0; - poll_wait(fp, &apm_waitqueue, wait); - if (!queue_empty(as)) - return POLLIN | POLLRDNORM; - return 0; -} - static int do_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { struct apm_user * as; - DECLARE_WAITQUEUE(wait, current); as = filp->private_data; if (check_apm_user(as, "ioctl")) @@ -1226,43 +1052,27 @@ return -EPERM; switch (cmd) { case APM_IOC_STANDBY: - if (as->standbys_read > 0) { - as->standbys_read--; - as->standbys_pending--; - standbys_pending--; - } else if (!send_event(APM_USER_STANDBY)) + if (!send_event(APM_USER_STANDBY)) return -EAGAIN; - else - queue_event(APM_USER_STANDBY, as); - if (standbys_pending <= 0) - standby(); + standby(); break; case APM_IOC_SUSPEND: - if (as->suspends_read > 0) { - as->suspends_read--; - as->suspends_pending--; - suspends_pending--; - } else if (!send_event(APM_USER_SUSPEND)) - return -EAGAIN; - else - queue_event(APM_USER_SUSPEND, as); - if (suspends_pending <= 0) { - if (suspend() != APM_SUCCESS) - return -EIO; - } else { + if(suspend_launched) { as->suspend_wait = 1; - add_wait_queue(&apm_suspend_waitqueue, &wait); - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - if ((as->suspend_wait == 0) - || signal_pending(current)) - break; - schedule(); + if(wait_event_interruptible(apm_suspend_waitqueue, + as->suspend_wait == 0)) { + as->suspend_wait = 0; + return -ERESTARTSYS; } - set_current_state(TASK_RUNNING); - remove_wait_queue(&apm_suspend_waitqueue, &wait); + return as->suspend_result; } + + suspend_launched = 1; + if (!send_event(APM_USER_SUSPEND)) + return -EAGAIN; + if (suspend() != APM_SUCCESS) + return -EIO; break; default: return -EINVAL; @@ -1279,16 +1089,7 @@ return 0; filp->private_data = NULL; lock_kernel(); - if (as->standbys_pending > 0) { - standbys_pending -= as->standbys_pending; - if (standbys_pending <= 0) - standby(); - } - if (as->suspends_pending > 0) { - suspends_pending -= as->suspends_pending; - if (suspends_pending <= 0) - (void) suspend(); - } + if (user_list == as) user_list = as->next; else { @@ -1320,11 +1121,10 @@ } 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; + /* * XXX - this is a tiny bit broken, when we consider BSD - * process accounting. If the device is opened by root, we + * process accounting. If the device is opened by root, we * instantly flag that we used superuser privs. Who knows, * we might close the device immediately without doing a * privileged operation -- cevans @@ -1578,8 +1378,6 @@ static struct file_operations apm_bios_fops = { owner: THIS_MODULE, - read: do_read, - poll: do_poll, ioctl: do_ioctl, open: do_open, release: do_release, diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/arch/mips/sgi/kernel/reset.c linux-2.4.4-boxevent/arch/mips/sgi/kernel/reset.c --- linux-2.4.4-orig/arch/mips/sgi/kernel/reset.c Sat May 13 16:29:14 2000 +++ linux-2.4.4-boxevent/arch/mips/sgi/kernel/reset.c Mon May 7 15:55:46 2001 @@ -7,11 +7,14 @@ * for more details. * * Copyright (C) 1997, 1998 by Ralf Baechle + * + * 2001 May 7 Mangled to use new boxevent interface by John Fremlin */ #include #include #include #include +#include #include #include #include @@ -21,22 +24,14 @@ #include /* - * Just powerdown if init hasn't done after POWERDOWN_TIMEOUT seconds. - * I'm not shure if this feature is a good idea, for now it's here just to - * make the power button make behave just like under IRIX. - */ -#define POWERDOWN_TIMEOUT 120 - -/* * Blink frequency during reboot grace period and when paniced. */ -#define POWERDOWN_FREQ (HZ / 4) #define PANIC_FREQ (HZ / 8) static unsigned char sgi_volume; -static struct timer_list power_timer, blink_timer, debounce_timer, volume_timer; -static int shuting_down, has_paniced; +static struct timer_list blink_timer, debounce_timer, volume_timer; +static int has_paniced; static void sgi_machine_restart(char *command) __attribute__((noreturn)); static void sgi_machine_halt(void) __attribute__((noreturn)); @@ -45,15 +40,11 @@ /* XXX How to pass the reboot command to the firmware??? */ static void sgi_machine_restart(char *command) { - if (shuting_down) - sgi_machine_power_off(); prom_reboot(); } static void sgi_machine_halt(void) { - if (shuting_down) - sgi_machine_power_off(); prom_imode(); } @@ -113,20 +104,7 @@ { if (has_paniced) return; - - if (shuting_down || kill_proc(1, SIGINT, 1)) { - /* No init process or button pressed twice. */ - sgi_machine_power_off(); - } - - shuting_down = 1; - blink_timer.data = POWERDOWN_FREQ; - blink_timeout(POWERDOWN_FREQ); - - init_timer(&power_timer); - power_timer.function = power_timeout; - power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ; - add_timer(&power_timer); + boxevent(BOXEVENT_OFF,"MIPS","button pressed"); } void inline sgi_volume_set(unsigned char volume) @@ -146,9 +124,11 @@ { del_timer(&volume_timer); + boxevent(BOXEVENT_NOTIFY,"MIPS","volume up button pressed"); + if (sgi_volume < 0xff) sgi_volume++; - + hpc3c0->pbus_extregs[2][0] = sgi_volume; hpc3c0->pbus_extregs[2][1] = sgi_volume; @@ -163,6 +143,8 @@ { del_timer(&volume_timer); + boxevent(BOXEVENT_NOTIFY,"MIPS","volume down button pressed"); + if (sgi_volume > 0) sgi_volume--; diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/arch/mips64/sgi-ip22/ip22-reset.c linux-2.4.4-boxevent/arch/mips64/sgi-ip22/ip22-reset.c --- linux-2.4.4-orig/arch/mips64/sgi-ip22/ip22-reset.c Sat May 13 16:30:17 2000 +++ linux-2.4.4-boxevent/arch/mips64/sgi-ip22/ip22-reset.c Mon May 7 15:58:56 2001 @@ -7,11 +7,14 @@ * Reset an IP22. * * Copyright (C) 1997, 1998, 1999 by Ralf Baechle + * + * 2001 May 7 Mangled to use new boxevent interface by John Fremlin */ #include #include #include #include +#include #include #include #include @@ -20,23 +23,14 @@ #include /* - * Just powerdown if init hasn't done after POWERDOWN_TIMEOUT seconds. - * I'm not shure if this feature is a good idea, for now it's here just to - * make the power button make behave just like under IRIX. - */ -#define POWERDOWN_TIMEOUT 120 - -/* * Blink frequency during reboot grace period and when paniced. */ -#define POWERDOWN_FREQ (HZ / 4) #define PANIC_FREQ (HZ / 8) static unsigned char sgi_volume; -static struct timer_list power_timer, blink_timer, debounce_timer, volume_timer; -static int shuting_down, has_paniced; - +static struct timer_list blink_timer, debounce_timer, volume_timer; +static int has_paniced; void machine_restart(char *command) __attribute__((noreturn)); void machine_halt(void) __attribute__((noreturn)); void machine_power_off(void) __attribute__((noreturn)); @@ -44,15 +38,11 @@ /* XXX How to pass the reboot command to the firmware??? */ void machine_restart(char *command) { - if (shuting_down) - machine_power_off(); ArcReboot(); } void machine_halt(void) { - if (shuting_down) - machine_power_off(); ArcEnterInteractiveMode(); } @@ -76,11 +66,6 @@ } } -static void power_timeout(unsigned long data) -{ - machine_power_off(); -} - static void blink_timeout(unsigned long data) { /* XXX Fix this for Fullhouse */ @@ -113,19 +98,7 @@ if (has_paniced) return; - if (shuting_down || kill_proc(1, SIGINT, 1)) { - /* No init process or button pressed twice. */ - machine_power_off(); - } - - shuting_down = 1; - blink_timer.data = POWERDOWN_FREQ; - blink_timeout(POWERDOWN_FREQ); - - init_timer(&power_timer); - power_timer.function = power_timeout; - power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ; - add_timer(&power_timer); + boxevent(BOXEVENT_OFF,"MIPS64-IP22","button pressed"); } void inline ip22_volume_set(unsigned char volume) @@ -145,6 +118,8 @@ { del_timer(&volume_timer); + boxevent(BOXEVENT_NOTIFY,"MIPS64-IP22","volume up button pressed"); + if (sgi_volume < 0xff) sgi_volume++; @@ -162,6 +137,8 @@ { del_timer(&volume_timer); + boxevent(BOXEVENT_NOTIFY,"MIPS64-IP22","volume down button pressed"); + if (sgi_volume > 0) sgi_volume--; diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/arch/sparc64/kernel/power.c linux-2.4.4-boxevent/arch/sparc64/kernel/power.c --- linux-2.4.4-orig/arch/sparc64/kernel/power.c Tue Jul 11 23:46:08 2000 +++ linux-2.4.4-boxevent/arch/sparc64/kernel/power.c Mon May 7 15:31:17 2001 @@ -10,10 +10,9 @@ #include #include #include +#include #include - -#define __KERNEL_SYSCALLS__ #include #ifdef CONFIG_PCI @@ -26,10 +25,7 @@ static void power_handler(int irq, void *dev_id, struct pt_regs *regs) { - if (button_pressed == 0) { - wake_up(&powerd_wait); - button_pressed = 1; - } + boxevent_intr(BOXEVENT_OFF,"SPARC-PCI","button pressed"); } #endif /* CONFIG_PCI */ @@ -52,30 +48,6 @@ } #ifdef CONFIG_PCI -static int powerd(void *__unused) -{ - static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; - char *argv[] = { "/sbin/shutdown", "-h", "now", NULL }; - - daemonize(); - sprintf(current->comm, "powerd"); - -again: - while(button_pressed == 0) { - spin_lock_irq(¤t->sigmask_lock); - flush_signals(current); - spin_unlock_irq(¤t->sigmask_lock); - interruptible_sleep_on(&powerd_wait); - } - - /* Ok, down we go... */ - if (execve("/sbin/shutdown", argv, envp) < 0) { - printk("powerd: shutdown execution failed\n"); - button_pressed = 0; - goto again; - } - return 0; -} void __init power_init(void) { @@ -93,11 +65,7 @@ found: power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4); printk("power: Control reg at %016lx ... ", power_reg); - if (kernel_thread(powerd, 0, CLONE_FS) < 0) { - printk("Failed to start power daemon.\n"); - return; - } - printk("powerd running.\n"); + if (edev->irqs[0] != 0) { if (request_irq(edev->irqs[0], power_handler, SA_SHIRQ, "power", diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/drivers/acpi/driver.c linux-2.4.4-boxevent/drivers/acpi/driver.c --- linux-2.4.4-orig/drivers/acpi/driver.c Thu Feb 22 18:28:26 2001 +++ linux-2.4.4-boxevent/drivers/acpi/driver.c Mon May 7 15:57:08 2001 @@ -21,6 +21,8 @@ * Changes * David Woodhouse 2000-12-6 * - Fix interruptible_sleep_on() races + * John Fremlin 2001-05-07 + * - Mangled to use new boxevent interface */ #include @@ -33,6 +35,7 @@ #include #include #include +#include #include #include "acpi.h" #include "driver.h" @@ -163,9 +166,11 @@ switch (event) { case ACPI_EVENT_POWER_BUTTON: + boxevent(BOXEVENT_OFF,"ACPI","power button pressed"); mask = ACPI_PWRBTN; break; case ACPI_EVENT_SLEEP_BUTTON: + boxevent(BOXEVENT_SLEEP,"ACPI","sleep button pressed"); mask = ACPI_SLPBTN; break; default: diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/drivers/char/Config.in linux-2.4.4-boxevent/drivers/char/Config.in --- linux-2.4.4-orig/drivers/char/Config.in Tue May 1 14:32:05 2001 +++ linux-2.4.4-boxevent/drivers/char/Config.in Mon May 7 15:55:47 2001 @@ -150,9 +150,6 @@ if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then tristate 'NetWinder thermometer support' CONFIG_DS1620 tristate 'NetWinder Button' CONFIG_NWBUTTON - if [ "$CONFIG_NWBUTTON" != "n" ]; then - bool ' Reboot Using Button' CONFIG_NWBUTTON_REBOOT - fi tristate 'NetWinder flash support' CONFIG_NWFLASH fi @@ -187,6 +184,8 @@ bool ' Generic SiS support' CONFIG_AGP_SIS bool ' ALI chipset support' CONFIG_AGP_ALI fi + +tristate '/dev/boxevent (userspace async event interface)' CONFIG_BOXEVENT source drivers/char/drm/Config.in diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/drivers/char/Makefile linux-2.4.4-boxevent/drivers/char/Makefile --- linux-2.4.4-orig/drivers/char/Makefile Tue May 1 14:33:51 2001 +++ linux-2.4.4-boxevent/drivers/char/Makefile Mon May 7 14:32:49 2001 @@ -179,6 +179,8 @@ obj-$(CONFIG_QIC02_TAPE) += tpqic02.o +obj-$(CONFIG_BOXEVENT) += boxevent.o + subdir-$(CONFIG_FTAPE) += ftape subdir-$(CONFIG_DRM) += drm subdir-$(CONFIG_PCMCIA) += pcmcia diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/drivers/char/boxevent.c linux-2.4.4-boxevent/drivers/char/boxevent.c --- linux-2.4.4-orig/drivers/char/boxevent.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.4-boxevent/drivers/char/boxevent.c Mon May 7 16:22:45 2001 @@ -0,0 +1,291 @@ +/* (C) 2001 John Fremlin */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static const char msg_overflow[] = "MSGFLOOD KERNEL messages lost\n"; + +#define N_MSGS 16 +#define MSG_MAXLEN 100 + +static const char ring[N_MSGS][MSG_MAXLEN]; +static unsigned ring_next; /*=0*/ + +struct fop_priv +{ + int fp_overflow; + unsigned fp_ringpos; + unsigned fp_msgpos; + + struct list_head fp_entry; +} +; + +static DECLARE_WAIT_QUEUE_HEAD(waiters); +static LIST_HEAD(listeners); +static spinlock_t listeners_lock = SPIN_LOCK_UNLOCKED; + /* protects listeners, ring, ring_next and all the ring_pos in the fop_priv */ + +/** + * boxevent - inform userspace listeners of a power management event + * + * @event_type: one of the BOXEVENT_* defines in linux/boxevent.h, + * general event class + * @subsystem: kernel subsystem generating the event (e.g. "APM") + * @desc: longer description of event (e.g. "lid closed") + * + * The arguments are copied, so the caller is responsible for + * freeing them. This function may be called from interrupt + * context. + */ + +void boxevent(const char* event_type, + const char* subsystem, + const char* desc) +{ + unsigned ring_cur; + unsigned long flags; + + /* No snprintf in kernel */ + if(strlen(event_type)+strlen(subsystem)+strlen(desc) + 5 >= + MSG_MAXLEN) { + panic("boxevent() arguments too long\n"); + } + + printk(KERN_DEBUG "box event: %s %s %s\n",event_type,subsystem,desc); + + spin_lock_irqsave(&listeners_lock,flags); + + ring_cur = ring_next; + + if(++ring_next >= N_MSGS) + ring_next = 0; + + { + struct list_head *i; + + list_for_each(i,&listeners) { + struct fop_priv *priv = list_entry(i, struct fop_priv, fp_entry); + if(ring_next == priv->fp_ringpos) { + /* we will actually overflow next item, + * but it is easier to complain now + */ + priv->fp_msgpos = 0; + priv->fp_overflow = 1; + } + } + + + } + + sprintf((char*)ring[ring_cur],"%s %s %s\n",event_type,subsystem,desc); + + spin_unlock_irqrestore(&listeners_lock,flags); + + wake_up_all(&waiters); /* Recipe for contention */ +} + +static ssize_t do_read(struct fop_priv*priv,char*buf,size_t count) +{ + ssize_t ret = 0; + char* msg; + + if(!priv->fp_overflow) { + if(priv->fp_ringpos == ring_next) { + ret = ret ? ret : -EAGAIN; + goto out; + } + msg = (char*)ring[priv->fp_ringpos]; + } + else + msg = (char*)msg_overflow; + + msg += priv->fp_msgpos; + ret = strlen(msg); + if(ret <= count){ + if(priv->fp_overflow){ + priv->fp_overflow = 0; + priv->fp_ringpos = ring_next; + /* This means the minimum number of + * messages is lost, which might not + * be an altogether good idea, because + * the reader is not given much chance + * to catch up with the flood + */ + } + + if (++priv->fp_ringpos >= N_MSGS) + priv->fp_ringpos = 0; + + priv->fp_msgpos = 0; + } else { + ret = count; + priv->fp_msgpos += count; + } + + if (copy_to_user(buf, msg, ret)) + ret = -EFAULT; + + out: + return ret; +} + + +static ssize_t fop_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + unsigned long flags; + struct fop_priv *priv = (struct fop_priv *)file->private_data; + + if (ppos != &file->f_pos) { + ret = -ESPIPE; + goto out; + } + + retry: + spin_lock_irqsave(&listeners_lock,flags); + + ret = do_read(priv,buf,count); + + spin_unlock_irqrestore(&listeners_lock,flags); + + if((ret == -EAGAIN) && !(file->f_flags&O_NONBLOCK)) { + if (wait_event_interruptible(waiters, + priv->fp_overflow || priv->fp_ringpos != ring_next) + == -ERESTARTSYS) { + ret = ret ? ret : -ERESTARTSYS; + goto out; + } + goto retry; + } + out: + return ret; +} + +static int fop_open(struct inode * inode, struct file * file) +{ + struct fop_priv*priv; + unsigned long flags; + + priv = kmalloc(sizeof *priv,GFP_KERNEL); + if(!priv) + return -ENOMEM; + + memset(priv,0,sizeof *priv); + + file->private_data = priv; + + spin_lock_irqsave(&listeners_lock,flags); + priv->fp_ringpos = ring_next; + list_add(&priv->fp_entry, &listeners); + spin_unlock_irqrestore(&listeners_lock,flags); + + return 0; +} + +static void do_remove_priv(struct fop_priv *priv) +{ + list_del(&priv->fp_entry); + kfree(priv); +} + +static int fop_release(struct inode * inode, struct file * file) +{ + struct fop_priv *priv = (struct fop_priv *)file->private_data; + unsigned long flags; + + spin_lock_irqsave(&listeners_lock,flags); + + do_remove_priv(priv); + + spin_unlock_irqrestore(&listeners_lock,flags); + + return 0; +} + +static unsigned int fop_poll(struct file *file, poll_table * wait) +{ + struct fop_priv *priv = (struct fop_priv *)file->private_data; + unsigned ret = 0; + unsigned long flags; + + poll_wait(file, &waiters, wait); + + spin_lock_irqsave(&listeners_lock,flags); + if(priv->fp_overflow || priv->fp_ringpos != ring_next) + ret = POLLIN | POLLRDNORM; + spin_unlock_irqrestore(&listeners_lock,flags); + + return ret; +} + + +static struct file_operations box_fops = { + owner: THIS_MODULE, + read: fop_read, + poll: fop_poll, + open: fop_open, + release: fop_release, +}; + +static struct miscdevice box_dev= +{ + BOXEVENT_MINOR, + "boxevent", + &box_fops +}; + +static int __init box_init(void) +{ + if(misc_register(&box_dev)){ + printk(KERN_DEBUG "boxevent: could not register device node\n"); + return -EBUSY; + } + + /* FIXME: remove if this gets into main tree */ + printk(KERN_INFO "boxevent: subsystem ready\n"); + return 0; +} + +static void __exit box_exit(void) +{ + struct list_head *i,*j; + unsigned long flags; + + if(misc_deregister(&box_dev)) + printk(KERN_DEBUG "boxevent: could not deregister device node\n"); + + /* FIXME: remove if this gets into main tree */ + printk(KERN_INFO "boxevent: shut down\n"); + + spin_lock_irqsave(&listeners_lock,flags); + + for(i=listeners.next;i!=&listeners;i=j){ + struct fop_priv *priv + = list_entry(i, struct fop_priv, fp_entry); + j = i->next; + do_remove_priv(priv); + } + + spin_unlock_irqrestore(&listeners_lock,flags); +} + +module_init(box_init); +module_exit(box_exit); + +MODULE_DESCRIPTION("Simple asynchronous event interface"); +MODULE_AUTHOR("John Fremlin"); +EXPORT_SYMBOL(boxevent); diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/drivers/char/nwbutton.c linux-2.4.4-boxevent/drivers/char/nwbutton.c --- linux-2.4.4-orig/drivers/char/nwbutton.c Sun Aug 13 17:54:15 2000 +++ linux-2.4.4-boxevent/drivers/char/nwbutton.c Mon May 7 15:26:02 2001 @@ -2,6 +2,7 @@ * NetWinder Button Driver- * Copyright (C) Alex Holden 1998, 1999. * + * 2001 May 7: Mangled for the the boxevent interface by John Fremlin */ #include @@ -12,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -28,11 +29,9 @@ static struct timer_list button_timer; /* Times for the end of a sequence */ static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */ static char button_output_buffer[32]; /* Stores data to write out of device */ -static int bcount; /* The number of bytes in the buffer */ static int bdelay = BUTTON_DELAY; /* The delay, in jiffies */ static struct button_callback button_callback_list[32]; /* The callback list */ static int callback_count; /* The number of callbacks registered */ -static int reboot_count = NUM_PRESSES_REBOOT; /* Number of presses to reboot */ /* * This function is called by other drivers to register a callback function @@ -119,19 +118,15 @@ * This function is called when the button_timer times out. * ie. When you don't press the button for bdelay jiffies, this is taken to * mean you have ended the sequence of key presses, and this function is - * called to wind things up (write the press_count out to /dev/button, call + * called to wind things up (write the press_count out to /dev/boxevent, call * any matching registered function callbacks, initiate reboot, etc.). */ static void button_sequence_finished (unsigned long parameters) { -#ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */ - if (button_press_count == reboot_count) { - kill_proc (1, SIGINT, 1); /* Ask init to reboot us */ - } -#endif /* CONFIG_NWBUTTON_REBOOT */ button_consume_callbacks (button_press_count); - bcount = sprintf (button_output_buffer, "%d\n", button_press_count); + sprintf (button_output_buffer, "%d presses", button_press_count); + boxevent(BOXEVENT_NOTIFY,"nwbutton",button_output_buffer); button_press_count = 0; /* Reset the button press counter */ wake_up_interruptible (&button_wait_queue); } @@ -157,53 +152,11 @@ } /* - * This function is called when a user space program attempts to read - * /dev/nwbutton. It puts the device to sleep on the wait queue until - * button_sequence_finished writes some data to the buffer and flushes - * the queue, at which point it writes the data out to the device and - * returns the number of characters it has written. This function is - * reentrant, so that many processes can be attempting to read from the - * device at any one time. - */ - -static int button_read (struct file *filp, char *buffer, - size_t count, loff_t *ppos) -{ - interruptible_sleep_on (&button_wait_queue); - return (copy_to_user (buffer, &button_output_buffer, bcount)) - ? -EFAULT : bcount; -} - -/* - * This structure is the file operations structure, which specifies what - * callbacks functions the kernel should call when a user mode process - * attempts to perform these operations on the device. - */ - -static struct file_operations button_fops = { - owner: THIS_MODULE, - read: button_read, -}; - -/* - * This structure is the misc device structure, which specifies the minor - * device number (158 in this case), the name of the device (for /proc/misc), - * and the address of the above file operations structure. - */ - -static struct miscdevice button_misc_device = { - BUTTON_MINOR, - "nwbutton", - &button_fops, -}; - -/* - * This function is called to initialise the driver, either from misc.c at - * bootup if the driver is compiled into the kernel, or from init_module - * below at module insert time. It attempts to register the device node - * and the IRQ and fails with a warning message if either fails, though - * neither ever should because the device number and IRQ are unique to - * this driver. + * This function is called to initialise the driver, either from + * misc.c at bootup if the driver is compiled into the kernel, or from + * init_module below at module insert time. It attempts to register + * the IRQ and fails with a warning message if this fails, though it + * never ever should because the IRQ is unique to this driver. */ static int __init nwbutton_init(void) @@ -214,17 +167,10 @@ printk (KERN_INFO "NetWinder Button Driver Version %s (C) Alex Holden " " 1998.\n", VERSION); - if (misc_register (&button_misc_device)) { - printk (KERN_WARNING "nwbutton: Couldn't register device 10, " - "%d.\n", BUTTON_MINOR); - return -EBUSY; - } - if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, SA_INTERRUPT, "nwbutton", NULL)) { printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n", IRQ_NETWINDER_BUTTON); - misc_deregister (&button_misc_device); return -EIO; } return 0; @@ -233,7 +179,6 @@ static void __exit nwbutton_exit (void) { free_irq (IRQ_NETWINDER_BUTTON, NULL); - misc_deregister (&button_misc_device); } EXPORT_NO_SYMBOLS; diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/drivers/char/nwbutton.h linux-2.4.4-boxevent/drivers/char/nwbutton.h --- linux-2.4.4-orig/drivers/char/nwbutton.h Wed Jul 5 21:22:07 2000 +++ linux-2.4.4-boxevent/drivers/char/nwbutton.h Mon May 7 15:20:28 2001 @@ -10,10 +10,8 @@ /* Various defines: */ -#define NUM_PRESSES_REBOOT 2 /* How many presses to activate shutdown */ #define BUTTON_DELAY 30 /* How many jiffies for sequence to end */ #define VERSION "0.3" /* Driver version number */ -#define BUTTON_MINOR 158 /* Major 10, Minor 158, /dev/nwbutton */ /* Structure definitions: */ diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/include/linux/boxevent.h linux-2.4.4-boxevent/include/linux/boxevent.h --- linux-2.4.4-orig/include/linux/boxevent.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.4-boxevent/include/linux/boxevent.h Mon May 7 16:04:11 2001 @@ -0,0 +1,34 @@ +/* (C) 2001 John Fremlin */ + +#ifndef _LINUX_BOXEVENT_H_ +#define _LINUX_BOXEVENT_H_ + +#define BOXEVENT_NOTIFY "NOTIFY" +#define BOXEVENT_SLEEP "SLEEP" +#define BOXEVENT_OFF "OFF" +#define BOXEVENT_WAKE "WAKE" +#define BOXEVENT_EMERGENCY "EMERGENCY" +#define BOXEVENT_POWERCHANGE BOXEVENT_NOTIFY + +#define BOXEVENT_FLOOD "MSGFLOOD" + /* only generated if a buffer + * internal to the pm event + * system overflows + */ +#ifdef __KERNEL__ +#include + +#ifdef CONFIG_BOXEVENT +void boxevent(const char* event_type, + const char* subsystem, + const char* desc); +#else +static inline void boxevent(const char* event_type, + const char* subsystem, + const char* desc) +{ +} +#endif +#endif + +#endif diff --new-file -u --recursive --exclude *~ linux-2.4.4-orig/include/linux/miscdevice.h linux-2.4.4-boxevent/include/linux/miscdevice.h --- linux-2.4.4-orig/include/linux/miscdevice.h Tue May 1 20:47:45 2001 +++ linux-2.4.4-boxevent/include/linux/miscdevice.h Mon May 7 16:21:26 2001 @@ -17,6 +17,7 @@ #define TEMP_MINOR 131 /* Temperature Sensor */ #define RTC_MINOR 135 #define EFI_RTC_MINOR 136 /* EFI Time services */ +#define BOXEVENT_MINOR 137 #define SUN_OPENPROM_MINOR 139 #define NVRAM_MINOR 144 #define I2O_MINOR 166