diff options
| author | Javier <dev.git@javispedro.com> | 2026-08-29 17:45:02 +0200 |
|---|---|---|
| committer | Javier <dev.git@javispedro.com> | 2026-08-29 17:45:02 +0200 |
| commit | 003a26a76982f512e2f3a1108e46b88aa29ab306 (patch) | |
| tree | 6c508e3ee1fc995ed9e13ffc5075927ff94ed5fe | |
| parent | d25f344b9980c2d030f8388df84aaf8ff88d2591 (diff) | |
| download | vbados-003a26a76982f512e2f3a1108e46b88aa29ab306.tar.gz vbados-003a26a76982f512e2f3a1108e46b88aa29ab306.zip | |
split bda from int10vga.h , update kitten version to latest from freedos
| -rw-r--r-- | bda.h | 48 | ||||
| -rw-r--r-- | int10vga.h | 29 | ||||
| -rw-r--r-- | kitten.c | 869 | ||||
| -rw-r--r-- | kitten.h | 58 | ||||
| -rw-r--r-- | serial.h | 210 |
5 files changed, 669 insertions, 545 deletions
@@ -0,0 +1,48 @@ +#ifndef BDA_H +#define BDA_H + +#include "utils.h" + +#define BIOS_DATA_AREA_SEGMENT 0x40 + +static inline uint32_t bda_get_dword(unsigned int offset) { + uint32_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset); + return *p; +} + +static inline uint16_t bda_get_word(unsigned int offset) { + uint16_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset); + return *p; +} + +static inline uint8_t bda_get_byte(unsigned int offset) { + uint8_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset); + return *p; +} + +#define bda_get_ebda_segment() bda_get_word(0x0e) + +#define bda_get_video_mode() bda_get_byte(0x49) +#define bda_get_num_columns() bda_get_word(0x4a) +#define bda_get_video_page_size() bda_get_word(0x4c) +#define bda_get_cur_video_page() bda_get_word(0x62) +#define bda_get_last_row() bda_get_byte(0x84) +#define bda_get_char_height() bda_get_word(0x85) + +#define bda_get_tick_count() bda_get_dword(0x6c) +#define bda_get_tick_count_lo() bda_get_word(0x6c) + +static inline void bda_wait_tick() { + uint16_t cur_ticks = bda_get_tick_count_lo(); + do { + pause(); + } while (cur_ticks == bda_get_tick_count_lo()); +} + +static inline void bda_wait_ticks(unsigned int ticks) { + for (; ticks > 0; ticks--) { + bda_wait_tick(); + } +} + +#endif // BDA_H @@ -23,34 +23,7 @@ #include <stdint.h> #include <conio.h> -#define BIOS_DATA_AREA_SEGMENT 0x40 - -static inline uint32_t bda_get_dword(unsigned int offset) { - uint32_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset); - return *p; -} - -static inline uint16_t bda_get_word(unsigned int offset) { - uint16_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset); - return *p; -} - -static inline uint8_t bda_get_byte(unsigned int offset) { - uint8_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset); - return *p; -} - -#define bda_get_ebda_segment() bda_get_word(0x0e) - -#define bda_get_video_mode() bda_get_byte(0x49) -#define bda_get_num_columns() bda_get_word(0x4a) -#define bda_get_video_page_size() bda_get_word(0x4c) -#define bda_get_cur_video_page() bda_get_word(0x62) -#define bda_get_last_row() bda_get_byte(0x84) -#define bda_get_char_height() bda_get_word(0x85) - -#define bda_get_tick_count() bda_get_dword(0x6c) -#define bda_get_tick_count_lo() bda_get_word(0x6c) +#include "bda.h" enum videotype { VIDEO_UNKNOWN, @@ -19,155 +19,142 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef NO_KITTEN - -#include <stdio.h> /* sprintf */ -#ifndef _MICROC_ -#include <stdlib.h> /* getenv */ -#include <string.h> /* strchr */ -#include <dos.h> -#ifndef __PACIFIC__ +#include <stdio.h> /* sprintf */ +#include <stdlib.h> /* getenv */ +#include <string.h> /* strchr */ #include <fcntl.h> -#else -#define O_RDONLY 0 -#define O_TEXT 0 -#endif -#else -#include <intr.h> -#include <file.h> -#define O_RDONLY READONLY -#define O_TEXT 0 +#include <dos.h> +#if !defined(__TURBOC__) +#include <sys/stat.h> +#include <sys/types.h> #endif -/* assert we are running in small model */ -/* else pointer below has to be done correctly */ -/* char verify_small_pointers[sizeof(void*) == 2 ? 1 : -1]; */ #include "kitten.h" -char catcontents[8192]; +#if defined(__TURBOC__) +int dos_open(char *filename, int mode); +#define open(filename,mode) dos_open(filename,mode) -struct catstring -{ +int dos_read(int file, void *ptr, unsigned count); +#define read(file, ptr, count) dos_read(file,ptr,count) + +int dos_write(int file, void *ptr, unsigned count); +#define write(file, ptr, count) dos_write(file,ptr,count) + +void dos_close(int file); +#define close(file) dos_close(file) +#endif + +static char catcontents[6144]; /* *** Maximum size of PROGRAM.%LANG% file *** */ + +struct catstring{ char key1; char key2; char *text; }; -/* Micro-C does not support typedef */ -#define catstring_t struct catstring +typedef struct catstring catstring_t; -catstring_t catpoints[128]; +static catstring_t catpoints[128]; /* max 128 strings can be defined... */ /* Local prototypes */ -int catread (char *catfile); /* Reads a catfile into the hash */ -char *processEscChars (char *line); /* Converts c escape sequences to chars */ +int catread (char *catfile); /* Reads a catfile into the hash */ +char *processEscChars(char *line); /* Converts c escape sequences to chars */ -int get_char (int file); /* not meant for external use */ +int get_char(int); /* not meant for external use */ /* external use would cause consistency problems if */ /* value or related file of the file handle changes */ -int mystrtoul (char *src, int base, int size); +int mystrtoul(char *, int, int); /* Globals */ -nl_catd _kitten_catalog = 0; /* _kitten_catalog descriptor or 0 */ -char catfile[_MAX_PATH]; /* full path to _kitten_catalog */ - -char getlbuf[8192]; /* read buffer for better speed */ -char *getlp; /* current point in buffer */ -int getlrem = -1; /* remaining bytes in buffer */ -char lastcr = 0; /* for 2byte CR LF sequences */ +static nl_catd _kitten_catalog = 0; /* _kitten_catalog descriptor or 0 */ +static char catfile[128]; /* full path to _kitten_catalog */ +static char getlbuf[1024]; /* read buffer (better speed) -- 7/2004: 1k, not 8k */ +static char *getlp; /* current point in buffer */ +static int getlrem = -1; /* remaining bytes in buffer */ -#ifndef _MICROC_ -#ifndef __DJGPP__ +#if defined(__TURBOC__) /* DOS handle based file usage */ -int -dos_open (char *filename) +int dos_open(char *filename, int mode) { - union REGS r; - struct SREGS s; - - r.h.ah = 0x3d; - r.h.al = 0; /* read mode only supoported now !! */ - r.x.dx = FP_OFF (filename); - s.ds = FP_SEG (filename); - intdosx (&r, &r, &s); - return ((r.x.cflag) ? -1 : (int) r.x.ax); + union REGS r; + struct SREGS s; + (void)mode; /* mode ignored - readonly supported */ + r.h.ah = 0x3d; + r.h.al = 0; /* read mode only supoported now !! */ + r.x.dx = FP_OFF(filename); + s.ds = FP_SEG(filename); + intdosx(&r,&r,&s); + return ( (r.x.cflag) ? -1 : r.x.ax ); } -int -dos_read (int file, void *ptr, unsigned count) +int dos_read(int file, void *ptr, unsigned count) { - union REGS r; - struct SREGS s; - r.h.ah = 0x3f; - r.x.bx = file; - r.x.cx = count; - r.x.dx = FP_OFF (ptr); - s.ds = FP_SEG (ptr); - intdosx (&r, &r, &s); - return ((r.x.cflag) ? 0 : r.x.ax); + union REGS r; + struct SREGS s; + r.h.ah = 0x3f; + r.x.bx = file; + r.x.cx = count; + r.x.dx = FP_OFF(ptr); + s.ds = FP_SEG(ptr); + intdosx(&r,&r,&s); + return ( (r.x.cflag) ? 0 : r.x.ax ); } -int -dos_write (int file, void *ptr, unsigned count) +int dos_write(int file, void *ptr, unsigned count) { - union REGS r; - struct SREGS s; - r.h.ah = 0x40; - r.x.bx = file; - r.x.cx = count; - r.x.dx = FP_OFF (ptr); - s.ds = FP_SEG (ptr); - intdosx (&r, &r, &s); - return ((r.x.cflag) ? 0 : r.x.ax); + union REGS r; + struct SREGS s; + r.h.ah = 0x40; + r.x.bx = file; + r.x.cx = count; + r.x.dx = FP_OFF(ptr); + s.ds = FP_SEG(ptr); + intdosx(&r,&r,&s); + return ( (r.x.cflag) ? 0 : r.x.ax ); } -void -dos_close (int file) +void dos_close(int file) { - union REGS r; - r.h.ah = 0x3e; - r.x.bx = file; - intdos (&r, &r); + union REGS r; + r.h.ah = 0x3e; + r.x.bx = file; + intdos(&r,&r); } +#else +#include <unistd.h> +#endif + -#endif /*DJGPP*/ -#endif /*Micro-C */ /* Functions */ + /** * On success, catgets() returns a pointer to an internal * buffer area containing the null-terminated message string. * On failure, catgets() returns the value 'message'. */ -char * -kittengets (int setnum, int msgnum, char *message) + +const char *kittengets(int setnum, int msgnum, const char *message) { -/* In Micro-C, variables must be defined at the start of the - * function and may not be immediately assigned a value - */ -#ifdef _MICROC_ - int i; - i = 0; -#else - int i = 0; -#endif - while ((catpoints[i].key1 != setnum) || (catpoints[i].key2 != msgnum)) - { - if ((catpoints[i].text == NULL) || (i > 127)) /* at EOF */ - return message; - i++; - } + int i = 0; + + while ((catpoints[i].key1 != setnum) || (catpoints[i].key2 != msgnum)) { + if ((catpoints[i].text == NULL) || (i>127)) /* at EOF */ + return message; + i++; + } if (catpoints[i].text == NULL) return message; @@ -175,60 +162,39 @@ kittengets (int setnum, int msgnum, char *message) return (catpoints[i].text); } -/** - * Obtains path to current exec. - */ -static char * get_cmd_path(char *buf) -{ - char cmd_drive[_MAX_DRIVE]; - char cmd_dir[_MAX_DIR]; - - _splitpath(__argv[0], cmd_drive, cmd_dir, NULL, NULL); - _makepath(buf, cmd_drive, cmd_dir, "", NULL); - - return buf; -} - /** * Initialize kitten for program (name). */ -nl_catd -kittenopen (char *name) +nl_catd kittenopen(char *name) { /* catopen() returns a message _kitten_catalog descriptor * * of type nl_catd on success. On failure, it returns -1. */ - char catlang[3]; /* from LANG environment var. */ - char *nlsptr; /* ptr to NLSPATH */ - char *lang; /* ptr to LANG */ + char catlang[3]; /* from LANG environment var. */ + char *nlsptr; /* ptr to NLSPATH */ + char *lang; /* ptr to LANG */ int i; -#ifdef _MICROC_ - char *tok; - int toklen; -#endif - + /* Open the _kitten_catalog file */ /* The value of `_kitten_catalog' will be set based on catread */ - if (_kitten_catalog) - { /* Already one open */ - write (1, "cat already open\r\n", strlen ("cat already open\r\n")); - return (-1); - } + if (_kitten_catalog) { /* Already one open */ + write(1,"cat already open\r\n",strlen("cat already open\r\n")); + return (-1); + } - for (i = 0; i < 128; i++) + for (i=0; i<128; i++) catpoints[i].text = NULL; - if (strchr (name, '\\')) - { - /* unusual case: 'name' is a filename */ - write (1, "found \\\r\n", 9); - _kitten_catalog = catread (name); - if (_kitten_catalog) - return (_kitten_catalog); - } + if (strchr (name, '\\')) { + /* unusual case: 'name' is a filename */ + write(1,"found \\\r\n",9); + _kitten_catalog = catread (name); + if (_kitten_catalog) + return (_kitten_catalog); + } /* If the message _kitten_catalog file name does not contain a directory * * separator, then we need to try to locate the message _kitten_catalog. */ @@ -238,100 +204,79 @@ kittenopen (char *name) lang = getenv ("LANG"); - if (lang == NULL) - { - /* printf("no lang= found\n"); *//* not fatal, though */ + if (lang == NULL) { + /* printf("no lang= found\n"); */ /* not fatal, though */ /* Return failure - we won't be able to locate the cat file */ return (-1); - } + } - if ((strlen (lang) < 2) || ((strlen (lang) > 2) && (lang[2] != '-'))) - { + if ( ( strlen(lang) < 2 ) || + ( (strlen(lang) > 2) && (lang[2] != '-') ) ) { /* Return failure - we won't be able to locate the cat file */ return (-1); - } + } - memcpy (catlang, lang, 2); + memcpy(catlang, lang, 2); /* we copy the full LANG value or the part before "-" if "-" found */ catlang[2] = '\0'; - - /* first try to find catalog file in the same path as exe */ - get_cmd_path(catfile); - - strcat (catfile, name); - strcat (catfile, "."); - strcat (catfile, catlang); - _kitten_catalog = catread (catfile); - if (_kitten_catalog) - return (_kitten_catalog); - - - /* otherwise step through NLSPATH */ + /* step through NLSPATH */ nlsptr = getenv ("NLSPATH"); - if (nlsptr == NULL) - { - /* printf("no NLSPATH= found\n"); *//* not fatal either */ + if (nlsptr == NULL) { + /* printf("no NLSPATH= found\n"); */ /* not fatal either */ /* Return failure - we won't be able to locate the cat file */ return (-1); - } + } catfile[0] = '\0'; - while (nlsptr && nlsptr[0]) - { -#ifdef _MICROC_ - tok = strchr (nlsptr, ';'); -#else - char *tok = strchr (nlsptr, ';'); + while (nlsptr != NULL) { + char *tok = strchr(nlsptr, ';'); int toklen; -#endif if (tok == NULL) - toklen = strlen (nlsptr); /* last segment */ + toklen = strlen(nlsptr); /* last segment */ else - toklen = tok - nlsptr; /* segment terminated by ';' */ - + toklen = (int)(tok - nlsptr); /* segment terminated by ';' */ + /* catfile = malloc(toklen+1+strlen(name)+1+strlen(lang)+1); */ /* Try to find the _kitten_catalog file in each path from NLSPATH */ - if ((toklen + 6 + strlen (name)) > sizeof (catfile)) - { - write (1, "NLSPATH overflow\r\n", strlen ("NLSPATH overflow\r\n")); - return 0; /* overflow in NLSPATH, should never happen */ - } + if ((toklen+6+strlen(name)) > sizeof(catfile)) { + write(1,"NLSPATH overflow\r\n",strlen("NLSPATH overflow\r\n")); + return 0; /* overflow in NLSPATH, should never happen */ + } /* Rule #1: %NLSPATH%\%LANG%\cat */ - memcpy (catfile, nlsptr, toklen); - strcpy (catfile + toklen, "\\"); - strcat (catfile, catlang); - strcat (catfile, "\\"); - strcat (catfile, name); - _kitten_catalog = catread (catfile); - if (_kitten_catalog) - return (_kitten_catalog); + memcpy(catfile, nlsptr, toklen); + strcpy(catfile+toklen,"\\"); + strcat(catfile,catlang); + strcat(catfile,"\\"); + strcat(catfile,name); + _kitten_catalog = catread (catfile); + if (_kitten_catalog) + return (_kitten_catalog); /* Rule #2: %NLSPATH%\cat.%LANG% */ - /* memcpy(catfile, nlsptr, toklen); */ - strcpy (catfile + toklen, "\\"); - strcat (catfile, name); - strcat (catfile, "."); - strcat (catfile, catlang); - _kitten_catalog = catread (catfile); - if (_kitten_catalog) - return (_kitten_catalog); + /* memcpy(catfile, nlsptr, toklen); */ + strcpy(catfile+toklen,"\\"); + strcat(catfile,name); + strcat(catfile,"."); + strcat(catfile,catlang); + _kitten_catalog = catread (catfile); + if (_kitten_catalog) + return (_kitten_catalog); /* Grab next tok for the next while iteration */ - nlsptr = tok; - if (nlsptr) - nlsptr++; - - } /* while tok */ + nlsptr = tok; + if (nlsptr) nlsptr++; + + } /* while tok */ /* We could not find it. Return failure. */ @@ -343,115 +288,92 @@ kittenopen (char *name) * Load a message catalog into memory. */ -int -catread (char *catfile) +int catread (char *catfile) { - int file; /* pointer to the catfile */ - int i; - char *where; - char *tok; -#ifdef _MICROC_ - char *msg; - char *key; - int key1; - int key2; -#endif + int file; /* pointer to the catfile */ + int i; + char *where; + char *tok; /* Get the whole catfile into a buffer and parse it */ + + file = open (catfile, O_RDONLY); + if (file < 0) + /* Cannot open the file. Return failure */ + return 0; - file = open (catfile, O_RDONLY | O_TEXT); - if (file < 0) - /* Cannot open the file. Return failure */ - return 0; - - for (i = 0; i < 128; i++) + for (i=0; i<128; i++) catpoints[i].text = NULL; - for (i = 0; (unsigned int) i < sizeof (catcontents); i++) + for (i=0; i<sizeof(catcontents); i++) catcontents[i] = '\0'; /* Read the file into memory */ - i = read (file, catcontents, sizeof (catcontents) - 1); + i = read (file, catcontents, sizeof(catcontents)-1); - if ((i == sizeof (catcontents) - 1) || (i < 1)) - return 0; /* file was too big or too small */ + if ((i == sizeof(catcontents)-1) || (i < 1)) + return 0; /* file was too big or too small */ where = catcontents; - i = 0; /* catpoints entry */ + i = 0; /* catpoints entry */ - do - { -#ifndef _MICROC_ - char *msg; - char *key; - int key1 = 0; - int key2 = 0; -#else - key1 = 0; - key2 = 0; -#endif + do { + char *msg; + char *key; + int key1 = 0; + int key2 = 0; - tok = strchr (where, '\n'); + tok = strchr(where, '\n'); - if (tok == NULL) - { /* done? */ - close (file); - return 1; /* success */ - } - - tok[0] = '\0'; /* terminate here */ - tok--; /* guess: \r before \n */ - if (tok[0] != '\r') - tok++; /* if not, go back */ - else - { - tok[0] = '\0'; /* terminate here already */ - tok++; - } - tok++; /* this is where the next line starts */ - - if ((where[0] >= '0') && (where[0] <= '9') && - ((msg = strchr (where, ':')) != NULL)) - { - /* Skip everything which starts with # or with no digit */ - /* Entries look like "1.2:This is a message" */ - - msg[0] = '\0'; /* remove : */ - msg++; /* go past the : */ - - if ((key = strchr (where, '.')) != NULL) - { - key[0] = '\0'; /* turn . into terminator */ - key++; /* go past the . */ - key1 = mystrtoul (where, 10, strlen (where)); - key2 = mystrtoul (key, 10, strlen (key)); - - if ((key1 >= 0) && (key2 >= 0)) - { - catpoints[i].key1 = key1; - catpoints[i].key2 = key2; - catpoints[i].text = processEscChars (msg); - if (catpoints[i].text == NULL) /* ESC parse error */ - catpoints[i].text = msg; - i++; /* next entry! */ - } /* valid keys */ - - } /* . found */ - - } /* : and digit found */ - - where = tok; /* go to next line */ + if (tok == NULL) { /* done? */ + close(file); + return 1; /* success */ + } + tok[0] = '\0'; /* terminate here */ + tok--; /* guess: \r before \n */ + if (tok[0] != '\r') + tok++; /* if not, go back */ + else { + tok[0] = '\0'; /* terminate here already */ + tok++; } - while (1); -#ifdef __PACIFIC__ - return 0; -#endif + tok++; /* this is where the next line starts */ + + if ( (where[0] >= '0') && (where[0] <= '9') && + ( (msg = strchr(where,':')) != NULL) ) { + /* Skip everything which starts with # or with no digit */ + /* Entries look like "1.2:This is a message" */ + + msg[0] = '\0'; /* remove : */ + msg++; /* go past the : */ + + if ((key = strchr (where, '.')) != NULL) { + key[0] = '\0'; /* turn . into terminator */ + key++; /* go past the . */ + key1 = mystrtoul(where, 10, strlen(where)); + key2 = mystrtoul(key, 10, strlen(key)); + + if ((key1 >= 0) && (key2 >= 0)) { + catpoints[i].key1 = key1; + catpoints[i].key2 = key2; + catpoints[i].text = processEscChars(msg); + if (catpoints[i].text == NULL) /* ESC parse error */ + catpoints[i].text = msg; + i++; /* next entry! */ + } /* valid keys */ + + } /* . found */ + + } /* : and digit found */ + + where = tok; /* go to next line */ + + } while (1); } -void -kittenclose (void) +void kittenclose (void) { /* close a message _kitten_catalog */ _kitten_catalog = 0; @@ -464,46 +386,33 @@ kittenclose (void) * chars of the string are parsed. */ -int -mystrtoul (char *src, int base, int size) +int mystrtoul(char *src, int base, int size) { -#ifdef _MICROC_ - int ret; - int digit; - int ch; - ret = 0; -#else - int ret = 0; -#endif - - for (; size > 0; size--) - { -#ifdef _MICROC_ - ch = *src; -#else - int digit; - int ch = *src; -#endif - src++; - - if (ch >= '0' && ch <= '9') - digit = ch - '0'; - else if (ch >= 'A' && ch <= 'Z') - digit = ch - 'A' + 10; - else if (ch >= 'a' && ch <= 'z') - digit = ch - 'a' + 10; - else - return -1; - - if (digit >= base) - return -1; - - ret = ret * base + digit; - } /* for */ - - return ret; -} - + int ret = 0; + + for (; size > 0; size--) { + int digit; + int ch = *src; + src++; + + if (ch >= '0' && ch <= '9') + digit = ch - '0'; + else if (ch >= 'A' && ch <= 'Z') + digit = ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'z') + digit = ch - 'a' + 10; + else + return -1; + + if (digit >= base) + return -1; + + ret = ret * base + digit; + } /* for */ + + return ret; +} + /** * Process strings, converting \n, \t, \v, \b, \r, \f, \\, @@ -514,118 +423,95 @@ mystrtoul (char *src, int base, int size) * Returns a pointer to input string. */ -char * -processEscChars (char *line) +char *processEscChars(char *line) { + char *src = line; + char *dst = line; /* possible as dst is shorter than src */ + /* used when converting \xdd and \ddd (hex or octal) characters */ char ch; -#ifdef _MICROC_ - char *src; - char *dst; - int chx; - src = line; - dst = line; -#else - char *src = line; - char *dst = line; /* possible as dst is shorter than src */ -#endif if (line == NULL) return line; /* cycle through copying characters, except when a \ is encountered. */ - while (*src != '\0') - { - ch = *src; + while (*src != '\0') { + ch = *src; + src++; + + if (ch == '\\') { + ch = *src; /* what follows slash? */ src++; - if (ch == '\\') - { - ch = *src; /* what follows slash? */ - src++; - - switch (ch) - { - case '\\': /* a single slash */ - *dst = '\\'; - dst++; - break; - case 'n': /* a newline (linefeed) */ - *dst = '\n'; - dst++; - break; - case 'r': /* a carriage return */ - *dst = '\r'; - dst++; - break; - case 't': /* a horizontal tab */ - *dst = '\t'; - dst++; - break; - case 'v': /* a vertical tab */ - *dst = '\v'; - dst++; - break; - case 'b': /* a backspace */ - *dst = '\b'; - dst++; - break; - case 'a': /* alert */ - *dst = '\a'; - dst++; - break; - case 'f': /* formfeed */ - *dst = '\f'; - dst++; - break; - case 'x': /* extension supporting hex numbers \xdd or \x0dd */ - { -#ifdef _MICROC_ - chx = mystrtoul (src, 16, 2); /* get value */ -#else - int chx = mystrtoul (src, 16, 2); /* get value */ -#endif - if (chx >= 0) - { /* store character */ - *dst = chx; - dst++; - src += 2; - } - else /* error so just store x (loose slash) */ - { - *dst = *src; - dst++; - } - } - break; - default: /* just store letter (loose slash) or handle octal */ - { -#ifdef _MICROC_ - chx = mystrtoul (src, 8, 3); /* get value */ -#else - int chx = mystrtoul (src, 8, 3); /* get value */ -#endif - if (chx >= 0) - { /* store character */ - *dst = chx; - dst++; - src += 3; - } - else - { - *dst = *src; - dst++; - } - } - break; - } /* switch */ - } /* if backslash */ - else - { - *dst = ch; + switch (ch) { + case '\\': /* a single slash */ + *dst = '\\'; + dst++; + break; + case 'n': /* a newline (linefeed) */ + *dst = '\n'; + dst++; + break; + case 'r': /* a carriage return */ + *dst = '\r'; dst++; - } - } /* while */ + break; + case 't': /* a horizontal tab */ + *dst = '\t'; + dst++; + break; + case 'v': /* a vertical tab */ + *dst = '\v'; + dst++; + break; + case 'b': /* a backspace */ + *dst = '\b'; + dst++; + break; + case 'a': /* alert */ + *dst = '\a'; + dst++; + break; + case 'f': /* formfeed */ + *dst = '\f'; + dst++; + break; + case 'x': /* extension supporting hex numbers \xdd or \x0dd */ + { + int chx = mystrtoul(src, 16, 2); /* get value */ + if (chx >= 0) { /* store character */ + *dst = chx; + dst++; + src += 2; + } else /* error so just store x (loose slash) */ + { + *dst = *src; + dst++; + } + } + break; + default: /* just store letter (loose slash) or handle octal */ + { + int chx = mystrtoul(src, 8, 3); /* get value */ + if (chx >= 0) {/* store character */ + *dst = chx; + dst++; + src += 3; + } else + { + *dst = *src; + dst++; + } + } + break; + } /* switch */ + } /* if backslash */ + else + { + *dst = ch; + dst++; + } + } /* while */ /* ensure '\0' terminated */ *dst = '\0'; @@ -634,30 +520,21 @@ processEscChars (char *line) } -int -get_char (int file) -{ -#ifdef _MICROC_ - int rval; - rval = -1; -#else +int get_char(int file) { int rval = -1; -#endif - if (getlrem <= 0) - { /* (re)init buffer */ - getlrem = read (file, getlbuf, sizeof (getlbuf)); - if (getlrem <= 0) - return -1; /* fail: read error / EOF */ - getlp = getlbuf; /* init pointer */ - } + if (getlrem <= 0) { /* (re)init buffer */ + getlrem = read(file, getlbuf, sizeof(getlbuf)); + if (getlrem <= 0) + return -1; /* fail: read error / EOF */ + getlp = getlbuf; /* init pointer */ + } - if (getlrem > 0) - { /* consume byte from buffer */ - rval = getlp[0]; - getlp++; - getlrem--; - } + if (getlrem > 0) { /* consume byte from buffer */ + rval = getlp[0]; + getlp++; + getlrem--; + } return rval; } @@ -670,53 +547,85 @@ get_char (int file) * be used for 2 files at the same time. */ -int -get_line (int file, char *str, int size) +int get_line (int file, char *orig_str, int size) { int ch; -#ifdef _MICROC_ - int success; - success = 0; -#else - int success = 0; -#endif + char *str = orig_str; - if ((size == 0) || (str == NULL)) - { /* re-init get_line buffers */ - getlp = getlbuf; - getlrem = -1; - lastcr = 0; - return 0; - } + if ((size == 0) || (str == NULL)) { /* re-init get_line buffers */ + getlp = getlbuf; + getlrem = -1; + return 0; + } str[0] = '\0'; - while ((size > 0) && (success == 0)) - { - ch = get_char (file); - if (ch < 0) - break; /* (can cause fail if no \n found yet) */ + while (size > 0) { + ch = get_char (file); + if (ch < 0) { + /* encountered EOF / read error, so no more content*/ + str[0] = '\0'; + + /* test if the pointers are equal, there is not content in the buffer */ + if(str == orig_str) + return 0; /* fail, no more content */ + + return 1; /* success */ + } - if (ch == '\r') - ch = get_char (file); /* ignore \r */ + if (ch == '\r') + ch = get_char (file); /* ignore \r */ - str[0] = ch; + str[0] = ch; - if ((ch == '\n') || (ch == '\r')) - { /* done? */ - str[0] = '\0'; - return 1; /* success */ - } + if ( (ch == '\n') || (ch == '\r') || (ch < 0) ) { /* done? */ + str[0] = '\0'; + return 1; /* success */ + } - str++; - size--; + str++; + size--; - } /* while */ + } /* while */ - str[0] = '\0'; /* terminate buffer */ + str[0] = '\0'; /* terminate buffer */ - return success; + return 0; /* fail, because the line is longer than the buffer? */ } -#endif /*NO_KITTEN */ +/* + * input + * s : input string to be parsed + * delimiters : start, intermediate and end + * responses : output buffer (has to be long enough for num chars) + * num : required number of responses + * + * return + * 0 on failure + * 1 on success + */ +int kitten_extract_response(const char *s, const char *delimiters, + char *responses, int num) { + int slen = strlen(s); + const char *p, *q; + int i; + + /* Response parsing requires substring usually of the form '(%c/%c)' */ + p = strchr(s, delimiters[0]); + if (!p) + return 0; + + /* Each response requires letter followed by a delimiter e.g. 'Y/' or 'N)' */ + if (p + 1 - s > slen - 2 * num) + return 0; + + for (i = 0; i < num; i++) { + q = p + 2 + i * 2; + if (*q != delimiters[1] && *q != delimiters[2]) + return 0; + responses[i] = *(p + 1 + i * 2); + } + + return 1; +} @@ -24,57 +24,41 @@ #define _CATGETS_H #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif -#ifdef NO_KITTEN - -#define kittengets(x,y,z) (z) -#define kittenclose() -#define kittenopen(a) - -#else - /* Data types */ -#define nl_catd int +#if defined(__GNUC__) +typedef int __attribute__((used)) nl_catd; +#else +typedef int nl_catd; +#endif /* Functions */ - -#define catgets(catalog, set,message_number,message) kittengets(set,message_number,message) +#ifdef NOCATS /* #define NOCATS to disable completely */ +#define catgets(c,x,y,s) s +#define catopen(x,y) 1 +#define catclose(x) +#define _(x,y,s) s +#else +#define catgets(catalog,set,message_number,message) kittengets(set,message_number,message) #define catopen(name,flag) kittenopen(name) #define catclose(catalog) kittenclose() - #define _(set,message_number,message) kittengets(set,message_number,message) +#endif +const char *kittengets(int setnum, int msgnum, const char *message); +nl_catd kittenopen(char *name); +void kittenclose (void); - char *kittengets (int set_number, int message_number, char *message); - nl_catd kittenopen (char *name); - void kittenclose (void); - - int get_line (int file, char *buffer, int size); - -#ifndef _MICROC_ -#ifndef __DJGPP__ - - int dos_open (char *filename); -#define open(filename,mode) dos_open(filename) - - int dos_read (int file, void *ptr, unsigned count); -#define read(file, ptr, count) dos_read(file,ptr,count) - - int dos_write (int file, void *ptr, unsigned count); -#define write(file, ptr, count) dos_write(file,ptr,count) +int get_line (int file, char *buffer, int size); - void dos_close (int file); -#define close(file) dos_close(file) +int kitten_extract_response(const char *s, const char *delimiters, + char *responses, int num); -#endif /*DJGPP*/ -#endif /*Micro-C */ -#endif /*NO_KITTEN */ #ifdef __cplusplus } #endif -#endif /* _CATGETS_H */ +#endif /* _CATGETS_H */ diff --git a/serial.h b/serial.h new file mode 100644 index 0000000..beeaf50 --- /dev/null +++ b/serial.h @@ -0,0 +1,210 @@ +#ifndef SERIAL_H +#define SERIAL_H + +#include <stdint.h> + +#include "bda.h" + +enum SERIAL_UART_REGS { + SERIAL_TX = 0, + SERIAL_RX = 0, + /** (only with DLAB enabled) LSB of divisor/baud rate */ + SERIAL_DIVISOR_LO = 0, + /** (only with DLAB enabled) MSB of divisor/baud rate */ + SERIAL_DIVISOR_HI = 1, + /** Interrupt Enable Register(read/write) */ + SERIAL_IER = 1, + /** Fifo Control Register (write-only) */ + SERIAL_FCR = 2, + /** Interrupt Identification Register (read-only) */ + SERIAL_IIR = 2, + /** Line Control Register (read/write), contains DLAB bit */ + SERIAL_LCR = 3, + /** Modem Control Register (read/write) */ + SERIAL_MCR = 4, + /** Line Status Register (read-only) */ + SERIAL_LSR = 5, + /** Modem Status Register (read-only) */ + SERIAL_MSR = 6 +}; + +#if 0 +// Comes straight from https://wiki.osdev.org/Serial_Ports#Initialization +outp(DLOG_TARGET_PORT + 1, 0x00); // Disable all interrupts +outp(DLOG_TARGET_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) +outp(DLOG_TARGET_PORT + 0, 0x01); // Set divisor to 1 (lo byte) 115200 baud +outp(DLOG_TARGET_PORT + 1, 0x00); // (hi byte) +outp(DLOG_TARGET_PORT + 3, 0x03); // 8 bits, no parity, one stop bit +outp(DLOG_TARGET_PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold +outp(DLOG_TARGET_PORT + 4, 0x03); // RTS/DSR set, IRQs disabled +#endif + +enum SERIAL_DIVISOR { + SERIAL_DIVISOR_115200 = 1, + SEIRAL_DIVISOR_9600 = 12, + SERIAL_DIVISOR_1200 = 96 +}; + +enum SERIAL_FCR { + SERIAL_FCR_RX_TRIGER_1 = 0 << 6, + SERIAL_FCR_RX_TRIGER_4 = 1 << 6, + SERIAL_FCR_RX_TRIGER_8 = 2 << 6, + SERIAL_FCR_RX_TRIGER_14 = 3 << 6, + SERIAL_FCR_DMA_SEL = 1 << 3, + SERIAL_FCR_TX_RESET = 1 << 2, + SERIAL_FCR_RX_RESET = 1 << 1, + SERIAL_FCR_FIFO_ENABLE = 1 << 0, +}; + +enum SERIAL_LCR { + /** Word Length = 5 bits */ + SERIAL_LCR_WL_5 = 0, + SERIAL_LCR_WL_6 = 1, + SERIAL_LCR_WL_7 = 2, + SERIAL_LCR_WL_8 = 3, + /** STop Bit */ + SERIAL_LCR_STB = 1 << 2, + /** Parity ENable */ + SERIAL_LCR_PEN = 1 << 3, + /** Even Parity Select. */ + SERIAL_LCR_EPS = 1 << 4, + /** Stick Parity */ + SERIAL_LCR_SP = 1 << 5, + SERIAL_LCR_PAR_NONE = 0, + SERIAL_LCR_PAR_ODD = SERIAL_LCR_PEN, + SERIAL_LCR_PAR_EVEN = SERIAL_LCR_PEN | SERIAL_LCR_EPS, + SERIAL_LCR_PAR_MARK = SERIAL_LCR_PEN | SERIAL_LCR_SP, + SERIAL_LCR_PAR_SPACE = SERIAL_LCR_PEN | SERIAL_LCR_EPS | SERIAL_LCR_SP, + /** Set Break */ + SERIAL_LCR_SB = 1 << 6, + /** Divisor Latch Access Bit */ + SERIAL_LCR_DLAB = 1 << 7, +}; + +enum SERIAL_MCR { + SERIAL_MCR_DTR = 1 << 0, + SERIAL_MCR_RTS = 1 << 1, + SERIAL_MCR_OUT1 = 1 << 2, + SERIAL_MCR_OUT2 = 1 << 3, + SERIAL_MCR_LOOP = 1 << 4, +}; + +enum SERIAL_LSR { + /** Data Ready (i.e., data ready to be read) */ + SERIAL_LSR_DR = 1 << 0, + SERIAL_LSR_OE = 1 << 1, + SERIAL_LSR_PE = 1 << 2, + SERIAL_LSR_FE = 1 << 3, + SERIAL_LSR_BI = 1 << 4, + /** Transmitter Holding Register Empty (i.e. space to send data is available) */ + SERIAL_LSR_THRE = 1 << 5, + SERIAL_LSR_TEMT = 1 << 6, + SERIAL_LSR_RXERR = 1 << 7, +}; + +enum SERIAL_MSR { + SERIAL_MSR_DCD = 1 << 7, + SERIAL_MSR_RI = 1 << 6, + SERIAL_MSR_DSR = 1 << 5, + SERIAL_MSR_CTS = 1 << 4, + SERIAL_MSR_DDCD = 1 << 3, + SERIAL_MSR_TERI = 1 << 2, + SERIAL_MSR_DDSR = 1 << 1, + SERIAL_MSR_DCTS = 1 << 0 +}; + +struct serial_config +{ + uint8_t divisor_lo, divisor_hi; + uint8_t ier, lcr, mcr; +}; + +static unsigned serial_num_ports() +{ + uint8_t equipment = bda_get_byte(0x11); + uint8_t numports = (equipment & 0xE) >> 1; + return numports; +} + +static uint16_t serial_get_iobase(unsigned port) +{ + uint16_t bdaport = bda_get_word((port - 1) * 2); + if (bdaport > 10) { + return bdaport; + } else if (port == 1) { + // Even if BIOS says no, hardcode the basic COM1 port at least. + return 0x3F8; + } + return 0; +} + +static void serial_save_config(unsigned iobase, struct serial_config *config) +{ + config->ier = inp(iobase + SERIAL_IER); + config->lcr = inp(iobase + SERIAL_LCR); + config->mcr = inp(iobase + SERIAL_MCR); + // Set DLAB so that we can read divisor + outp(iobase + SERIAL_LCR, config->lcr | SERIAL_LCR_DLAB); + config->divisor_lo = inp(iobase + SERIAL_DIVISOR_LO); + config->divisor_hi = inp(iobase + SERIAL_DIVISOR_HI); + // Restore DLAB to whatever it was + outp(iobase + SERIAL_LCR, config->lcr); +} + +static void serial_restore_config(unsigned iobase, const struct serial_config *config) +{ + outp(iobase + SERIAL_LCR, config->lcr | SERIAL_LCR_DLAB); + outp(iobase + SERIAL_DIVISOR_LO, config->divisor_lo); + outp(iobase + SERIAL_DIVISOR_HI, config->divisor_hi); + outp(iobase + SERIAL_LCR, config->lcr); + outp(iobase + SERIAL_MCR, config->mcr); + outp(iobase + SERIAL_IER, config->ier); +} + +static void serial_configure(unsigned iobase, uint16_t divisor, uint8_t lcr) +{ + outp(iobase + SERIAL_IER, 0); // Disable all interrupts + outp(iobase + SERIAL_LCR, SERIAL_LCR_DLAB); // Enable DLAB and clear all other flags + outp(iobase + SERIAL_DIVISOR_LO, divisor); + outp(iobase + SERIAL_DIVISOR_HI, divisor >> 8); + outp(iobase + SERIAL_LCR, lcr); // This also disables DLAB + // Enable and reset both FIFOs + outp(iobase + SERIAL_FCR, SERIAL_FCR_RX_TRIGER_14|SERIAL_FCR_FIFO_ENABLE|SERIAL_FCR_RX_RESET|SERIAL_FCR_TX_RESET); +} + +static inline void serial_set_modem_control(unsigned iobase, uint8_t mcr) +{ + outp(iobase + SERIAL_MCR, mcr); +} + +static inline void serial_set_modem_status(unsigned iobase, uint8_t msr) +{ + outp(iobase + SERIAL_MSR, msr); +} + +static inline uint8_t serial_get_line_status(unsigned iobase) +{ + return inp(iobase + SERIAL_LSR); +} + +static inline bool serial_data_ready(unsigned iobase) +{ + return serial_get_line_status(iobase) & SERIAL_LSR_DR; +} + +static inline uint8_t serial_read_data(unsigned iobase) +{ + return inp(iobase + SERIAL_RX); +} + +static inline bool serial_tx_ready(unsigned iobase) +{ + return serial_get_line_status(iobase) & SERIAL_LSR_THRE; +} + +static inline void serial_send_data(unsigned iobase, uint8_t data) +{ + outp(iobase + SERIAL_TX, data); +} + +#endif // SERIAL_H |
