Annotation of qemu/roms/openbios/drivers/escc.c, revision 1.1

1.1     ! root        1: #include "config.h"
        !             2: #include "libopenbios/bindings.h"
        !             3: #include "libc/byteorder.h"
        !             4: #include "libc/vsprintf.h"
        !             5: #include "drivers/drivers.h"
        !             6: #include "libopenbios/ofmem.h"
        !             7: 
        !             8: #include "escc.h"
        !             9: 
        !            10: /* ******************************************************************
        !            11:  *                       serial console functions
        !            12:  * ****************************************************************** */
        !            13: 
        !            14: static volatile unsigned char *serial_dev;
        !            15: 
        !            16: #define CTRL(addr) (*(volatile unsigned char *)(uintptr_t)(addr))
        !            17: #ifdef CONFIG_DRIVER_ESCC_SUN
        !            18: #define DATA(addr) (*(volatile unsigned char *)(uintptr_t)(addr + 2))
        !            19: #else
        !            20: #define DATA(addr) (*(volatile unsigned char *)(uintptr_t)(addr + 16))
        !            21: #endif
        !            22: 
        !            23: /* Conversion routines to/from brg time constants from/to bits
        !            24:  * per second.
        !            25:  */
        !            26: #define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
        !            27: 
        !            28: #ifdef CONFIG_DRIVER_ESCC_SUN
        !            29: #define ESCC_CLOCK              4915200 /* Zilog input clock rate. */
        !            30: #else
        !            31: #define ESCC_CLOCK              3686400
        !            32: #endif
        !            33: #define ESCC_CLOCK_DIVISOR      16      /* Divisor this driver uses. */
        !            34: 
        !            35: /* Write Register 3 */
        !            36: #define RxENAB          0x1     /* Rx Enable */
        !            37: #define Rx8             0xc0    /* Rx 8 Bits/Character */
        !            38: 
        !            39: /* Write Register 4 */
        !            40: #define SB1             0x4     /* 1 stop bit/char */
        !            41: #define X16CLK          0x40    /* x16 clock mode */
        !            42: 
        !            43: /* Write Register 5 */
        !            44: #define RTS             0x2     /* RTS */
        !            45: #define TxENAB          0x8     /* Tx Enable */
        !            46: #define Tx8             0x60    /* Tx 8 bits/character */
        !            47: #define DTR             0x80    /* DTR */
        !            48: 
        !            49: /* Write Register 14 (Misc control bits) */
        !            50: #define BRENAB  1       /* Baud rate generator enable */
        !            51: #define BRSRC   2       /* Baud rate generator source */
        !            52: 
        !            53: /* Read Register 0 */
        !            54: #define Rx_CH_AV        0x1     /* Rx Character Available */
        !            55: #define Tx_BUF_EMP      0x4     /* Tx Buffer empty */
        !            56: 
        !            57: int uart_charav(uintptr_t port)
        !            58: {
        !            59:     return (CTRL(port) & Rx_CH_AV) != 0;
        !            60: }
        !            61: 
        !            62: char uart_getchar(uintptr_t port)
        !            63: {
        !            64:     while (!uart_charav(port))
        !            65:         ;
        !            66:     return DATA(port) & 0177;
        !            67: }
        !            68: 
        !            69: static void uart_putchar(uintptr_t port, unsigned char c)
        !            70: {
        !            71:     if (!serial_dev)
        !            72:         return;
        !            73: 
        !            74:     if (c == '\n')
        !            75:         uart_putchar(port, '\r');
        !            76:     while (!(CTRL(port) & Tx_BUF_EMP))
        !            77:         ;
        !            78:     DATA(port) = c;
        !            79: }
        !            80: 
        !            81: static void uart_init_line(volatile unsigned char *port, unsigned long baud)
        !            82: {
        !            83:     CTRL(port) = 4; // reg 4
        !            84:     CTRL(port) = SB1 | X16CLK; // no parity, async, 1 stop bit, 16x
        !            85:                                // clock
        !            86: 
        !            87:     baud = BPS_TO_BRG(baud, ESCC_CLOCK / ESCC_CLOCK_DIVISOR);
        !            88: 
        !            89:     CTRL(port) = 12; // reg 12
        !            90:     CTRL(port) = baud & 0xff;
        !            91:     CTRL(port) = 13; // reg 13
        !            92:     CTRL(port) = (baud >> 8) & 0xff;
        !            93:     CTRL(port) = 14; // reg 14
        !            94:     CTRL(port) = BRSRC | BRENAB;
        !            95: 
        !            96:     CTRL(port) = 3; // reg 3
        !            97:     CTRL(port) = RxENAB | Rx8; // enable rx, 8 bits/char
        !            98: 
        !            99:     CTRL(port) = 5; // reg 5
        !           100:     CTRL(port) = RTS | TxENAB | Tx8 | DTR; // enable tx, 8 bits/char,
        !           101:                                            // set RTS & DTR
        !           102: 
        !           103: }
        !           104: 
        !           105: int uart_init(phys_addr_t port, unsigned long speed)
        !           106: {
        !           107: #ifdef CONFIG_DRIVER_ESCC_SUN
        !           108:     serial_dev = (unsigned char *)ofmem_map_io(port & ~7ULL, ZS_REGS);
        !           109:     serial_dev += port & 7ULL;
        !           110: #else
        !           111:     serial_dev = (unsigned char *)(uintptr_t)port;
        !           112: #endif
        !           113:     uart_init_line(serial_dev, speed);
        !           114:     return -1;
        !           115: }
        !           116: 
        !           117: void serial_putchar(int c)
        !           118: {
        !           119:     uart_putchar((uintptr_t)serial_dev, (unsigned char) (c & 0xff));
        !           120: }
        !           121: 
        !           122: void serial_cls(void)
        !           123: {
        !           124:     serial_putchar(27);
        !           125:     serial_putchar('[');
        !           126:     serial_putchar('H');
        !           127:     serial_putchar(27);
        !           128:     serial_putchar('[');
        !           129:     serial_putchar('J');
        !           130: }
        !           131: 
        !           132: /* ( addr len -- actual ) */
        !           133: static void
        !           134: escc_read(phys_addr_t *address)
        !           135: {
        !           136:     char *addr;
        !           137:     int len;
        !           138: 
        !           139:     len = POP();
        !           140:     addr = (char *)cell2pointer(POP());
        !           141: 
        !           142:     if (len < 1)
        !           143:         printk("escc_read: bad len, addr %p len %x\n", addr, len);
        !           144: 
        !           145:     if (uart_charav(*address)) {
        !           146:         *addr = (char)uart_getchar(*address);
        !           147:         PUSH(1);
        !           148:     } else {
        !           149:         PUSH(0);
        !           150:     }
        !           151: }
        !           152: 
        !           153: /* ( addr len -- actual ) */
        !           154: static void
        !           155: escc_write(phys_addr_t *address)
        !           156: {
        !           157:     unsigned char *addr;
        !           158:     int i, len;
        !           159: 
        !           160:     len = POP();
        !           161:     addr = (unsigned char *)cell2pointer(POP());
        !           162: 
        !           163:     for (i = 0; i < len; i++) {
        !           164:         uart_putchar(*address, addr[i]);
        !           165:     }
        !           166:     PUSH(len);
        !           167: }
        !           168: 
        !           169: static void
        !           170: escc_close(void)
        !           171: {
        !           172: }
        !           173: 
        !           174: static void
        !           175: escc_open(phys_addr_t *address)
        !           176: {
        !           177: #ifdef CONFIG_DRIVER_ESCC_SUN
        !           178:     int len;
        !           179:     phandle_t ph;
        !           180:     unsigned long *prop;
        !           181:     char *args;
        !           182: 
        !           183:     fword("my-self");
        !           184:     fword("ihandle>phandle");
        !           185:     ph = (phandle_t)POP();
        !           186:     prop = (unsigned long *)get_property(ph, "address", &len);
        !           187:     *address = *prop;
        !           188:     fword("my-args");
        !           189:     args = pop_fstr_copy();
        !           190:     if (args) {
        !           191:         if (args[0] == 'a')
        !           192:             *address += 4;
        !           193:         //printk("escc_open: address %lx, args %s\n", *address, args);
        !           194:         free(args);
        !           195:     }
        !           196: #else
        !           197:     *address = (unsigned long)serial_dev; // XXX
        !           198: #endif
        !           199:     RET ( -1 );
        !           200: }
        !           201: 
        !           202: DECLARE_UNNAMED_NODE(escc, INSTALL_OPEN, sizeof(phys_addr_t));
        !           203: 
        !           204: NODE_METHODS(escc) = {
        !           205:     { "open",               escc_open              },
        !           206:     { "close",              escc_close             },
        !           207:     { "read",               escc_read              },
        !           208:     { "write",              escc_write             },
        !           209: };
        !           210: 
        !           211: #ifdef CONFIG_DRIVER_ESCC_SUN
        !           212: static volatile unsigned char *kbd_dev;
        !           213: 
        !           214: void kbd_init(phys_addr_t base)
        !           215: {
        !           216:     kbd_dev = (unsigned char *)ofmem_map_io(base, 2 * 4);
        !           217:     kbd_dev += 4;
        !           218: }
        !           219: 
        !           220: static const unsigned char sunkbd_keycode[128] = {
        !           221:     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
        !           222:     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0,
        !           223:     '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 8,
        !           224:     0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
        !           225:     'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
        !           226:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           227:     'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '\\', 13,
        !           228:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           229:     'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
        !           230:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           231:     ' ',
        !           232: };
        !           233: 
        !           234: static const unsigned char sunkbd_keycode_shifted[128] = {
        !           235:     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
        !           236:     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0,
        !           237:     '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0, 8,
        !           238:     0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
        !           239:     'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}',
        !           240:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           241:     'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '|', 13,
        !           242:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           243:     'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
        !           244:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           245:     ' ',
        !           246: };
        !           247: 
        !           248: static int shiftstate;
        !           249: 
        !           250: int
        !           251: keyboard_dataready(void)
        !           252: {
        !           253:     return ((kbd_dev[0] & 1) == 1);
        !           254: }
        !           255: 
        !           256: unsigned char
        !           257: keyboard_readdata(void)
        !           258: {
        !           259:     unsigned char ch;
        !           260: 
        !           261:     while (!keyboard_dataready()) { }
        !           262: 
        !           263:     do {
        !           264:         ch = kbd_dev[2] & 0xff;
        !           265:         if (ch == 99)
        !           266:             shiftstate |= 1;
        !           267:         else if (ch == 110)
        !           268:             shiftstate |= 2;
        !           269:         else if (ch == 227)
        !           270:             shiftstate &= ~1;
        !           271:         else if (ch == 238)
        !           272:             shiftstate &= ~2;
        !           273:         //printk("getch: %d\n", ch);
        !           274:     } // If release, wait for key press
        !           275:     while ((ch & 0x80) == 0x80 || ch == 238 || ch == 227);
        !           276:     //printk("getch rel: %d\n", ch);
        !           277:     ch &= 0x7f;
        !           278:     if (shiftstate)
        !           279:         ch = sunkbd_keycode_shifted[ch];
        !           280:     else
        !           281:         ch = sunkbd_keycode[ch];
        !           282:     //printk("getch xlate: %d\n", ch);
        !           283: 
        !           284:     return ch;
        !           285: }
        !           286: 
        !           287: /* ( addr len -- actual ) */
        !           288: static void
        !           289: escc_read_keyboard(void)
        !           290: {
        !           291:     unsigned char *addr;
        !           292:     int len;
        !           293: 
        !           294:     len = POP();
        !           295:     addr = (unsigned char *)POP();
        !           296: 
        !           297:     if (len < 1)
        !           298:         printk("escc_read: bad len, addr %p len %x\n", addr, len);
        !           299: 
        !           300:     if (keyboard_dataready()) {
        !           301:         *addr = keyboard_readdata();
        !           302:         PUSH(1);
        !           303:     } else {
        !           304:         PUSH(0);
        !           305:     }
        !           306: }
        !           307: 
        !           308: DECLARE_UNNAMED_NODE(escc_keyboard, INSTALL_OPEN, sizeof(phys_addr_t));
        !           309: 
        !           310: NODE_METHODS(escc_keyboard) = {
        !           311:     { "open",               escc_open              },
        !           312:     { "close",              escc_close             },
        !           313:     { "read",               escc_read_keyboard     },
        !           314: };
        !           315: 
        !           316: void
        !           317: ob_zs_init(phys_addr_t base, uint64_t offset, int intr, int slave, int keyboard)
        !           318: {
        !           319:     char nodebuff[256];
        !           320:     phandle_t aliases;
        !           321: 
        !           322:     ob_new_obio_device("zs", "serial");
        !           323: 
        !           324:     ob_reg(base, offset, ZS_REGS, 1);
        !           325: 
        !           326:     PUSH(slave);
        !           327:     fword("encode-int");
        !           328:     push_str("slave");
        !           329:     fword("property");
        !           330: 
        !           331:     if (keyboard) {
        !           332:         PUSH(-1);
        !           333:         fword("encode-int");
        !           334:         push_str("keyboard");
        !           335:         fword("property");
        !           336: 
        !           337:         PUSH(-1);
        !           338:         fword("encode-int");
        !           339:         push_str("mouse");
        !           340:         fword("property");
        !           341:     }
        !           342: 
        !           343:     ob_intr(intr);
        !           344: 
        !           345:     PUSH(0);
        !           346:     PUSH(0);
        !           347:     push_str("port-a-ignore-cd");
        !           348:     fword("property");
        !           349: 
        !           350:     PUSH(0);
        !           351:     PUSH(0);
        !           352:     push_str("port-b-ignore-cd");
        !           353:     fword("property");
        !           354: 
        !           355:     fword("finish-device");
        !           356: 
        !           357:     snprintf(nodebuff, sizeof(nodebuff), "/obio/zs@0,%x",
        !           358:              (int)offset & 0xffffffff);
        !           359:     if (keyboard) {
        !           360:         REGISTER_NODE_METHODS(escc_keyboard, nodebuff);
        !           361: 
        !           362:         aliases = find_dev("/aliases");
        !           363:         set_property(aliases, "keyboard", nodebuff, strlen(nodebuff) + 1);
        !           364:     } else {
        !           365:         REGISTER_NODE_METHODS(escc, nodebuff);
        !           366: 
        !           367:         aliases = find_dev("/aliases");
        !           368:         snprintf(nodebuff, sizeof(nodebuff), "/obio/zs@0,%x:a",
        !           369:                  (int)offset & 0xffffffff);
        !           370:         set_property(aliases, "ttya", nodebuff, strlen(nodebuff) + 1);
        !           371: 
        !           372:         snprintf(nodebuff, sizeof(nodebuff), "/obio/zs@0,%x:b",
        !           373:                  (int)offset & 0xffffffff);
        !           374:         set_property(aliases, "ttyb", nodebuff, strlen(nodebuff) + 1);
        !           375: 
        !           376:     }
        !           377: }
        !           378: 
        !           379: #else
        !           380: 
        !           381: static void
        !           382: escc_add_channel(const char *path, const char *node, phys_addr_t addr,
        !           383:                  uint32_t offset)
        !           384: {
        !           385:     char buf[64], tty[32];
        !           386:     phandle_t dnode, aliases;
        !           387:     int len;
        !           388:     cell props[2];
        !           389: 
        !           390:     /* add device */
        !           391: 
        !           392:     snprintf(buf, sizeof(buf), "%s/ch-%s", path, node);
        !           393: 
        !           394:     REGISTER_NAMED_NODE(escc, buf);
        !           395: 
        !           396:     activate_device(buf);
        !           397: 
        !           398:     /* add aliases */
        !           399: 
        !           400:     aliases = find_dev("/aliases");
        !           401: 
        !           402:     snprintf(buf, sizeof(buf), "%s/ch-%s", path, node);
        !           403:     OLDWORLD(snprintf(tty, sizeof(tty), "tty%s", node));
        !           404:     OLDWORLD(set_property(aliases, tty, buf, strlen(buf) + 1));
        !           405:     snprintf(tty, sizeof(tty), "scc%s", node);
        !           406:     set_property(aliases, tty, buf, strlen(buf) + 1);
        !           407: 
        !           408:     /* add properties */
        !           409: 
        !           410:     dnode = find_dev(buf);
        !           411:     set_property(dnode, "device_type", "serial",
        !           412:                  strlen("serial") + 1);
        !           413: 
        !           414:     snprintf(buf, sizeof(buf), "ch-%s", node);
        !           415:     len = strlen(buf) + 1;
        !           416:     snprintf(buf + len, sizeof(buf) - len, "CHRP,es2");
        !           417:     set_property(dnode, "compatible", buf, len + 9);
        !           418: 
        !           419:     props[0] = IO_ESCC_OFFSET + offset * 0x20;
        !           420:     props[1] = 0x00000020;
        !           421:     set_property(dnode, "reg", (char *)&props, 2 * sizeof(cell));
        !           422: 
        !           423:     props[0] = addr + IO_ESCC_OFFSET + offset * 0x20;
        !           424:     OLDWORLD(set_property(dnode, "AAPL,address",
        !           425:             (char *)&props, 1 * sizeof(cell)));
        !           426: 
        !           427:     props[0] = 0x00000010 - offset;
        !           428:     OLDWORLD(set_property(dnode, "AAPL,interrupts",
        !           429:             (char *)&props, 1 * sizeof(cell)));
        !           430: 
        !           431:     props[0] = (0x24) + offset;
        !           432:     props[1] = 0;
        !           433:     NEWWORLD(set_property(dnode, "interrupts",
        !           434:              (char *)&props, 2 * sizeof(cell)));
        !           435: 
        !           436:     device_end();
        !           437: 
        !           438:     uart_init_line((unsigned char*)addr + IO_ESCC_OFFSET + offset * 0x20,
        !           439:                    CONFIG_SERIAL_SPEED);
        !           440: }
        !           441: 
        !           442: void
        !           443: escc_init(const char *path, phys_addr_t addr)
        !           444: {
        !           445:     char buf[64];
        !           446:     int props[2];
        !           447:     phandle_t dnode;
        !           448: 
        !           449:     push_str(path);
        !           450:     fword("find-device");
        !           451:     fword("new-device");
        !           452: 
        !           453:     push_str("escc");
        !           454:     fword("device-name");
        !           455: 
        !           456:     snprintf(buf, sizeof(buf), "%s/escc", path);
        !           457: 
        !           458:     dnode = find_dev(buf);
        !           459: 
        !           460:     set_int_property(dnode, "#address-cells", 1);
        !           461:     props[0] = __cpu_to_be32(IO_ESCC_OFFSET);
        !           462:     props[1] = __cpu_to_be32(IO_ESCC_SIZE);
        !           463:     set_property(dnode, "reg", (char *)&props, sizeof(props));
        !           464:     set_property(dnode, "device_type", "escc",
        !           465:                  strlen("escc") + 1);
        !           466:     set_property(dnode, "compatible", "escc\0CHRP,es0", 14);
        !           467: 
        !           468:     fword("finish-device");
        !           469: 
        !           470:     escc_add_channel(buf, "a", addr, 1);
        !           471:     escc_add_channel(buf, "b", addr, 0);
        !           472: 
        !           473:     serial_dev = (unsigned char *)addr + IO_ESCC_OFFSET +
        !           474:                  (CONFIG_SERIAL_PORT ? 0 : 0x20);
        !           475: }
        !           476: #endif

unix.superglobalmegacorp.com

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