Annotation of qemu/roms/openbios/drivers/escc.c, revision 1.1.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.