]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/drivers/uart-16550.cpp
86e85bca62247335af4fb3c374d2440e84f14dbd
[l4.git] / kernel / fiasco / src / drivers / uart-16550.cpp
1 INTERFACE [16550-{ia32,amd64}]:
2
3 EXTENSION class Uart
4 {
5 public:
6   enum {
7     Base_rate     = 115200,
8     Base_ier_bits = 0,
9
10     Access_shift  = 0,
11   };
12 };
13
14
15 INTERFACE[16550]:
16
17 #include "types.h"
18
19 /**
20  * 16550 implementation of the UART interface.
21  */
22 EXTENSION class Uart
23 {
24 public:
25
26   /**
27    * Start this serial port for I/O.
28    * @param port the I/O port base address.
29    * @param irq the IRQ assigned to this port, -1 if none.
30    */
31   bool startup(Address port, int irq);
32
33   enum {
34     PAR_NONE = 0x00,
35     PAR_EVEN = 0x18,
36     PAR_ODD  = 0x08,
37     DAT_5    = 0x00,
38     DAT_6    = 0x01,
39     DAT_7    = 0x02,
40     DAT_8    = 0x03,
41     STOP_1   = 0x00,
42     STOP_2   = 0x04,
43
44     MODE_8N1 = PAR_NONE | DAT_8 | STOP_1,
45     MODE_7E1 = PAR_EVEN | DAT_7 | STOP_1,
46
47   // these two values are to leave either mode
48   // or baud rate unchanged on a call to change_mode
49     MODE_NC  = 0x1000000,
50     BAUD_NC  = 0x1000000,
51   };
52
53 private:
54
55   enum Registers {
56     TRB      = 0, // Transmit/Receive Buffer  (read/write)
57     BRD_LOW  = 0, // Baud Rate Divisor LSB if bit 7 of LCR is set  (read/write)
58     IER      = 1, // Interrupt Enable Register  (read/write)
59     BRD_HIGH = 1, // Baud Rate Divisor MSB if bit 7 of LCR is set  (read/write)
60     IIR      = 2, // Interrupt Identification Register  (read only)
61     FCR      = 2, // 16550 FIFO Control Register  (write only)
62     LCR      = 3, // Line Control Register  (read/write)
63     MCR      = 4, // Modem Control Register  (read/write)
64     LSR      = 5, // Line Status Register  (read only)
65     MSR      = 6, // Modem Status Register  (read only)
66     SPR      = 7, // Scratch Pad Register  (read/write)
67   };
68
69   Address port;
70   int _irq;
71 };
72
73
74 IMPLEMENTATION[16550]:
75
76 #include "io.h"
77 #include "processor.h"
78
79
80 IMPLEMENT
81 Uart::Uart() : port(~0U), _irq(-1)
82 {}
83
84 IMPLEMENT
85 Uart::~Uart()
86 {}
87
88
89 PRIVATE inline NEEDS["io.h"]
90 void Uart::outb( Unsigned8 b, Registers reg )
91 {
92   Io::out8(b, port + (reg << Access_shift));
93 }
94
95 PRIVATE inline NEEDS["io.h"]
96 Unsigned8 Uart::inb( Registers reg ) const
97 {
98   return Io::in8(port + (reg << Access_shift));
99 }
100
101
102 PRIVATE inline NEEDS[Uart::outb]
103 void Uart::mcr(Unsigned8 b)
104 {
105   outb(b, MCR);
106 }
107
108 PRIVATE inline NEEDS[Uart::inb]
109 Unsigned8 Uart::mcr() const
110 {
111   return inb(MCR);
112 }
113
114 PRIVATE inline NEEDS[Uart::outb]
115 void Uart::fcr(Unsigned8 b)
116 {
117   outb(b, FCR);
118 }
119
120 PRIVATE inline NEEDS[Uart::outb]
121 void Uart::lcr(Unsigned8 b)
122 {
123   outb(b, LCR);
124 }
125
126 PRIVATE inline NEEDS[Uart::inb]
127 Unsigned8 Uart::lcr() const
128 {
129   return inb(LCR);
130 }
131
132 PRIVATE inline NEEDS[Uart::outb]
133 void Uart::ier(Unsigned8 b)
134 {
135   outb(b, IER);
136 }
137
138 PRIVATE inline NEEDS[Uart::inb]
139 Unsigned8 Uart::ier() const
140 {
141   return inb(IER);
142 }
143
144 PRIVATE inline NEEDS[Uart::inb]
145 Unsigned8 Uart::iir() const
146 {
147   return inb(IIR);
148 }
149
150 PRIVATE inline NEEDS[Uart::inb]
151 Unsigned8 Uart::msr() const
152 {
153   return inb(MSR);
154 }
155
156 PRIVATE inline NEEDS[Uart::inb]
157 Unsigned8 Uart::lsr() const
158 {
159   return inb(LSR);
160 }
161
162 PRIVATE inline NEEDS[Uart::outb]
163 void Uart::trb(Unsigned8 b)
164 {
165   outb(b, TRB);
166 }
167
168 PRIVATE inline NEEDS[Uart::inb]
169 Unsigned8 Uart::trb() const
170 {
171   return inb(TRB);
172 }
173
174 PRIVATE
175 bool Uart::valid()
176 {
177   Unsigned8 scratch, scratch2, scratch3;
178
179   scratch = ier();
180   ier(0x00);
181
182   Io::iodelay();
183
184   scratch2 = ier();
185   ier(0x0f);
186   Io::iodelay();
187
188   scratch3 = ier();
189   ier(scratch);
190
191   return (scratch2 == 0x00 && scratch3 == 0x0f);
192 }
193
194 IMPLEMENT
195 bool Uart::startup(Address _port, int __irq)
196 {
197   port = _port;
198   _irq  = __irq;
199
200   Proc::Status o = Proc::cli_save();
201
202   if (!valid())
203     {
204       Proc::sti_restore(o);
205       fail();
206       return false;
207     }
208
209   ier(Base_ier_bits);/* disable all rs-232 interrupts */
210   mcr(0x0b);         /* out2, rts, and dtr enabled */
211   fcr(1);            /* enable fifo */
212   fcr(0x07);         /* clear rcv xmit fifo */
213   fcr(1);            /* enable fifo */
214   lcr(0);            /* clear line control register */
215
216   /* clearall interrupts */
217   /*read*/ msr(); /* IRQID 0*/
218   /*read*/ iir(); /* IRQID 1*/
219   /*read*/ trb(); /* IRQID 2*/
220   /*read*/ lsr(); /* IRQID 3*/
221
222   while(lsr() & 1/*DATA READY*/) /*read*/ trb();
223   Proc::sti_restore(o);
224   return true;
225 }
226
227
228 IMPLEMENT
229 void Uart::shutdown()
230 {
231   Proc::Status o = Proc::cli_save();
232   mcr(0x06);
233   fcr(0);
234   lcr(0);
235   ier(0);
236   Proc::sti_restore(o);
237 }
238
239 IMPLEMENT
240 bool Uart::change_mode(TransferMode m, BaudRate r)
241 {
242   Proc::Status o = Proc::cli_save();
243   Unsigned8 old_lcr = lcr();
244   if(r != BAUD_NC) {
245     lcr(old_lcr | 0x80/*DLAB*/);
246     Unsigned16 divisor = Base_rate/r;
247     trb( divisor & 0x0ff );        /* BRD_LOW  */
248     ier( (divisor >> 8) & 0x0ff ); /* BRD_HIGH */
249     lcr(old_lcr);
250   }
251   if( m != MODE_NC ) {
252     lcr( m & 0x07f );
253   }
254
255   Proc::sti_restore(o);
256   return true;
257 }
258
259 IMPLEMENT
260 Uart::TransferMode Uart::get_mode()
261 {
262   return lcr() & 0x7f;
263 }
264
265 IMPLEMENT
266 int Uart::write(char const *s, size_t count)
267 {
268   /* disable uart irqs */
269   Unsigned8 old_ier;
270   old_ier = ier();
271   ier(old_ier & ~0x0f);
272
273   /* transmission */
274   for (unsigned i = 0; i < count; i++)
275     {
276       while (!(lsr() & 0x20 /* THRE */))
277         ;
278       trb(s[i]);
279     }
280
281   /* wait till everything is transmitted */
282   while (!(lsr() & 0x40 /* TSRE */))
283     ;
284
285   ier(old_ier);
286   return count;
287 }
288
289 IMPLEMENT
290 int Uart::getchar(bool blocking)
291 {
292   if (!blocking && !(lsr() & 1 /* DATA READY */))
293     return -1;
294
295   Unsigned8 old_ier, ch;
296   old_ier = ier();
297   ier(old_ier & ~0x0f);
298   while (!(lsr() & 1 /* DATA READY */))
299     ;
300   ch = trb();
301   ier(old_ier);
302   return ch;
303 }
304
305 IMPLEMENT
306 int Uart::char_avail() const
307 {
308   if (lsr() & 1 /* DATA READY */)
309     return 1;
310
311   return 0;
312 }
313
314
315 IMPLEMENT inline
316 int Uart::irq() const
317 {
318   return _irq;
319 }
320
321 IMPLEMENT inline NEEDS[Uart::ier]
322 void Uart::disable_rcv_irq()
323 {
324   ier(ier() & ~1);
325 }
326
327
328 // ------------------------------------------------------------------------
329 IMPLEMENTATION [16550-{ia32,amd64}]:
330
331 IMPLEMENT inline NEEDS[Uart::ier]
332 void Uart::enable_rcv_irq()
333 {
334   ier(ier() | 1);
335 }