[librm] Use libflat to enable A20 line on each real-to-protected transition
[gpxe.git] / src / arch / i386 / drivers / net / undiload.c
index 6f34404..8271b50 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+FILE_LICENCE ( GPL2_OR_LATER );
+
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
@@ -56,6 +58,12 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
        uint16_t exit;
        int rc;
 
+       /* Only one UNDI instance may be loaded at any given time */
+       if ( undi_loader_entry.segment ) {
+               DBG ( "UNDI %p cannot load multiple instances\n", undi );
+               return -EBUSY;
+       }
+
        /* Set up START_UNDI parameters */
        memset ( &undi_loader, 0, sizeof ( undi_loader ) );
        undi_loader.AX = undi->pci_busdevfn;
@@ -96,17 +104,10 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
                               : "a" ( __from_data16 ( &undi_loader ) )
                               : "ebx", "ecx", "edx", "esi", "edi", "ebp" );
 
-       /* UNDI API calls may rudely change the status of A20 and not
-        * bother to restore it afterwards.  Intel is known to be
-        * guilty of this.
-        *
-        * Note that we will return to this point even if A20 gets
-        * screwed up by the UNDI driver, because Etherboot always
-        * resides in an even megabyte of RAM.
-        */     
-       gateA20_set();
-
        if ( exit != PXENV_EXIT_SUCCESS ) {
+               /* Clear entry point */
+               memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
+
                rc = -undi_loader.Status;
                if ( rc == 0 ) /* Paranoia */
                        rc = -EIO;
@@ -149,6 +150,9 @@ int undi_unload ( struct undi_device *undi ) {
 
        DBGC ( undi, "UNDI %p unloading\n", undi );
 
+       /* Clear entry point */
+       memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
+
        /* Erase signatures */
        if ( undi->pxenv.segment )
                put_real ( dead, undi->pxenv.segment, undi->pxenv.offset );