core, pxe: Don't push on one stack and pop from the other in pxenv
[syslinux.git] / core / serirq.c
blobe230b98de63ff0cfc0e04359ffbd21081234280a
1 /*
2 * -----------------------------------------------------------------------
4 * Copyright 2009 Intel Corporation; author: H. Peter Anvin
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 * Boston MA 02111-1307, USA; either version 2 of the License, or
10 * (at your option) any later version; incorporated herein by reference.
12 * -----------------------------------------------------------------------
14 * serirq.c
16 * Serial port IRQ code
18 * We don't know what IRQ, if any, we have, so map all of them...
20 #include <sys/io.h>
21 #include <string.h>
23 #include <fs.h>
24 #include "bios.h"
26 static char serial_buf[serial_buf_size];
28 static unsigned short SerialIRQPort; /* Serial port w IRQ service */
29 char *SerialHead = serial_buf; /* Head of serial port rx buffer */
30 char *SerialTail = serial_buf; /* Tail of serial port rx buffer */
32 static unsigned char IRQMask[2]; /* PIC IRQ mask status */
34 static unsigned int oldirq[16];
36 typedef void (*irqhandler_t)(void);
38 void sirq_cleanup(void);
40 static void irq_common(unsigned short old_irq)
42 char *dst;
43 irqhandler_t next;
44 char val;
46 dst = SerialHead;
47 next = (irqhandler_t)oldirq[old_irq];
49 /* LSR */
50 val = inb(SerialPort + 5);
52 /* Received data */
53 while (val & 1) {
54 /* RDR */
55 *dst++ = inb(SerialPort);
56 /* LSR */
57 val = inb(SerialPort + 5);
58 if ((val & FlowIgnore) == FlowIgnore) {
59 /* Wrap around if necessary */
60 dst = (char *)((unsigned long)dst & (serial_buf_size - 1));
62 /* Would this cause overflow? */
63 if (dst != SerialTail)
64 SerialHead = dst;
68 /* Chain to next handler */
69 next();
72 #define SERIAL_IRQ_HANDLER(n) \
73 static void serstub_irq##n(void) \
74 { \
75 irq_common(n); \
78 SERIAL_IRQ_HANDLER(0);
79 SERIAL_IRQ_HANDLER(1);
80 SERIAL_IRQ_HANDLER(2);
81 SERIAL_IRQ_HANDLER(3);
82 SERIAL_IRQ_HANDLER(4);
83 SERIAL_IRQ_HANDLER(5);
84 SERIAL_IRQ_HANDLER(6);
85 SERIAL_IRQ_HANDLER(7);
86 SERIAL_IRQ_HANDLER(8);
87 SERIAL_IRQ_HANDLER(9);
88 SERIAL_IRQ_HANDLER(10);
89 SERIAL_IRQ_HANDLER(11);
90 SERIAL_IRQ_HANDLER(12);
91 SERIAL_IRQ_HANDLER(13);
92 SERIAL_IRQ_HANDLER(14);
93 SERIAL_IRQ_HANDLER(15);
95 static inline void save_irq_vectors(uint32_t *src, uint32_t *dst)
97 int i;
99 for (i = 0; i < 8; i++)
100 *dst++ = *src++;
103 static inline void install_irq_vectors(uint32_t *dst, int first)
105 if (first) {
106 *dst++ = (uint32_t)serstub_irq0;
107 *dst++ = (uint32_t)serstub_irq1;
108 *dst++ = (uint32_t)serstub_irq2;
109 *dst++ = (uint32_t)serstub_irq3;
110 *dst++ = (uint32_t)serstub_irq4;
111 *dst++ = (uint32_t)serstub_irq5;
112 *dst++ = (uint32_t)serstub_irq6;
113 *dst++ = (uint32_t)serstub_irq7;
114 } else {
115 *dst++ = (uint32_t)serstub_irq8;
116 *dst++ = (uint32_t)serstub_irq9;
117 *dst++ = (uint32_t)serstub_irq10;
118 *dst++ = (uint32_t)serstub_irq11;
119 *dst++ = (uint32_t)serstub_irq12;
120 *dst++ = (uint32_t)serstub_irq13;
121 *dst++ = (uint32_t)serstub_irq14;
122 *dst++ = (uint32_t)serstub_irq15;
126 __export void sirq_install(void)
128 char val, val2;
130 sirq_cleanup();
132 save_irq_vectors((uint32_t *)(4 * 0x8), oldirq);
133 save_irq_vectors((uint32_t *)(4 * 0x70), &oldirq[8]);
135 install_irq_vectors((uint32_t *)(4 * 0x8), 1);
136 install_irq_vectors((uint32_t *)(4 * 0x70), 0);
138 SerialIRQPort = SerialPort;
140 /* Clear DLAB (should already be...) */
141 outb(0x3, SerialIRQPort + 5);
142 io_delay();
144 /* Enable receive interrupt */
145 outb(0x1, SerialIRQPort + 1);
146 io_delay();
149 * Enable all the interrupt lines at the PIC. Some BIOSes only
150 * enable the timer interrupts and other interrupts actively
151 * in use by the BIOS.
154 /* Secondary PIC mask register */
155 val = inb(0xA1);
156 val2 = inb(0x21);
157 IRQMask[0] = val;
158 IRQMask[1] = val2;
160 io_delay();
162 /* Remove all interrupt masks */
163 outb(0x21, 0);
164 outb(0xA1, 0);
167 __export void sirq_cleanup_nowipe(void)
169 uint32_t *dst;
170 int i;
172 if (!SerialIRQPort)
173 return;
175 /* Clear DLAB */
176 outb(0x3, SerialIRQPort + 5);
177 io_delay();
179 /* Clear IER */
180 outb(0x0, SerialIRQPort + 1);
181 io_delay();
183 /* Restore PIC masks */
184 outb(IRQMask[0], 0x21);
185 outb(IRQMask[1], 0xA1);
187 /* Restore the original interrupt vectors */
188 dst = (uint32_t *)(4 * 0x8);
189 for (i = 0; i < 8; i++)
190 *dst++ = oldirq[i];
192 dst = (uint32_t *)(4 * 0x70);
193 for (i = 8; i < 16; i++)
194 *dst++ = oldirq[i];
196 /* No active interrupt system */
197 SerialIRQPort = 0;
200 void sirq_cleanup(void)
202 sirq_cleanup_nowipe();
203 memcpy(SerialHead, 0x0, serial_buf_size);