Files
net/dev/nsserial/nsserial.c
2026-01-06 15:51:03 -08:00

132 lines
3.1 KiB
C

#include <stddef.h>
#include <stdint.h>
#include <exec/list.h>
#include <exec/sync.h>
#include <exec/task.h>
#include <exec/port.h>
#include <exec/device.h>
#include <exec/debcon.h>
#define STACK_SIZE 512
struct NS8250_Unit {
struct Unit unit;
uint16_t io_base;
uint8_t irq;
struct Semaphore mutex;
};
static const int COM_IO_BASES[3] = {0x3F8, 0x2F8, 0x3E8};
static const int COM_IRQS[3] = {4, 3, 4};
static struct NS8250_Unit units[3] = {0};
static Signals wait_mask = 0;
static uint32_t nop(void) { return 0; }
static uint32_t PCLPT_OpenDevice(void *_IExec, struct Device *dev, uint32_t unitNumber, struct IORequest *ior, uint32_t flags) {
if (unitNumber > 2) return ODE_BADUNIT;
ior->unit = &units[unitNumber].unit;
return 0;
}
uint32_t PCLPT_BeginIO(struct IORequest *ior);
static struct DevFuncTable pclpt_functable = {
.open = PCLPT_OpenDevice,
.close = nop,
.expunge = nop,
.null = nop,
.beginio = PCLPT_BeginIO,
.abortio = nop
};
static struct Device pclpt_device = {
.library = {
.node = {
.name = "nsserial.device"
},
.vectors = (uintptr_t *)&pclpt_functable
}
};
static void WriteChars(uint8_t *data, uint32_t reqlen, uint16_t ioBase) {
for (int i = 0; i < reqlen; i++) {
/* busy */
while (!(inb(ioBase + 1) & 0x80));
/* output data */
outb(ioBase, data[i]);
/* strobe */
uint8_t c = inb(ioBase + 2);
outb(ioBase + 2, c | 1);
for (int j = 0; j < 0x10000; j++);
outb(ioBase + 2, c);
}
}
static void Dispatch(struct IOStdReq *sir) {
struct PCLPT_Unit *unit = (struct PCLPT_Unit *)sir->ior.unit;
Acquire(&unit->mutex);
switch (sir->ior.command) {
case CMD_WRITE:
WriteChars(sir->data, sir->reqlen, unit->io_base);
sir->reslen = sir->reqlen;
sir->ior.error = DS_OK;
break;
default:
sir->ior.error = DS_BADFUN;
break;
}
Release(&unit->mutex);
ReplyMsg(&sir->ior.message);
}
static void Task(void) {
struct IOStdReq *sir;
DebconPrint("PCLPT.device initialized\n");
for (;;) {
sir = NULL;
for (;;) {
for (int i = 0; i < 3; i++) {
if ((sir = (struct IOStdReq *)GetMsg(&units[i].unit.port)) != NULL) {
goto got_msg;
}
}
Wait(wait_mask);
};
got_msg:
Dispatch(sir);
}
}
uint32_t PCLPT_BeginIO(struct IORequest *ior) {
if (ior->flags & IOF_QUICK) {
Dispatch((struct IOStdReq *)ior);
return 0;
} else {
PutMsg(&ior->unit->port, &ior->message);
return 0;
}
}
void PCLPT_Init(void) {
struct Task *t = CreateTask("LPT.device", 0, (uintptr_t)Task, STACK_SIZE);
for (int i = 0; i < 3; i++) {
/* port */
NewPort(&units[i].unit.port, 0);
units[i].unit.port.signal_task = t;
units[i].unit.port.signal_bit = SIGNAL_MY_BASE + i;
wait_mask |= SIGNAL(units[i].unit.port.signal_bit);
/* units */
/* mutex */
NewMutex(&units[i].mutex, SF_BLOCK);
}
AddDevice(&pclpt_device);
}