xref: /reactos/drivers/serial/serial/legacy.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         Serial port driver
4  * FILE:            drivers/bus/serial/legacy.c
5  * PURPOSE:         Legacy serial port enumeration
6  *
7  * PROGRAMMERS:     Herv� Poussineau (hpoussin@reactos.org)
8  *                  Mark Junker (mjscod@gmx.de)
9  */
10 
11 #include "serial.h"
12 
13 #include <debug.h>
14 
15 UART_TYPE
SerialDetectUartType(IN PUCHAR BaseAddress)16 SerialDetectUartType(
17 	IN PUCHAR BaseAddress)
18 {
19 	UCHAR Lcr, TestLcr;
20 	UCHAR OldScr, Scr5A, ScrA5;
21 	BOOLEAN FifoEnabled;
22 	UCHAR NewFifoStatus;
23 
24 	Lcr = READ_PORT_UCHAR(SER_LCR(BaseAddress));
25 	WRITE_PORT_UCHAR(SER_LCR(BaseAddress), Lcr ^ 0xFF);
26 	TestLcr = READ_PORT_UCHAR(SER_LCR(BaseAddress)) ^ 0xFF;
27 	WRITE_PORT_UCHAR(SER_LCR(BaseAddress), Lcr);
28 
29 	/* Accessing the LCR must work for a usable serial port */
30 	if (TestLcr != Lcr)
31 		return UartUnknown;
32 
33 	/* Ensure that all following accesses are done as required */
34 	READ_PORT_UCHAR(SER_RBR(BaseAddress));
35 	READ_PORT_UCHAR(SER_IER(BaseAddress));
36 	READ_PORT_UCHAR(SER_IIR(BaseAddress));
37 	READ_PORT_UCHAR(SER_LCR(BaseAddress));
38 	READ_PORT_UCHAR(SER_MCR(BaseAddress));
39 	READ_PORT_UCHAR(SER_LSR(BaseAddress));
40 	READ_PORT_UCHAR(SER_MSR(BaseAddress));
41 	READ_PORT_UCHAR(SER_SCR(BaseAddress));
42 
43 	/* Test scratch pad */
44 	OldScr = READ_PORT_UCHAR(SER_SCR(BaseAddress));
45 	WRITE_PORT_UCHAR(SER_SCR(BaseAddress), 0x5A);
46 	Scr5A = READ_PORT_UCHAR(SER_SCR(BaseAddress));
47 	WRITE_PORT_UCHAR(SER_SCR(BaseAddress), 0xA5);
48 	ScrA5 = READ_PORT_UCHAR(SER_SCR(BaseAddress));
49 	WRITE_PORT_UCHAR(SER_SCR(BaseAddress), OldScr);
50 
51 	/* When non-functional, we have a 8250 */
52 	if (Scr5A != 0x5A || ScrA5 != 0xA5)
53 		return Uart8250;
54 
55 	/* Test FIFO type */
56 	FifoEnabled = (READ_PORT_UCHAR(SER_IIR(BaseAddress)) & 0x80) != 0;
57 	WRITE_PORT_UCHAR(SER_FCR(BaseAddress), SR_FCR_ENABLE_FIFO);
58 	NewFifoStatus = READ_PORT_UCHAR(SER_IIR(BaseAddress)) & 0xC0;
59 	if (!FifoEnabled)
60 		WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0);
61 	switch (NewFifoStatus)
62 	{
63 		case 0x00:
64 			return Uart16450;
65 		case 0x40:
66 		case 0x80:
67 			/* Not sure about this but the documentation says that 0x40
68 			 * indicates an unusable FIFO but my tests only worked
69 			 * with 0x80 */
70 			return Uart16550;
71 	}
72 
73 	/* FIFO is only functional for 16550A+ */
74 	return Uart16550A;
75 }
76