|  | @@ -22,25 +22,27 @@
 | 
		
	
		
			
			| 22 | 22 |  					   enable data line
 | 
		
	
		
			
			| 23 | 23 |  					   disable clock line */
 | 
		
	
		
			
			| 24 | 24 |  
 | 
		
	
		
			
			|  | 25 | +#define SCP_A		0x92		/* System Control Port A */
 | 
		
	
		
			
			|  | 26 | +
 | 
		
	
		
			
			|  | 27 | +#define A20_MAX_RETRIES	32
 | 
		
	
		
			
			|  | 28 | +
 | 
		
	
		
			
			| 25 | 29 |  enum { Disable_A20 = 0x2400, Enable_A20 = 0x2401, Query_A20_Status = 0x2402,
 | 
		
	
		
			
			| 26 | 30 |  	Query_A20_Support = 0x2403 };
 | 
		
	
		
			
			| 27 | 31 |  
 | 
		
	
		
			
			| 28 |  | -#define CF ( 1 << 0 )
 | 
		
	
		
			
			| 29 |  | -
 | 
		
	
		
			
			| 30 |  | -#ifndef IBM_L40
 | 
		
	
		
			
			|  | 32 | +/**
 | 
		
	
		
			
			|  | 33 | + * Drain keyboard controller
 | 
		
	
		
			
			|  | 34 | + */
 | 
		
	
		
			
			| 31 | 35 |  static void empty_8042 ( void ) {
 | 
		
	
		
			
			| 32 | 36 |  	unsigned long time;
 | 
		
	
		
			
			| 33 | 37 |  
 | 
		
	
		
			
			| 34 | 38 |  	time = currticks() + TICKS_PER_SEC;	/* max wait of 1 second */
 | 
		
	
		
			
			| 35 |  | -	while ( ( inb ( K_CMD ) & K_IBUF_FUL ) &&
 | 
		
	
		
			
			|  | 39 | +	while ( ( inb ( K_CMD ) & ( K_IBUF_FUL | K_OBUF_FUL ) ) &&
 | 
		
	
		
			
			| 36 | 40 |  		currticks() < time ) {
 | 
		
	
		
			
			| 37 |  | -		/* Do nothing.  In particular, do *not* read from
 | 
		
	
		
			
			| 38 |  | -		 * K_RDWR, because that will drain the keyboard buffer
 | 
		
	
		
			
			| 39 |  | -		 * and lose keypresses.
 | 
		
	
		
			
			| 40 |  | -		 */
 | 
		
	
		
			
			|  | 41 | +		SLOW_DOWN_IO;
 | 
		
	
		
			
			|  | 42 | +		( void ) inb ( K_RDWR );
 | 
		
	
		
			
			|  | 43 | +		SLOW_DOWN_IO;
 | 
		
	
		
			
			| 41 | 44 |  	}
 | 
		
	
		
			
			| 42 | 45 |  }
 | 
		
	
		
			
			| 43 |  | -#endif	/* IBM_L40 */
 | 
		
	
		
			
			| 44 | 46 |  
 | 
		
	
		
			
			| 45 | 47 |  /**
 | 
		
	
		
			
			| 46 | 48 |   * Fast test to see if gate A20 is already set
 | 
		
	
	
		
			
			|  | @@ -82,6 +84,8 @@ static int gateA20_is_set ( void ) {
 | 
		
	
		
			
			| 82 | 84 |  void gateA20_set ( void ) {
 | 
		
	
		
			
			| 83 | 85 |  	static char reentry_guard = 0;
 | 
		
	
		
			
			| 84 | 86 |  	unsigned int discard_a;
 | 
		
	
		
			
			|  | 87 | +	unsigned int scp_a;
 | 
		
	
		
			
			|  | 88 | +	int retries = 0;
 | 
		
	
		
			
			| 85 | 89 |  
 | 
		
	
		
			
			| 86 | 90 |  	/* Avoid potential infinite recursion */
 | 
		
	
		
			
			| 87 | 91 |  	if ( reentry_guard )
 | 
		
	
	
		
			
			|  | @@ -92,31 +96,49 @@ void gateA20_set ( void ) {
 | 
		
	
		
			
			| 92 | 96 |  	if ( gateA20_is_set() )
 | 
		
	
		
			
			| 93 | 97 |  		goto out;
 | 
		
	
		
			
			| 94 | 98 |  
 | 
		
	
		
			
			| 95 |  | -	/* Try INT 15 method first */
 | 
		
	
		
			
			| 96 |  | -	__asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
 | 
		
	
		
			
			| 97 |  | -			       : "=a" ( discard_a )
 | 
		
	
		
			
			| 98 |  | -			       : "a" ( Enable_A20 ) );
 | 
		
	
		
			
			| 99 |  | -	if ( gateA20_is_set() )
 | 
		
	
		
			
			| 100 |  | -		goto out;
 | 
		
	
		
			
			| 101 |  | -	
 | 
		
	
		
			
			| 102 |  | -	/* INT 15 method failed, try alternatives */
 | 
		
	
		
			
			| 103 |  | -#ifdef	IBM_L40
 | 
		
	
		
			
			| 104 |  | -	outb(0x2, 0x92);
 | 
		
	
		
			
			| 105 |  | -#else	/* IBM_L40 */
 | 
		
	
		
			
			| 106 |  | -	empty_8042();
 | 
		
	
		
			
			| 107 |  | -	outb(KC_CMD_WOUT, K_CMD);
 | 
		
	
		
			
			| 108 |  | -	empty_8042();
 | 
		
	
		
			
			| 109 |  | -	outb(KB_SET_A20, K_RDWR);
 | 
		
	
		
			
			| 110 |  | -	empty_8042();
 | 
		
	
		
			
			| 111 |  | -#endif	/* IBM_L40 */
 | 
		
	
		
			
			| 112 |  | -	if ( gateA20_is_set() )
 | 
		
	
		
			
			| 113 |  | -		goto out;
 | 
		
	
		
			
			|  | 99 | +	for ( ; retries < A20_MAX_RETRIES ; retries++ ) {
 | 
		
	
		
			
			|  | 100 | +
 | 
		
	
		
			
			|  | 101 | +		/* Try INT 15 method first */
 | 
		
	
		
			
			|  | 102 | +		__asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
 | 
		
	
		
			
			|  | 103 | +				       : "=a" ( discard_a )
 | 
		
	
		
			
			|  | 104 | +				       : "a" ( Enable_A20 ) );
 | 
		
	
		
			
			|  | 105 | +		if ( gateA20_is_set() ) {
 | 
		
	
		
			
			|  | 106 | +			DBG ( "Enabled gate A20 using BIOS\n" );
 | 
		
	
		
			
			|  | 107 | +			goto out;
 | 
		
	
		
			
			|  | 108 | +		}
 | 
		
	
		
			
			|  | 109 | +
 | 
		
	
		
			
			|  | 110 | +		/* Try keyboard controller method */
 | 
		
	
		
			
			|  | 111 | +		empty_8042();
 | 
		
	
		
			
			|  | 112 | +		outb ( KC_CMD_WOUT, K_CMD );
 | 
		
	
		
			
			|  | 113 | +		empty_8042();
 | 
		
	
		
			
			|  | 114 | +		outb ( KB_SET_A20, K_RDWR );
 | 
		
	
		
			
			|  | 115 | +		empty_8042();
 | 
		
	
		
			
			|  | 116 | +		if ( gateA20_is_set() ) {
 | 
		
	
		
			
			|  | 117 | +			DBG ( "Enabled gate A20 using keyboard controller\n" );
 | 
		
	
		
			
			|  | 118 | +			goto out;
 | 
		
	
		
			
			|  | 119 | +		}
 | 
		
	
		
			
			|  | 120 | +
 | 
		
	
		
			
			|  | 121 | +		/* Try "Fast gate A20" method */
 | 
		
	
		
			
			|  | 122 | +		scp_a = inb ( SCP_A );
 | 
		
	
		
			
			|  | 123 | +		scp_a &= ~0x01; /* Avoid triggering a reset */
 | 
		
	
		
			
			|  | 124 | +		scp_a |= 0x02; /* Enable A20 */
 | 
		
	
		
			
			|  | 125 | +		SLOW_DOWN_IO;
 | 
		
	
		
			
			|  | 126 | +		outb ( scp_a, SCP_A );
 | 
		
	
		
			
			|  | 127 | +		SLOW_DOWN_IO;
 | 
		
	
		
			
			|  | 128 | +		if ( gateA20_is_set() ) {
 | 
		
	
		
			
			|  | 129 | +			DBG ( "Enabled gate A20 using Fast Gate A20\n" );
 | 
		
	
		
			
			|  | 130 | +			goto out;
 | 
		
	
		
			
			|  | 131 | +		}
 | 
		
	
		
			
			|  | 132 | +	}
 | 
		
	
		
			
			| 114 | 133 |  
 | 
		
	
		
			
			| 115 | 134 |  	/* Better to die now than corrupt memory later */
 | 
		
	
		
			
			| 116 | 135 |  	printf ( "FATAL: Gate A20 stuck\n" );
 | 
		
	
		
			
			| 117 | 136 |  	while ( 1 ) {}
 | 
		
	
		
			
			| 118 | 137 |  
 | 
		
	
		
			
			| 119 | 138 |   out:
 | 
		
	
		
			
			|  | 139 | +	if ( retries )
 | 
		
	
		
			
			|  | 140 | +		DBG ( "%d attempts were required to enable A20\n",
 | 
		
	
		
			
			|  | 141 | +		      ( retries + 1 ) );
 | 
		
	
		
			
			| 120 | 142 |  	reentry_guard = 0;
 | 
		
	
		
			
			| 121 | 143 |  }
 | 
		
	
		
			
			| 122 | 144 |  
 |