Package: acpid
Version: 1.0.4-1
Severity: normal
Tags: patch


ACPI often doesn't report power changes while the system is off or
suspended. For example, if you suspend a system on AC and resume it on
battery, no ACPI event is sent and tools like battery status applets are
still reporting the system to be on AC.

There are hacks which modify the ACPI tables to fake an ACPI power
change event during resume but I believe this is not suitable for
average users. Instead, I thought acpid would be a better location for
this kind of hack.

I modified acpid.c such that it will fake a power change event whenever
it receives a USR2 signal. In order to trigger this, I simply execute

  # trigger ac_adapter event in acpid
  killall -USR2 acpid

in my suspend/resume scripts as the last action. Works like a charm for me...

If you believe this might be useful for others, please have a look at the attached patch. The event simulation code probably needs to be a bit smarter to generate events which match the system it's running on but I currently don't have access to other laptops running Linux so I can't check what they would expect.

Thanks,
--Christian


-- System Information:
Debian Release: 3.1
Architecture: i386 (i686)
Kernel: Linux 2.6.8-cm1.1
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)

Versions of packages acpid depends on:
ii  debconf                       1.4.30.13  Debian configuration management sy

-- debconf information:
  acpid/noacpi:
  acpid/modules: ac processor battery button fan thermal
*** /home/chris/tmp/acpid-1.0.4/acpid.c	Mon Apr 24 22:20:02 2006

--- acpid.c	Tue Mar  7 15:20:22 2006

***************

*** 43,48 ****

--- 43,50 ----

  static void clean_exit(int sig);

  static void reopen_logs(int sig);

  static void reload_conf(int sig);

+ static void ac_event(int sig);

+ static void simlulate_ac_event(void);

  static char *read_line(int fd);

  

  /* global debug level */

***************

*** 57,62 ****

--- 59,65 ----

  static const char *socketgroup;

  static mode_t socketmode = ACPI_SOCKETMODE;

  static int foreground;

+ static int got_usr2;

  

  int

  main(int argc, char **argv)

***************

*** 164,169 ****

--- 167,173 ----

  	/* trap key signals */

  	signal(SIGHUP, reload_conf);

  	signal(SIGUSR1, reopen_logs);

+         signal(SIGUSR2, ac_event);

  	signal(SIGINT, clean_exit);

  	signal(SIGQUIT, clean_exit);

  	signal(SIGTERM, clean_exit);

***************

*** 178,183 ****

--- 182,198 ----

  		int r;

  		int fds = 0;

  		

+ 		/* Check for USR2 before polling; this way we will also catch

+ 		 * signals received while we were processing an event. There's

+ 		 * still a small chance we miss a signal between here and

+ 		 * when we call poll() but this is very unlikely and the

+ 		 * USR2 feature is not mission-critical, anyway.

+ 		 */

+ 		if (got_usr2) {

+ 			simlulate_ac_event();

+ 			got_usr2 = 0;

+ 		}

+ 

  		/* poll for the socket and the event file */

  		ar[0].fd = event_fd; ar[0].events = POLLIN; fds++;

  		if (!nosocket) {

***************

*** 195,201 ****

  		/* was it an event? */

  		if (ar[0].revents) {

  			char *event;

! 			

  			/* this shouldn't happen */

  			if (!ar[0].revents & POLLIN) {

  				acpid_log("odd, poll set flags 0x%x\n", 

--- 210,216 ----

  		/* was it an event? */

  		if (ar[0].revents) {

  			char *event;

! 

  			/* this shouldn't happen */

  			if (!ar[0].revents & POLLIN) {

  				acpid_log("odd, poll set flags 0x%x\n", 

***************

*** 460,465 ****

--- 475,488 ----

  	acpid_log("logfile reopened\n");

  }

  

+ static void

+ ac_event(int sig)

+ {

+ 	/* main work will be done after poll() got interrutped */

+ 	got_usr2 = 1;

+ }

+ 

+ 

  int 

  acpid_log(const char *fmt, ...)

  {

***************

*** 479,484 ****

--- 502,537 ----

  	return 0;

  }

  

+ static void

+ simlulate_ac_event(void)

+ {

+         char event[100];

+ 	char *buf;

+ 	char *s;

+ 	int fh;

+ 

+ 	acpid_log("received USR2; simulating ac_adapter event\n");

+ 

+ 	if ((fh = open("/proc/acpi/ac_adapter/ACAD/state", O_RDONLY)) == -1) {

+ 		acpid_log("couldn't open /proc/acpi/ac_adapter/ACAD/state\n");

+ 		return;

+ 	}

+ 	buf = read_line(fh);

+ 	close(fh);

+ 

+ 	if (buf == NULL ||

+ 	    (s = strtok(buf, " \t")) == NULL ||

+ 	    (s = strtok(NULL, " \t")) == NULL) {

+ 		acpid_log("couldn't read or parse ac_adapter state\n");

+ 		return;

+ 	}

+ 

+ 	sprintf(event, "ac_adapter ACAD 00000080 0000000%d",

+ 	        !strcmp(s, "on-line") ? 1 : 0);

+ 	acpid_handle_event(event);

+ 	acpid_log("completed simulated ac_adapter event\n");

+ }

+ 

  /* 

   * This depends on fixes in linux ACPI after 2.4.8

   */

Reply via email to