|
|
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.