ReactOS 0.4.16-dev-2491-g3dc6630
cport_pc98.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS ComPort Library for NEC PC-98 series
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: NEC PC-98 series UART support routines
5 * COPYRIGHT: Copyright 2020-2026 Dmitry Borisov <di.sean@protonmail.com>
6 */
7
8/* INCLUDES *******************************************************************/
9
10/*
11 * Some PC-98 models have a second internal COM port (2ndCCU).
12 * It is a 16550-compatible UART controller with I/O port address 238-23F and IRQ5.
13 */
14#include "ns16550.c"
15
16#include <drivers/pc98/serial.h>
18#include <drivers/pc98/pit.h>
19#include <drivers/pc98/cpu.h>
20
21#define IS_COM1(IoBase) ((IoBase) == UlongToPtr(0x30))
22#define IS_NS16550(IoBase) ((IoBase) == UlongToPtr(0x238))
23
24/* ioaccess.h header extension */
25#define READ_PORT_BUFFER_UCHAR(port, buffer, count) __inbytestring(H2I(port), buffer, count)
26#define WRITE_PORT_BUFFER_UCHAR(port, buffer, count) __outbytestring(H2I(port), buffer, count)
27
28/* GLOBALS ********************************************************************/
29
33
34/* FUNCTIONS ******************************************************************/
35
36static
39{
40 UCHAR Input[4] = "NP2";
41 UCHAR Output[4] = { 0 };
42
43 if (READ_PORT_UCHAR((PUCHAR)0x7EF) != 0x00)
44 return FALSE;
45
48
49 return (*(PULONG)Input == *(PULONG)Output);
50}
51
52static
55{
56 if (READ_PORT_UCHAR((PUCHAR)0x42) & 0x20)
57 return TIMER_FREQUENCY_1;
58 else
59 return TIMER_FREQUENCY_2;
60}
61
62static
63VOID
65{
66 ULONG i;
67
68 for (i = 0; i < 6; i++)
70}
71
72static
75{
76 UCHAR IntValue1, IntValue2;
77
80
81 return !!((IntValue1 ^ IntValue2) & SR_8251F_IIR_FIFO_DET);
82}
83
84static
87 _In_ PUCHAR IoBase)
88{
90
91 Data = READ_PORT_UCHAR(IoBase);
92 Status = READ_PORT_UCHAR(IoBase + 2);
93
94 return ((Data & Status) != 0xFF && (Data | Status) != 0x00);
95}
96
97static
100 _In_ PUCHAR IoBase)
101{
102 if (Cpi8251IsPortResponding(IoBase))
103 return TRUE;
104
105 /*
106 * Setting FIFO mode effectively disables the data and status ports
107 * by wiring them to 0xFF, making the detection attempt fail.
108 * The FIFO mode may have been enabled earlier by the kernel bootloader,
109 * so try to disable it, and retry.
110 */
111 if (IS_COM1(IoBase))
112 {
113 BOOLEAN WasDetected;
114 UCHAR FifoControl;
115
116 if (!Cpi8251HasFifo())
117 return FALSE;
118
119 /* Disable the FIFO logic */
122
123 WasDetected = Cpi8251IsPortResponding(IoBase);
124
125 /* Restore the previous state */
127
128 return WasDetected;
129 }
130
131 return FALSE;
132}
133
135NTAPI
138{
139 if (IS_NS16550(Address))
141
143}
144
145VOID
146NTAPI
150{
151 UCHAR Value;
152
153 if (IS_NS16550(Address))
154 {
156 return;
157 }
158
159 if (!HasFifo)
160 return;
161
163
164 if (Enable)
166 else
169}
170
171VOID
172NTAPI
175 _In_ ULONG BaudRate)
176{
177 ULONG i;
178
179 if (IS_NS16550(Port->Address))
180 {
181 Uart16550SetBaud(Port, BaudRate);
182 return;
183 }
184
185 if (IS_COM1(Port->Address))
186 {
187 TIMER_CONTROL_PORT_REGISTER TimerControl;
188 SYSTEM_CONTROL_PORT_C_REGISTER SystemControl;
190
191 /* Disable the serial interrupts */
192 SystemControl.Bits = READ_PORT_UCHAR((PUCHAR)PPI_IO_i_PORT_C);
193 SystemControl.InterruptEnableRxReady = FALSE;
194 SystemControl.InterruptEnableTxEmpty = FALSE;
195 SystemControl.InterruptEnableTxReady = FALSE;
197
198 /* Disable V-FAST mode */
199 if (HasFifo)
201
202 Count = (CpiGetPitTickRate() / 16) / BaudRate;
203
204 /* Set the baud rate */
205 TimerControl.BcdMode = FALSE;
206 TimerControl.OperatingMode = PitOperatingMode3;
207 TimerControl.AccessMode = PitAccessModeLowHigh;
208 TimerControl.Channel = PitChannel2;
209 Write8253Timer(TimerControl, Count);
210
211 /* Unlock the legacy registers (0x30 and 0x32) */
212 if (HasFifo)
214 }
215
216 /* Software reset */
217 for (i = 0; i < 3; ++i)
218 {
220 CpiWait();
221 }
223 CpiWait();
224
225 /* Mode instruction */
228 CpiWait();
229
230 /* Command instruction */
237 CpiWait();
238
239 /* Restore the FIFO state */
240 if (IsFifoEnabled)
241 {
244 }
245}
246
248NTAPI
252 _In_ ULONG BaudRate)
253{
254 PUCHAR DataReg;
255
256 if (IS_NS16550(Address))
257 return Uart16550Initialize(Port, Address, BaudRate);
258
259 if (Port == NULL || Address == NULL || BaudRate == 0)
261
263 return STATUS_NOT_FOUND;
264
265 /* Initialize port data */
267 Port->BaudRate = 0;
268 Port->Flags = 0;
269
270 if (IS_COM1(Address))
271 {
274 }
275
276 /* Perform port initialization */
277 CpSetBaud(Port, BaudRate);
279
280 /* Read junk out of the data register */
281 if (IsFifoEnabled)
282 DataReg = UlongToPtr(SER_8251F_REG_RBR);
283 else
284 DataReg = Port->Address;
285 READ_PORT_UCHAR(DataReg);
286
287 return STATUS_SUCCESS;
288}
289
290static UCHAR
291NTAPI
294 _In_ UCHAR ExpectedValue)
295{
296 UCHAR Lsr, Msr;
297
298 if (IS_NS16550(Port->Address))
299 return Cp16550ReadLsr(Port, ExpectedValue);
300
301 if (IsFifoEnabled)
302 {
304
305 if (!(Lsr & ExpectedValue))
306 {
308
309 RingIndicator |= (Msr & SR_8251F_MSR_RI) ? 1 : 2;
310 }
311 }
312 else
313 {
314 Lsr = READ_PORT_UCHAR(Port->Address + 2);
315
316 if (!(Lsr & ExpectedValue))
317 {
318 SYSTEM_CONTROL_PORT_B_REGISTER SystemControl;
319
320 SystemControl.Bits = READ_PORT_UCHAR((PUCHAR)PPI_IO_i_PORT_B);
321
322 RingIndicator |= SystemControl.RingIndicator ? 1 : 2;
323 }
324 }
325
326 /* If the ring indicator reaches 3, we've seen this on/off twice */
327 if (RingIndicator == 3)
329
330 return Lsr;
331}
332
333USHORT
334NTAPI
339 _In_ BOOLEAN Poll)
340{
341 ULONG RetryCount;
342 UCHAR RxReadyFlags, ErrorFlags;
343
344 if (IS_NS16550(Port->Address))
345 return Uart16550GetByte(Port, Byte, Wait, Poll);
346
347 /* Handle early read-before-init */
348 if (!Port->Address)
349 return CP_GET_NODATA;
350
351 // FIXME HACK: NP21/W emulation bug, needs to be fixed on the emulator side.
352 // Do a read from 0x136 to receive bytes by an emulated serial port.
353 if (IsNp21W)
355
356 if (IsFifoEnabled)
357 {
358 RxReadyFlags = SR_8251F_LSR_RxRDY;
359 ErrorFlags = SR_8251F_LSR_PE | SR_8251F_LSR_OE;
360 }
361 else
362 {
363 RxReadyFlags = SR_8251A_STATUS_RxRDY;
365 }
366
367 /* Poll for data ready */
368 for (RetryCount = Wait ? TIMEOUT_COUNT : 1; RetryCount > 0; RetryCount--)
369 {
370 UCHAR Lsr = CpReadLsr(Port, RxReadyFlags);
371 PUCHAR DataReg;
372
373 if (!(Lsr & RxReadyFlags))
374 continue;
375
376 /* Handle error condition */
377 if (Lsr & ErrorFlags)
378 {
379 if (IsFifoEnabled)
381
382 /* Clear error flag */
389
390 if (IsFifoEnabled)
392
393 *Byte = 0;
394 return CP_GET_ERROR;
395 }
396
397 if (Poll)
398 return CP_GET_SUCCESS;
399
400 if (IsFifoEnabled)
401 DataReg = UlongToPtr(SER_8251F_REG_RBR);
402 else
403 DataReg = Port->Address;
404 *Byte = READ_PORT_UCHAR(DataReg);
405
406 // TODO: Handle CD if port is in modem control mode
407
408 return CP_GET_SUCCESS;
409 }
410
411 /* Reset LSR, no data was found */
412 CpReadLsr(Port, 0);
413 return CP_GET_NODATA;
414}
415
416VOID
417NTAPI
421{
422 PUCHAR DataReg;
423 UCHAR TxReadyFlags;
424
425 if (IS_NS16550(Port->Address))
426 {
428 return;
429 }
430
431 if (IsFifoEnabled)
432 {
433 DataReg = UlongToPtr(SER_8251F_REG_RBR);
434 TxReadyFlags = SR_8251F_LSR_TxEMPTY;
435
436 /*
437 * Unlike 16550, a call to CpDoesPortExist for the 8251 will succeed even
438 * when if the user has not plug the serial port into PC-98 machine.
439 * To avoid an infinite loop, we need to check if the other side is ready
440 * to receive data.
441 */
443 return;
444 }
445 else
446 {
447 DataReg = Port->Address;
448 TxReadyFlags = SR_8251A_STATUS_TxEMPTY;
449 }
450
451 while (!(CpReadLsr(Port, TxReadyFlags) & TxReadyFlags))
452 NOTHING;
453
454 WRITE_PORT_UCHAR(DataReg, Byte);
455}
#define VOID
Definition: acefi.h:82
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
static BOOLEAN IsNp21W
Definition: cport_pc98.c:30
USHORT NTAPI CpGetByte(_Inout_ PCPPORT Port, _Out_ PUCHAR Byte, _In_ BOOLEAN Wait, _In_ BOOLEAN Poll)
Definition: cport_pc98.c:335
#define READ_PORT_BUFFER_UCHAR(port, buffer, count)
Definition: cport_pc98.c:25
static VOID CpiWait(VOID)
Definition: cport_pc98.c:64
#define IS_NS16550(IoBase)
Definition: cport_pc98.c:22
static BOOLEAN CpiIsNekoProject(VOID)
Definition: cport_pc98.c:38
VOID NTAPI CpPutByte(_Inout_ PCPPORT Port, _In_ UCHAR Byte)
Definition: cport_pc98.c:418
NTSTATUS NTAPI CpInitialize(_Inout_ PCPPORT Port, _In_ PUCHAR Address, _In_ ULONG BaudRate)
Definition: cport_pc98.c:249
static ULONG CpiGetPitTickRate(VOID)
Definition: cport_pc98.c:54
BOOLEAN NTAPI CpDoesPortExist(_In_ PUCHAR Address)
Definition: cport_pc98.c:136
#define WRITE_PORT_BUFFER_UCHAR(port, buffer, count)
Definition: cport_pc98.c:26
static BOOLEAN Cpi8251DoesPortExist(_In_ PUCHAR IoBase)
Definition: cport_pc98.c:99
static UCHAR NTAPI CpReadLsr(_Inout_ PCPPORT Port, _In_ UCHAR ExpectedValue)
Definition: cport_pc98.c:292
static BOOLEAN Cpi8251HasFifo(VOID)
Definition: cport_pc98.c:74
static BOOLEAN Cpi8251IsPortResponding(_In_ PUCHAR IoBase)
Definition: cport_pc98.c:86
static BOOLEAN IsFifoEnabled
Definition: cport_pc98.c:32
#define IS_COM1(IoBase)
Definition: cport_pc98.c:21
static BOOLEAN HasFifo
Definition: cport_pc98.c:31
VOID NTAPI CpSetBaud(_Inout_ PCPPORT Port, _In_ ULONG BaudRate)
Definition: cport_pc98.c:173
VOID NTAPI CpEnableFifo(_In_ PUCHAR Address, _In_ BOOLEAN Enable)
Definition: cport_pc98.c:147
#define CP_GET_SUCCESS
Definition: cportlib.h:17
#define CP_GET_NODATA
Definition: cportlib.h:18
#define CPPORT_FLAG_MODEM_CONTROL
Definition: cportlib.h:24
#define CP_GET_ERROR
Definition: cportlib.h:19
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned char Byte
Definition: zlib.h:37
#define UlongToPtr(u)
Definition: config.h:106
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
@ PitChannel2
Definition: halhw.h:104
@ PitAccessModeLowHigh
Definition: halhw.h:97
@ PitOperatingMode3
Definition: halhw.h:85
CPPORT Port[4]
Definition: headless.c:38
#define NOTHING
Definition: input_list.c:10
#define _Inout_
Definition: no_sal2.h:162
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
int Count
Definition: noreturn.cpp:7
#define TIMEOUT_COUNT
Definition: ns16550.c:32
VOID NTAPI Uart16550SetBaud(_Inout_ PCPPORT Port, _In_ ULONG BaudRate)
Definition: ns16550.c:158
USHORT NTAPI Uart16550GetByte(_Inout_ PCPPORT Port, _Out_ PUCHAR Byte, _In_ BOOLEAN Wait, _In_ BOOLEAN Poll)
Definition: ns16550.c:250
NTSTATUS NTAPI Uart16550Initialize(_Inout_ PCPPORT Port, _In_ PUCHAR Address, _In_ ULONG BaudRate)
Definition: ns16550.c:182
VOID NTAPI Uart16550PutByte(_Inout_ PCPPORT Port, _In_ UCHAR Byte)
Definition: ns16550.c:303
VOID NTAPI Uart16550EnableFifo(_In_ PUCHAR Address, _In_ BOOLEAN Enable)
Definition: ns16550.c:146
static UCHAR NTAPI Cp16550ReadLsr(_Inout_ PCPPORT Port, _In_ UCHAR ExpectedValue)
Definition: ns16550.c:226
BOOLEAN NTAPI Uart16550DoesPortExist(_In_ PUCHAR Address)
Definition: ns16550.c:138
UCHAR RingIndicator
Definition: ns16550.c:34
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:142
#define READ_PORT_UCHAR(p)
Definition: pc98vid.h:22
#define WRITE_PORT_UCHAR(p, d)
Definition: pc98vid.h:21
unsigned short USHORT
Definition: pedump.c:61
static WCHAR Address[46]
Definition: ping.c:68
@ Input
Definition: arc.h:93
@ Output
Definition: arc.h:94
#define CPU_IO_o_ARTIC_DELAY
Definition: cpu.h:22
#define TIMER_FREQUENCY_1
Definition: pit.h:16
FORCEINLINE VOID Write8253Timer(TIMER_CONTROL_PORT_REGISTER TimerControl, USHORT Count)
Definition: pit.h:90
#define TIMER_FREQUENCY_2
Definition: pit.h:17
#define SR_8251F_IIR_FIFO_DET
Definition: serial.h:82
#define SER_8251F_REG_IIR
Definition: serial.h:54
#define SR_8251A_STATUS_RxRDY
Definition: serial.h:14
#define SR_8251A_STATUS_PE
Definition: serial.h:16
#define SER_8251F_REG_FCR
Definition: serial.h:55
#define SR_8251F_LSR_OE
Definition: serial.h:61
#define SR_8251A_MODE_CLOCKx16
Definition: serial.h:35
#define SR_8251F_LSR_RxRDY
Definition: serial.h:60
#define SER_8251F_REG_RBR
Definition: serial.h:51
#define SR_8251F_MSR_RI
Definition: serial.h:71
#define SR_8251F_FCR_ENABLE
Definition: serial.h:85
#define SR_8251A_COMMMAND_TxEN
Definition: serial.h:42
#define SR_8251A_COMMMAND_RxEN
Definition: serial.h:44
#define SR_8251F_FCR_DISABLE
Definition: serial.h:84
#define SR_8251A_COMMMAND_IR
Definition: serial.h:48
#define SR_8251A_COMMMAND_DTR
Definition: serial.h:43
#define SR_8251F_FCR_TXMT_RESET
Definition: serial.h:87
#define SR_8251F_MSR_CTS
Definition: serial.h:69
#define SR_8251A_COMMMAND_RTS
Definition: serial.h:47
#define SER_8251F_REG_MSR
Definition: serial.h:53
#define SR_8251A_STATUS_OE
Definition: serial.h:17
#define SR_8251F_DLR_MODE_LEGACY
Definition: serial.h:102
#define SER_8251F_REG_DLR
Definition: serial.h:56
#define SR_8251A_MODE_1_STOP
Definition: serial.h:38
#define SR_8251A_MODE_LENGTH_8
Definition: serial.h:31
#define SR_8251A_STATUS_FE
Definition: serial.h:18
#define SR_8251A_COMMMAND_ER
Definition: serial.h:46
#define SER_8251F_REG_LSR
Definition: serial.h:52
#define SR_8251A_STATUS_TxEMPTY
Definition: serial.h:15
#define SR_8251F_FCR_RCVR_RESET
Definition: serial.h:86
#define SR_8251F_LSR_PE
Definition: serial.h:62
#define SR_8251F_LSR_TxEMPTY
Definition: serial.h:58
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_NOT_FOUND
Definition: shellext.h:72
PUCHAR Address
Definition: cportlib.h:28
ULONG BaudRate
Definition: cportlib.h:29
USHORT Flags
Definition: cportlib.h:30
#define PPI_IO_i_PORT_C
Definition: sysport.h:20
#define PPI_IO_i_PORT_B
Definition: sysport.h:19
#define PPI_IO_o_PORT_C
Definition: sysport.h:10
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:170
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
unsigned char UCHAR
Definition: xmlstorage.h:181