1 /* 2 * ----------------------------------------------------------------------- 3 * 4 * Copyright 1994-2008 H. Peter Anvin - All Rights Reserved 5 * Copyright 2009-2014 Intel Corporation; author: H. Peter Anvin 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, Inc., 53 Temple Place Ste 330, 10 * Boston MA 02111-1307, USA; either version 2 of the License, or 11 * (at your option) any later version; incorporated herein by reference. 12 * 13 * ----------------------------------------------------------------------- 14 * 15 * 16 * conio.c 17 * 18 * Console I/O code, except: 19 * writechr, writestr_early - module-dependent 20 * writestr, crlf - writestr.inc 21 * writehex* - writehex.inc 22 */ 23 #include <sys/io.h> 24 #include <stddef.h> 25 #include <stdio.h> 26 #include <string.h> 27 #include <fs.h> 28 #include <com32.h> 29 #include <sys/cpu.h> 30 #include <syslinux/firmware.h> 31 32 #include "bios.h" 33 #include "graphics.h" 34 35 union screen _cursor; 36 union screen _screensize; 37 38 /* 39 * Serial console stuff. 40 */ 41 __export uint16_t SerialPort = 0; /* Serial port base (or 0 for no serial port) */ 42 __export uint8_t FlowInput = 0; /* Input bits for serial flow */ 43 __export uint16_t BaudDivisor = 115200/9600; /* Baud rate divisor */ 44 __export uint8_t FlowIgnore = 0; /* Ignore input unless these bits set */ 45 __export uint16_t DisplayCon = 0x01; /* Display console enabled */ 46 __export uint8_t FlowOutput = 0; /* Output to assert for serial flow */ 47 48 __export uint8_t DisplayMask = 0x07; /* Display modes mask */ 49 50 uint8_t ScrollAttribute = 0x07; /* Grey on white (normal text color) */ 51 52 /* 53 * loadkeys: Load a LILO-style keymap 54 * 55 * Returns 0 on success, or -1 on error. 56 */ 57 __export int loadkeys(const char *filename) 58 { 59 FILE *f; 60 61 f = fopen(filename, "r"); 62 if (!f) 63 return -1; 64 65 fread(KbdMap, 1, sizeof(KbdMap), f); 66 67 fclose(f); 68 return 0; 69 } 70 71 /* 72 * write_serial: If serial output is enabled, write character on 73 * serial port. 74 */ 75 __export void write_serial(char data) 76 { 77 if (!SerialPort) 78 return; 79 80 if (!(DisplayMask & 0x04)) 81 return; 82 83 while (1) { 84 char ch; 85 86 ch = inb(SerialPort + 5); /* LSR */ 87 88 /* Wait for space in transmit register */ 89 if (!(ch & 0x20)) 90 continue; 91 92 /* Wait for input flow control */ 93 ch = inb(SerialPort + 6); 94 ch &= FlowInput; 95 if (ch != FlowInput) 96 continue; 97 98 break; 99 } 100 101 outb(data, SerialPort); /* Send data */ 102 io_delay(); 103 } 104 105 void pm_write_serial(com32sys_t *regs) 106 { 107 write_serial(regs->eax.b[0]); 108 } 109 110 void serialcfg(uint16_t *iobase, uint16_t *divisor, uint16_t *flowctl) 111 { 112 uint8_t al, ah; 113 114 *iobase = SerialPort; 115 *divisor = BaudDivisor; 116 117 al = FlowOutput; 118 ah = FlowInput; 119 120 al |= ah; 121 ah = FlowIgnore; 122 ah >>= 4; 123 124 if (!DisplayCon) 125 ah |= 0x80; 126 127 *flowctl = al | (ah << 8); 128 } 129 130 void pm_serialcfg(com32sys_t *regs) 131 { 132 serialcfg(®s->eax.w[0], ®s->ecx.w[0], ®s->ebx.w[0]); 133 } 134 135 /* 136 * write_serial_str: write_serial for strings 137 */ 138 __export void write_serial_str(char *data) 139 { 140 char ch; 141 142 while ((ch = *data++)) 143 write_serial(ch); 144 } 145 146 /* 147 * pollchar: check if we have an input character pending 148 * 149 * Returns 1 if character pending. 150 */ 151 int bios_pollchar(void) 152 { 153 com32sys_t ireg, oreg; 154 uint8_t data = 0; 155 156 memset(&ireg, 0, sizeof(ireg)); 157 158 ireg.eax.b[1] = 0x11; /* Poll keyboard */ 159 __intcall(0x16, &ireg, &oreg); 160 161 if (!(oreg.eflags.l & EFLAGS_ZF)) 162 return 1; 163 164 if (SerialPort) { 165 cli(); 166 167 /* Already-queued input? */ 168 if (SerialTail == SerialHead) { 169 /* LSR */ 170 data = inb(SerialPort + 5) & 1; 171 if (data) { 172 /* MSR */ 173 data = inb(SerialPort + 6); 174 175 /* Required status bits */ 176 data &= FlowIgnore; 177 178 if (data == FlowIgnore) 179 data = 1; 180 else 181 data = 0; 182 } 183 } else 184 data = 1; 185 sti(); 186 } 187 188 return data; 189 } 190 191 __export int pollchar(void) 192 { 193 return firmware->i_ops->pollchar(); 194 } 195 196 void pm_pollchar(com32sys_t *regs) 197 { 198 if (pollchar()) 199 regs->eflags.l &= ~EFLAGS_ZF; 200 else 201 regs->eflags.l |= EFLAGS_ZF; 202 } 203 204 char bios_getchar(char *hi) 205 { 206 com32sys_t ireg, oreg; 207 unsigned char data; 208 209 memset(&ireg, 0, sizeof(ireg)); 210 memset(&oreg, 0, sizeof(oreg)); 211 while (1) { 212 __idle(); 213 214 ireg.eax.b[1] = 0x11; /* Poll keyboard */ 215 __intcall(0x16, &ireg, &oreg); 216 217 if (oreg.eflags.l & EFLAGS_ZF) { 218 if (!SerialPort) 219 continue; 220 221 cli(); 222 if (SerialTail != SerialHead) { 223 /* serial queued */ 224 sti(); /* We already know we'll consume data */ 225 data = *SerialTail++; 226 227 if (SerialTail > SerialHead + serial_buf_size) 228 SerialTail = SerialHead; 229 } else { 230 /* LSR */ 231 data = inb(SerialPort + 5) & 1; 232 if (!data) { 233 sti(); 234 continue; 235 } 236 data = inb(SerialPort + 6); 237 data &= FlowIgnore; 238 if (data != FlowIgnore) { 239 sti(); 240 continue; 241 } 242 243 data = inb(SerialPort); 244 sti(); 245 break; 246 } 247 } else { 248 /* Keyboard input? */ 249 ireg.eax.b[1] = 0x10; /* Get keyboard input */ 250 __intcall(0x16, &ireg, &oreg); 251 252 data = oreg.eax.b[0]; 253 *hi = oreg.eax.b[1]; 254 255 if (data == 0xE0) 256 data = 0; 257 258 if (data) { 259 /* Convert character sets */ 260 data = KbdMap[data]; 261 } 262 } 263 264 break; 265 } 266 267 reset_idle(); /* Character received */ 268 return data; 269 } 270 271 uint8_t bios_shiftflags(void) 272 { 273 com32sys_t reg; 274 uint8_t ah, al; 275 276 memset(®, 0, sizeof reg); 277 reg.eax.b[1] = 0x12; 278 __intcall(0x16, ®, ®); 279 ah = reg.eax.b[1]; 280 al = reg.eax.b[0]; 281 282 /* 283 * According to the Interrupt List, "many machines" don't correctly 284 * fold the Alt state, presumably because it might be AltGr. 285 * Explicitly fold the Alt and Ctrl states; it fits our needs 286 * better. 287 */ 288 289 if (ah & 0x0a) 290 al |= 0x08; 291 if (ah & 0x05) 292 al |= 0x04; 293 294 return al; 295 } 296 297 __export uint8_t kbd_shiftflags(void) 298 { 299 if (firmware->i_ops->shiftflags) 300 return firmware->i_ops->shiftflags(); 301 else 302 return 0; /* Unavailable on this firmware */ 303 } 304 305 /* 306 * getchar: Read a character from keyboard or serial port 307 */ 308 __export char getchar(char *hi) 309 { 310 return firmware->i_ops->getchar(hi); 311 } 312 313 void pm_getchar(com32sys_t *regs) 314 { 315 regs->eax.b[0] = getchar((char *)®s->eax.b[1]); 316 } 317