diff options
author | David S. Miller <davem@davemloft.net> | 2006-06-29 18:14:03 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-29 19:37:46 -0400 |
commit | 1708d242d222e751a0922e3c56ef857cf60bbedd (patch) | |
tree | 94d6c849e3e0edf686db1f6fae82cf889acc9e9e /drivers/serial/sunsu.c | |
parent | 4fa97dcf9d48b02934c60a48873199850351e760 (diff) |
[SERIAL] sunsu: Convert to of_driver framework.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/serial/sunsu.c')
-rw-r--r-- | drivers/serial/sunsu.c | 491 |
1 files changed, 157 insertions, 334 deletions
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 6e28c25138cf..4ef47c810de9 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c | |||
@@ -40,11 +40,8 @@ | |||
40 | 40 | ||
41 | #include <asm/io.h> | 41 | #include <asm/io.h> |
42 | #include <asm/irq.h> | 42 | #include <asm/irq.h> |
43 | #include <asm/oplib.h> | 43 | #include <asm/prom.h> |
44 | #include <asm/ebus.h> | 44 | #include <asm/of_device.h> |
45 | #ifdef CONFIG_SPARC64 | ||
46 | #include <asm/isa.h> | ||
47 | #endif | ||
48 | 45 | ||
49 | #if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | 46 | #if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) |
50 | #define SUPPORT_SYSRQ | 47 | #define SUPPORT_SYSRQ |
@@ -94,10 +91,10 @@ struct uart_sunsu_port { | |||
94 | /* Probing information. */ | 91 | /* Probing information. */ |
95 | enum su_type su_type; | 92 | enum su_type su_type; |
96 | unsigned int type_probed; /* XXX Stupid */ | 93 | unsigned int type_probed; /* XXX Stupid */ |
97 | int port_node; | 94 | unsigned long reg_size; |
98 | 95 | ||
99 | #ifdef CONFIG_SERIO | 96 | #ifdef CONFIG_SERIO |
100 | struct serio *serio; | 97 | struct serio serio; |
101 | int serio_open; | 98 | int serio_open; |
102 | #endif | 99 | #endif |
103 | }; | 100 | }; |
@@ -509,7 +506,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg | |||
509 | /* Stop-A is handled by drivers/char/keyboard.c now. */ | 506 | /* Stop-A is handled by drivers/char/keyboard.c now. */ |
510 | if (up->su_type == SU_PORT_KBD) { | 507 | if (up->su_type == SU_PORT_KBD) { |
511 | #ifdef CONFIG_SERIO | 508 | #ifdef CONFIG_SERIO |
512 | serio_interrupt(up->serio, ch, 0, regs); | 509 | serio_interrupt(&up->serio, ch, 0, regs); |
513 | #endif | 510 | #endif |
514 | } else if (up->su_type == SU_PORT_MS) { | 511 | } else if (up->su_type == SU_PORT_MS) { |
515 | int ret = suncore_mouse_baud_detection(ch, is_break); | 512 | int ret = suncore_mouse_baud_detection(ch, is_break); |
@@ -523,7 +520,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg | |||
523 | 520 | ||
524 | case 0: | 521 | case 0: |
525 | #ifdef CONFIG_SERIO | 522 | #ifdef CONFIG_SERIO |
526 | serio_interrupt(up->serio, ch, 0, regs); | 523 | serio_interrupt(&up->serio, ch, 0, regs); |
527 | #endif | 524 | #endif |
528 | break; | 525 | break; |
529 | }; | 526 | }; |
@@ -1031,99 +1028,14 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) | |||
1031 | { | 1028 | { |
1032 | unsigned char status1, status2, scratch, scratch2, scratch3; | 1029 | unsigned char status1, status2, scratch, scratch2, scratch3; |
1033 | unsigned char save_lcr, save_mcr; | 1030 | unsigned char save_lcr, save_mcr; |
1034 | struct linux_ebus_device *dev = NULL; | ||
1035 | struct linux_ebus *ebus; | ||
1036 | #ifdef CONFIG_SPARC64 | ||
1037 | struct sparc_isa_bridge *isa_br; | ||
1038 | struct sparc_isa_device *isa_dev; | ||
1039 | #endif | ||
1040 | #ifndef CONFIG_SPARC64 | ||
1041 | struct linux_prom_registers reg0; | ||
1042 | #endif | ||
1043 | unsigned long flags; | 1031 | unsigned long flags; |
1044 | 1032 | ||
1045 | if (!up->port_node || !up->su_type) | 1033 | if (up->su_type == SU_PORT_NONE) |
1046 | return; | 1034 | return; |
1047 | 1035 | ||
1048 | up->type_probed = PORT_UNKNOWN; | 1036 | up->type_probed = PORT_UNKNOWN; |
1049 | up->port.iotype = UPIO_MEM; | 1037 | up->port.iotype = UPIO_MEM; |
1050 | 1038 | ||
1051 | /* | ||
1052 | * First we look for Ebus-bases su's | ||
1053 | */ | ||
1054 | for_each_ebus(ebus) { | ||
1055 | for_each_ebusdev(dev, ebus) { | ||
1056 | if (dev->prom_node->node == up->port_node) { | ||
1057 | /* | ||
1058 | * The EBus is broken on sparc; it delivers | ||
1059 | * virtual addresses in resources. Oh well... | ||
1060 | * This is correct on sparc64, though. | ||
1061 | */ | ||
1062 | up->port.membase = (char *) dev->resource[0].start; | ||
1063 | /* | ||
1064 | * This is correct on both architectures. | ||
1065 | */ | ||
1066 | up->port.mapbase = dev->resource[0].start; | ||
1067 | up->port.irq = dev->irqs[0]; | ||
1068 | goto ebus_done; | ||
1069 | } | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | #ifdef CONFIG_SPARC64 | ||
1074 | for_each_isa(isa_br) { | ||
1075 | for_each_isadev(isa_dev, isa_br) { | ||
1076 | if (isa_dev->prom_node->node == up->port_node) { | ||
1077 | /* Same on sparc64. Cool architecure... */ | ||
1078 | up->port.membase = (char *) isa_dev->resource.start; | ||
1079 | up->port.mapbase = isa_dev->resource.start; | ||
1080 | up->port.irq = isa_dev->irq; | ||
1081 | goto ebus_done; | ||
1082 | } | ||
1083 | } | ||
1084 | } | ||
1085 | #endif | ||
1086 | |||
1087 | #ifdef CONFIG_SPARC64 | ||
1088 | /* | ||
1089 | * Not on Ebus, bailing. | ||
1090 | */ | ||
1091 | return; | ||
1092 | #else | ||
1093 | /* | ||
1094 | * Not on Ebus, must be OBIO. | ||
1095 | */ | ||
1096 | if (prom_getproperty(up->port_node, "reg", | ||
1097 | (char *)®0, sizeof(reg0)) == -1) { | ||
1098 | prom_printf("sunsu: no \"reg\" property\n"); | ||
1099 | return; | ||
1100 | } | ||
1101 | prom_apply_obio_ranges(®0, 1); | ||
1102 | if (reg0.which_io != 0) { /* Just in case... */ | ||
1103 | prom_printf("sunsu: bus number nonzero: 0x%x:%x\n", | ||
1104 | reg0.which_io, reg0.phys_addr); | ||
1105 | return; | ||
1106 | } | ||
1107 | up->port.mapbase = reg0.phys_addr; | ||
1108 | if ((up->port.membase = ioremap(reg0.phys_addr, reg0.reg_size)) == 0) { | ||
1109 | prom_printf("sunsu: Cannot map registers.\n"); | ||
1110 | return; | ||
1111 | } | ||
1112 | |||
1113 | /* | ||
1114 | * 0x20 is sun4m thing, Dave Redman heritage. | ||
1115 | * See arch/sparc/kernel/irq.c. | ||
1116 | */ | ||
1117 | #define IRQ_4M(n) ((n)|0x20) | ||
1118 | |||
1119 | /* | ||
1120 | * There is no intr property on MrCoffee, so hardwire it. | ||
1121 | */ | ||
1122 | up->port.irq = IRQ_4M(13); | ||
1123 | #endif | ||
1124 | |||
1125 | ebus_done: | ||
1126 | |||
1127 | spin_lock_irqsave(&up->port.lock, flags); | 1039 | spin_lock_irqsave(&up->port.lock, flags); |
1128 | 1040 | ||
1129 | if (!(up->port.flags & UPF_BUGGY_UART)) { | 1041 | if (!(up->port.flags & UPF_BUGGY_UART)) { |
@@ -1269,18 +1181,13 @@ static struct uart_driver sunsu_reg = { | |||
1269 | .major = TTY_MAJOR, | 1181 | .major = TTY_MAJOR, |
1270 | }; | 1182 | }; |
1271 | 1183 | ||
1272 | static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) | 1184 | static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up) |
1273 | { | 1185 | { |
1274 | int quot, baud; | 1186 | int quot, baud; |
1275 | #ifdef CONFIG_SERIO | 1187 | #ifdef CONFIG_SERIO |
1276 | struct serio *serio; | 1188 | struct serio *serio; |
1277 | #endif | 1189 | #endif |
1278 | 1190 | ||
1279 | spin_lock_init(&up->port.lock); | ||
1280 | up->port.line = channel; | ||
1281 | up->port.type = PORT_UNKNOWN; | ||
1282 | up->port.uartclk = (SU_BASE_BAUD * 16); | ||
1283 | |||
1284 | if (up->su_type == SU_PORT_KBD) { | 1191 | if (up->su_type == SU_PORT_KBD) { |
1285 | up->cflag = B1200 | CS8 | CLOCAL | CREAD; | 1192 | up->cflag = B1200 | CS8 | CLOCAL | CREAD; |
1286 | baud = 1200; | 1193 | baud = 1200; |
@@ -1292,41 +1199,31 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) | |||
1292 | 1199 | ||
1293 | sunsu_autoconfig(up); | 1200 | sunsu_autoconfig(up); |
1294 | if (up->port.type == PORT_UNKNOWN) | 1201 | if (up->port.type == PORT_UNKNOWN) |
1295 | return -1; | 1202 | return -ENODEV; |
1296 | |||
1297 | printk(KERN_INFO "su%d at 0x%p (irq = %d) is a %s\n", | ||
1298 | channel, | ||
1299 | up->port.membase, up->port.irq, | ||
1300 | sunsu_type(&up->port)); | ||
1301 | 1203 | ||
1302 | #ifdef CONFIG_SERIO | 1204 | #ifdef CONFIG_SERIO |
1303 | up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | 1205 | serio = &up->serio; |
1304 | if (serio) { | 1206 | serio->port_data = up; |
1305 | memset(serio, 0, sizeof(*serio)); | ||
1306 | |||
1307 | serio->port_data = up; | ||
1308 | |||
1309 | serio->id.type = SERIO_RS232; | ||
1310 | if (up->su_type == SU_PORT_KBD) { | ||
1311 | serio->id.proto = SERIO_SUNKBD; | ||
1312 | strlcpy(serio->name, "sukbd", sizeof(serio->name)); | ||
1313 | } else { | ||
1314 | serio->id.proto = SERIO_SUN; | ||
1315 | serio->id.extra = 1; | ||
1316 | strlcpy(serio->name, "sums", sizeof(serio->name)); | ||
1317 | } | ||
1318 | strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"), | ||
1319 | sizeof(serio->phys)); | ||
1320 | 1207 | ||
1321 | serio->write = sunsu_serio_write; | 1208 | serio->id.type = SERIO_RS232; |
1322 | serio->open = sunsu_serio_open; | 1209 | if (up->su_type == SU_PORT_KBD) { |
1323 | serio->close = sunsu_serio_close; | 1210 | serio->id.proto = SERIO_SUNKBD; |
1324 | 1211 | strlcpy(serio->name, "sukbd", sizeof(serio->name)); | |
1325 | serio_register_port(serio); | ||
1326 | } else { | 1212 | } else { |
1327 | printk(KERN_WARNING "su%d: not enough memory for serio port\n", | 1213 | serio->id.proto = SERIO_SUN; |
1328 | channel); | 1214 | serio->id.extra = 1; |
1215 | strlcpy(serio->name, "sums", sizeof(serio->name)); | ||
1329 | } | 1216 | } |
1217 | strlcpy(serio->phys, | ||
1218 | (!(up->port.line & 1) ? "su/serio0" : "su/serio1"), | ||
1219 | sizeof(serio->phys)); | ||
1220 | |||
1221 | serio->write = sunsu_serio_write; | ||
1222 | serio->open = sunsu_serio_open; | ||
1223 | serio->close = sunsu_serio_close; | ||
1224 | serio->dev.parent = up->port.dev; | ||
1225 | |||
1226 | serio_register_port(serio); | ||
1330 | #endif | 1227 | #endif |
1331 | 1228 | ||
1332 | sunsu_change_speed(&up->port, up->cflag, 0, quot); | 1229 | sunsu_change_speed(&up->port, up->cflag, 0, quot); |
@@ -1458,22 +1355,20 @@ static struct console sunsu_cons = { | |||
1458 | * Register console. | 1355 | * Register console. |
1459 | */ | 1356 | */ |
1460 | 1357 | ||
1461 | static inline struct console *SUNSU_CONSOLE(void) | 1358 | static inline struct console *SUNSU_CONSOLE(int num_uart) |
1462 | { | 1359 | { |
1463 | int i; | 1360 | int i; |
1464 | 1361 | ||
1465 | if (con_is_present()) | 1362 | if (con_is_present()) |
1466 | return NULL; | 1363 | return NULL; |
1467 | 1364 | ||
1468 | for (i = 0; i < UART_NR; i++) { | 1365 | for (i = 0; i < num_uart; i++) { |
1469 | int this_minor = sunsu_reg.minor + i; | 1366 | int this_minor = sunsu_reg.minor + i; |
1470 | 1367 | ||
1471 | if ((this_minor - 64) == (serial_console - 1)) | 1368 | if ((this_minor - 64) == (serial_console - 1)) |
1472 | break; | 1369 | break; |
1473 | } | 1370 | } |
1474 | if (i == UART_NR) | 1371 | if (i == num_uart) |
1475 | return NULL; | ||
1476 | if (sunsu_ports[i].port_node == 0) | ||
1477 | return NULL; | 1372 | return NULL; |
1478 | 1373 | ||
1479 | sunsu_cons.index = i; | 1374 | sunsu_cons.index = i; |
@@ -1481,252 +1376,180 @@ static inline struct console *SUNSU_CONSOLE(void) | |||
1481 | return &sunsu_cons; | 1376 | return &sunsu_cons; |
1482 | } | 1377 | } |
1483 | #else | 1378 | #else |
1484 | #define SUNSU_CONSOLE() (NULL) | 1379 | #define SUNSU_CONSOLE(num_uart) (NULL) |
1485 | #define sunsu_serial_console_init() do { } while (0) | 1380 | #define sunsu_serial_console_init() do { } while (0) |
1486 | #endif | 1381 | #endif |
1487 | 1382 | ||
1488 | static int __init sunsu_serial_init(void) | 1383 | static enum su_type __devinit su_get_type(struct device_node *dp) |
1489 | { | 1384 | { |
1490 | int instance, ret, i; | 1385 | struct device_node *ap = of_find_node_by_path("/aliases"); |
1491 | |||
1492 | /* How many instances do we need? */ | ||
1493 | instance = 0; | ||
1494 | for (i = 0; i < UART_NR; i++) { | ||
1495 | struct uart_sunsu_port *up = &sunsu_ports[i]; | ||
1496 | 1386 | ||
1497 | if (up->su_type == SU_PORT_MS || | 1387 | if (ap) { |
1498 | up->su_type == SU_PORT_KBD) | 1388 | char *keyb = of_get_property(ap, "keyboard", NULL); |
1499 | continue; | 1389 | char *ms = of_get_property(ap, "mouse", NULL); |
1500 | 1390 | ||
1501 | spin_lock_init(&up->port.lock); | 1391 | if (keyb) { |
1502 | up->port.flags |= UPF_BOOT_AUTOCONF; | 1392 | if (dp == of_find_node_by_path(keyb)) |
1503 | up->port.type = PORT_UNKNOWN; | 1393 | return SU_PORT_KBD; |
1504 | up->port.uartclk = (SU_BASE_BAUD * 16); | 1394 | } |
1395 | if (ms) { | ||
1396 | if (dp == of_find_node_by_path(ms)) | ||
1397 | return SU_PORT_MS; | ||
1398 | } | ||
1399 | } | ||
1505 | 1400 | ||
1506 | sunsu_autoconfig(up); | 1401 | return SU_PORT_PORT; |
1507 | if (up->port.type == PORT_UNKNOWN) | 1402 | } |
1508 | continue; | ||
1509 | 1403 | ||
1510 | up->port.line = instance++; | 1404 | static int __devinit su_probe(struct of_device *op, const struct of_device_id *match) |
1511 | up->port.ops = &sunsu_pops; | 1405 | { |
1512 | } | 1406 | static int inst; |
1407 | struct device_node *dp = op->node; | ||
1408 | struct uart_sunsu_port *up; | ||
1409 | struct resource *rp; | ||
1410 | int err; | ||
1513 | 1411 | ||
1514 | sunsu_reg.minor = sunserial_current_minor; | 1412 | if (inst >= UART_NR) |
1413 | return -EINVAL; | ||
1515 | 1414 | ||
1516 | sunsu_reg.nr = instance; | 1415 | up = &sunsu_ports[inst]; |
1416 | up->port.line = inst; | ||
1517 | 1417 | ||
1518 | ret = uart_register_driver(&sunsu_reg); | 1418 | spin_lock_init(&up->port.lock); |
1519 | if (ret < 0) | ||
1520 | return ret; | ||
1521 | 1419 | ||
1522 | sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; | 1420 | up->su_type = su_get_type(dp); |
1523 | 1421 | ||
1524 | sunserial_current_minor += instance; | 1422 | rp = &op->resource[0]; |
1423 | up->port.mapbase = op->resource[0].start; | ||
1525 | 1424 | ||
1526 | sunsu_reg.cons = SUNSU_CONSOLE(); | 1425 | up->reg_size = (rp->end - rp->start) + 1; |
1426 | up->port.membase = of_ioremap(rp, 0, up->reg_size, "su"); | ||
1427 | if (!up->port.membase) | ||
1428 | return -ENOMEM; | ||
1527 | 1429 | ||
1528 | for (i = 0; i < UART_NR; i++) { | 1430 | up->port.irq = op->irqs[0]; |
1529 | struct uart_sunsu_port *up = &sunsu_ports[i]; | ||
1530 | 1431 | ||
1531 | /* Do not register Keyboard/Mouse lines with UART | 1432 | up->port.dev = &op->dev; |
1532 | * layer. | ||
1533 | */ | ||
1534 | if (up->su_type == SU_PORT_MS || | ||
1535 | up->su_type == SU_PORT_KBD) | ||
1536 | continue; | ||
1537 | 1433 | ||
1538 | if (up->port.type == PORT_UNKNOWN) | 1434 | up->port.type = PORT_UNKNOWN; |
1539 | continue; | 1435 | up->port.uartclk = (SU_BASE_BAUD * 16); |
1540 | 1436 | ||
1541 | uart_add_one_port(&sunsu_reg, &up->port); | 1437 | err = 0; |
1438 | if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) { | ||
1439 | err = sunsu_kbd_ms_init(up); | ||
1440 | if (err) | ||
1441 | goto out_unmap; | ||
1542 | } | 1442 | } |
1543 | 1443 | ||
1544 | return 0; | 1444 | up->port.flags |= UPF_BOOT_AUTOCONF; |
1545 | } | ||
1546 | 1445 | ||
1547 | static int su_node_ok(int node, char *name, int namelen) | 1446 | sunsu_autoconfig(up); |
1548 | { | ||
1549 | if (strncmp(name, "su", namelen) == 0 || | ||
1550 | strncmp(name, "su_pnp", namelen) == 0) | ||
1551 | return 1; | ||
1552 | |||
1553 | if (strncmp(name, "serial", namelen) == 0) { | ||
1554 | char compat[32]; | ||
1555 | int clen; | ||
1556 | |||
1557 | /* Is it _really_ a 'su' device? */ | ||
1558 | clen = prom_getproperty(node, "compatible", compat, sizeof(compat)); | ||
1559 | if (clen > 0) { | ||
1560 | if (strncmp(compat, "sab82532", 8) == 0) { | ||
1561 | /* Nope, Siemens serial, not for us. */ | ||
1562 | return 0; | ||
1563 | } | ||
1564 | } | ||
1565 | return 1; | ||
1566 | } | ||
1567 | 1447 | ||
1568 | return 0; | 1448 | err = -ENODEV; |
1569 | } | 1449 | if (up->port.type == PORT_UNKNOWN) |
1450 | goto out_unmap; | ||
1570 | 1451 | ||
1571 | #define SU_PROPSIZE 128 | 1452 | up->port.ops = &sunsu_pops; |
1572 | 1453 | ||
1573 | /* | 1454 | err = uart_add_one_port(&sunsu_reg, &up->port); |
1574 | * Scan status structure. | 1455 | if (err) |
1575 | * "prop" is a local variable but it eats stack to keep it in each | 1456 | goto out_unmap; |
1576 | * stack frame of a recursive procedure. | ||
1577 | */ | ||
1578 | struct su_probe_scan { | ||
1579 | int msnode, kbnode; /* PROM nodes for mouse and keyboard */ | ||
1580 | int msx, kbx; /* minors for mouse and keyboard */ | ||
1581 | int devices; /* scan index */ | ||
1582 | char prop[SU_PROPSIZE]; | ||
1583 | }; | ||
1584 | 1457 | ||
1585 | /* | 1458 | dev_set_drvdata(&op->dev, up); |
1586 | * We have several platforms which present 'su' in different parts | ||
1587 | * of the device tree. 'su' may be found under obio, ebus, isa and pci. | ||
1588 | * We walk over the tree and find them wherever PROM hides them. | ||
1589 | */ | ||
1590 | static void __init su_probe_any(struct su_probe_scan *t, int sunode) | ||
1591 | { | ||
1592 | struct uart_sunsu_port *up; | ||
1593 | int len; | ||
1594 | 1459 | ||
1595 | if (t->devices >= UART_NR) | 1460 | inst++; |
1596 | return; | ||
1597 | 1461 | ||
1598 | for (; sunode != 0; sunode = prom_getsibling(sunode)) { | 1462 | return 0; |
1599 | len = prom_getproperty(sunode, "name", t->prop, SU_PROPSIZE); | 1463 | |
1600 | if (len <= 1) | 1464 | out_unmap: |
1601 | continue; /* Broken PROM node */ | 1465 | of_iounmap(up->port.membase, up->reg_size); |
1602 | 1466 | return err; | |
1603 | if (su_node_ok(sunode, t->prop, len)) { | ||
1604 | up = &sunsu_ports[t->devices]; | ||
1605 | if (t->kbnode != 0 && sunode == t->kbnode) { | ||
1606 | t->kbx = t->devices; | ||
1607 | up->su_type = SU_PORT_KBD; | ||
1608 | } else if (t->msnode != 0 && sunode == t->msnode) { | ||
1609 | t->msx = t->devices; | ||
1610 | up->su_type = SU_PORT_MS; | ||
1611 | } else { | ||
1612 | #ifdef CONFIG_SPARC64 | ||
1613 | /* | ||
1614 | * Do not attempt to use the truncated | ||
1615 | * keyboard/mouse ports as serial ports | ||
1616 | * on Ultras with PC keyboard attached. | ||
1617 | */ | ||
1618 | if (prom_getbool(sunode, "mouse")) | ||
1619 | continue; | ||
1620 | if (prom_getbool(sunode, "keyboard")) | ||
1621 | continue; | ||
1622 | #endif | ||
1623 | up->su_type = SU_PORT_PORT; | ||
1624 | } | ||
1625 | up->port_node = sunode; | ||
1626 | ++t->devices; | ||
1627 | } else { | ||
1628 | su_probe_any(t, prom_getchild(sunode)); | ||
1629 | } | ||
1630 | } | ||
1631 | } | 1467 | } |
1632 | 1468 | ||
1633 | static int __init sunsu_probe(void) | 1469 | static int __devexit su_remove(struct of_device *dev) |
1634 | { | 1470 | { |
1635 | int node; | 1471 | struct uart_sunsu_port *up = dev_get_drvdata(&dev->dev);; |
1636 | int len; | ||
1637 | struct su_probe_scan scan; | ||
1638 | 1472 | ||
1639 | /* | 1473 | if (up->su_type == SU_PORT_MS || |
1640 | * First, we scan the tree. | 1474 | up->su_type == SU_PORT_KBD) { |
1641 | */ | 1475 | #ifdef CONFIG_SERIO |
1642 | scan.devices = 0; | 1476 | serio_unregister_port(&up->serio); |
1643 | scan.msx = -1; | 1477 | #endif |
1644 | scan.kbx = -1; | 1478 | } else if (up->port.type != PORT_UNKNOWN) |
1645 | scan.kbnode = 0; | 1479 | uart_remove_one_port(&sunsu_reg, &up->port); |
1646 | scan.msnode = 0; | ||
1647 | 1480 | ||
1648 | /* | 1481 | return 0; |
1649 | * Get the nodes for keyboard and mouse from 'aliases'... | 1482 | } |
1650 | */ | ||
1651 | node = prom_getchild(prom_root_node); | ||
1652 | node = prom_searchsiblings(node, "aliases"); | ||
1653 | if (node != 0) { | ||
1654 | len = prom_getproperty(node, "keyboard", scan.prop, SU_PROPSIZE); | ||
1655 | if (len > 0) { | ||
1656 | scan.prop[len] = 0; | ||
1657 | scan.kbnode = prom_finddevice(scan.prop); | ||
1658 | } | ||
1659 | 1483 | ||
1660 | len = prom_getproperty(node, "mouse", scan.prop, SU_PROPSIZE); | 1484 | static struct of_device_id su_match[] = { |
1661 | if (len > 0) { | 1485 | { |
1662 | scan.prop[len] = 0; | 1486 | .name = "su", |
1663 | scan.msnode = prom_finddevice(scan.prop); | 1487 | }, |
1664 | } | 1488 | { |
1665 | } | 1489 | .name = "su_pnp", |
1490 | }, | ||
1491 | { | ||
1492 | .name = "serial", | ||
1493 | .compatible = "su", | ||
1494 | }, | ||
1495 | {}, | ||
1496 | }; | ||
1497 | MODULE_DEVICE_TABLE(of, su_match); | ||
1666 | 1498 | ||
1667 | su_probe_any(&scan, prom_getchild(prom_root_node)); | 1499 | static struct of_platform_driver su_driver = { |
1500 | .name = "su", | ||
1501 | .match_table = su_match, | ||
1502 | .probe = su_probe, | ||
1503 | .remove = __devexit_p(su_remove), | ||
1504 | }; | ||
1668 | 1505 | ||
1669 | /* | 1506 | static int num_uart; |
1670 | * Second, we process the special case of keyboard and mouse. | ||
1671 | * | ||
1672 | * Currently if we got keyboard and mouse hooked to "su" ports | ||
1673 | * we do not use any possible remaining "su" as a serial port. | ||
1674 | * Thus, we ignore values of .msx and .kbx, then compact ports. | ||
1675 | */ | ||
1676 | if (scan.msx != -1 && scan.kbx != -1) { | ||
1677 | sunsu_ports[0].su_type = SU_PORT_MS; | ||
1678 | sunsu_ports[0].port_node = scan.msnode; | ||
1679 | sunsu_kbd_ms_init(&sunsu_ports[0], 0); | ||
1680 | 1507 | ||
1681 | sunsu_ports[1].su_type = SU_PORT_KBD; | 1508 | static int __init sunsu_init(void) |
1682 | sunsu_ports[1].port_node = scan.kbnode; | 1509 | { |
1683 | sunsu_kbd_ms_init(&sunsu_ports[1], 1); | 1510 | struct device_node *dp; |
1511 | int err; | ||
1684 | 1512 | ||
1685 | return 0; | 1513 | num_uart = 0; |
1514 | for_each_node_by_name(dp, "su") { | ||
1515 | if (su_get_type(dp) == SU_PORT_PORT) | ||
1516 | num_uart++; | ||
1686 | } | 1517 | } |
1687 | 1518 | for_each_node_by_name(dp, "su_pnp") { | |
1688 | if (scan.msx != -1 || scan.kbx != -1) { | 1519 | if (su_get_type(dp) == SU_PORT_PORT) |
1689 | printk("sunsu_probe: cannot match keyboard and mouse, confused\n"); | 1520 | num_uart++; |
1690 | return -ENODEV; | 1521 | } |
1522 | for_each_node_by_name(dp, "serial") { | ||
1523 | if (of_device_is_compatible(dp, "su")) { | ||
1524 | if (su_get_type(dp) == SU_PORT_PORT) | ||
1525 | num_uart++; | ||
1526 | } | ||
1691 | } | 1527 | } |
1692 | 1528 | ||
1693 | if (scan.devices == 0) | 1529 | if (num_uart) { |
1694 | return -ENODEV; | 1530 | sunsu_reg.minor = sunserial_current_minor; |
1531 | sunsu_reg.nr = num_uart; | ||
1532 | err = uart_register_driver(&sunsu_reg); | ||
1533 | if (err) | ||
1534 | return err; | ||
1535 | sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; | ||
1536 | sunserial_current_minor += num_uart; | ||
1537 | sunsu_reg.cons = SUNSU_CONSOLE(num_uart); | ||
1538 | } | ||
1695 | 1539 | ||
1696 | /* | 1540 | err = of_register_driver(&su_driver, &of_bus_type); |
1697 | * Console must be initiated after the generic initialization. | 1541 | if (err && num_uart) |
1698 | */ | 1542 | uart_unregister_driver(&sunsu_reg); |
1699 | sunsu_serial_init(); | ||
1700 | 1543 | ||
1701 | return 0; | 1544 | return err; |
1702 | } | 1545 | } |
1703 | 1546 | ||
1704 | static void __exit sunsu_exit(void) | 1547 | static void __exit sunsu_exit(void) |
1705 | { | 1548 | { |
1706 | int i, saw_uart; | 1549 | if (num_uart) |
1707 | |||
1708 | saw_uart = 0; | ||
1709 | for (i = 0; i < UART_NR; i++) { | ||
1710 | struct uart_sunsu_port *up = &sunsu_ports[i]; | ||
1711 | |||
1712 | if (up->su_type == SU_PORT_MS || | ||
1713 | up->su_type == SU_PORT_KBD) { | ||
1714 | #ifdef CONFIG_SERIO | ||
1715 | if (up->serio) { | ||
1716 | serio_unregister_port(up->serio); | ||
1717 | up->serio = NULL; | ||
1718 | } | ||
1719 | #endif | ||
1720 | } else if (up->port.type != PORT_UNKNOWN) { | ||
1721 | uart_remove_one_port(&sunsu_reg, &up->port); | ||
1722 | saw_uart++; | ||
1723 | } | ||
1724 | } | ||
1725 | |||
1726 | if (saw_uart) | ||
1727 | uart_unregister_driver(&sunsu_reg); | 1550 | uart_unregister_driver(&sunsu_reg); |
1728 | } | 1551 | } |
1729 | 1552 | ||
1730 | module_init(sunsu_probe); | 1553 | module_init(sunsu_init); |
1731 | module_exit(sunsu_exit); | 1554 | module_exit(sunsu_exit); |
1732 | MODULE_LICENSE("GPL"); | 1555 | MODULE_LICENSE("GPL"); |