diff options
| -rw-r--r-- | drivers/serial/uartlite.c | 99 |
1 files changed, 65 insertions, 34 deletions
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 10e0da97811e..c00a627ef89e 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c | |||
| @@ -413,59 +413,90 @@ static struct uart_driver ulite_uart_driver = { | |||
| 413 | #endif | 413 | #endif |
| 414 | }; | 414 | }; |
| 415 | 415 | ||
| 416 | static int __devinit ulite_probe(struct platform_device *pdev) | 416 | static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) |
| 417 | { | 417 | { |
| 418 | struct resource *res, *res2; | ||
| 419 | struct uart_port *port; | 418 | struct uart_port *port; |
| 419 | int rc; | ||
| 420 | 420 | ||
| 421 | if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS) | 421 | /* if id = -1; then scan for a free id and use that */ |
| 422 | if (id < 0) { | ||
| 423 | for (id = 0; id < ULITE_NR_UARTS; id++) | ||
| 424 | if (ulite_ports[id].mapbase == 0) | ||
| 425 | break; | ||
| 426 | } | ||
| 427 | if (id < 0 || id >= ULITE_NR_UARTS) { | ||
| 428 | dev_err(dev, "%s%i too large\n", ULITE_NAME, id); | ||
| 422 | return -EINVAL; | 429 | return -EINVAL; |
| 430 | } | ||
| 423 | 431 | ||
| 424 | if (ulite_ports[pdev->id].membase) | 432 | if (ulite_ports[id].mapbase) { |
| 433 | dev_err(dev, "cannot assign to %s%i; it is already in use\n", | ||
| 434 | ULITE_NAME, id); | ||
| 425 | return -EBUSY; | 435 | return -EBUSY; |
| 436 | } | ||
| 426 | 437 | ||
| 427 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 438 | port = &ulite_ports[id]; |
| 428 | if (!res) | ||
| 429 | return -ENODEV; | ||
| 430 | 439 | ||
| 431 | res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 440 | spin_lock_init(&port->lock); |
| 432 | if (!res2) | 441 | port->fifosize = 16; |
| 433 | return -ENODEV; | 442 | port->regshift = 2; |
| 443 | port->iotype = UPIO_MEM; | ||
| 444 | port->iobase = 1; /* mark port in use */ | ||
| 445 | port->mapbase = base; | ||
| 446 | port->membase = NULL; | ||
| 447 | port->ops = &ulite_ops; | ||
| 448 | port->irq = irq; | ||
| 449 | port->flags = UPF_BOOT_AUTOCONF; | ||
| 450 | port->dev = dev; | ||
| 451 | port->type = PORT_UNKNOWN; | ||
| 452 | port->line = id; | ||
| 453 | |||
| 454 | dev_set_drvdata(dev, port); | ||
| 455 | |||
| 456 | /* Register the port */ | ||
| 457 | rc = uart_add_one_port(&ulite_uart_driver, port); | ||
| 458 | if (rc) { | ||
| 459 | dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc); | ||
| 460 | port->mapbase = 0; | ||
| 461 | dev_set_drvdata(dev, NULL); | ||
| 462 | return rc; | ||
| 463 | } | ||
| 434 | 464 | ||
| 435 | port = &ulite_ports[pdev->id]; | 465 | return 0; |
| 466 | } | ||
| 436 | 467 | ||
| 437 | port->fifosize = 16; | 468 | static int __devinit ulite_release(struct device *dev) |
| 438 | port->regshift = 2; | 469 | { |
| 439 | port->iotype = UPIO_MEM; | 470 | struct uart_port *port = dev_get_drvdata(dev); |
| 440 | port->iobase = 1; /* mark port in use */ | 471 | int rc = 0; |
| 441 | port->mapbase = res->start; | ||
| 442 | port->membase = NULL; | ||
| 443 | port->ops = &ulite_ops; | ||
| 444 | port->irq = res2->start; | ||
| 445 | port->flags = UPF_BOOT_AUTOCONF; | ||
| 446 | port->dev = &pdev->dev; | ||
| 447 | port->type = PORT_UNKNOWN; | ||
| 448 | port->line = pdev->id; | ||
| 449 | 472 | ||
| 450 | uart_add_one_port(&ulite_uart_driver, port); | 473 | if (port) { |
| 451 | platform_set_drvdata(pdev, port); | 474 | rc = uart_remove_one_port(&ulite_uart_driver, port); |
| 475 | dev_set_drvdata(dev, NULL); | ||
| 476 | port->mapbase = 0; | ||
| 477 | } | ||
| 452 | 478 | ||
| 453 | return 0; | 479 | return rc; |
| 454 | } | 480 | } |
| 455 | 481 | ||
| 456 | static int ulite_remove(struct platform_device *pdev) | 482 | static int __devinit ulite_probe(struct platform_device *pdev) |
| 457 | { | 483 | { |
| 458 | struct uart_port *port = platform_get_drvdata(pdev); | 484 | struct resource *res, *res2; |
| 459 | 485 | ||
| 460 | platform_set_drvdata(pdev, NULL); | 486 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 487 | if (!res) | ||
| 488 | return -ENODEV; | ||
| 461 | 489 | ||
| 462 | if (port) | 490 | res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| 463 | uart_remove_one_port(&ulite_uart_driver, port); | 491 | if (!res2) |
| 492 | return -ENODEV; | ||
| 464 | 493 | ||
| 465 | /* mark port as free */ | 494 | return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start); |
| 466 | port->membase = NULL; | 495 | } |
| 467 | 496 | ||
| 468 | return 0; | 497 | static int ulite_remove(struct platform_device *pdev) |
| 498 | { | ||
| 499 | return ulite_release(&pdev->dev); | ||
| 469 | } | 500 | } |
| 470 | 501 | ||
| 471 | static struct platform_driver ulite_platform_driver = { | 502 | static struct platform_driver ulite_platform_driver = { |
