source: abuse/branches/pd/abuse/net/serial.c @ 636

Last change on this file since 636 was 49, checked in by Sam Hocevar, 15 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 3.5 KB
Line 
1
2#include <stdio.h>
3
4char *uart_names[]={"none",
5                    "8250 without scratch register",
6                    "8250A or 16450",
7                    "16C1450",
8                    "16550 with defective FIFO",
9                    "16550AF/C/CF",
10                    "16C1550",
11                    "16552 dual",
12                    "82510"};
13
14enum { UART_NONE,
15       UART_8250,
16       UART_8250A,
17       UART_16C1450,
18       UART_16550d,
19       UART_16550AF,
20       UART_16C1550,
21       UART_16552,
22       UART_82510 };
23       
24
25
26
27enum {
28  INTERRUPT_ID_REG=2,
29  LINE_CONTROL_REG=3,
30  MODEM_CONTROL_REG=4,
31  SCRATCH_PAD_REG=7
32};
33 
34void clear_interrupts();
35#pragma aux clear_interrupts = "cli";
36
37void enable_interrupts();
38#pragma aux enable_interrupts = "sti";
39
40void out_byte(int port, char value);
41#pragma aux out_byte parm [dx] [al] = \
42       "out dx, al", \
43       "jmp short +2", \
44       "jmp short +2";
45
46
47char in_byte(int port);
48#pragma aux in_byte parm [dx] = \
49    "in al, dx",  \
50    "jmp short +2", \
51    "jmp short +2" \
52    modify [al];
53
54
55
56static void set_divisor_latch_bit1(short port)
57{
58  out_byte(port,in_byte(port+LINE_CONTROL_REG)&0x80);
59}
60
61static void set_divisor_latch_bit0(short port)
62{
63  out_byte(port,in_byte(port+LINE_CONTROL_REG)&0x7f);
64}
65
66
67// writes a byte to a port and reads it back returns read value
68static char io_test(short port, char test_val)
69{
70  out_byte(port,test_val);
71  return in_byte(port);
72}
73
74static int is_1655x(int port)
75{
76  set_divisor_latch_bit1(port);
77  char bh=io_test(port+INTERRUPT_ID_REG,7);
78  out_byte(port+INTERRUPT_ID_REG,0);     // reset register select
79  if (bh!=7)
80  {
81    out_byte(port+MODEM_CONTROL_REG,0x80);     // turn power off
82    char al=in_byte(port+MODEM_CONTROL_REG);   // check to see if bit was set
83    out_byte(port+MODEM_CONTROL_REG,0);        // turn power back on
84    if (al&0x80)
85      return UART_16C1550;
86    else return UART_16550AF;
87  }
88  return UART_16552;
89}
90
91int detect_uart(short port)
92{
93  int type;
94  clear_interrupts();
95  set_divisor_latch_bit1(port);
96  if (io_test(port,0x5a)!=0x5a || io_test(port,0xa5)!=0xa5)
97    type=UART_NONE;
98  {
99    enable_interrupts(); 
100    if (io_test(port+SCRATCH_PAD_REG,0x5a)!=0x5a ||
101        io_test(port+SCRATCH_PAD_REG,0xa5)!=0xa5)
102      type=UART_8250;
103    else
104    {
105      clear_interrupts();     
106      if ((in_byte(port+INTERRUPT_ID_REG)&0xc0)==0xc0)  // FIFO not enabled, try to enable it
107        type=is_1655x(port);
108      else
109      {
110        out_byte(port+INTERRUPT_ID_REG,1);    // set to bank 0
111        char bh=in_byte(port+INTERRUPT_ID_REG);
112        out_byte(port+INTERRUPT_ID_REG,0);    // disable FIFO on 16550
113
114        if ((bh&0xc0)==0xc0)                  // 1655x
115          type=is_1655x(port);
116        else
117        {
118          if ((bh&0xc0)==0x40)
119            type=UART_16550AF;
120          else if ((bh&0xc0)==0x80)
121            type=UART_16550d;
122          else
123          {
124            out_byte(port+INTERRUPT_ID_REG,0x60);    // set bank 3
125            char bh=in_byte(port+INTERRUPT_ID_REG);
126            out_byte(port+INTERRUPT_ID_REG,0);       // set bank 0
127            if ((bh&0x60)==0x60)
128              type=UART_82510;
129            else
130            {
131              out_byte(port+MODEM_CONTROL_REG,0x80);    // see if power down is available
132              char bh=in_byte(port+MODEM_CONTROL_REG);
133              out_byte(port+MODEM_CONTROL_REG,0);    // power back on         
134              if (bh&0x80)
135                type=UART_16C1450;
136              else type=UART_8250A;
137            }
138          }
139        }               
140      }
141    }
142  }
143
144  enable_interrupts(); 
145  set_divisor_latch_bit1(port);
146  return type;
147}
148
149
150
151main()
152{
153  for (int i=0;i<4;i++)
154  {
155    int port=*((unsigned short *)((0x40<<4)+i*2));
156    char *name=(port==0 ? "None" : uart_names[detect_uart(port)]);
157    printf("com%d : %x, %s\n",i,port,name);
158  }
159}
Note: See TracBrowser for help on using the repository browser.