source: bootcd/isolinux/syslinux-6.03/com32/libupload/serial.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: 3.7 KB
Line 
1#include <stdbool.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <console.h>
5#include <sys/io.h>
6#include <sys/cpu.h>
7#include <syslinux/config.h>
8
9#include "serial.h"
10
11enum {
12    THR = 0,
13    RBR = 0,
14    DLL = 0,
15    DLM = 1,
16    IER = 1,
17    IIR = 2,
18    FCR = 2,
19    LCR = 3,
20    MCR = 4,
21    LSR = 5,
22    MSR = 6,
23    SCR = 7,
24};
25
26
27int serial_init(struct serial_if *sif, const char *argv[])
28{
29    const struct syslinux_serial_console_info *sci
30        = syslinux_serial_console_info();
31    uint16_t port;
32    unsigned int divisor;
33    uint8_t dll, dlm, lcr;
34
35    if (!argv[0]) {
36        if (sci->iobase) {
37            port = sci->iobase;
38        } else {
39            printf("No port number specified and not using serial console!\n");
40            return -1;
41        }
42    } else {
43        port = strtoul(argv[0], NULL, 0);
44        if (port <= 3) {
45            uint16_t addr = ((uint16_t *)0x400)[port];
46            if (!addr) {
47                printf("No serial port address found!\n");
48            return -1;
49            }
50            printf("Serial port %u is at 0x%04x\n", port, addr);
51            port = addr;
52        }
53    }
54
55    sif->port = port;
56    sif->console = false;
57
58    divisor = 1;                /* Default speed = 115200 bps */
59
60    /* Check to see if this is the same as the serial console */
61    if (port == sci->iobase) {
62        /* Overlaying the console... */
63        sif->console = true;
64
65        /* Default to already configured speed */
66        divisor = sci->divisor;
67
68        /* Shut down I/O to the console for the time being */
69        openconsole(&dev_null_r, &dev_null_w);
70    }
71
72    if (argv[0] && argv[1])
73        divisor = 115200/strtoul(argv[1], NULL, 0);
74
75    cli();                      /* Just in case... */
76
77    /* Save old register settings */
78    sif->old.lcr = inb(port + LCR);
79    sif->old.mcr = inb(port + MCR);
80    sif->old.iir = inb(port + IIR);
81
82    /* Set speed */
83    outb(0x83, port + LCR);     /* Enable divisor access */
84    sif->old.dll = inb(port + DLL);
85    sif->old.dlm = inb(port + DLM);
86    outb(divisor, port + DLL);
87    outb(divisor >> 8, port + DLM);
88    (void)inb(port + IER);      /* Synchronize */
89
90    dll = inb(port + DLL);
91    dlm = inb(port + DLM);
92    lcr = inb(port + LCR);
93    outb(0x03, port + LCR);     /* Enable data access, n81 */
94    (void)inb(port + IER);      /* Synchronize */
95    sif->old.ier = inb(port + IER);
96
97    /* Disable interrupts */
98    outb(0, port + IER);
99
100    sti();
101
102    if (dll != (uint8_t)divisor ||
103        dlm != (uint8_t)(divisor >> 8) ||
104        lcr != 0x83) {
105        serial_cleanup(sif);
106        printf("No serial port detected!\n");
107        return -1;              /* This doesn't look like a serial port */
108    }
109
110    /* Enable 16550A FIFOs if available */
111    outb(0x01, port + FCR);     /* Enable FIFO */
112    (void)inb(port + IER);      /* Synchronize */
113    if (inb(port + IIR) < 0xc0)
114        outb(0x00, port + FCR); /* Disable FIFOs if non-functional */
115    (void)inb(port + IER);      /* Synchronize */
116
117    return 0;
118}
119
120void serial_write(struct serial_if *sif, const void *data, size_t n)
121{
122    uint16_t port = sif->port;
123    const char *p = data;
124    uint8_t lsr;
125
126    while (n--) {
127        do {
128            lsr = inb(port + LSR);
129        } while (!(lsr & 0x20));
130
131        outb(*p++, port + THR);
132    }
133}
134
135void serial_read(struct serial_if *sif, void *data, size_t n)
136{
137    uint16_t port = sif->port;
138    char *p = data;
139    uint8_t lsr;
140
141    while (n--) {
142        do {
143            lsr = inb(port + LSR);
144        } while (!(lsr & 0x01));
145
146        *p++ = inb(port + RBR);
147    }
148}
149
150void serial_cleanup(struct serial_if *sif)
151{
152    uint16_t port = sif->port;
153
154    outb(0x83, port + LCR);
155    (void)inb(port + IER);
156    outb(sif->old.dll, port + DLL);
157    outb(sif->old.dlm, port + DLM);
158    (void)inb(port + IER);
159    outb(sif->old.lcr & 0x7f, port + LCR);
160    (void)inb(port + IER);
161    outb(sif->old.mcr, port + MCR);
162    outb(sif->old.ier, port + IER);
163    if (sif->old.iir < 0xc0)
164        outb(0x00, port + FCR); /* Disable FIFOs */
165
166    /* Re-enable console messages, if we shut them down */
167    if (sif->console)
168        openconsole(&dev_null_r, &dev_stdcon_w);
169}
Note: See TracBrowser for help on using the repository browser.