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 = { |