Hi Alan,

Alan Cox <[EMAIL PROTECTED]> writes:
> 
> Changes in 2.4.0test11ac2
> 
> o     APM update                                      (Stephen Rothwell)
> o     Work arounds for broken Dell laptop APM         (me)

Here is (in my opinion) a better patch.  It also means that we can
use apm as a module and have the Dell workaround work.

Most of this patch is a change of mind on my part after I posted
my previous patch ... (sorry about that).

This patch also make unloading of the apm module impossible is
someone has /proc/apm open ...  (BUG FIX)

Patch against 2.4.0test11ac2.

Cheers,
Stephen
-- 
Stephen Rothwell, Open Source Researcher, Linuxcare, Inc.
+61-2-62628990 tel, +61-2-62628991 fax 
[EMAIL PROTECTED], http://www.linuxcare.com/ 
Linuxcare. Support for the revolution.

diff -ruN 2.4.0-test11-ac2/arch/i386/kernel/apm.c 
2.4.0-test11-ac2-APM.2/arch/i386/kernel/apm.c
--- 2.4.0-test11-ac2/arch/i386/kernel/apm.c     Thu Nov 23 10:29:19 2000
+++ 2.4.0-test11-ac2-APM.2/arch/i386/kernel/apm.c       Thu Nov 23 12:47:02 2000
@@ -338,7 +338,6 @@
 #endif
 static int                     debug;
 static int                     apm_disabled;
-static int                     dell_crap;      /* Set for broken 5000e */
 #ifdef CONFIG_SMP
 static int                     power_off;
 #else
@@ -564,7 +563,7 @@
 #ifdef ALWAYS_CALL_BUSY
        clock_slowed = 1;
 #else
-       clock_slowed = (apm_info.bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
+       clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;
 #endif
        return 1;
 }
@@ -675,15 +674,15 @@
 {
        u32     eax;
 
-       if ((enable == 0) && (apm_info.bios_info.flags & APM_BIOS_DISENGAGED))
+       if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))
                return APM_NOT_ENGAGED;
        if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
                        enable, &eax))
                return (eax >> 8) & 0xff;
        if (enable)
-               apm_info.bios_info.flags &= ~APM_BIOS_DISABLED;
+               apm_info.bios.flags &= ~APM_BIOS_DISABLED;
        else
-               apm_info.bios_info.flags |= APM_BIOS_DISABLED;
+               apm_info.bios.flags |= APM_BIOS_DISABLED;
        return APM_SUCCESS;
 }
 #endif
@@ -696,6 +695,8 @@
        u32     edx;
        u32     dummy;
 
+       if (apm_info.get_power_status_broken)
+               return APM_32_UNSUPPORTED;
        if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,
                        &eax, &ebx, &ecx, &edx, &dummy))
                return (eax >> 8) & 0xff;
@@ -739,15 +740,15 @@
        u32     eax;
 
        if ((enable == 0) && (device == APM_DEVICE_ALL)
-           && (apm_info.bios_info.flags & APM_BIOS_DISABLED))
+           && (apm_info.bios.flags & APM_BIOS_DISABLED))
                return APM_DISABLED;
        if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
                return (eax >> 8) & 0xff;
        if (device == APM_DEVICE_ALL) {
                if (enable)
-                       apm_info.bios_info.flags &= ~APM_BIOS_DISENGAGED;
+                       apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;
                else
-                       apm_info.bios_info.flags |= APM_BIOS_DISENGAGED;
+                       apm_info.bios.flags |= APM_BIOS_DISENGAGED;
        }
        return APM_SUCCESS;
 }
@@ -1333,19 +1334,6 @@
        return 0;
 }
 
