aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/sunsu.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-07-13 00:04:21 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-07-13 04:50:11 -0400
commit91d1ed1a6d225e3cf4bd8ede6235b1be65f7651a (patch)
tree38df1d1daebf331969348ac280f5b9add80b2adb /drivers/serial/sunsu.c
parenta23c3a86e9952a8badb49a6bb1de455c1f5bad6d (diff)
[SERIAL] sunsu: Handle keyboard and mouse ports directly.
The sunsu_ports[] array exists merely to be able to easily use an integer index to get at the proper serial console port struct. We size this only for real ports, not for the keyboard and mouse, and thus keyboard and mouse port registration would fail. Fix this by dynamically allocating the port struct for the keyboard and mouse, instead of using the sunsu_ports[] array. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/serial/sunsu.c')
-rw-r--r--drivers/serial/sunsu.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index f9013baba05..93bdaa3169f 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1406,25 +1406,35 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
1406 struct device_node *dp = op->node; 1406 struct device_node *dp = op->node;
1407 struct uart_sunsu_port *up; 1407 struct uart_sunsu_port *up;
1408 struct resource *rp; 1408 struct resource *rp;
1409 enum su_type type;
1409 int err; 1410 int err;
1410 1411
1411 if (inst >= UART_NR) 1412 type = su_get_type(dp);
1412 return -EINVAL; 1413 if (type == SU_PORT_PORT) {
1414 if (inst >= UART_NR)
1415 return -EINVAL;
1416 up = &sunsu_ports[inst];
1417 } else {
1418 up = kzalloc(sizeof(*up), GFP_KERNEL);
1419 if (!up)
1420 return -ENOMEM;
1421 }
1413 1422
1414 up = &sunsu_ports[inst];
1415 up->port.line = inst; 1423 up->port.line = inst;
1416 1424
1417 spin_lock_init(&up->port.lock); 1425 spin_lock_init(&up->port.lock);
1418 1426
1419 up->su_type = su_get_type(dp); 1427 up->su_type = type;
1420 1428
1421 rp = &op->resource[0]; 1429 rp = &op->resource[0];
1422 up->port.mapbase = op->resource[0].start; 1430 up->port.mapbase = rp->start;
1423
1424 up->reg_size = (rp->end - rp->start) + 1; 1431 up->reg_size = (rp->end - rp->start) + 1;
1425 up->port.membase = of_ioremap(rp, 0, up->reg_size, "su"); 1432 up->port.membase = of_ioremap(rp, 0, up->reg_size, "su");
1426 if (!up->port.membase) 1433 if (!up->port.membase) {
1434 if (type != SU_PORT_PORT)
1435 kfree(up);
1427 return -ENOMEM; 1436 return -ENOMEM;
1437 }
1428 1438
1429 up->port.irq = op->irqs[0]; 1439 up->port.irq = op->irqs[0];
1430 1440
@@ -1436,8 +1446,11 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
1436 err = 0; 1446 err = 0;
1437 if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) { 1447 if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) {
1438 err = sunsu_kbd_ms_init(up); 1448 err = sunsu_kbd_ms_init(up);
1439 if (err) 1449 if (err) {
1450 kfree(up);
1440 goto out_unmap; 1451 goto out_unmap;
1452 }
1453 dev_set_drvdata(&op->dev, up);
1441 1454
1442 return 0; 1455 return 0;
1443 } 1456 }
@@ -1476,8 +1489,12 @@ static int __devexit su_remove(struct of_device *dev)
1476#ifdef CONFIG_SERIO 1489#ifdef CONFIG_SERIO
1477 serio_unregister_port(&up->serio); 1490 serio_unregister_port(&up->serio);
1478#endif 1491#endif
1479 } else if (up->port.type != PORT_UNKNOWN) 1492 kfree(up);
1493 } else if (up->port.type != PORT_UNKNOWN) {
1480 uart_remove_one_port(&sunsu_reg, &up->port); 1494 uart_remove_one_port(&sunsu_reg, &up->port);
1495 }
1496
1497 dev_set_drvdata(&dev->dev, NULL);
1481 1498
1482 return 0; 1499 return 0;
1483} 1500}