// TST_UART.C
// Программа определения типа микросхемы UART асинхронного адаптера

#define    UART_8250     1
#define    UART_16450    2
#define    UART_16550    3
#define    UART_16550A   4


void main(void) {

	// номер асинхронного порта может быть 0 для COM1
	// или 1 для COM2

	int port = 0;

	int test;

	printf("\n(c) Frolov G.V. 1992.   "
		   "Программа определения типа UART\n\n");

	printf("\введите номер асинхронного порта (COM1 - 0, COM2 - 1):");
	scanf( "%d", &port );
	if(( port != 0 ) && ( port != 1 )){
		printf( "асинхронный порт COM%d не поддерживается\n", port );
		exit( -1 );
	}

	// проверяем является ли микросхема UART - UART 8250

	if( is_UART_8250(port) == UART_8250 ) {
		printf("обнаружена микросхема UART 8250\n");
		exit(0);
	}

	// проверяем другие типы микросхем UART

	if(( test = is_UART_FIFO(port) ) == UART_16550A ) {
		printf("обнаружена микросхема UART 16550A\n");
		exit(0);
	}

	else if(test == UART_16550) {
		printf("обнаружена микросхема UART 16550\n");
		exit(0);
	}

	printf("обнаружена микросхема UART 16450\n");
}


/**
*.Name         is_UART_8250
*
*.Title        Определяет тип UART.
*
*.Descr        Эта функция определляет тип микросхемы,
*              используемый данным последовательным асинхронным
*              адаптером (UART).
*
*.Proto        int is_UART_8250( int port );
*
*.Params       int port - номер асинхронного адаптера:
*                 0 - COM1, 1 - COM2
*
*.Return       для UART 8250 - возвращает константу UART_8250,
*              в остальных случаях возвращает 0
*
*.Sample       tst_uart.c
**/
int is_UART_8250( int port ) {

	int save_scr, in_scr;

	// сохраняем значения регистра расширения
	save_scr = inp( 0x3ff - 0x100 * port );

	// записываем в регистр расширения число 0x5A
	outp( 0x3ff - 0x100 * port, 0x5A );

	// считываем регистр расширения
	in_scr = inp( 0x3ff - 0x100 * port  );

	// сохранилось ли записанное число?
	if( in_scr != 0x5A ) {

		// если нет значит регистр расширения отсутствует и
		// следовательно тип микросхемы UART 8250

		// восстанавливаем значение регистра расширения
		outp( 0x3ff - 0x100 * port, save_scr );
		return( UART_8250 );
	}

	// записываем в регистр расширения другое число - 0xA5
	outp( 0x3ff - 0x100 * port, 0xA5 );

	// считываем регистр расширения
	in_scr = inp( 0x3ff - 0x100 * port  );

	// восстанавливаем значение регистра расширения
	outp( 0x3ff - 0x100 * port, save_scr );

	// сохранилось ли записанное число?
	if( in_scr != 0xA5 )

		// если нет значит регистр расширения отсутствует и
		// следовательно тип микросхемы UART 8250
		return( UART_8250 );

	// в противном случае регистр расширения есть и надо выполнить
	// дальнейшее тестирование для определения типа UART
	return( 0 );
}



/**
*.Name         is_UART_FIFO
*
*.Title        Определяет тип UART.
*
*.Descr        Эта функция определляет тип микросхемы,
*              используемый данным последовательным асинхронным
*              адаптером (UART).
*
*.Proto        int is_UART_FIFO( int port );
*
*.Params       int port - номер асинхронного адаптера:
*                 0 - COM1, 1 - COM2
*
*.Return       для UART 164550 - возвращает константу UART_16450,
*              для UART 16550 - возвращает константу UART_16550,
*              для UART 16550A - возвращает константу UART_16550A
*
*.Sample       tst_uart.c
**/
int is_UART_FIFO( int port ) {

	int save_iir, in_iir;

	// сохраняем значение регистра определения прерывания
	save_iir = inp( 0x3fa - 0x100 * port );

	// разрешаем использование FIFO
	outp( 0x3fa - 0x100 * port, 0x1 );

	// читаем значение регистра определения прерывания
	in_iir = inp( 0x3fa - 0x100 * port  );

	// ввосстанавливаем  значение регистра определения прерывания
	outp( 0x3fa - 0x100 * port, 0x0 );

	// если бит D6 содержит единицу, значит мы имеем UART 16550A
	if(( in_iir & 0x40 ) == 1 )
		return( UART_16550A );

	// если бит D7 содержит единицу, значит мы имеем UART 16550
	if(( in_iir & 0x80 ) == 1 )
		return( UART_16550 );

	// если биты D7 и D6 содержат нули, значит мы имеем UART 16450
	// (буфер FIFO отсутствует)
	return( UART_16450 );
}

