2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
5 Desc: functions for serial RawIOInit/RawPutChar
8 Note: serial io from "PC-intern" examples
10 #include <proto/exec.h>
14 #undef __restore_flags
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
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;
64 #if AROS_SERIAL_DEBUG == 2
65 UWORD __serial_rawio_port
= 0x2F8;
67 UWORD __serial_rawio_port
= 0;
71 int ser_UARTType (short);
72 void ser_FIFOLevel(short, BYTE
);
73 int ser_Init(short, LONG
, BYTE
);
75 /*****i***********************************************************************
78 AROS_LH0(void, SerialRawIOInit
,
81 struct ExecBase
*, SysBase
, 84, Exec
)
84 This is a private function. It initializes raw IO. After you
85 have called this function, you can use (!RawMayGetChar()) and
95 This function is for very low level debugging only.
102 RawPutChar(), RawMayGetChar()
108 *****************************************************************************/
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);
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)
126 outb_p(0x55, port
+SER_DIVISOR_MSB
); /* write Divisor */
127 if (inb_p(port
+SER_DIVISOR_MSB
) != 0x55)
129 outb_p(0x55, port
+SER_LINE_CONTROL
); /* clear Divisor-Latch */
130 if (inb_p(port
+SER_LINE_CONTROL
) != 0x55)
132 outb_p(0x55, port
+SER_IRQ_ENABLE
);
133 if (inb_p(port
+SER_IRQ_ENABLE
) != 0x05)
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)
139 outb_p(0xF5, port
+SER_MODEM_CONTROL
);
140 if (inb_p(port
+SER_MODEM_CONTROL
) != 0x15)
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)
146 outb_p(0x1F, port
+SER_MODEM_CONTROL
);
147 if ((inb_p(port
+SER_MODEM_STATUS
) & 0xF0) != 0xF0)
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)
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)
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
) {
176 outb_p(level
| SER_FIFO_ENABLE
, port
+SER_FIFO
);
178 outb_p(SER_FIFO_RESETRECEIVE
| SER_FIFO_RESETTRANSMIT
, port
+SER_FIFO
);
181 int ser_Init(short port
, LONG baudRate
, BYTE params
) {
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
);
199 int ser_WriteByte(short, UBYTE
, ULONG
, BYTE
, BYTE
);
200 int ser_IsWritingPossible(short);
203 AROS_LH1(void, SerialRawPutChar
,
206 AROS_LHA(UBYTE
, chr
, D0
),
209 struct ExecBase
*, SysBase
, 86, Exec
)
212 Emits a single character.
215 chr - The character to emit
221 This function is for very low level debugging only.
228 RawIOInit(), RawPutChar(), RawMayGetChar()
234 *****************************************************************************/
240 if ((__serial_rawio_port
> 0) && (chr
))
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 */
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
259 __restore_flags(flags
);
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
) {
274 while (!ser_IsWritingPossible(port
) && timeout
)
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
;
288 return SER_ERRSIGNALS
;