-/*
- *     This is called by the DMI code when it finds an Inspiron 5000e
- *     (aka compal reference board). We actually do the check by the BIOS
- *     vendor name, version and serial so we can extend it to try and catch
- *     non Dell stuff later.
- */
- 
-void apm_battery_horked(void)
-{
-       dell_crap = 1;
-}
-
-
 static int apm_get_info(char *buf, char **start, off_t fpos, int length)
 {
        char *          p;
@@ -1362,7 +1350,7 @@
 
        p = buf;
 
-       if ((smp_num_cpus == 1) && !dell_crap &&
+       if ((smp_num_cpus == 1) &&
            !(error = apm_get_power_status(&bx, &cx, &dx))) {
                ac_line_status = (bx >> 8) & 0xff;
                battery_status = bx & 0xff;
@@ -1417,9 +1405,9 @@
 
        p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
                     driver_version,
-                    (apm_info.bios_info.version >> 8) & 0xff,
-                    apm_info.bios_info.version & 0xff,
-                    apm_info.bios_info.flags,
+                    (apm_info.bios.version >> 8) & 0xff,
+                    apm_info.bios.version & 0xff,
+                    apm_info.bios.flags,
                     ac_line_status,
                     battery_status,
                     battery_flag,
@@ -1448,7 +1436,7 @@
        current->tty = NULL;    /* get rid of controlling tty */
 
        if (apm_info.connection_version == 0) {
-               apm_info.connection_version = apm_info.bios_info.version;
+               apm_info.connection_version = apm_info.bios.version;
                if (apm_info.connection_version > 0x100) {
                        /*
                         * We only support BIOSs up to version 1.2
@@ -1470,7 +1458,7 @@
                        apm_info.connection_version & 0xff);
 
 #ifdef CONFIG_APM_DO_ENABLE
-       if (apm_info.bios_info.flags & APM_BIOS_DISABLED) {
+       if (apm_info.bios.flags & APM_BIOS_DISABLED) {
                /*
                 * This call causes my NEC UltraLite Versa 33/C to hang if it
                 * is booted with PM disabled but not in the docking station.
@@ -1484,7 +1472,7 @@
        }
 #endif
 
-       if ((apm_info.bios_info.flags & APM_BIOS_DISENGAGED)
+       if ((apm_info.bios.flags & APM_BIOS_DISENGAGED)
            && (apm_info.connection_version > 0x0100)) {
                error = apm_engage_power_management(APM_DEVICE_ALL, 1);
                if (error) {
@@ -1610,17 +1598,19 @@
  */
 static int __init apm_init(void)
 {
-       if (apm_info.bios_info.version == 0) {
+       struct proc_dir_entry *apm_proc;
+
+       if (apm_info.bios.version == 0) {
                printk(KERN_INFO "apm: BIOS not found.\n");
                return -ENODEV;
        }
        printk(KERN_INFO
                "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
-               ((apm_info.bios_info.version >> 8) & 0xff),
-               (apm_info.bios_info.version & 0xff),
-               apm_info.bios_info.flags,
+               ((apm_info.bios.version >> 8) & 0xff),
+               (apm_info.bios.version & 0xff),
+               apm_info.bios.flags,
                driver_version);
-       if ((apm_info.bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
+       if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
                printk(KERN_INFO "apm: no 32 bit BIOS support\n");
                return -ENODEV;
        }
@@ -1629,23 +1619,23 @@
         * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
         * but is reportedly a 1.0 BIOS.
         */
-       if (apm_info.bios_info.version == 0x001)
-               apm_info.bios_info.version = 0x100;
+       if (apm_info.bios.version == 0x001)
+               apm_info.bios.version = 0x100;
 
        /* BIOS < 1.2 doesn't set cseg_16_len */
-       if (apm_info.bios_info.version < 0x102)
-               apm_info.bios_info.cseg_16_len = 0; /* 64k */
+       if (apm_info.bios.version < 0x102)
+               apm_info.bios.cseg_16_len = 0; /* 64k */
 
        if (debug) {
                printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
-                       apm_info.bios_info.cseg, apm_info.bios_info.offset,
-                       apm_info.bios_info.cseg_16, apm_info.bios_info.dseg);
-               if (apm_info.bios_info.version > 0x100)
+                       apm_info.bios.cseg, apm_info.bios.offset,
+                       apm_info.bios.cseg_16, apm_info.bios.dseg);
+               if (apm_info.bios.version > 0x100)
                        printk(" cseg len %x, dseg len %x",
-                               apm_info.bios_info.cseg_len,
-                               apm_info.bios_info.dseg_len);
-               if (apm_info.bios_info.version > 0x101)
-                       printk(" cseg16 len %x", apm_info.bios_info.cseg_16_len);
+                               apm_info.bios.cseg_len,
+                               apm_info.bios.dseg_len);
+               if (apm_info.bios.version > 0x101)
+                       printk(" cseg16 len %x", apm_info.bios.cseg_16_len);
                printk("\n");
        }
 
@@ -1673,16 +1663,16 @@
                 __va((unsigned long)0x40 << 4));
        _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
 
-       apm_bios_entry.offset = apm_info.bios_info.offset;
+       apm_bios_entry.offset = apm_info.bios.offset;
        apm_bios_entry.segment = APM_CS;
        set_base(gdt[APM_CS >> 3],
-                __va((unsigned long)apm_info.bios_info.cseg << 4));
+                __va((unsigned long)apm_info.bios.cseg << 4));
        set_base(gdt[APM_CS_16 >> 3],
-                __va((unsigned long)apm_info.bios_info.cseg_16 << 4));
+                __va((unsigned long)apm_info.bios.cseg_16 << 4));
        set_base(gdt[APM_DS >> 3],
-                __va((unsigned long)apm_info.bios_info.dseg << 4));
+                __va((unsigned long)apm_info.bios.dseg << 4));
 #ifndef APM_RELAX_SEGMENTS
-       if (apm_info.bios_info.version == 0x100) {
+       if (apm_info.bios.version == 0x100) {
 #endif
                /* For ASUS motherboard, Award BIOS rev 110 (and others?) */
                _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
@@ -1693,15 +1683,17 @@
 #ifndef APM_RELAX_SEGMENTS
        } else {
                _set_limit((char *)&gdt[APM_CS >> 3],
-                       (apm_info.bios_info.cseg_len - 1) & 0xffff);
+                       (apm_info.bios.cseg_len - 1) & 0xffff);
                _set_limit((char *)&gdt[APM_CS_16 >> 3],
-                       (apm_info.bios_info.cseg_16_len - 1) & 0xffff);
+                       (apm_info.bios.cseg_16_len - 1) & 0xffff);
                _set_limit((char *)&gdt[APM_DS >> 3],
-                       (apm_info.bios_info.dseg_len - 1) & 0xffff);
+                       (apm_info.bios.dseg_len - 1) & 0xffff);
        }
 #endif
 
