MOS Source Code
Loading...
Searching...
No Matches
serial.c
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/device/serial.h"
4
5#include <mos/mos_global.h>
6#include <mos/syslog/printk.h>
7
8typedef enum
9{
10 MODEM_DCTS = 1 << 0, // Clear To Send input has changed since last read.
11 MODEM_DDSR = 1 << 1, // Data Set Ready input has changed since last read.
12 MODEM_TERI = 1 << 2, // Ring Indicator input has changed since last read.
13 MODEM_DDCD = 1 << 3, // Data Carrier Detect input has changed since last read.
19
20typedef enum
21{
22 MODEM_DTR = 1 << 0, // Data Terminal Ready
23 MODEM_RTS = 1 << 1, // Request To Send
24 MODEM_UNUSED_PIN1 = 1 << 2, // Unused
25 MODEM_IRQ = 1 << 3, // Interrupt Request
26 MODEM_LOOP = 1 << 4, // Loopback
28
29typedef enum
30{
31 LINE_DATA_READY = 1 << 0, // Data ready to be read.
32 LINE_ERR_OVERRUN = 1 << 1, // There has been data lost.
33 LINE_ERR_PARITY = 1 << 2, // Parity error.
34 LINE_ERR_FRAMING = 1 << 3, // Stop bit is missing.
35 LINE_ERR_BREAK = 1 << 4, // Break detected.
36 LINE_TRANSMITR_BUF_EMPTY = 1 << 5, // (transmitter buffer is empty) Data can be sent.
37 LINE_TRANSMITR_EMPTY = 1 << 6, // Transmitter is not doing anything.
38 LINE_ERR_IMPENDING = 1 << 7, // There is an error with a word in the input buffer
40
42{
43 // Set the most significant bit of the Line Control Register. This is the DLAB bit, and allows access to the divisor registers.
45 reg |= 0x80; // set DLAB bit
46
48
49 // Send the least significant byte of the divisor value to [PORT + 0].
51
52 // Send the most significant byte of the divisor value to [PORT + 1].
54
55 // Clear the most significant bit of the Line Control Register.
56 reg &= ~0x80;
58}
59
61{
62 u8 control = dev->driver->read_register(dev, OFFSET_LINE_CONTROL);
63 control &= dev->char_length;
64 dev->driver->write_register(dev, OFFSET_LINE_CONTROL, control);
65}
66
68{
69 byte_t control = { .byte = dev->driver->read_register(dev, OFFSET_LINE_CONTROL) };
70 control.bits.b1 = dev->stop_bits == STOP_BITS_15_OR_2;
71 dev->driver->write_register(dev, OFFSET_LINE_CONTROL, control.byte);
72}
73
75{
76 u8 byte = dev->driver->read_register(dev, OFFSET_LINE_CONTROL);
77 byte |= ((u8) parity) << 3;
79}
80
81static void serial_set_interrupts(serial_device_t *dev, int interrupts)
82{
83 char control = dev->driver->read_register(dev, OFFSET_INTERRUPT_ENABLE);
84 control = interrupts;
86}
87
89{
90 byte_t byte = { .byte = dev->driver->read_register(dev, OFFSET_MODEM_CONTROL) };
91 switch (control)
92 {
93 case MODEM_DTR: byte.bits.b0 = enable; break;
94 case MODEM_RTS: byte.bits.b1 = enable; break;
95 case MODEM_UNUSED_PIN1: byte.bits.b2 = enable; break;
96 case MODEM_IRQ: byte.bits.b3 = enable; break;
97 case MODEM_LOOP: byte.bits.b4 = enable; break;
98 }
99 dev->driver->write_register(dev, OFFSET_MODEM_CONTROL, byte.byte);
100}
101
103{
104 return dev->driver->read_register(dev, OFFSET_LINE_STATUS);
105}
106
111
113{
115 set_baudrate_divisor(device);
116 set_data_bits(device);
117 set_stop_bits(device);
118 set_parity(device, device->parity);
119
120 serial_set_modem_options(device, MODEM_DTR, true);
121 serial_set_modem_options(device, MODEM_RTS, true);
122
123 // Try send a byte to the serial port.
124 // If it fails, then the serial port is not connected.
125 {
126 const char challenge = 'H';
127 char response = { 0 };
129 serial_device_write(device, &challenge, 1);
130 serial_device_read(device, &response, 1);
131 serial_set_modem_options(device, MODEM_LOOP, false);
132 if (response != 'H')
133 return false;
134 }
135
136 serial_set_modem_options(device, MODEM_IRQ, true);
138 return true;
139}
140
145
147{
148 while (!serial_dev_get_data_ready(device))
149 ;
150}
151
153{
155 ;
156}
157
158int serial_device_write(serial_device_t *device, const char *data, size_t length)
159{
160 size_t i = 0;
161 for (; i < length; i++)
162 {
164 device->driver->write_data(device, data[i]);
165 }
166 return i;
167}
168
169int serial_device_read(serial_device_t *device, char *data, size_t length)
170{
171 for (size_t i = 0; i < length; i++)
172 {
174 data[i] = device->driver->read_data(device);
175 }
176
177 return length;
178}
#define __maybe_unused
Definition mos_global.h:33
int serial_device_read(serial_device_t *device, char *data, size_t length)
Definition serial.c:169
static char serial_get_line_status(serial_device_t *dev)
Definition serial.c:102
serial_modem_control_t
Definition serial.c:21
@ MODEM_RTS
Definition serial.c:23
@ MODEM_UNUSED_PIN1
Definition serial.c:24
@ MODEM_IRQ
Definition serial.c:25
@ MODEM_DTR
Definition serial.c:22
@ MODEM_LOOP
Definition serial.c:26
bool serial_dev_get_data_ready(serial_device_t *device)
Definition serial.c:141
static void set_parity(serial_device_t *dev, serial_parity_t parity)
Definition serial.c:74
static void serial_dev_wait_ready_to_write(serial_device_t *device)
Definition serial.c:152
static void serial_set_modem_options(serial_device_t *dev, serial_modem_control_t control, bool enable)
Definition serial.c:88
static void set_stop_bits(serial_device_t *dev)
Definition serial.c:67
serial_line_status_t
Definition serial.c:30
@ LINE_ERR_BREAK
Definition serial.c:35
@ LINE_ERR_OVERRUN
Definition serial.c:32
@ LINE_TRANSMITR_BUF_EMPTY
Definition serial.c:36
@ LINE_ERR_FRAMING
Definition serial.c:34
@ LINE_DATA_READY
Definition serial.c:31
@ LINE_TRANSMITR_EMPTY
Definition serial.c:37
@ LINE_ERR_IMPENDING
Definition serial.c:38
@ LINE_ERR_PARITY
Definition serial.c:33
static void set_data_bits(serial_device_t *dev)
Definition serial.c:60
static void serial_dev_wait_ready_to_read(serial_device_t *device)
Definition serial.c:146
bool serial_device_setup(serial_device_t *device)
Definition serial.c:112
serial_modem_status_t
Definition serial.c:9
@ MODEM_DATA_SET_READY
Definition serial.c:15
@ MODEM_DATA_CARRIER_DETECT
Definition serial.c:17
@ MODEM_DCTS
Definition serial.c:10
@ MODEM_DDSR
Definition serial.c:11
@ MODEM_DDCD
Definition serial.c:13
@ MODEM_TERI
Definition serial.c:12
@ MODEM_RING_INDICATOR
Definition serial.c:16
@ MODEM_CLEAR_TO_SEND
Definition serial.c:14
int serial_device_write(serial_device_t *device, const char *data, size_t length)
Definition serial.c:158
static void set_baudrate_divisor(serial_device_t *dev)
Definition serial.c:41
static void serial_set_interrupts(serial_device_t *dev, int interrupts)
Definition serial.c:81
static __maybe_unused char serial_get_modem_status(serial_device_t *dev)
Definition serial.c:107
@ STOP_BITS_15_OR_2
Definition serial.h:32
@ INTERRUPT_DATA_AVAILABLE
Definition serial.h:46
@ INTERRUPT_NONE
Definition serial.h:50
@ OFFSET_LINE_STATUS
Definition serial.h:13
@ OFFSET_DLAB_DIVISOR_LSB
Definition serial.h:17
@ OFFSET_MODEM_CONTROL
Definition serial.h:12
@ OFFSET_INTERRUPT_ENABLE
Definition serial.h:9
@ OFFSET_DLAB_DIVISOR_MSB
Definition serial.h:18
@ OFFSET_MODEM_STATUS
Definition serial.h:14
@ OFFSET_LINE_CONTROL
Definition serial.h:11
serial_parity_t
Definition serial.h:36
serial_baudrate_t baudrate_divisor
Definition serial.h:85
serial_parity_t parity
Definition serial.h:88
serial_charlength_t char_length
Definition serial.h:86
const serial_driver_t * driver
Definition serial.h:82
serial_stopbits_t stop_bits
Definition serial.h:87
u8(* read_data)(serial_device_t *dev)
Definition serial.h:73
void(* write_register)(serial_device_t *dev, serial_register_t offset, u8 value)
Definition serial.h:77
u8(* read_register)(serial_device_t *dev, serial_register_t offset)
Definition serial.h:76
void(* write_data)(serial_device_t *dev, u8 data)
Definition serial.h:74
unsigned char u8
Definition types.h:19
Definition types.h:57
bool b1
Definition types.h:61
struct byte_t::@20 bits
u8 byte
Definition types.h:69