Annotation of qemu/roms/seabios/src/serial.c, revision 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.