Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / i386-pc / exec / serialrawio.c
blob396bdbd57218d5a94b318bde464d7fe1a4164d68
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: functions for serial RawIOInit/RawPutChar
6 Lang: english
8 Note: serial io from "PC-intern" examples
9 */
10 #include <proto/exec.h>
11 #include <asm/io.h>
13 #undef __save_flags
14 #undef __restore_flags
15 #undef __cli
16 #undef __sti
18 #define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
19 #define __restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
20 #define __cli() __asm__ __volatile__("cli": : :"memory")
21 #define __sti() __asm__ __volatile__("sti": : :"memory")
23 #define SER_ERRSIGNALS 0x0300
25 #define SER_LSR_OVERRUNERROR 0x02
26 #define SER_LSR_PARITYERROR 0x04
27 #define SER_LSR_FRAMINGERROR 0x08
28 #define SER_LSR_BREAKDETECT 0x10
29 #define SER_LSR_ERRORMSK (SER_LSR_OVERRUNERROR|SER_LSR_PARITYERROR|\
30 SER_LSR_FRAMINGERROR|SER_LSR_BREAKDETECT)
31 #define SER_LSR_TSREMPTY 0x40
33 #define SER_LCR_8BITS 0x03
34 #define SER_LCR_1STOPBIT 0x00
35 #define SER_LCR_NOPARITY 0x00
36 #define SER_LCR_SETDIVISOR 0x80
38 #define SER_TXBUFFER 0x00
39 #define SER_DIVISOR_LSB 0x00
40 #define SER_DIVISOR_MSB 0x01
41 #define SER_IRQ_ENABLE 0x01
42 #define SER_IRQ_ID 0x02
43 #define SER_FIFO 0x02
44 #define SER_2FUNCTION 0x02
45 #define SER_LINE_CONTROL 0x03
46 #define SER_MODEM_CONTROL 0x04
47 #define SER_LINE_STATUS 0x05
48 #define SER_MODEM_STATUS 0x06
49 #define SER_SCRATCH 0x07
51 #define SER_MCR_DTR 0x01
52 #define SER_MCR_RTS 0x02
53 #define SER_MCR_LOOP 0x10
55 #define SER_FIFO_ENABLE 0x01
56 #define SER_FIFO_RESETRECEIVE 0x02
57 #define SER_FIFO_RESETTRANSMIT 0x04
59 #define SER_MAXBAUD 115200L
61 #if AROS_SERIAL_DEBUG == 1
62 UWORD __serial_rawio_port = 0x3F8;
63 #else
64 #if AROS_SERIAL_DEBUG == 2
65 UWORD __serial_rawio_port = 0x2F8;
66 #else
67 UWORD __serial_rawio_port = 0;
68 #endif
69 #endif
71 int ser_UARTType (short);
72 void ser_FIFOLevel(short, BYTE);
73 int ser_Init(short, LONG, BYTE);
75 /*****i***********************************************************************
77 NAME */
78 AROS_LH0(void, SerialRawIOInit,
80 /* LOCATION */
81 struct ExecBase *, SysBase, 84, Exec)
83 /* FUNCTION
84 This is a private function. It initializes raw IO. After you
85 have called this function, you can use (!RawMayGetChar()) and
86 RawPutChar().
88 INPUTS
89 None.
91 RESULT
92 None.
94 NOTES
95 This function is for very low level debugging only.
97 EXAMPLE
99 BUGS
101 SEE ALSO
102 RawPutChar(), RawMayGetChar()
104 INTERNALS
106 HISTORY
108 *****************************************************************************/
110 AROS_LIBFUNC_INIT
111 if (__serial_rawio_port > 0)
113 if (ser_Init(__serial_rawio_port, 115200,SER_LCR_8BITS | SER_LCR_1STOPBIT | SER_LCR_NOPARITY))
114 ser_FIFOLevel(__serial_rawio_port, 0);
117 return;
118 AROS_LIBFUNC_EXIT
119 } /* RawIOInit */
121 int ser_UARTType (short port) {
123 outb_p(0xAA, port+SER_LINE_CONTROL); /* set Divisor-Latch */
124 if (inb_p(port+SER_LINE_CONTROL) != 0xAA)
125 return 1;
126 outb_p(0x55, port+SER_DIVISOR_MSB); /* write Divisor */
127 if (inb_p(port+SER_DIVISOR_MSB) != 0x55)
128 return 1;
129 outb_p(0x55, port+SER_LINE_CONTROL); /* clear Divisor-Latch */
130 if (inb_p(port+SER_LINE_CONTROL) != 0x55)
131 return 1;
132 outb_p(0x55, port+SER_IRQ_ENABLE);
133 if (inb_p(port+SER_IRQ_ENABLE) != 0x05)
134 return 1;
135 outb_p(0, port+SER_FIFO); /* clear FIFO and IRQ */
136 outb_p(0, port+SER_IRQ_ENABLE);
137 if (inb_p(port+SER_IRQ_ID) != 1)
138 return 1;
139 outb_p(0xF5, port+SER_MODEM_CONTROL);
140 if (inb_p(port+SER_MODEM_CONTROL) != 0x15)
141 return 1;
142 outb_p(SER_MCR_LOOP, port+SER_MODEM_CONTROL); /* Looping */
143 inb_p(port+SER_MODEM_STATUS);
144 if ((inb_p(port+SER_MODEM_STATUS) & 0xF0) != 0)
145 return 1;
146 outb_p(0x1F, port+SER_MODEM_CONTROL);
147 if ((inb_p(port+SER_MODEM_STATUS) & 0xF0) != 0xF0)
148 return 1;
149 outb_p(SER_MCR_DTR | SER_MCR_RTS, port + SER_MODEM_CONTROL);
151 outb_p(0x55, port+SER_SCRATCH); /* Scratch-Register ?*/
152 if (inb_p(port+SER_SCRATCH) != 0x55)
153 return 2; //INS8250;
154 outb_p(0, port+SER_SCRATCH);
156 outb_p(0xCF, port+SER_FIFO); /* FIFO ? */
157 if ((inb_p(port+SER_IRQ_ID) & 0xC0) != 0xC0)
158 return 3; //NS16450;
159 outb_p(0, port+SER_FIFO);
160 /* Alternate-Function Register ? */
161 outb_p(SER_LCR_SETDIVISOR, port+SER_LINE_CONTROL);
162 outb_p(0x07, port+SER_2FUNCTION);
163 if (inb_p(port+SER_2FUNCTION ) != 0x07)
165 outb_p(0, port+SER_LINE_CONTROL);
166 return 4; //NS16550A;
168 outb_p(0, port+SER_LINE_CONTROL); /* reset registers */
169 outb_p(0, port+SER_2FUNCTION);
170 return 5; //NS16C552;
173 void ser_FIFOLevel(short port, BYTE level) {
175 if (level)
176 outb_p(level | SER_FIFO_ENABLE, port+SER_FIFO);
177 else
178 outb_p(SER_FIFO_RESETRECEIVE | SER_FIFO_RESETTRANSMIT, port+SER_FIFO);
181 int ser_Init(short port, LONG baudRate, BYTE params) {
182 WORD uDivisor;
184 if (ser_UARTType(port)!=1)
186 uDivisor=(WORD)(SER_MAXBAUD / baudRate);
187 outb_p(inb_p(port+SER_LINE_CONTROL) | SER_LCR_SETDIVISOR, port+SER_LINE_CONTROL);
188 outb_p(uDivisor & 0xFF, port+SER_DIVISOR_LSB);
189 outb_p(uDivisor>>8, port+SER_DIVISOR_MSB);
190 outb_p(inb_p(port+SER_LINE_CONTROL) & ~SER_LCR_SETDIVISOR, port+SER_LINE_CONTROL);
192 outb_p(params, port+SER_LINE_CONTROL);
193 inb_p(port+SER_TXBUFFER);
194 return 1;
196 return 0;
199 int ser_WriteByte(short, UBYTE , ULONG , BYTE , BYTE );
200 int ser_IsWritingPossible(short);
203 AROS_LH1(void, SerialRawPutChar,
205 /* SYNOPSIS */
206 AROS_LHA(UBYTE, chr, D0),
208 /* LOCATION */
209 struct ExecBase *, SysBase, 86, Exec)
211 /* FUNCTION
212 Emits a single character.
214 INPUTS
215 chr - The character to emit
217 RESULT
218 None.
220 NOTES
221 This function is for very low level debugging only.
223 EXAMPLE
225 BUGS
227 SEE ALSO
228 RawIOInit(), RawPutChar(), RawMayGetChar()
230 INTERNALS
232 HISTORY
234 *****************************************************************************/
236 AROS_LIBFUNC_INIT
238 unsigned long flags;
240 if ((__serial_rawio_port > 0) && (chr))
242 __save_flags(flags);
244 /* stegerg: Don't use Disable/Enable, because we want
245 interrupt enabled flag to stay the same as
246 it was before the Disable() call */
247 __cli();
249 if (chr==0x0A)
251 // Send <CR> before <LF>
252 ser_WriteByte(__serial_rawio_port, 0x0D, 0, 0, 0);
254 ser_WriteByte(__serial_rawio_port, chr, 0, 0, 0);
256 /* Interrupt flag is stored in flags - if it was
257 enabled before, it will be renabled when the flags
258 are restored */
259 __restore_flags(flags);
262 AROS_LIBFUNC_EXIT
263 } /* RawPutChar */
265 int ser_IsWritingPossible(short port) {
267 return inb_p(port+SER_LINE_STATUS) & SER_LSR_TSREMPTY;
270 int ser_WriteByte(short port, UBYTE data, ULONG timeout, BYTE sigmask, BYTE sigvals) {
272 if (timeout)
274 while (!ser_IsWritingPossible(port) && timeout)
275 timeout--;
276 if (!timeout)
277 return 1;
279 else
280 while (!ser_IsWritingPossible(port));
282 if ((inb_p(port+SER_MODEM_STATUS) & sigmask) == sigvals)
284 outb_p(data, port+SER_TXBUFFER);
285 return inb_p(port+SER_LINE_STATUS) & SER_LSR_ERRORMSK;
287 else
288 return SER_ERRSIGNALS;