|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.