Annotation of qemu/roms/seabios/src/serial.c, revision 1.1.1.1

1.1       root        1: // 16bit code to handle serial and printer services.
                      2: //
                      3: // Copyright (C) 2008,2009  Kevin O'Connor <[email protected]>
                      4: // Copyright (C) 2002  MandrakeSoft S.A.
                      5: //
                      6: // This file may be distributed under the terms of the GNU LGPLv3 license.
                      7: 
                      8: #include "biosvar.h" // SET_BDA
                      9: #include "util.h" // debug_enter
                     10: #include "bregs.h" // struct bregs
                     11: 
                     12: // Timers based on 18.2Hz clock irq.
                     13: struct tick_timer_s {
                     14:     u16 last_tick, remaining;
                     15: };
                     16: 
                     17: struct tick_timer_s
                     18: initTickTimer(u16 count)
                     19: {
                     20:     struct tick_timer_s tt = {GET_BDA(timer_counter), count};
                     21:     return tt;
                     22: }
                     23: 
                     24: int
                     25: checkTickTimer(struct tick_timer_s *tt)
                     26: {
                     27:     u16 timer = GET_BDA(timer_counter);
                     28:     if (tt->last_tick != timer) {
                     29:         tt->last_tick = timer;
                     30:         tt->last_tick--;
                     31:         if (!tt->last_tick)
                     32:             return 1;
                     33:     }
                     34:     return 0;
                     35: }
                     36: 
                     37: 
                     38: /****************************************************************
                     39:  * COM ports
                     40:  ****************************************************************/
                     41: 
                     42: static u16
                     43: detect_serial(u16 port, u8 timeout, u8 count)
                     44: {
                     45:     outb(0x02, port+SEROFF_IER);
                     46:     u8 ier = inb(port+SEROFF_IER);
                     47:     if (ier != 0x02)
                     48:         return 0;
                     49:     u8 iir = inb(port+SEROFF_IIR);
                     50:     if ((iir & 0x3f) != 0x02)
                     51:         return 0;
                     52: 
                     53:     outb(0x00, port+SEROFF_IER);
                     54:     SET_BDA(port_com[count], port);
                     55:     SET_BDA(com_timeout[count], timeout);
                     56:     return 1;
                     57: }
                     58: 
                     59: void
                     60: serial_setup()
                     61: {
                     62:     if (! CONFIG_SERIAL)
                     63:         return;
                     64:     dprintf(3, "init serial\n");
                     65: 
                     66:     u16 count = 0;
                     67:     count += detect_serial(PORT_SERIAL1, 0x0a, count);
                     68:     count += detect_serial(PORT_SERIAL2, 0x0a, count);
                     69:     count += detect_serial(PORT_SERIAL3, 0x0a, count);
                     70:     count += detect_serial(PORT_SERIAL4, 0x0a, count);
                     71:     dprintf(1, "Found %d serial ports\n", count);
                     72: 
                     73:     // Equipment word bits 9..11 determing # serial ports
                     74:     u16 eqb = GET_BDA(equipment_list_flags);
                     75:     SET_BDA(equipment_list_flags, (eqb & 0xf1ff) | (count << 9));
                     76: }
                     77: 
                     78: static u16
                     79: getComAddr(struct bregs *regs)
                     80: {
                     81:     if (regs->dx >= 4) {
                     82:         set_invalid(regs);
                     83:         return 0;
                     84:     }
                     85:     u16 addr = GET_BDA(port_com[regs->dx]);
                     86:     if (! addr)
                     87:         set_invalid(regs);
                     88:     return addr;
                     89: }
                     90: 
                     91: // SERIAL - INITIALIZE PORT
                     92: static void
                     93: handle_1400(struct bregs *regs)
                     94: {
                     95:     u16 addr = getComAddr(regs);
                     96:     if (!addr)
                     97:         return;
                     98:     outb(inb(addr+SEROFF_LCR) | 0x80, addr+SEROFF_LCR);
                     99:     if ((regs->al & 0xE0) == 0) {
                    100:         outb(0x17, addr+SEROFF_DLL);
                    101:         outb(0x04, addr+SEROFF_DLH);
                    102:     } else {
                    103:         u16 val16 = 0x600 >> ((regs->al & 0xE0) >> 5);
                    104:         outb(val16 & 0xFF, addr+SEROFF_DLL);
                    105:         outb(val16 >> 8, addr+SEROFF_DLH);
                    106:     }
                    107:     outb(regs->al & 0x1F, addr+SEROFF_LCR);
                    108:     regs->ah = inb(addr+SEROFF_LSR);
                    109:     regs->al = inb(addr+SEROFF_MSR);
                    110:     set_success(regs);
                    111: }
                    112: 
                    113: // SERIAL - WRITE CHARACTER TO PORT
                    114: static void
                    115: handle_1401(struct bregs *regs)
                    116: {
                    117:     u16 addr = getComAddr(regs);
                    118:     if (!addr)
                    119:         return;
                    120:     struct tick_timer_s tt = initTickTimer(GET_BDA(com_timeout[regs->dx]));
                    121:     for (;;) {
                    122:         u8 lsr = inb(addr+SEROFF_LSR);
                    123:         if ((lsr & 0x60) == 0x60) {
                    124:             // Success - can write data
                    125:             outb(regs->al, addr+SEROFF_DATA);
                    126:             // XXX - reread lsr?
                    127:             regs->ah = lsr;
                    128:             break;
                    129:         }
                    130:         if (checkTickTimer(&tt)) {
                    131:             // Timed out - can't write data.
                    132:             regs->ah = lsr | 0x80;
                    133:             break;
                    134:         }
                    135:         yield();
                    136:     }
                    137:     set_success(regs);
                    138: }
                    139: 
                    140: // SERIAL - READ CHARACTER FROM PORT
                    141: static void
                    142: handle_1402(struct bregs *regs)
                    143: {
                    144:     u16 addr = getComAddr(regs);
                    145:     if (!addr)
                    146:         return;
                    147:     struct tick_timer_s tt = initTickTimer(GET_BDA(com_timeout[regs->dx]));
                    148:     for (;;) {
                    149:         u8 lsr = inb(addr+SEROFF_LSR);
                    150:         if (lsr & 0x01) {
                    151:             // Success - can read data
                    152:             regs->al = inb(addr+SEROFF_DATA);
                    153:             regs->ah = lsr;
                    154:             break;
                    155:         }
                    156:         if (checkTickTimer(&tt)) {
                    157:             // Timed out - can't read data.
                    158:             regs->ah = lsr | 0x80;
                    159:             break;
                    160:         }
                    161:         yield();
                    162:     }
                    163:     set_success(regs);
                    164: }
                    165: 
                    166: // SERIAL - GET PORT STATUS
                    167: static void
                    168: handle_1403(struct bregs *regs)
                    169: {
                    170:     u16 addr = getComAddr(regs);
                    171:     if (!addr)
                    172:         return;
                    173:     regs->ah = inb(addr+SEROFF_LSR);
                    174:     regs->al = inb(addr+SEROFF_MSR);
                    175:     set_success(regs);
                    176: }
                    177: 
                    178: static void
                    179: handle_14XX(struct bregs *regs)
                    180: {
                    181:     set_unimplemented(regs);
                    182: }
                    183: 
                    184: // INT 14h Serial Communications Service Entry Point
                    185: void VISIBLE16
                    186: handle_14(struct bregs *regs)
                    187: {
                    188:     debug_enter(regs, DEBUG_HDL_14);
                    189:     if (! CONFIG_SERIAL) {
                    190:         handle_14XX(regs);
                    191:         return;
                    192:     }
                    193: 
                    194:     switch (regs->ah) {
                    195:     case 0x00: handle_1400(regs); break;
                    196:     case 0x01: handle_1401(regs); break;
                    197:     case 0x02: handle_1402(regs); break;
                    198:     case 0x03: handle_1403(regs); break;
                    199:     default:   handle_14XX(regs); break;
                    200:     }
                    201: }
                    202: 
                    203: // XXX - Baud Rate Generator Table
                    204: u8 BaudTable[16] VAR16FIXED(0xe729);
                    205: 
                    206: 
                    207: /****************************************************************
                    208:  * LPT ports
                    209:  ****************************************************************/
                    210: 
                    211: static u16
                    212: detect_parport(u16 port, u8 timeout, u8 count)
                    213: {
                    214:     // clear input mode
                    215:     outb(inb(port+2) & 0xdf, port+2);
                    216: 
                    217:     outb(0xaa, port);
                    218:     if (inb(port) != 0xaa)
                    219:         // Not present
                    220:         return 0;
                    221:     SET_BDA(port_lpt[count], port);
                    222:     SET_BDA(lpt_timeout[count], timeout);
                    223:     return 1;
                    224: }
                    225: 
                    226: void
                    227: lpt_setup()
                    228: {
                    229:     if (! CONFIG_LPT)
                    230:         return;
                    231:     dprintf(3, "init lpt\n");
                    232: 
                    233:     u16 count = 0;
                    234:     count += detect_parport(PORT_LPT1, 0x14, count);
                    235:     count += detect_parport(PORT_LPT2, 0x14, count);
                    236:     dprintf(1, "Found %d lpt ports\n", count);
                    237: 
                    238:     // Equipment word bits 14..15 determing # parallel ports
                    239:     u16 eqb = GET_BDA(equipment_list_flags);
                    240:     SET_BDA(equipment_list_flags, (eqb & 0x3fff) | (count << 14));
                    241: }
                    242: 
                    243: static u16
                    244: getLptAddr(struct bregs *regs)
                    245: {
                    246:     if (regs->dx >= 3) {
                    247:         set_invalid(regs);
                    248:         return 0;
                    249:     }
                    250:     u16 addr = GET_BDA(port_lpt[regs->dx]);
                    251:     if (! addr)
                    252:         set_invalid(regs);
                    253:     return addr;
                    254: }
                    255: 
                    256: // INT 17 - PRINTER - WRITE CHARACTER
                    257: static void
                    258: handle_1700(struct bregs *regs)
                    259: {
                    260:     u16 addr = getLptAddr(regs);
                    261:     if (!addr)
                    262:         return;
                    263: 
                    264:     struct tick_timer_s tt = initTickTimer(GET_BDA(lpt_timeout[regs->dx]));
                    265: 
                    266:     outb(regs->al, addr);
                    267:     u8 val8 = inb(addr+2);
                    268:     outb(val8 | 0x01, addr+2); // send strobe
                    269:     udelay(5);
                    270:     outb(val8 & ~0x01, addr+2);
                    271: 
                    272:     for (;;) {
                    273:         u8 v = inb(addr+1);
                    274:         if (!(v & 0x40)) {
                    275:             // Success
                    276:             regs->ah = v ^ 0x48;
                    277:             break;
                    278:         }
                    279:         if (checkTickTimer(&tt)) {
                    280:             // Timeout
                    281:             regs->ah = (v ^ 0x48) | 0x01;
                    282:             break;
                    283:         }
                    284:         yield();
                    285:     }
                    286: 
                    287:     set_success(regs);
                    288: }
                    289: 
                    290: // INT 17 - PRINTER - INITIALIZE PORT
                    291: static void
                    292: handle_1701(struct bregs *regs)
                    293: {
                    294:     u16 addr = getLptAddr(regs);
                    295:     if (!addr)
                    296:         return;
                    297: 
                    298:     u8 val8 = inb(addr+2);
                    299:     outb(val8 & ~0x04, addr+2); // send init
                    300:     udelay(5);
                    301:     outb(val8 | 0x04, addr+2);
                    302: 
                    303:     regs->ah = inb(addr+1) ^ 0x48;
                    304:     set_success(regs);
                    305: }
                    306: 
                    307: // INT 17 - PRINTER - GET STATUS
                    308: static void
                    309: handle_1702(struct bregs *regs)
                    310: {
                    311:     u16 addr = getLptAddr(regs);
                    312:     if (!addr)
                    313:         return;
                    314:     regs->ah = inb(addr+1) ^ 0x48;
                    315:     set_success(regs);
                    316: }
                    317: 
                    318: static void
                    319: handle_17XX(struct bregs *regs)
                    320: {
                    321:     set_unimplemented(regs);
                    322: }
                    323: 
                    324: // INT17h : Printer Service Entry Point
                    325: void VISIBLE16
                    326: handle_17(struct bregs *regs)
                    327: {
                    328:     debug_enter(regs, DEBUG_HDL_17);
                    329:     if (! CONFIG_LPT) {
                    330:         handle_17XX(regs);
                    331:         return;
                    332:     }
                    333: 
                    334:     switch (regs->ah) {
                    335:     case 0x00: handle_1700(regs); break;
                    336:     case 0x01: handle_1701(regs); break;
                    337:     case 0x02: handle_1702(regs); break;
                    338:     default:   handle_17XX(regs); break;
                    339:     }
                    340: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.