-       create_proc_info_entry("apm", 0, NULL, apm_get_info);
+       apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info);
+       if (apm_proc)
+               apm_proc->owner = THIS_MODULE;
 
        kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
 
@@ -1720,7 +1712,7 @@
 {
        int     error;
 
-       if (((apm_info.bios_info.flags & APM_BIOS_DISENGAGED) == 0)
+       if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
            && (apm_info.connection_version > 0x0100)) {
                error = apm_engage_power_management(APM_DEVICE_ALL, 0);
                if (error)
diff -ruN 2.4.0-test11-ac2/arch/i386/kernel/dmi_scan.c 
2.4.0-test11-ac2-APM.2/arch/i386/kernel/dmi_scan.c
--- 2.4.0-test11-ac2/arch/i386/kernel/dmi_scan.c        Thu Nov 23 10:29:19 2000
+++ 2.4.0-test11-ac2-APM.2/arch/i386/kernel/dmi_scan.c  Thu Nov 23 12:49:28 2000
@@ -3,6 +3,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/apm_bios.h>
 #include <asm/io.h>
 
 struct dmi_header
@@ -127,11 +128,8 @@
                           strcmp(dmi_string(dm, data[5]), "A04")==0)
 //                        &&strcmp(dmi_string(dm, data[8]), "???")==0)
                        {
-#ifdef CONFIG_APM
-                               extern void apm_battery_horked(void);
-                               apm_battery_horked();                           
-                               printk(KERN_WARNING "BIOS strings suggest APM bugs, 
disabling battery reporting.\n");
-#endif                         
+                               apm_info.get_power_status_broken = 1;
+                               printk(KERN_WARNING "BIOS strings suggest APM bugs, 
+disabling power status reporting.\n");
                        }
                        break;
                case 1:
diff -ruN 2.4.0-test11-ac2/arch/i386/kernel/setup.c 
2.4.0-test11-ac2-APM.2/arch/i386/kernel/setup.c
--- 2.4.0-test11-ac2/arch/i386/kernel/setup.c   Thu Nov 23 10:29:19 2000
+++ 2.4.0-test11-ac2-APM.2/arch/i386/kernel/setup.c     Thu Nov 23 12:06:10 2000
@@ -608,7 +608,7 @@
        ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
        drive_info = DRIVE_INFO;
        screen_info = SCREEN_INFO;
-       apm_info.bios_info = APM_BIOS_INFO;
+       apm_info.bios = APM_BIOS_INFO;
        if( SYS_DESC_TABLE.length != 0 ) {
                MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
                machine_id = SYS_DESC_TABLE.table[0];
diff -ruN 2.4.0-test11-ac2/include/linux/apm_bios.h 
2.4.0-test11-ac2-APM.2/include/linux/apm_bios.h
--- 2.4.0-test11-ac2/include/linux/apm_bios.h   Thu Nov 23 10:29:22 2000
+++ 2.4.0-test11-ac2-APM.2/include/linux/apm_bios.h     Thu Nov 23 12:47:33 2000
@@ -49,8 +49,9 @@
  * Data for APM that is persistant across module unload/load
  */
 struct apm_info {
-       struct apm_bios_info    bios_info;
+       struct apm_bios_info    bios;
        unsigned short          connection_version;
+       int                     get_power_status_broken;
 };
 
 /*
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
Please read the FAQ at http://www.tux.org/lkml/

Reply via email to