/* -*- c -*- ------------------------------------------------------------- * * * Copyright 2004 Murali Krishnan Ganapathy - All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, Inc., 53 Temple Place Ste 330, * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ #include "string.h" #include "biosio.h" /* * Note: don't use "r" or "g" for 8-bit values. Some versions of gcc * will actually try to generate x86-64 registers that way! Use * "abcd" or "abcdmi", respectively. Newer gccs have the newer "q" * and "Q" constraints, but older gccs don't know those. */ /* BIOS Assisted output routines */ void bios_int10(void) { asm volatile("pushl %ebp ; int $0x10 ; popl %ebp"); } /* Print character and attribute at cursor */ static inline void asm_cprint(char chr, char attr, int times, char disppage) { asm volatile("movb $0x09,%%ah ; call bios_int10" : "+a" (chr) : "b" (attr + (disppage << 8)), "c" (times)); } void cprint(char chr,char attr,int times,char disppage) { asm_cprint(chr,attr,times,disppage); } static inline void asm_setdisppage(char num) { asm volatile("movb $0x05,%%ah ; call bios_int10" : "+a" (num)); } void setdisppage(char num) // Set the display page to specified number { asm_setdisppage(num); } static inline char asm_getdisppage(void) { char page; asm("movb $0x0f,%%ah ; " "call bios_int10 ; " "movb %%bh,%0" : "=abcdm" (page) : : "eax"); return page; } char getdisppage() // Get current display page { return asm_getdisppage(); } static inline void asm_getpos(char *row, char *col, char page) { asm("movb %2,%%bh ; " "movb $0x03,%%ah ; " "call bios_int10 ; " "movb %%dh,%0 ; " "movb %%dl,%1" : "=m" (*row), "=m" (*col) : "abcdmi" (page) : "eax", "ebx", "ecx", "edx"); } void getpos(char * row, char * col, char page) { asm_getpos(row,col,page); } static inline void asm_gotoxy(char row,char col, char page) { asm volatile("movb %1,%%bh ; " "movb $0x02,%%ah ; " "call bios_int10" : : "d" ((row << 8) + col), "abcdmi" (page) : "eax", "ebx"); } void gotoxy(char row,char col, char page) { asm_gotoxy(row,col,page); } static inline unsigned char asm_sleep(unsigned int milli) { // ah = 86, int 15, cx:dx = microseconds // mul op16 : dx:ax = ax * op16 unsigned char ans; asm volatile ("mul %%cx; " "xchg %%dx, %%ax; " "movw %%ax, %%cx; " "movb $0x86, %%ah;" "int $0x15;" "setnc %0" : "=r" (ans) : "a" (milli), "c" (1000) : "edx"); return ans; } unsigned char sleep(unsigned int msec) { return asm_sleep(msec); } void asm_beep() { // For a beep the page number (bh) does not matter, so set it to zero asm volatile("movw $0x0E07, %%ax;" "xor %%bh,%%bh;" "call bios_int10" : : : "eax","ebx"); } void beep() { asm_beep(); } static inline void asm_putchar(char x, char attr,char page) { asm volatile("movb %1,%%bh;" "movb %2,%%bl;" "movb $0x09,%%ah;" "movw $0x1, %%cx;" "call bios_int10" : "+a" (x) : "abcdmi" (page), "acdmi" (attr) : "ebx", "ecx", "ebp"); } void putch(char x, char attr, char page) { asm_putchar(x,attr,page); } void scrollup() { unsigned short dx = (getnumrows()<< 8) + getnumcols(); asm volatile("movw $0x0601, %%ax;" "movb $0x07, %%bh;" "xor %%cx, %%cx;" "call bios_int10" : "+d" (dx) : : "eax","ebx","ecx"); } /* Print a C string (NUL-terminated) */ void csprint(const char *str,char attr) { char page = asm_getdisppage(); char newattr=0,cha,chb; char row,col; asm_getpos(&row,&col,page); while ( *str ) { switch (*str) { case '\b': --col; break; case '\n': ++row; break; case '\r': col=0; break; case BELL: // Bell Char asm_beep(); break; case CHRELATTR: // change attribute (relatively) case CHABSATTR: // change attribute (absolute) cha = *(str+1); chb = *(str+2); if ((((cha >= '0') && (cha <= '9')) || ((cha >= 'A') && (cha <= 'F'))) && (((chb >= '0') && (chb <= '9')) || ((chb >= 'A') && (chb <= 'F')))) // Next two chars are legal { if ((cha >= 'A') && (cha <= 'F')) cha = cha - 'A'+10; else cha = cha - '0'; if ((chb >= 'A') && (chb <= 'F')) chb = chb - 'A'+10; else chb = chb - '0'; newattr = (cha << 4) + chb; attr = (*str == CHABSATTR ? newattr : attr ^ newattr); str += 2; // Will be incremented again later } break; default: asm_putchar(*str, attr, page); ++col; } if (col > getnumcols()) { ++row; col=0; } if (row > getnumrows()) { scrollup(); row= getnumrows(); } asm_gotoxy(row,col,page); str++; } } void clearwindow(char top, char left, char bot, char right, char page, char fillchar, char fillattr) { char x; for (x=top; x < bot+1; x++) { gotoxy(x,left,page); asm_cprint(fillchar,fillattr,right-left+1,page); } } void cls(void) { gotoxy(0,0,getdisppage()); asm_cprint(' ',0x07,getnumrows()*getnumcols(),getdisppage()); } char asm_inputc(char *scancode) { unsigned short ax; asm volatile("movb $0x10,%%ah ; " "int $0x16" : "=a" (ax)); if (scancode) *scancode = (ax >> 8); return (char)ax; } char inputc(char * scancode) { return asm_inputc(scancode); } static inline void asm_cursorshape(char start, char end) { asm volatile("movb $0x01,%%ah ; int $0x10" : : "c" ((start << 8) + end) : "eax"); } void cursoroff(void) { asm_cursorshape(32,32); } void cursoron(void) { asm_cursorshape(6,7); } char bkspstr[] = " \b$"; char eolstr[] = "\n$"; static inline char asm_getchar(void) { char v; /* Get key without echo */ asm("movb $0x08,%%ah ; int $0x21" : "=a" (v)); return v; } #define GETSTRATTR 0x07 // Reads a line of input from stdin. Replace CR with NUL byte void getstring(char *str, unsigned int size) { char c; char *p = str; char page = asm_getdisppage(); char row,col; while ( (c = asm_getchar()) != '\r' ) { switch (c) { case '\0': /* Extended char prefix */ asm_getchar(); /* Drop */ break; case '\b': if ( p > str ) { p--; csprint("\b \b",GETSTRATTR); } break; case '\x15': /* Ctrl-U: kill input */ while ( p > str ) { p--; csprint("\b \b",GETSTRATTR); } break; default: if ( c >= ' ' && (unsigned int)(p-str) < size-1 ) { *p++ = c; asm_getpos(&row,&col,page); asm_putchar(c, GETSTRATTR, page); asm_gotoxy(row,col+1,page); } break; } } *p = '\0'; csprint("\r\n",GETSTRATTR); } static inline void asm_setvideomode(char mode) { /* This BIOS function is notoriously register-dirty, so push/pop around it */ asm volatile("pushal ; xorb %%ah,%%ah ; int $0x10 ; popal" : : "a" (mode) ); } void setvideomode(char mode) { asm_setvideomode(mode); } static inline unsigned char asm_checkkbdbuf() { unsigned char ans; asm volatile("movb $0x11, %%ah;" "int $0x16 ;" "setnz %0;" : "=abcdm" (ans) : : "eax"); return ans; } unsigned char checkkbdbuf() { return asm_checkkbdbuf(); } void clearkbdbuf() { while (asm_checkkbdbuf()) asm_inputc(NULL); }