132 lines
3.1 KiB
C
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);
|
|
} |