]>
Commit | Line | Data |
---|---|---|
55e303ae A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
e5568f75 A |
6 | * The contents of this file constitute Original Code as defined in and |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
55e303ae | 11 | * |
e5568f75 A |
12 | * This Original Code and all software distributed under the License are |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
55e303ae A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
e5568f75 A |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
55e303ae A |
19 | * |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | ||
23 | /* | |
24 | * file: pe_serial.c | |
25 | * Polled-mode 16x50 UART driver. | |
26 | */ | |
27 | ||
28 | #include <pexpert/protos.h> | |
29 | #include <pexpert/pexpert.h> | |
30 | ||
31 | /* standard port addresses */ | |
32 | enum { | |
33 | COM1_PORT_ADDR = 0x3f8, | |
34 | COM2_PORT_ADDR = 0x2f8 | |
35 | }; | |
36 | ||
37 | /* UART register offsets */ | |
38 | enum { | |
39 | UART_RBR = 0, /* receive buffer Register (R) */ | |
40 | UART_THR = 0, /* transmit holding register (W) */ | |
41 | UART_DLL = 0, /* DLAB = 1, divisor latch (LSB) */ | |
42 | UART_IER = 1, /* interrupt enable register */ | |
43 | UART_DLM = 1, /* DLAB = 1, divisor latch (MSB) */ | |
44 | UART_IIR = 2, /* interrupt ident register (R) */ | |
45 | UART_FCR = 2, /* fifo control register (W) */ | |
46 | UART_LCR = 3, /* line control register */ | |
47 | UART_MCR = 4, /* modem control register */ | |
48 | UART_LSR = 5, /* line status register */ | |
49 | UART_MSR = 6 /* modem status register */ | |
50 | }; | |
51 | ||
52 | enum { | |
53 | UART_LCR_8BITS = 0x03, | |
54 | UART_LCR_DLAB = 0x80 | |
55 | }; | |
56 | ||
57 | enum { | |
58 | UART_MCR_DTR = 0x01, | |
59 | UART_MCR_RTS = 0x02, | |
60 | UART_MCR_OUT1 = 0x04, | |
61 | UART_MCR_OUT2 = 0x08, | |
62 | UART_MCR_LOOP = 0x10 | |
63 | }; | |
64 | ||
65 | enum { | |
66 | UART_LSR_THRE = 0x20 | |
67 | }; | |
68 | ||
69 | #define UART_BAUD_RATE 115200 | |
70 | #define UART_PORT_ADDR COM1_PORT_ADDR | |
71 | ||
72 | #define WRITE(r, v) outb(UART_PORT_ADDR + UART_##r, v) | |
73 | #define READ(r) inb(UART_PORT_ADDR + UART_##r) | |
74 | #define DELAY(x) { volatile int _d_; for (_d_ = 0; _d_ < (10000*x); _d_++) ; } | |
75 | ||
76 | static int uart_initted = 0; /* 1 if init'ed */ | |
77 | ||
78 | static int | |
79 | uart_probe( void ) | |
80 | { | |
81 | /* Verify that the Divisor Register is accessible */ | |
82 | ||
83 | WRITE( LCR, UART_LCR_DLAB ); | |
84 | WRITE( DLL, 0x5a ); | |
85 | if (READ(DLL) != 0x5a) return 0; | |
86 | WRITE( DLL, 0xa5 ); | |
87 | if (READ(DLL) != 0xa5) return 0; | |
88 | WRITE( LCR, 0x00 ); | |
89 | return 1; | |
90 | } | |
91 | ||
92 | static void | |
93 | uart_set_baud_rate( unsigned long baud_rate ) | |
94 | { | |
95 | #define UART_CLOCK 1843200 /* 1.8432 MHz clock */ | |
96 | ||
97 | const unsigned char lcr = READ( LCR ); | |
98 | unsigned long div; | |
99 | ||
100 | if (baud_rate == 0) baud_rate = 9600; | |
101 | div = UART_CLOCK / 16 / baud_rate; | |
102 | WRITE( LCR, lcr | UART_LCR_DLAB ); | |
103 | WRITE( DLM, (unsigned char)(div >> 8) ); | |
104 | WRITE( DLL, (unsigned char) div ); | |
105 | WRITE( LCR, lcr & ~UART_LCR_DLAB); | |
106 | } | |
107 | ||
108 | static void | |
109 | uart_putc( char c ) | |
110 | { | |
111 | if (!uart_initted) return; | |
112 | ||
113 | /* Wait for THR empty */ | |
114 | while ( !(READ(LSR) & UART_LSR_THRE) ) DELAY(1); | |
115 | ||
116 | WRITE( THR, c ); | |
117 | } | |
118 | ||
119 | int serial_init( void ) | |
120 | { | |
121 | if ( uart_initted || uart_probe() == 0 ) return 0; | |
122 | ||
123 | /* Disable hardware interrupts */ | |
124 | ||
125 | WRITE( MCR, 0 ); | |
126 | WRITE( IER, 0 ); | |
127 | ||
128 | /* Disable FIFO's for 16550 devices */ | |
129 | ||
130 | WRITE( FCR, 0 ); | |
131 | ||
132 | /* Set for 8-bit, no parity, DLAB bit cleared */ | |
133 | ||
134 | WRITE( LCR, UART_LCR_8BITS ); | |
135 | ||
136 | /* Set baud rate */ | |
137 | ||
138 | uart_set_baud_rate( UART_BAUD_RATE ); | |
139 | ||
140 | /* Assert DTR# and RTS# lines (OUT2?) */ | |
141 | ||
142 | WRITE( MCR, UART_MCR_DTR | UART_MCR_RTS ); | |
143 | ||
144 | /* Clear any garbage in the input buffer */ | |
145 | ||
146 | READ( RBR ); | |
147 | ||
148 | uart_initted = 1; | |
149 | ||
150 | return 1; | |
151 | } | |
152 | ||
153 | void serial_putc( char c ) | |
154 | { | |
155 | uart_putc(c); | |
156 | if (c == '\n') uart_putc('\r'); | |
157 | } | |
158 | ||
159 | int serial_getc( void ) | |
160 | { | |
161 | return 0; /* not supported */ | |
162 | } |