1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
#include <asm-i386/io.h>
#include <xeno/sched.h> /* this has request_irq() proto for some reason */
#include <xeno/keyhandler.h>
#include <xeno/reboot.h>
#include <xeno/irq.h>
/* Register offsets */
#define NS16550_RBR 0x00 /* receive buffer */
#define NS16550_THR 0x00 /* transmit holding */
#define NS16550_IER 0x01 /* interrupt enable */
#define NS16550_IIR 0x02 /* interrupt identity */
#define NS16550_FCR 0x02 /* FIFO control */
#define NS16550_LCR 0x03 /* line control */
#define NS16550_MCR 0x04 /* MODEM control */
#define NS16550_LSR 0x05 /* line status */
#define NS16550_MSR 0x06 /* MODEM status */
#define NS16550_SCR 0x07 /* scratch */
#define NS16550_DDL 0x00 /* divisor latch (ls) ( DLAB=1) */
#define NS16550_DLM 0x01 /* divisor latch (ms) ( DLAB=1) */
/* Interrupt enable register */
#define NS16550_IER_ERDAI 0x01 /* rx data recv'd */
#define NS16550_IER_ETHREI 0x02 /* tx reg. empty */
#define NS16550_IER_ELSI 0x04 /* rx line status */
#define NS16550_IER_EMSI 0x08 /* MODEM status */
/* FIFO control register */
#define NS16550_FCR_ENABLE 0x01 /* enable FIFO */
#define NS16550_FCR_CLRX 0x02 /* clear Rx FIFO */
#define NS16550_FCR_CLTX 0x04 /* clear Tx FIFO */
#define NS16550_FCR_DMA 0x10 /* enter DMA mode */
#define NS16550_FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */
#define NS16550_FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */
#define NS16550_FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
#define NS16550_FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
/* MODEM control register */
#define NS16550_MCR_DTR 0x01 /* Data Terminal Ready */
#define NS16550_MCR_RTS 0x02 /* Request to Send */
#define NS16550_MCR_OUT1 0x04 /* OUT1: unused */
#define NS16550_MCR_OUT2 0x08 /* OUT2: interrupt mask */
#define NS16550_MCR_LOOP 0x10 /* Loop */
#define SERIAL_BASE 0x3f8 /* XXX SMH: horrible hardwired COM1 */
static int serial_echo = 0; /* default is not to echo; change with 'e' */
void toggle_echo(u_char key, void *dev_id, struct pt_regs *regs)
{
serial_echo = !serial_echo;
}
static void serial_rx_int(int irq, void *dev_id, struct pt_regs *regs)
{
u_char c;
key_handler *handler;
/* clear the interrupt by reading the character */
c = inb(SERIAL_BASE + NS16550_RBR);
/* if there's a handler, call it: we trust it won't screw us too badly */
if((handler = get_key_handler(c)) != NULL)
(*handler)(c, dev_id, regs);
if(serial_echo)
printk("%c", c);
}
void initialize_serial()
{
int fifo, rc;
/* setup key handler */
add_key_handler('~', toggle_echo, "toggle serial echo");
/* Should detect this, but must be a ns16550a at least, surely? */
fifo = 1;
if(fifo) {
/* Clear FIFOs, enable, trigger at 1 byte */
outb(NS16550_FCR_TRG1 | NS16550_FCR_ENABLE |
NS16550_FCR_CLRX | NS16550_FCR_CLTX, SERIAL_BASE+NS16550_FCR);
}
outb(NS16550_MCR_OUT2, SERIAL_BASE + NS16550_MCR); /* Modem control */
outb(NS16550_IER_ERDAI, SERIAL_BASE + NS16550_IER ); /* Setup interrupts */
if((rc = request_irq(4, serial_rx_int, 0, "serial", 0)))
printk("initialize_serial: failed to get IRQ4, rc=%d\n", rc);
}
|