Subject: port-i386/10545: multiple battery support in APM
To: None <gnats-bugs@gnats.netbsd.org>
From: None <itojun@itojun.org>
List: netbsd-bugs
Date: 07/08/2000 20:26:13
>Number:         10545
>Category:       port-i386
>Synopsis:       multiple battery support in APM
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    port-i386-maintainer
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sat Jul 08 20:27:00 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     Jun-ichiro itojun Hagino
>Release:        latest current
>Organization:
	itojun.org
>Environment:
System: NetBSD starfruit.itojun.org 1.5B NetBSD 1.5B (STARFRUIT) #40: Sun Jul 9 11:49:28 JST 2000 itojun@starfruit.itojun.org:/usr/home/itojun/NetBSD/src/sys/arch/i386/compile/STARFRUIT i386


>Description:
	the attached patch tries to add multiple battery support into APM code.
	at this moment we can only be able to see # of batteries on the system.
	once we define some ioctl, we can query status for non-default
	batteries.  could someone finish it?
>How-To-Repeat:
>Fix:

Index: sys/arch/i386/include/apmvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/include/apmvar.h,v
retrieving revision 1.9
diff -c -r1.9 apmvar.h
*** apmvar.h	1999/08/17 19:05:53	1.9
--- apmvar.h	2000/07/09 03:23:06
***************
*** 280,286 ****
  	u_char battery_life;
  	u_char spare1;
  	u_int minutes_left;		/* estimate */
