added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / arch / i386-pc / exec / serialrawio.c
blob1edaf71d2b9498d857ea91b047386325bf98ce3f
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 int ser_UARTType (short);
62 void ser_FIFOLevel(short, BYTE);
63 int ser_Init(short, LONG, BYTE);
65 /*****i***********************************************************************
67 NAME */
68 AROS_LH0(void, SerialRawIOInit,
70 /* LOCATION */
71 struct ExecBase *, SysBase, 84, Exec)
73 /* FUNCTION
74 This is a private function. It initializes raw IO. After you
75 have called this function, you can use (!RawMayGetChar()) and
76 RawPutChar().
78 INPUTS
79 None.
81 RESULT
82 None.
84 NOTES
85 This function is for very low level debugging only.
87 EXAMPLE
89 BUGS
91 SEE ALSO
92 RawPutChar(), RawMayGetChar()
94 INTERNALS
96 HISTORY
98 *****************************************************************************/
100 AROS_LIBFUNC_INIT
101 #if AROS_SERIAL_DEBUG == 1
102 if (ser_Init(0x3F8, 9600,SER_LCR_8BITS | SER_LCR_1STOPBIT | SER_LCR_NOPARITY))
103 ser_FIFOLevel(0x3F8, 0);
104 #endif
105 #if AROS_SERIAL_DEBUG == 2
106 if (ser_Init(0x2F8, 9600,SER_LCR_8BITS | SER_LCR_1STOPBIT | SER_LCR_NOPARITY))
107 ser_FIFOLevel(0x2F8, 0);
108 #endif
109 return;
110 AROS_LIBFUNC_EXIT
111 } /* RawIOInit */
113 int ser_UARTType (short port) {
115 outb_p(0xAA, port+SER_LINE_CONTROL); /* set Divisor-Latch */
116 if (inb_p(port+SER_LINE_CONTROL) != 0xAA)
117 return 1;
118 outb_p(0x55, port+SER_DIVISOR_MSB); /* write Divisor */
119 if (inb_p(port+SER_DIVISOR_MSB) != 0x55)
120 return 1;
121 outb_p(0x55, port+SER_LINE_CONTROL); /* clear Divisor-Latch */
122 if (inb_p(port+SER_LINE_CONTROL) != 0x55)
123 return 1;
124 outb_p(0x55, port+SER_IRQ_ENABLE);
125 if (inb_p(port+SER_IRQ_ENABLE) != 0x05)
126 return 1;
127 outb_p(0, port+SER_FIFO); /* clear FIFO and IRQ */
128 outb_p(0, port+SER_IRQ_ENABLE);
129 if (inb_p(port+SER_IRQ_ID) != 1)
130 return 1;
131 outb_p(0xF5, port+SER_MODEM_CONTROL);
132 if (inb_p(port+SER_MODEM_CONTROL) != 0x15)
133 return 1;
134 outb_p(SER_MCR_LOOP, port+SER_MODEM_CONTROL); /* Looping */
135 inb_p(port+SER_MODEM_STATUS);
136 if ((inb_p(port+SER_MODEM_STATUS) & 0xF0) != 0)
137 return 1;
138 outb_p(0x1F, port+SER_MODEM_CONTROL);
139 if ((inb_p(port+SER_MODEM_STATUS) & 0xF0) != 0xF0)
140 return 1;
141 outb_p(SER_MCR_DTR | SER_MCR_RTS, port + SER_MODEM_CONTROL);
143 outb_p(0x55, port+SER_SCRATCH); /* Scratch-Register ?*/
144 if (inb_p(port+SER_SCRATCH) != 0x55)
145 return 2; //INS8250;
146 outb_p(0, port+SER_SCRATCH);
148 outb_p(0xCF, port+SER_FIFO); /* FIFO ? */
149 if ((inb_p(port+SER_IRQ_ID) & 0xC0) != 0xC0)
150 return 3; //NS16450;
151 outb_p(0, port+SER_FIFO);
152 /* Alternate-Function Register ? */
153 outb_p(SER_LCR_SETDIVISOR, port+SER_LINE_CONTROL);
154 outb_p(0x07, port+SER_2FUNCTION);
155 if (inb_p(port+SER_2FUNCTION ) != 0x07)
157 outb_p(0, port+SER_LINE_CONTROL);
158 return 4; //NS16550A;
160 outb_p(0, port+SER_LINE_CONTROL); /* reset registers */
161 outb_p(0, port+SER_2FUNCTION);
162 return 5; //NS16C552;
165 void ser_FIFOLevel(short port, BYTE level) {
167 if (level)
168 outb_p(level | SER_FIFO_ENABLE, port+SER_FIFO);
169 else
170 outb_p(SER_FIFO_RESETRECEIVE | SER_FIFO_RESETTRANSMIT, port+SER_FIFO);
173 int ser_Init(short port, LONG baudRate, BYTE params) {
174 WORD uDivisor;
176 if (ser_UARTType(port)!=1)
178 uDivisor=(WORD)(SER_MAXBAUD / baudRate);
179 outb_p(inb_p(port+SER_LINE_CONTROL) | SER_LCR_SETDIVISOR, port+SER_LINE_CONTROL);
180 outb_p(uDivisor & 0xFF, port+SER_DIVISOR_LSB);
181 outb_p(uDivisor>>8, port+SER_DIVISOR_MSB);
182 outb_p(inb_p(port+SER_LINE_CONTROL) & ~SER_LCR_SETDIVISOR, port+SER_LINE_CONTROL);
184 outb_p(params, port+SER_LINE_CONTROL);
185 inb_p(port+SER_TXBUFFER);
186 return 1;
188 return 0;
191 int ser_WriteByte(short, UBYTE , ULONG , BYTE , BYTE );
192 int ser_IsWritingPossible(short);
195 AROS_LH1(void, SerialRawPutChar,
197 /* SYNOPSIS */
198 AROS_LHA(UBYTE, chr, D0),
200 /* LOCATION */
201 struct ExecBase *, SysBase, 86, Exec)
203 /* FUNCTION
204 Emits a single character.
206 INPUTS
207 chr - The character to emit
209 RESULT
210 None.
212 NOTES
213 This function is for very low level debugging only.
215 EXAMPLE
217 BUGS
219 SEE ALSO
220 RawIOInit(), RawPutChar(), RawMayGetChar()
222 INTERNALS
224 HISTORY
226 *****************************************************************************/
228 AROS_LIBFUNC_INIT
230 /* stegerg: Don't use Disable/Enable, because we want
231 interrupt enabled flag to stay the same as
232 it was before the Disable() call */
234 unsigned long flags;
236 __save_flags(flags);
237 __cli();
239 /* Disable(); */
241 /* Don't write 0 bytes */
242 if (chr)
244 //if (chr==0x0A)
245 // ser_WriteByte(0x2F8, 0x0D, 1, 0, 0);
246 #if AROS_SERIAL_DEBUG == 1
247 ser_WriteByte(0x3F8, chr, 0, 0, 0);
248 #endif
249 #if AROS_SERIAL_DEBUG == 2
250 ser_WriteByte(0x2F8, chr, 0, 0, 0);
251 #endif
254 __restore_flags(flags);
256 /* Enable(); */
258 AROS_LIBFUNC_EXIT
259 } /* RawPutChar */
261 int ser_IsWritingPossible(short port) {
263 return inb_p(port+SER_LINE_STATUS) & SER_LSR_TSREMPTY;
266 int ser_WriteByte(short port, UBYTE data, ULONG timeout, BYTE sigmask, BYTE sigvals) {
268 if (timeout)
270 while (!ser_IsWritingPossible(port) && timeout)
271 timeout--;
272 if (!timeout)
273 return 1;
275 else
276 while (!ser_IsWritingPossible(port));
278 if ((inb_p(port+SER_MODEM_STATUS) & sigmask) == sigvals)
280 outb_p(data, port+SER_TXBUFFER);
281 return inb_p(port+SER_LINE_STATUS) & SER_LSR_ERRORMSK;
283 else
284 return SER_ERRSIGNALS;