migrate substitution keywords to SVN
[reactos.git] / reactos / drivers / dd / serial / serial.c
1 /* $Id$
2 *
3 * Serial driver
4 * Written by Jason Filby (jasonfilby@yahoo.com)
5 * For ReactOS (www.reactos.com)
6 *
7 */
8
9 #include <ddk/ntddk.h>
10 //#include <internal/mmhal.h>
11 //#include "../../../ntoskrnl/include/internal/i386/io.h"
12 //#include "../../../ntoskrnl/include/internal/io.h"
13
14 #define outb_p(a,p) WRITE_PORT_UCHAR((PUCHAR)a,p)
15 #define outw_p(a,p) WRITE_PORT_USHORT((PUSHORT)a,p)
16 #define inb_p(p) READ_PORT_UCHAR((PUCHAR)p)
17
18 #define NDEBUG
19 #include <debug.h>
20
21
22 #define COM1 0x3F8
23 #define COM2 0x2F8
24 #define COM3 0x3E8
25 #define COM4 0x2E8
26
27 #define UART_BAUDRATE 96 // 1200 BPS
28 #define UART_LCRVAL 0x1b // 0x1b for 8e1
29 #define UARY_FCRVAL 0x7
30
31 int uart_detect(unsigned base)
32 {
33 // Returns 0 if no UART detected
34
35 outb_p(base+4, 0x10);
36 if ((inb_p(base+6) & 0xf0)) return 0;
37 return 1;
38 };
39
40 int irq_setup(unsigned base)
41 {
42 // Returns -1 if not found -- otherwise returns interrupt level
43
44 char ier, mcr, imrm, imrs, maskm, masks, irqm, irqs;
45
46 __asm("cli"); // disable all CPU interrupts
47 ier = inb_p(base+1); // read IER
48 outb_p(base+1,0); // disable all UART ints
49 while (!(inb_p(base+5)&0x20)); // wait for the THR to be empty
50 mcr = inb_p(base+4); // read MCR
51 outb_p(base+4,0x0F); // connect UART to irq line
52 imrm = inb_p(0x21); // read contents of master ICU mask register
53 imrs = inb_p(0xA1); // read contents of slave ICU mask register
54 outb_p(0xA0,0x0A); // next read access to 0xA0 reads out IRR
55 outb_p(0x20,0x0A); // next read access to 0x20 reads out IRR
56 outb_p(base+1,2); // let's generate interrupts...
57 maskm = inb_p(0x20); // this clears all bits except for the one
58 masks = inb_p(0xA0); // that corresponds to the int
59 outb_p(base+1,0); // drop the int line
60 maskm &= ~inb_p(0x20); // this clears all bits except for the one
61 masks &= ~inb_p(0xA0); // that corresponds to the int
62 outb_p(base+1,2); // and raise it again just to be sure...
63 maskm &= inb_p(0x20); // this clears all bits except for the one
64 masks &= inb_p(0xA0); // that corresponds to the int
65 outb_p(0xA1,~masks); // now let us unmask this interrupt only
66 outb_p(0x21,~maskm);
67 outb_p(0xA0,0x0C); // enter polled mode
68 outb_p(0x20,0x0C); // that order is important with Pentium/PCI systems
69 irqs = inb_p(0xA0); // and accept the interrupt
70 irqm = inb_p(0x20);
71 inb_p(base+2); // reset transmitter interrupt in UART
72 outb_p(base+4,mcr); // restore old value of MCR
73 outb_p(base+1,ier); // restore old value of IER
74 if (masks) outb_p(0xA0,0x20); // send an EOI to slave
75 if (maskm) outb_p(0x20,0x20); // send an EOI to master
76 outb_p(0x21,imrm); // restore old mask register contents
77 outb_p(0xA1,imrs);
78 __asm("sti");
79 if (irqs&0x80) // slave interrupt occured
80 return (irqs&0x07)+8;
81 if (irqm&0x80) // master interrupt occured
82 return irqm&0x07;
83 return -1;
84 };
85
86 void uart_init(unsigned uart_base)
87 {
88 // Initialize the UART
89 outb_p(uart_base+3, 0x80);
90 outw_p(uart_base, UART_BAUDRATE);
91 outb_p(uart_base+3, UART_LCRVAL);
92 outb_p(uart_base+4, 0);
93 };
94
95 unsigned uart_getchar(unsigned uart_base)
96 {
97 unsigned x;
98
99 x=(inb_p(uart_base+5) & 0x9f) << 8;
100 if(x & 0x100) x|=((unsigned)inb_p(uart_base)) & 0xff;
101 return x;
102 };
103
104 void InitializeSerial(void)
105 {
106 unsigned comports[4] = { COM1, COM2, COM3, COM4 };
107 char *comname[4] = { "COM1", "COM2", "COM3", "COM4" };
108 int i, irq_level;
109
110 for (i=0; i<4; i++)
111 {
112 if(uart_detect(comports[i])==0)
113 {
114 DbgPrint("%s not detected\n", comname[i]);
115 } else {
116 uart_init(comports[i]);
117 irq_level=irq_setup(comports[i]);
118 if(irq_level==-1)
119 {
120 DbgPrint("Warning: IRQ not detected!\n");
121 } else {
122 DbgPrint("%s hooked to interrupt level %d\n", comname[i], irq_level);
123 };
124 };
125 };
126 };
127
128 // For testing purposes
129 void testserial(void)
130 {
131 int i=0;
132 char testc;
133
134 union {
135 unsigned val;
136 char character;
137 } x;
138
139 DbgPrint("Testing serial input...\n");
140
141 while(i==0) {
142 x.val=uart_getchar(COM1);
143 // if(!x.val) continue;
144 // if(x.val & 0x100)
145
146 testc=inb_p(COM1);
147
148 // DbgPrint("(%x-%c) %c\n", x.val, x.character, testc);
149 };
150 };
151
152 NTSTATUS STDCALL
153 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
154 {
155 DbgPrint("Serial Driver 0.0.2\n");
156 // InitializeSerial();
157 // testserial();
158 return(STATUS_SUCCESS);
159 };
160