! 	u_int spare2[6];
  };
  
  struct apm_ctl {
--- 280,288 ----
  	u_char battery_life;
  	u_char spare1;
  	u_int minutes_left;		/* estimate */
! 	u_int nbattery;		
! 	u_int batteryid;
! 	u_int spare2[4];
  };
  
  struct apm_ctl {
Index: sys/arch/i386/i386/apm.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/i386/apm.c,v
retrieving revision 1.50
diff -c -r1.50 apm.c
*** apm.c	2000/06/04 22:36:27	1.50
--- apm.c	2000/07/09 03:23:09
***************
*** 145,151 ****
  #endif
  static void	apm_event_handle __P((struct apm_softc *, struct bioscallregs *));
  static int	apm_get_event __P((struct bioscallregs *));
! static int	apm_get_powstat __P((struct bioscallregs *));
  #if 0
  static void	apm_get_powstate __P((u_int));
  #endif
--- 145,151 ----
  #endif
  static void	apm_event_handle __P((struct apm_softc *, struct bioscallregs *));
  static int	apm_get_event __P((struct bioscallregs *));
! static int	apm_get_powstat __P((struct bioscallregs *, u_int));
  #if 0
  static void	apm_get_powstate __P((u_int));
  #endif
***************
*** 160,166 ****
  static void	apm_powmgt_enable __P((int));
  static void	apm_powmgt_engage __P((int, u_int));
  static int	apm_record_event __P((struct apm_softc *, u_int));
! static void	apm_get_capabilities __P((void));
  static void	apm_set_ver __P((struct apm_softc *));
  static void	apm_standby __P((struct apm_softc *));
  static const char *apm_strerror __P((int));
--- 160,166 ----
  static void	apm_powmgt_enable __P((int));
  static void	apm_powmgt_engage __P((int, u_int));
  static int	apm_record_event __P((struct apm_softc *, u_int));
! static void	apm_get_capabilities __P((struct bioscallregs *));
  static void	apm_set_ver __P((struct apm_softc *));
  static void	apm_standby __P((struct apm_softc *));
  static const char *apm_strerror __P((int));
***************
*** 545,551 ****
  
  	case APM_POWER_CHANGE:
  		DPRINTF(APMDEBUG_EVENTS, ("apmev: power status change\n"));
! 		error = apm_get_powstat(&nregs);
  #ifdef APM_POWER_PRINT
  		/* only print if nobody is catching events. */
  		if (error == 0 &&
--- 545,551 ----
  
  	case APM_POWER_CHANGE:
  		DPRINTF(APMDEBUG_EVENTS, ("apmev: power status change\n"));
! 		error = apm_get_powstat(&nregs, 0);
  #ifdef APM_POWER_PRINT
  		/* only print if nobody is catching events. */
  		if (error == 0 &&
***************
*** 592,599 ****
  		if (apm_minver < 2) {
  			DPRINTF(APMDEBUG_EVENTS, ("apm: unexpected event\n"));
  		} else {
! 			apm_get_capabilities();
! 			apm_get_powstat(&nregs); /* XXX */
  		}
  		break;
  
--- 592,599 ----
  		if (apm_minver < 2) {
  			DPRINTF(APMDEBUG_EVENTS, ("apm: unexpected event\n"));
  		} else {
! 			apm_get_capabilities(&nregs);
! 			apm_get_powstat(&nregs, 0); /* XXX */
  		}
  		break;
  
***************
*** 761,794 ****
  
  /* V1.2 */
  static void
! apm_get_capabilities()
  {
- 	struct bioscallregs regs;
  
! 	regs.BX = APM_DEV_APM_BIOS;
! 	if (apmcall(APM_GET_CAPABILITIES, &regs) != 0) {
! 		apm_perror("get capabilities", &regs);
  		return;
  	}
  
  #ifdef APMDEBUG
  	/* print out stats */
! 	printf("apm: %d batteries", APM_NBATTERIES(&regs));
! 	if (regs.CX & APM_GLOBAL_STANDBY)
  	    printf(", global standby");
! 	if (regs.CX & APM_GLOBAL_SUSPEND)
  	    printf(", global suspend");
! 	if (regs.CX & APM_RTIMER_STANDBY)
  	    printf(", rtimer standby");
! 	if (regs.CX & APM_RTIMER_SUSPEND)
  	    printf(", rtimer suspend");
! 	if (regs.CX & APM_IRRING_STANDBY)
  	    printf(", internal standby");
! 	if (regs.CX & APM_IRRING_SUSPEND)
  	    printf(", internal suspend");
! 	if (regs.CX & APM_PCRING_STANDBY)
  	    printf(", pccard standby");
! 	if (regs.CX & APM_PCRING_SUSPEND)
  	    printf(", pccard suspend");
  	printf("\n");
  #endif
--- 761,794 ----
  
  /* V1.2 */
  static void
! apm_get_capabilities(regs)
! 	struct bioscallregs *regs;
  {
  
! 	regs->BX = APM_DEV_APM_BIOS;
! 	if (apmcall(APM_GET_CAPABILITIES, regs) != 0) {
! 		apm_perror("get capabilities", regs);
  		return;
  	}
  
  #ifdef APMDEBUG
  	/* print out stats */
! 	printf("apm: %d batteries", APM_NBATTERIES(regs));
! 	if (regs->CX & APM_GLOBAL_STANDBY)
  	    printf(", global standby");
! 	if (regs->CX & APM_GLOBAL_SUSPEND)
  	    printf(", global suspend");
! 	if (regs->CX & APM_RTIMER_STANDBY)
  	    printf(", rtimer standby");
! 	if (regs->CX & APM_RTIMER_SUSPEND)
  	    printf(", rtimer suspend");
! 	if (regs->CX & APM_IRRING_STANDBY)
  	    printf(", internal standby");
! 	if (regs->CX & APM_IRRING_SUSPEND)
  	    printf(", internal suspend");
! 	if (regs->CX & APM_PCRING_STANDBY)
  	    printf(", pccard standby");
! 	if (regs->CX & APM_PCRING_SUSPEND)
  	    printf(", pccard suspend");
  	printf("\n");
  #endif
***************
*** 842,852 ****
  }
  
  static int
! apm_get_powstat(regs)
  	struct bioscallregs *regs;
  {
  
! 	regs->BX = APM_DEV_ALLDEVS;
  	return apmcall(APM_POWER_STATUS, regs);
  }
  
--- 842,856 ----
  }
  
  static int
! apm_get_powstat(regs, batteryid)
  	struct bioscallregs *regs;
+ 	u_int batteryid;
  {
  
! 	if (batteryid == 0)
! 		regs->BX = APM_DEV_ALLDEVS;
! 	else
! 		regs->BX = APM_DEV_BATTERY(batteryid);
  	return apmcall(APM_POWER_STATUS, regs);
  }
  
***************
*** 1267,1273 ****
  	apm_set_ver(apmsc);		/* prints version info */
  	printf("\n");
  	if (apm_minver >= 2)
! 		apm_get_capabilities();
  
  	/*
  	 * enable power management if it's disabled.
--- 1271,1277 ----
  	apm_set_ver(apmsc);		/* prints version info */
  	printf("\n");
  	if (apm_minver >= 2)
! 		apm_get_capabilities(&regs);
  
  	/*
  	 * enable power management if it's disabled.
***************
*** 1295,1301 ****
  	apm_powmgt_engage(1, APM_DEV_PCMCIA(APM_DEV_ALLUNITS));
  #endif
  	memset(&regs, 0, sizeof(regs));
! 	error = apm_get_powstat(&regs);
  	if (error == 0) {
  #ifdef APM_POWER_PRINT
  		apm_power_print(apmsc, &regs);
--- 1299,1305 ----
  	apm_powmgt_engage(1, APM_DEV_PCMCIA(APM_DEV_ALLUNITS));
  #endif
  	memset(&regs, 0, sizeof(regs));
! 	error = apm_get_powstat(&regs, 0);
  	if (error == 0) {
  #ifdef APM_POWER_PRINT
  		apm_power_print(apmsc, &regs);
***************
*** 1476,1481 ****
--- 1480,1486 ----
  #if 0
  	struct apm_ctl *actl;
  #endif
+ 	u_int batteryid, nbattery;
  	int i, error = 0;
  
  	APM_LOCK(sc);
***************
*** 1527,1539 ****
  
  	case APM_IOC_GETPOWER:
  		powerp = (struct apm_power_info *)data;
! 		if (apm_get_powstat(&regs)) {
  			apm_perror("ioctl get power status", &regs);
  			error = EIO;
  			break;
  		}
  
  		memset(powerp, 0, sizeof(*powerp));
  		if (APM_BATT_LIFE(&regs) != APM_BATT_LIFE_UNKNOWN)
  			powerp->battery_life = APM_BATT_LIFE(&regs);
  		powerp->ac_state = APM_AC_STATE(&regs);
--- 1532,1561 ----
  
  	case APM_IOC_GETPOWER:
  		powerp = (struct apm_power_info *)data;
! 		batteryid = 0;	/* need a way to pass it from the userland */
! 		if (apm_minver >= 2) {
! 			apm_get_capabilities(&regs);
! 			if (batteryid > APM_NBATTERIES(&regs)) {
! 				error = EIO;
! 				break;
! 			}
! 			nbattery = APM_NBATTERIES(&regs);
! 		} else {
! 			if (batteryid > 0) {
! 				error = EIO;
! 				break;
! 			}
! 			nbattery = 0;
! 		}
! 		if (apm_get_powstat(&regs, batteryid)) {
  			apm_perror("ioctl get power status", &regs);
  			error = EIO;
  			break;
  		}
  
  		memset(powerp, 0, sizeof(*powerp));
+ 		powerp->batteryid = batteryid;
+ 		powerp->nbattery = nbattery;
  		if (APM_BATT_LIFE(&regs) != APM_BATT_LIFE_UNKNOWN)
  			powerp->battery_life = APM_BATT_LIFE(&regs);
  		powerp->ac_state = APM_AC_STATE(&regs);
Index: usr.sbin/apm/apm.c
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/apm/apm.c,v
retrieving revision 1.8
diff -c -r1.8 apm.c
*** apm.c	1999/01/15 00:29:02	1.8
--- apm.c	2000/07/09 03:23:10
***************
*** 298,303 ****
--- 298,307 ----
  		    printf("A/C adapter state: %s\n", ac_state(reply.batterystate.ac_state));
  		if (dostatus)
  		    printf("Power management enabled\n");
+ 		if (reply.batterystate.nbattery) {
+ 		    printf("Number of batteries: %u\n",
+ 			reply.batterystate.nbattery);
+ 		}
  	    } else {
  		if (dobstate)
  		    printf("%d\n", reply.batterystate.battery_state);
>Release-Note:
>Audit-Trail:
>Unformatted: