#include <kernel/kernel.h> #include <kernel/serial.h> #define PIC PORT_8259M #define PICM (PORT_8259M + 1) /* ;; *********************************************************** ;; ISR Service Jump Table ;; *********************************************************** ISR_Service dd offset ISR_Exit ;; xxxxx00xb dd offset ISR_Transmit ;; xxxxx01xb dd offset ISR_Receive ;; xxxxx10xb dd offset ISR_Exit ;; xxxxx11xb */ /* ;; *********************************************************** ;; Register Indexes for the 8250 UART ;; NOTE: Indexes have been multiplied by 2 to get the ;; correct location in the register table. ;; *********************************************************** */ #define THR 0 // Transmit Holding Register (DLAB==0) #define RBR 0 // Recieve Buffer Register (DLAB==0) #define BAUDL 0 // Baud Rate Divisor, Low byte (DLAB==1) #define BAUDH 1 // Baud Rate Divisor, High Byte (DLAB==1) #define IER 1 // Interrupt Enable Register #define IIR 2 // Interrupt Identification Register #define FCR 2 // FIFO Control Register (UARTS 16550+) #define LCR 3 // Line Control Register #define MCR 4 // Modem Control Register #define LSR 5 // Line Status Register #define MSR 6 // Modem Status Register /* ;; *********************************************************** ;; COMM Routine Variables ;; *********************************************************** */ /* ;; *********************************************************** ;; Multi-Port Asynchronous Variables (later version) ;; *********************************************************** */ typedef struct serial_t serial_t; struct serial_t { word Base; // Port Base byte IRQ; // Port IRQ byte Flags; // Port Bit-Flags }; #define UART 0x3 // UART Flags #define MODE 0xc // Port Mode serial_t PortTable; // Single Port Routines dword PortCode; // Port Used Bit-Field (1-used) /* ;; *********************************************************** ;; Variables set by ioOpenPort() ;; *********************************************************** */ word PortInUse = 0xff; // Initialized COMM port flag word Port; // Port Base Address word Registers[7]; // Register Index Map byte Vector; // Vector Number byte EnableIRQ; // Mask to enable 8259 IRQ byte DisableIRQ; // Mask to disable 8259 IRQ word ISR_OldS; // Old Vector Segment dword ISR_OldO; // Old Vector Offset /* ;; *********************************************************** ;; Send and Receive Buffers ;; NOTE: The buffer sizes (SendSize & RecvSize) must be of a ;; size X such that log2(X+1)=Integer. In otherwords, ;; take a power of 2, subtract one, and that is a legal ;; buffer size. (1, 3, 7, 15, 31, 63, 127 ... 2^X-1) ;; *********************************************************** */ /*#define SendSize 4095 // 2^X-1 Send Buffer Size (4095) byte SendBuffer[SendSize]; // Send FIFO Buffer word SendHead; // Send FIFO Buffer Head Index word SendTail; // Send FIFO Buffer Tail Index #define RecvSize 4095 // 2^X-1 Receive Buffer Size (4095) byte RecvBuffer[RecvSize]; // Receive FIFO Buffer word RecvHead; // Receive FIFO Buffer Head Index word RecvTail; // Receive FIFO Buffer Tail Index bool in_serial_isr;*/ //;; ************************************************************************ //;; ** C O D E 3 2 ****************************************************** /* ;; *********************************************************** ;; Routines callable from Watcom C/C++ 32 ;; *********************************************************** PUBLIC ioOpenPort_, ioClosePort_ ;; Set/Reset Serial I/O PUBLIC ioClearWrite_, ioClearRead_ ;; Reset Serial Buffers PUBLIC ioReadByte_, ioWriteByte_ ;; I/O with Serial Port PUBLIC ioReadStatus_, ioWriteStatus_ ;; Check I/O Status PUBLIC ioGetBaud_, ioSetBaud_ ;; Get/Set Baud Rate PUBLIC ioSetHandShake_, ioGetHandShake_ ;; Get/Set Hand Shaking PUBLIC ioGetStatus_ ;; Get Modem/Line Status PUBLIC ioGetControl_, ioSetControl_ ;; Get/Set Line Control PUBLIC ioGetMode_, ioSetMode_ ;; Get/Set ISR Mode */ int ioGetMode(COMM address) { return 0; } int ioSetMode(COMM address, int mode) { return 0; } /* ;; ************************************************************************ ;; Interrupt Service Routine for Serial I/O (in protected mode) ;; ************************************************************************ */ /* void serial_isr(dword context, int irq) { byte intr, state; in_serial_isr = true; out(0x21, in(0x21) | ~0xef); //do //{ intr = (in(Registers[IIR]) & 6) >> 1; wprintf(L"serial_isr: %x\n", intr); switch (intr) { case 0: // nothing case 3: state = in(Registers[IER]); //wprintf(L"state = %x ", state); out(Registers[IER], 0); //_cputws(L"out(0) "); out(Registers[IER], state); //_cputws(L"out(state)\n"); goto finished; case 1: // transmit if (SendHead == SendTail) { out(Registers[IER], in(Registers[IER]) & 0xFD); goto finished; } else { wprintf(L"transmit: %c\n", SendBuffer[SendTail]); out(Registers[THR], SendBuffer[SendTail]); SendTail = (SendTail + 1) & SendSize; } break; case 2: // receive RecvBuffer[RecvHead] = in(Registers[RBR]); if (((RecvHead + 1) & RecvSize) != RecvTail) RecvHead = (RecvHead + 1) & RecvSize; break; } //} while ((in(Registers[IIR]) & 1) == 0); finished: _cputws(L"finish: "); out(Registers[MCR], in(Registers[MCR]) | 8); out(Registers[IER], 1); out(0x21, in(0x21) & 0xef); _cputws(L"done\n"); in_serial_isr = false; } */ /* ;; ************************************************************************ ;; int ioOpenPort(int BASE, int IRQ); ;; PURPOSE: Initializes COMM port and sets up the ISR for it. ;; PASS: BASE = EDX, IRQ = ECX ;; Defaults are: ;; COM1 = 03F8h 4 (INT 0Ch) ;; COM2 = 02F8h 3 (INT 0Bh) ;; COM3 = 03E8h 4 (INT 0Ch) ;; COM4 = 02E8h 3 (INT 0Bh) ;; RETURNS: Returns a Port ID Structure Address for use when these ;; routines are multi-port based. ;; 0 Failure | > 0 Success ;; ************************************************************************ */ COMM ioOpenPort(int base, int irq) { int i; /* ;; *********************************************************** ;; Check to see if COM Routines installed ;; *********************************************************** */ if (!PortInUse) return 0; /* ;; *********************************************************** ;; Verify that all passed info is good ;; *********************************************************** */ if (irq < 0 || irq >= 8) return 0; /* ;; *********************************************************** ;; Set up COMM variables ;; *********************************************************** */ PortInUse = true; Port = base; //Vector = irq + 8; //DisableIRQ = 1 << irq; //EnableIRQ = ~DisableIRQ; /* ;; *********************************************************** ;; Set up the Register Port Indexes ;; *********************************************************** */ for (i = 6; i > 0; i--) Registers[i] = base + i; /* ;; *********************************************************** ;; Initialize the Read/Write Buffers ;; *********************************************************** */ ioClearWrite(NULL); ioClearRead(NULL); /* ;; *********************************************************** ;; Install the ISR ;; *********************************************************** */ //sysRegisterIrq(irq, serial_isr, 0); //out(Registers[MCR], in(Registers[MCR]) | 8); //out(Registers[LCR], in(Registers[LCR]) & 0x7F); //out(Registers[IER], 1); /* ;; *********************************************************** ;; Clear the buffers again, just in case . . . ;; *********************************************************** */ //ioClearWrite(NULL); //ioClearRead(NULL); /* ;; *********************************************************** ;; Exit with grace . . . ;; *********************************************************** */ PortCode = (dword) &PortTable; return (COMM) &PortTable; } /* ;; ************************************************************************ ;; int ioClosePort(COMM Address); ;; PURPOSE: Shuts off the COMM port and resets the ISR for it. ;; PASS: Address = EAX Address of the PortID structure ;; RETURNS: -1 Failure | 0 Success ;; ;; NOTE: In this release, the passed address does nothing (no multi port). ;; ************************************************************************ */ int ioClosePort(COMM address) { /* ;; *********************************************************** ;; First, make sure there is a COMM port initialized ;; *********************************************************** */ if (!PortInUse) return -1; /* ;; *********************************************************** ;; Shut off the 8259 IRQ ;; *********************************************************** @@: in al,PICM ;; Fetch PIC Mask or al,DisableIRQ ;; : Toggle OFF the ISR's IRQ line out PICM,al ;; : */ /* ;; *********************************************************** ;; Disable the 8250 Interrupt (DLAB clear perhaps before this) ;; *********************************************************** */ out(Registers[IER], 0); out(Registers[MCR], in(Registers[MCR]) & 0xF7); /* ;; *********************************************************** ;; ISR is disabled, so reset old ISR Vector ;; *********************************************************** */ //sysRegisterIrq(Vector, NULL, 0); PortInUse = false; return 0; } /* ;; ************************************************************************ ;; void ioClearRead(COMM Address); ;; PASS: EAX = Address Address of the PortID Structure ;; PURPOSE: Clears the Read buffer ;; ;; NOTE: In this release, the passed address does nothing (no multi port). ;; ************************************************************************ */ void ioClearRead(COMM address) { //disable(); //RecvHead = RecvTail = 0; //enable(); } /* ;; ************************************************************************ ;; void ioClearWrite(COMM Address); ;; PASS: EAX = Address Address of the PortID Structure ;; PURPOSE: Clears the Write buffer ;; ;; NOTE: In this release, the passed address does nothing (no multi port). ;; ************************************************************************ */ void ioClearWrite(COMM address) { //disable(); //SendHead = SendTail = 0; //enable(); } /* ;; ************************************************************************ ;; char ioReadByte(COMM Address); ;; PURPOSE: Fetches a byte from the Read buffer. ;; PASS: EAX = Address Address of PortID Structure ;; RETURNS: duh.... If buffer is empty, then it returns NUL, else ... ;; ;; NOTE: Blah!!!! ;; ************************************************************************ */ char ioReadByte(COMM address) { //byte data; //if (RecvHead == RecvTail) //return 0; //data = RecvBuffer[RecvTail]; //RecvTail = (RecvTail + 1) & RecvSize; //return data; return in(Registers[RBR]); } /* ;; ************************************************************************ ;; char int ioWriteByte(COMM Address, char byte); ;; PURPOSE: Places a byte into the Send buffer. ;; PASS: Address = EAX, BYTE = ECX ;; RETURNS: !0 = Success | 0 == Failure (buffer full) ;; ;; NOTE: Same old thang . . . get the next version for multi-port. ;; ************************************************************************ */ int ioWriteByte(COMM address, char data) { /* ;; *********************************************************** ;; Check if buffer is FULL ;; *********************************************************** */ //if (((SendHead + 1) & SendSize) == SendTail || //in_serial_isr) //return 0; //SendBuffer[SendHead] = data; //SendHead = (SendHead + 1) & SendSize; /* ;; *********************************************************** ;; Enable the THRE Interrupt ;; *********************************************************** */ //out(Registers[IER], in(Registers[IER]) | 2); out(Registers[THR], data); return -1; } /* ;; ************************************************************************ ;; int ioReadStatus(COMM Address); ;; PURPOSE: Reports the number of bytes in the Receive Buffer ;; PASS: You know the number by now . . . ;; RETURNS: Number of bytes in buffer ;; ************************************************************************ */ int ioReadStatus(COMM address) { /*if (RecvHead >= RecvTail) return RecvHead - RecvTail; else return RecvHead - RecvTail + RecvSize;*/ return 0; } /* ;; ************************************************************************ ;; int ioWriteStatus(); ;; PURPOSE: Reports the number of bytes in the Send Buffer ;; PASS: Blah . . . ;; RETURNS: Number of bytes in buffer ;; ************************************************************************ */ int ioWriteStatus(COMM address) { /*if (SendHead >= SendTail) return SendHead - SendTail; else return SendHead - SendTail + SendSize;*/ return 0; } /* ;; ************************************************************************ ;; void void ioSetBaud(COMM Address, int BAUD); ;; PURPOSE: Set the BAUD rate for the initialized port. ;; PASS: Address = EAX, BAUD = EBX ;; RATES: 150, 300, 600, 1200, 2400, 4800, 9600, ;; 19200, 28800, 38400, 57600, 115200 ;; ************************************************************************ */ void ioSetBaud(COMM address, int baud) { byte divisor; if (baud == 0) return; divisor = 115200 / baud; //disable(); out(Registers[LCR], in(Registers[LCR]) | 0x80); out(Registers[BAUDL], divisor % 256); out(Registers[BAUDH], divisor / 256); out(Registers[LCR], in(Registers[LCR]) & 0x7F); //enable(); } /* ;; ************************************************************************ ;; int ioGetBaud(COMM Address); ;; PURPOSE: Get the BAUD rate from the initialized port. ;; PASS: Address = EAX ;; RETURNS: BAUD Rate = EAX ;; ************************************************************************ */ int ioGetBaud(COMM address) { word divisor; //disable(); out(Registers[LCR], in(Registers[LCR]) | 0x80); divisor = in(Registers[BAUDL]) | in(Registers[BAUDH]) << 8; out(Registers[LCR], in(Registers[LCR]) & 0x7F); //enable(); if (divisor == 0) return 0; return 115200 / divisor; } /* ;; ************************************************************************ ;; void ioSetHandShake(COMM Address, int HAND); ;; PURPOSE: Set various handshaking lines. ;; PASS: Address = ECX, HAND = EAX ;; Bit fields are: ;; (80h) (40h) (20h) (10h) (08h) (04h) (02h) (01h) ;; Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 ;; 0 0 0 Loop OUT2 OUT1 RTS DTR ;; ************************************************************************ */ void ioSetHandShake(COMM address, int hand) { out(Registers[MCR], (byte) hand | 8); } /* ;; ************************************************************************ ;; int ioGetHandShake(COMM Address); ;; PURPOSE: Get current handshaking status. ;; PASS: ... ;; RETURNS: Handshaking bitfield (See SetHandShake() for field info) ;; ************************************************************************ */ int ioGetHandShake(COMM address) { return in(Registers[MCR]); } /* ;; ************************************************************************ ;; int ioGetStatus(COMM Address); ;; PURPOSE: Fetches Modem/Line Status Register ;; RETURNS: Upper 8-bits==MSR & Lower 8-bits==LSR ;; ************************************************************************ */ int ioGetStatus(COMM address) { return in(Registers[MSR]) << 8 | in(Registers[LSR]); } /* ;; ************************************************************************ ;; int GetControl(COMM Address); ;; PURPOSE: Fetches Line Control Register ;; PASS: Blah blah blah. Give me money and I'll let u pass sometin. ;; RETURNS: Lower 8-bits==LCR ;; ************************************************************************ */ int ioGetControl(COMM address) { return in(Registers[LCR]) & 0xf; } /* ;; ************************************************************************ ;; void ioSetControl(COMM Address, int Control); ;; PURPOSE: Sets the Line Control Register ;; PASS: ECX = Address, Control = Lower 8-bits==LCR = EAX ;; ************************************************************************ */ void ioSetControl(COMM address, int control) { out(Registers[LCR], (byte) control & 0x7F); } int ioWriteBuffer(COMM address, const void* buf, size_t len) { size_t i; for (i = 0; i < len; i++) if (ioWriteByte(address, ((const byte*) buf)[i]) == 0) return 0; return -1; }