patch-2.1.88 linux/drivers/char/apm_bios.c
Next file: linux/drivers/char/atarimouse.c
Previous file: linux/drivers/char/amigamouse.c
Back to the patch index
Back to the overall index
- Lines: 161
- Date:
Thu Feb 19 14:58:40 1998
- Orig file:
v2.1.87/linux/drivers/char/apm_bios.c
- Orig date:
Thu Feb 12 20:56:05 1998
diff -u --recursive --new-file v2.1.87/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c
@@ -141,6 +141,8 @@
* U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
* [Confirmed by BIOS disassembly]
* P: Toshiba 1950S: battery life information only gets updated after resume
+ * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking
+ * broken in BIOS [Reported by Garst R. Reese <reese@isn.net>]
*
* Legend: U = unusable with APM patches
* P = partially usable with APM patches
@@ -279,9 +281,15 @@
: "a" (0x530a), "b" (1) \
APM_BIOS_CALL_END
-#define APM_GET_EVENT(event, error) \
+#define APM_GET_BATTERY_STATUS(which, bx, cx, dx, si, error) \
APM_BIOS_CALL(al) \
- : "=a" (error), "=b" (event) \
+ : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx), "=S" (si) \
+ : "a" (0x530a), "b" (0x8000 | (which)) \
+ APM_BIOS_CALL_END
+
+#define APM_GET_EVENT(event, info, error) \
+ APM_BIOS_CALL(al) \
+ : "=a" (error), "=b" (event), "=c" (info) \
: "a" (0x530b) \
APM_BIOS_CALL_END
@@ -356,7 +364,8 @@
"critical suspend",
"user standby",
"user suspend",
- "system standby resume"
+ "system standby resume",
+ "capabilities change"
};
#define NR_APM_EVENT_NAME \
(sizeof(apm_event_name) / sizeof(apm_event_name[0]))
@@ -406,6 +415,8 @@
{ APM_BAD_DEVICE, "Unrecognized device ID" },
{ APM_BAD_PARAM, "Parameter out of range" },
{ APM_NOT_ENGAGED, "Interface not engaged" },
+ { APM_BAD_FUNCTION, "Function not supported" },
+ { APM_RESUME_DISABLED, "Resume timer disabled" },
{ APM_BAD_STATE, "Unable to enter requested state" },
/* N/A { APM_NO_EVENTS, "No events pending" }, */
{ APM_NOT_PRESENT, "No APM present" }
@@ -423,13 +434,15 @@
return APM_SUCCESS;
}
-static int apm_get_event(apm_event_t *event)
+static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
{
u_short error;
- APM_GET_EVENT(*event, error);
+ APM_GET_EVENT(*event, *info, error);
if (error & 0xff)
return (error >> 8);
+ if (apm_bios_info.version < 0x0102)
+ *info = ~0; /* indicate info not valid */
return APM_SUCCESS;
}
@@ -481,6 +494,24 @@
return APM_SUCCESS;
}
+static int apm_get_battery_status(u_short which,
+ u_short *bat, u_short *life, u_short *nbat)
+{
+ u_short status, error;
+
+ if (apm_bios_info.version < 0x0102) {
+ /* pretend we only have one battery. */
+ if (which!=1) return APM_BAD_DEVICE;
+ *nbat = 1;
+ return apm_get_power_status(&status, bat, life);
+ }
+
+ APM_GET_BATTERY_STATUS(which, status, *bat, *life, *nbat, error);
+ if (error & 0xff)
+ return (error >> 8);
+ return APM_SUCCESS;
+}
+
static inline int apm_engage_power_management(u_short device)
{
u_short error;
@@ -652,10 +683,12 @@
{
int error;
apm_event_t event;
+ apm_eventinfo_t info;
static int notified = 0;
- error = apm_get_event(&event);
+ /* we don't use the eventinfo */
+ error = apm_get_event(&event, &info);
if (error == APM_SUCCESS)
return event;
@@ -718,6 +751,7 @@
case APM_LOW_BATTERY:
case APM_POWER_STATUS_CHANGE:
+ case APM_CAPABILITY_CHANGE:
send_event(event, 0, NULL);
break;
@@ -1106,12 +1140,17 @@
if (apm_bios_info.version == 0x001)
apm_bios_info.version = 0x100;
+ /* BIOS < 1.2 doesn't set cseg_16_len */
+ if (apm_bios_info.version < 0x102)
+ apm_bios_info.cseg_16_len = 0xFFFF; /* 64k */
+
printk(KERN_INFO " Entry %x:%lx cseg16 %x dseg %x",
apm_bios_info.cseg, apm_bios_info.offset,
apm_bios_info.cseg_16, apm_bios_info.dseg);
if (apm_bios_info.version > 0x100)
- printk(" cseg len %x, dseg len %x",
- apm_bios_info.cseg_len, apm_bios_info.dseg_len);
+ printk(" cseg len %x, cseg16 len %x, dseg len %x",
+ apm_bios_info.cseg_len, apm_bios_info.cseg_16_len,
+ apm_bios_info.dseg_len);
printk("\n");
/*
@@ -1146,19 +1185,25 @@
set_limit(gdt[APM_DS >> 3], 64 * 1024);
#else
set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len);
- set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
+ set_limit(gdt[APM_CS_16 >> 3], apm_bios_info.cseg_16_len);
set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len);
#endif
- apm_bios_info.version = 0x0101;
+ /* The APM 1.2 docs state that the apm_driver_version
+ * call can fail if we try to connect as 1.2 to a 1.1 bios.
+ */
+ apm_bios_info.version = 0x0102;
error = apm_driver_version(&apm_bios_info.version);
- if (error != 0)
+ if (error != 0) { /* Fall back to an APM 1.1 connection. */
+ apm_bios_info.version = 0x0101;
+ error = apm_driver_version(&apm_bios_info.version);
+ }
+ if (error != 0) /* Fall back to an APM 1.0 connection. */
apm_bios_info.version = 0x100;
else {
apm_engage_power_management(0x0001);
printk( " Connection version %d.%d\n",
(apm_bios_info.version >> 8) & 0xff,
apm_bios_info.version & 0xff );
- apm_bios_info.version = 0x0101;
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov