source: bootcd/isolinux/syslinux-6.03/core/serirq.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 4.4 KB
RevLine 
[e16e8f2]1/*
2 * -----------------------------------------------------------------------
3 *
4 *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
5 *
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.
11 *
12 * -----------------------------------------------------------------------
13 *
14 * serirq.c
15 *
16 * Serial port IRQ code
17 *
18 * We don't know what IRQ, if any, we have, so map all of them...
19 */
20#include <sys/io.h>
21#include <string.h>
22
23#include <fs.h>
24#include "bios.h"
25
26static char serial_buf[serial_buf_size];
27
28static unsigned short SerialIRQPort; /* Serial port w IRQ service */
29char *SerialHead = serial_buf;    /* Head of serial port rx buffer */
30char *SerialTail = serial_buf;    /* Tail of serial port rx buffer */
31
32static unsigned char IRQMask[2];             /* PIC IRQ mask status */
33
34static unsigned int oldirq[16];
35
36typedef void (*irqhandler_t)(void);
37
38void sirq_cleanup(void);
39
40static void irq_common(unsigned short old_irq)
41{
42        char *dst;
43        irqhandler_t next;
44        char val;
45
46        dst = SerialHead;
47        next = (irqhandler_t)oldirq[old_irq];
48
49        /* LSR */
50        val = inb(SerialPort + 5);
51
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));
61
62                        /* Would this cause overflow? */
63                        if (dst != SerialTail)
64                                SerialHead = dst;
65                }
66        }
67
68        /* Chain to next handler */
69        next();
70}
71
72#define SERIAL_IRQ_HANDLER(n) \
73        static void serstub_irq##n(void)        \
74        {                                       \
75                irq_common(n);                  \
76        }
77
78SERIAL_IRQ_HANDLER(0);
79SERIAL_IRQ_HANDLER(1);
80SERIAL_IRQ_HANDLER(2);
81SERIAL_IRQ_HANDLER(3);
82SERIAL_IRQ_HANDLER(4);
83SERIAL_IRQ_HANDLER(5);
84SERIAL_IRQ_HANDLER(6);
85SERIAL_IRQ_HANDLER(7);
86SERIAL_IRQ_HANDLER(8);
87SERIAL_IRQ_HANDLER(9);
88SERIAL_IRQ_HANDLER(10);
89SERIAL_IRQ_HANDLER(11);
90SERIAL_IRQ_HANDLER(12);
91SERIAL_IRQ_HANDLER(13);
92SERIAL_IRQ_HANDLER(14);
93SERIAL_IRQ_HANDLER(15);
94
95static inline void save_irq_vectors(uint32_t *src, uint32_t *dst)
96{
97        int i;
98
99        for (i = 0; i < 8; i++)
100                *dst++ = *src++;
101}
102
103static inline void install_irq_vectors(uint32_t *dst, int first)
104{
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;
123        }
124}
125
126__export void sirq_install(void)
127{
128        char val, val2;
129
130        sirq_cleanup();
131
132        save_irq_vectors((uint32_t *)(4 * 0x8), oldirq);
133        save_irq_vectors((uint32_t *)(4 * 0x70), &oldirq[8]);
134
135        install_irq_vectors((uint32_t *)(4 * 0x8), 1);
136        install_irq_vectors((uint32_t *)(4 * 0x70), 0);
137
138        SerialIRQPort = SerialPort;
139
140        /* Clear DLAB (should already be...) */
141        outb(0x3, SerialIRQPort + 5);
142        io_delay();
143
144        /* Enable receive interrupt */
145        outb(0x1, SerialIRQPort + 1);
146        io_delay();
147
148        /*
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.
152         */
153
154        /* Secondary PIC mask register */
155        val = inb(0xA1);
156        val2 = inb(0x21);
157        IRQMask[0] = val;
158        IRQMask[1] = val2;
159
160        io_delay();
161
162        /* Remove all interrupt masks */
163        outb(0x21, 0);
164        outb(0xA1, 0);
165}
166
167__export void sirq_cleanup_nowipe(void)
168{
169        uint32_t *dst;
170        int i;
171
172        if (!SerialIRQPort)
173                return;
174
175        /* Clear DLAB */
176        outb(0x3, SerialIRQPort + 5);
177        io_delay();
178
179        /* Clear IER */
180        outb(0x0, SerialIRQPort + 1);
181        io_delay();
182
183        /* Restore PIC masks */
184        outb(IRQMask[0], 0x21);
185        outb(IRQMask[1], 0xA1);
186
187        /* Restore the original interrupt vectors */
188        dst = (uint32_t *)(4 * 0x8);
189        for (i = 0; i < 8; i++)
190                *dst++ = oldirq[i];
191
192        dst = (uint32_t *)(4 * 0x70);
193        for (i = 8; i < 16; i++)
194                *dst++ = oldirq[i];
195
196        /* No active interrupt system */
197        SerialIRQPort = 0;
198}
199
200void sirq_cleanup(void)
201{
202        sirq_cleanup_nowipe();
203        memcpy(SerialHead, 0x0, serial_buf_size);
204}
Note: See TracBrowser for help on using the repository browser.