Relicense Sortix to the ISC license.
I hereby relicense all my work on Sortix under the ISC license as below.
All Sortix contributions by other people are already under this license,
are not substantial enough to be copyrightable, or have been removed.
All imported code from other projects is compatible with this license.
All GPL licensed code from other projects had previously been removed.
Copyright 2011-2016 Jonas 'Sortie' Termansen and contributors.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2016-03-02 22:38:16 +00:00
|
|
|
/*
|
2023-07-05 20:53:12 +00:00
|
|
|
* Copyright (c) 2011, 2012, 2014, 2015, 2016, 2023 Jonas 'Sortie' Termansen.
|
Relicense Sortix to the ISC license.
I hereby relicense all my work on Sortix under the ISC license as below.
All Sortix contributions by other people are already under this license,
are not substantial enough to be copyrightable, or have been removed.
All imported code from other projects is compatible with this license.
All GPL licensed code from other projects had previously been removed.
Copyright 2011-2016 Jonas 'Sortie' Termansen and contributors.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2016-03-02 22:38:16 +00:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
* com.cpp
|
|
|
|
* Handles communication to COM serial ports.
|
|
|
|
*/
|
2012-03-17 14:18:03 +00:00
|
|
|
|
2023-07-05 20:53:12 +00:00
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
2013-10-27 00:42:10 +00:00
|
|
|
#include <errno.h>
|
2014-10-09 15:32:17 +00:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
2013-10-27 00:42:10 +00:00
|
|
|
|
2014-01-16 19:45:47 +00:00
|
|
|
#include <sortix/fcntl.h>
|
2013-10-27 00:42:10 +00:00
|
|
|
#include <sortix/stat.h>
|
|
|
|
|
2012-08-07 22:19:44 +00:00
|
|
|
#include <sortix/kernel/descriptor.h>
|
2013-10-27 00:42:10 +00:00
|
|
|
#include <sortix/kernel/inode.h>
|
2012-08-07 22:19:44 +00:00
|
|
|
#include <sortix/kernel/interlock.h>
|
2013-01-09 22:30:36 +00:00
|
|
|
#include <sortix/kernel/interrupt.h>
|
2013-10-27 00:42:10 +00:00
|
|
|
#include <sortix/kernel/ioctx.h>
|
2014-03-03 17:22:30 +00:00
|
|
|
#include <sortix/kernel/ioport.h>
|
2013-10-27 00:42:10 +00:00
|
|
|
#include <sortix/kernel/kernel.h>
|
|
|
|
#include <sortix/kernel/kthread.h>
|
2013-05-12 22:41:30 +00:00
|
|
|
#include <sortix/kernel/process.h>
|
2013-10-27 00:42:10 +00:00
|
|
|
#include <sortix/kernel/refcount.h>
|
2013-05-12 22:41:30 +00:00
|
|
|
#include <sortix/kernel/thread.h>
|
2013-01-09 22:30:36 +00:00
|
|
|
|
2012-03-17 14:18:03 +00:00
|
|
|
#include "com.h"
|
2023-07-05 20:53:12 +00:00
|
|
|
#include "tty.h"
|
2012-03-17 14:18:03 +00:00
|
|
|
|
2015-03-16 16:24:42 +00:00
|
|
|
extern "C" unsigned char nullpage[4096];
|
|
|
|
|
2012-03-17 14:18:03 +00:00
|
|
|
namespace Sortix {
|
|
|
|
namespace COM {
|
|
|
|
|
2014-10-09 15:32:17 +00:00
|
|
|
static const uint16_t TXR = 0; // Transmit register
|
|
|
|
static const uint16_t RXR = 0; // Receive register
|
|
|
|
static const uint16_t IER = 1; // Interrupt Enable
|
|
|
|
static const uint16_t IIR = 2; // Interrupt ID
|
|
|
|
static const uint16_t FCR = 2; // FIFO control
|
|
|
|
static const uint16_t LCR = 3; // Line control
|
|
|
|
static const uint16_t MCR = 4; // Modem control
|
|
|
|
static const uint16_t LSR = 5; // Line Status
|
|
|
|
static const uint16_t MSR = 6; // Modem Status
|
|
|
|
static const uint16_t SCR = 7; // Scratch Register
|
|
|
|
static const uint16_t DLL = 0; // Divisor Latch Low
|
|
|
|
static const uint16_t DLM = 1; // Divisor latch High
|
|
|
|
|
|
|
|
static const uint8_t LCR_DLAB = 0x80; // Divisor latch access bit
|
|
|
|
static const uint8_t LCR_SBC = 0x40; // Set break control
|
|
|
|
static const uint8_t LCR_SPAR = 0x20; // Stick parity (?)
|
|
|
|
static const uint8_t LCR_EPAR = 0x10; // Even parity select
|
|
|
|
static const uint8_t LCR_PARITY = 0x08; // Parity Enable
|
|
|
|
static const uint8_t LCR_STOP = 0x04; // Stop bits: 0=1 bit, 1=2 bits
|
|
|
|
static const uint8_t LCR_WLEN5 = 0x00; // Wordlength: 5 bits
|
|
|
|
static const uint8_t LCR_WLEN6 = 0x01; // Wordlength: 6 bits
|
|
|
|
static const uint8_t LCR_WLEN7 = 0x02; // Wordlength: 7 bits
|
|
|
|
static const uint8_t LCR_WLEN8 = 0x03; // Wordlength: 8 bits
|
|
|
|
|
|
|
|
static const uint8_t LSR_TEMT = 0x40; // Transmitter empty
|
|
|
|
static const uint8_t LSR_THRE = 0x20; // Transmit-hold-register empty
|
|
|
|
static const uint8_t LSR_READY = 0x01; // Data received
|
|
|
|
static const uint8_t LSR_BOTH_EMPTY = LSR_TEMT | LSR_THRE;
|
|
|
|
|
|
|
|
static const uint8_t IIR_NO_INTERRUPT = 1 << 0;
|
|
|
|
static const uint8_t IIR_INTERRUPT_TYPE = 1 << 1 | 1 << 2 | 1 << 3;
|
|
|
|
static const uint8_t IIR_TIMEOUT = 1 << 2 | 1 << 3;
|
|
|
|
static const uint8_t IIR_RECV_LINE_STATUS = 1 << 1 | 1 << 2;
|
|
|
|
static const uint8_t IIR_RECV_DATA = 1 << 2;
|
|
|
|
static const uint8_t IIR_SENT_DATA = 1 << 1;
|
|
|
|
static const uint8_t IIR_MODEM_STATUS = 0;
|
|
|
|
|
|
|
|
static const uint8_t IER_DATA = 1 << 0;
|
|
|
|
static const uint8_t IER_SENT = 1 << 1;
|
|
|
|
static const uint8_t IER_LINE_STATUS = 1 << 2;
|
|
|
|
static const uint8_t IER_MODEM_STATUS = 1 << 3;
|
|
|
|
static const uint8_t IER_SLEEP_MODE = 1 << 4;
|
|
|
|
static const uint8_t IER_LOW_POWER = 1 << 5;
|
|
|
|
|
|
|
|
static const unsigned BASE_BAUD = 1843200 / 16;
|
|
|
|
|
|
|
|
static const unsigned int UART_8250 = 1;
|
|
|
|
static const unsigned int UART_16450 = 2;
|
|
|
|
static const unsigned int UART_16550 = 3;
|
|
|
|
static const unsigned int UART_16550A = 4;
|
|
|
|
static const unsigned int UART_16750 = 5;
|
|
|
|
|
|
|
|
static const size_t NUM_COM_PORTS = 4;
|
2012-03-17 14:18:03 +00:00
|
|
|
|
|
|
|
// Uses various characteristics of the UART chips to determine the hardware.
|
2014-10-09 15:32:17 +00:00
|
|
|
static unsigned int HardwareProbe(uint16_t port)
|
2012-03-17 14:18:03 +00:00
|
|
|
{
|
|
|
|
// Set the value "0xE7" to the FCR to test the status of the FIFO flags.
|
2014-03-03 17:22:30 +00:00
|
|
|
outport8(port + FCR, 0xE7);
|
|
|
|
uint8_t iir = inport8(port + IIR);
|
2014-10-09 15:32:17 +00:00
|
|
|
if ( iir & (1 << 6) )
|
2012-03-17 14:18:03 +00:00
|
|
|
{
|
2014-10-09 15:32:17 +00:00
|
|
|
if ( iir & (1 << 7) )
|
|
|
|
return iir & (1 << 5) ? UART_16750 : UART_16550A;
|
|
|
|
return UART_16550;
|
2012-03-17 14:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// See if the scratch register returns what we write into it. The 8520
|
|
|
|
// doesn't do it. This is technically undefined behavior, but it is useful
|
|
|
|
// to detect hardware versions.
|
2014-10-09 15:32:17 +00:00
|
|
|
uint16_t any_value = 0x2A;
|
|
|
|
outport8(port + SCR, any_value);
|
|
|
|
return inport8(port + SCR) == any_value ? UART_16450 : UART_8250;
|
2012-03-17 14:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void WaitForEmptyBuffers(uint16_t port)
|
|
|
|
{
|
2014-10-09 15:32:17 +00:00
|
|
|
while ( (inport8(port + LSR) & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY )
|
|
|
|
{
|
|
|
|
}
|
2012-03-17 14:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool IsLineReady(uint16_t port)
|
|
|
|
{
|
2014-03-03 17:22:30 +00:00
|
|
|
return inport8(port + LSR) & LSR_READY;
|
2012-03-17 14:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool CanWriteByte(uint16_t port)
|
|
|
|
{
|
2014-03-03 17:22:30 +00:00
|
|
|
return inport8(port + LSR) & LSR_THRE;
|
2012-03-17 14:18:03 +00:00
|
|
|
}
|
|
|
|
|
2023-07-05 20:53:12 +00:00
|
|
|
class DevCOMPort : public TTY
|
2012-03-17 14:18:03 +00:00
|
|
|
{
|
|
|
|
public:
|
2023-07-05 20:53:12 +00:00
|
|
|
DevCOMPort(dev_t dev, uid_t owner, gid_t group, mode_t mode, uint16_t port,
|
|
|
|
const char* name);
|
2012-03-17 14:18:03 +00:00
|
|
|
virtual ~DevCOMPort();
|
2023-07-05 20:53:12 +00:00
|
|
|
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
|
2012-08-07 22:19:44 +00:00
|
|
|
virtual int sync(ioctx_t* ctx);
|
2023-07-05 20:53:12 +00:00
|
|
|
virtual void tty_output(const unsigned char* buffer, size_t length);
|
|
|
|
|
|
|
|
public:
|
|
|
|
bool Initialize(int interrupt);
|
|
|
|
|
|
|
|
private:
|
|
|
|
static void InterruptHandler(struct interrupt_context*, void*);
|
|
|
|
static void InterruptWorkHandler(void* context);
|
|
|
|
void OnInterrupt();
|
|
|
|
void InterruptWork();
|
2012-03-17 14:18:03 +00:00
|
|
|
|
|
|
|
private:
|
2014-10-09 15:32:17 +00:00
|
|
|
kthread_mutex_t port_lock;
|
2023-07-05 20:53:12 +00:00
|
|
|
struct interrupt_handler irq_registration;
|
|
|
|
struct interrupt_work interrupt_work;
|
|
|
|
struct winsize ws;
|
2012-08-07 22:19:44 +00:00
|
|
|
uint16_t port;
|
2014-10-09 15:32:17 +00:00
|
|
|
uint8_t pending_input_byte;
|
|
|
|
bool has_pending_input_byte;
|
2012-03-17 14:18:03 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2012-08-07 22:19:44 +00:00
|
|
|
DevCOMPort::DevCOMPort(dev_t dev, uid_t owner, gid_t group, mode_t mode,
|
2023-07-05 20:53:12 +00:00
|
|
|
uint16_t port, const char* name) : TTY(dev, ino, mode,
|
|
|
|
owner, group, name)
|
2012-03-17 14:18:03 +00:00
|
|
|
{
|
|
|
|
this->port = port;
|
2014-10-09 15:32:17 +00:00
|
|
|
this->port_lock = KTHREAD_MUTEX_INITIALIZER;
|
|
|
|
this->has_pending_input_byte = false;
|
2023-07-05 20:53:12 +00:00
|
|
|
interrupt_work.handler = InterruptWorkHandler;
|
|
|
|
interrupt_work.context = this;
|
2012-03-17 14:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DevCOMPort::~DevCOMPort()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-07-05 20:53:12 +00:00
|
|
|
bool DevCOMPort::Initialize(int interrupt)
|
2012-08-07 22:19:44 +00:00
|
|
|
{
|
2023-07-05 20:53:12 +00:00
|
|
|
uint8_t interrupts = 1;
|
|
|
|
// TODO: This was 9600.
|
|
|
|
tio.c_ispeed = B19200;
|
|
|
|
tio.c_ospeed = B19200;
|
|
|
|
uint16_t divisor = 115200 / tio.c_ispeed;
|
|
|
|
outport8(port + FCR, 0);
|
|
|
|
outport8(port + LCR, LCR_DLAB);
|
|
|
|
outport8(port + DLL, divisor & 0xFF);
|
|
|
|
outport8(port + DLM, divisor >> 8);
|
|
|
|
outport8(port + LCR, LCR_WLEN8); // 8n1
|
|
|
|
outport8(port + MCR, 0x1 /* DTR */ | 0x2 /* RTS */);
|
|
|
|
outport8(port + IER, interrupts);
|
|
|
|
irq_registration.handler = DevCOMPort::InterruptHandler;
|
|
|
|
irq_registration.context = this;
|
|
|
|
Interrupt::RegisterHandler(interrupt, &irq_registration);
|
|
|
|
return true;
|
2012-08-07 22:19:44 +00:00
|
|
|
}
|
2012-03-17 14:18:03 +00:00
|
|
|
|
2023-07-05 20:53:12 +00:00
|
|
|
void DevCOMPort::InterruptHandler(struct interrupt_context*, void* user)
|
2012-03-17 14:18:03 +00:00
|
|
|
{
|
2023-07-05 20:53:12 +00:00
|
|
|
((DevCOMPort*) user)->OnInterrupt();
|
|
|
|
}
|
2012-03-17 14:18:03 +00:00
|
|
|
|
2023-07-05 20:53:12 +00:00
|
|
|
void DevCOMPort::OnInterrupt()
|
|
|
|
{
|
|
|
|
if ( !IsLineReady(port) )
|
|
|
|
return;
|
|
|
|
Interrupt::ScheduleWork(&interrupt_work);
|
|
|
|
}
|
2012-03-17 14:18:03 +00:00
|
|
|
|
2023-07-05 20:53:12 +00:00
|
|
|
void DevCOMPort::InterruptWorkHandler(void* context)
|
|
|
|
{
|
|
|
|
((DevCOMPort*) context)->InterruptWork();
|
|
|
|
}
|
2014-10-09 15:32:17 +00:00
|
|
|
|
2023-07-05 20:53:12 +00:00
|
|
|
void DevCOMPort::InterruptWork()
|
|
|
|
{
|
|
|
|
ScopedLock lock1(&termlock);
|
|
|
|
ScopedLock lock2(&port_lock);
|
|
|
|
while ( IsLineReady(port) )
|
|
|
|
{
|
|
|
|
unsigned char byte = inport8(port + RXR);
|
|
|
|
if ( tio.c_cflag & CREAD )
|
|
|
|
ProcessByte(byte);
|
2014-01-16 19:45:47 +00:00
|
|
|
}
|
2023-07-05 20:53:12 +00:00
|
|
|
}
|
2012-03-17 14:18:03 +00:00
|
|
|
|
2023-07-05 20:53:12 +00:00
|
|
|
int DevCOMPort::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
|
|
|
|
{
|
|
|
|
ScopedLock lock(&termlock);
|
|
|
|
if ( hungup )
|
|
|
|
return errno = EIO, -1;
|
|
|
|
if ( cmd == TIOCGWINSZ )
|
|
|
|
{
|
|
|
|
struct winsize* user_ws = (struct winsize*) arg;
|
|
|
|
if ( !ctx->copy_to_dest(user_ws, &ws, sizeof(ws)) )
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if ( cmd == TIOCSWINSZ )
|
|
|
|
{
|
|
|
|
const struct winsize* user_ws = (const struct winsize*) arg;
|
|
|
|
if ( !ctx->copy_from_src(&ws, user_ws, sizeof(ws)) )
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
lock.Reset();
|
|
|
|
return TTY::ioctl(ctx, cmd, arg);
|
2012-03-17 14:18:03 +00:00
|
|
|
}
|
|
|
|
|
2023-07-05 20:53:12 +00:00
|
|
|
int DevCOMPort::sync(ioctx_t* /*ctx*/)
|
2012-03-17 14:18:03 +00:00
|
|
|
{
|
2014-10-09 15:32:17 +00:00
|
|
|
ScopedLock lock(&port_lock);
|
2023-07-05 20:53:12 +00:00
|
|
|
WaitForEmptyBuffers(port);
|
|
|
|
return 0;
|
|
|
|
}
|
2012-08-01 15:30:34 +00:00
|
|
|
|
2023-07-05 20:53:12 +00:00
|
|
|
void DevCOMPort::tty_output(const unsigned char* buffer, size_t length)
|
|
|
|
{
|
|
|
|
for ( size_t i = 0; i < length; i++ )
|
2014-01-16 19:45:47 +00:00
|
|
|
{
|
2014-10-09 15:32:17 +00:00
|
|
|
unsigned long attempt = 0;
|
2014-01-16 19:45:47 +00:00
|
|
|
while ( !CanWriteByte(port) )
|
2012-08-01 15:30:34 +00:00
|
|
|
{
|
2014-10-09 15:32:17 +00:00
|
|
|
attempt++;
|
|
|
|
if ( attempt <= 10 )
|
|
|
|
continue;
|
2023-07-05 20:53:12 +00:00
|
|
|
if ( attempt <= 15 )
|
2014-10-09 15:32:17 +00:00
|
|
|
{
|
2016-10-22 21:44:46 +00:00
|
|
|
kthread_mutex_unlock(&port_lock);
|
2014-10-09 15:32:17 +00:00
|
|
|
kthread_yield();
|
2016-10-22 21:44:46 +00:00
|
|
|
kthread_mutex_lock(&port_lock);
|
2014-01-16 19:45:47 +00:00
|
|
|
continue;
|
2014-10-09 15:32:17 +00:00
|
|
|
}
|
2014-01-16 19:45:47 +00:00
|
|
|
if ( i )
|
2023-07-05 20:53:12 +00:00
|
|
|
return;
|
|
|
|
// TODO: This is problematic.
|
2014-01-16 19:45:47 +00:00
|
|
|
if ( Signal::IsPending() )
|
2023-07-05 20:53:12 +00:00
|
|
|
{
|
|
|
|
errno = EINTR;
|
|
|
|
return;
|
|
|
|
}
|
2012-08-01 15:30:34 +00:00
|
|
|
}
|
2023-07-05 20:53:12 +00:00
|
|
|
outport8(port + TXR, buffer[i]);
|
2014-01-16 19:45:47 +00:00
|
|
|
}
|
2012-03-17 14:18:03 +00:00
|
|
|
}
|
|
|
|
|
2014-10-09 15:32:17 +00:00
|
|
|
static Ref<DevCOMPort> com_devices[1 + NUM_COM_PORTS];
|
2014-09-29 21:17:36 +00:00
|
|
|
|
2012-08-07 22:19:44 +00:00
|
|
|
void Init(const char* devpath, Ref<Descriptor> slashdev)
|
2012-03-17 14:18:03 +00:00
|
|
|
{
|
2015-03-16 16:24:42 +00:00
|
|
|
uint16_t com_ports[1 + NUM_COM_PORTS];
|
|
|
|
unsigned int hw_version[1 + NUM_COM_PORTS];
|
|
|
|
|
|
|
|
const uint16_t* bioscom_ports = (const uint16_t*) (nullpage + 0x400);
|
|
|
|
|
|
|
|
for ( size_t i = 1; i <= NUM_COM_PORTS; i++ )
|
|
|
|
{
|
|
|
|
if ( !(com_ports[i] = bioscom_ports[i-1]) )
|
|
|
|
continue;
|
|
|
|
hw_version[i] = HardwareProbe(com_ports[i]);
|
|
|
|
outport8(com_ports[i] + IER, 0x0);
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) hw_version;
|
|
|
|
|
2012-08-07 22:19:44 +00:00
|
|
|
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
2012-03-17 14:18:03 +00:00
|
|
|
|
2014-10-09 15:32:17 +00:00
|
|
|
for ( size_t i = 1; i <= NUM_COM_PORTS; i++ )
|
|
|
|
{
|
|
|
|
if ( !com_ports[i] )
|
|
|
|
{
|
|
|
|
com_devices[i] = Ref<DevCOMPort>();
|
|
|
|
continue;
|
|
|
|
}
|
2023-07-05 20:53:12 +00:00
|
|
|
char ttyname[TTY_NAME_MAX+1];
|
|
|
|
snprintf(ttyname, sizeof(ttyname), "com%zu", i);
|
|
|
|
Ref<DevCOMPort> com(
|
|
|
|
new DevCOMPort(slashdev->dev, 0, 0, 0660, com_ports[i], ttyname));
|
|
|
|
if ( !com )
|
2014-10-09 15:32:17 +00:00
|
|
|
PanicF("Unable to allocate device for COM port %zu", i);
|
2023-07-05 20:53:12 +00:00
|
|
|
com_devices[i] = com;
|
|
|
|
int interrupt = i == 1 || i == 3 ? Interrupt::IRQ4 : Interrupt::IRQ3;
|
|
|
|
com->Initialize(interrupt);
|
|
|
|
if ( LinkInodeInDir(&ctx, slashdev, ttyname, com) != 0 )
|
|
|
|
PanicF("Unable to link %s/%s to COM port driver.", devpath, ttyname);
|
2014-10-09 15:32:17 +00:00
|
|
|
}
|
2012-03-17 14:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace COM
|
|
|
|
} // namespace Sortix
|