diff options
-rw-r--r-- | drivers/char/mxser_new.c | 175 |
1 files changed, 88 insertions, 87 deletions
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index 792524ab348e..c06c5920bf1c 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c | |||
@@ -283,8 +283,7 @@ struct mxser_port { | |||
283 | }; | 283 | }; |
284 | 284 | ||
285 | struct mxser_board { | 285 | struct mxser_board { |
286 | struct pci_dev *pdev; /* temporary (until pci probing) */ | 286 | unsigned int idx; |
287 | |||
288 | int irq; | 287 | int irq; |
289 | const struct mxser_cardinfo *info; | 288 | const struct mxser_cardinfo *info; |
290 | unsigned long vector; | 289 | unsigned long vector; |
@@ -2383,10 +2382,9 @@ static const struct tty_operations mxser_ops = { | |||
2383 | * The MOXA Smartio/Industio serial driver boot-time initialization code! | 2382 | * The MOXA Smartio/Industio serial driver boot-time initialization code! |
2384 | */ | 2383 | */ |
2385 | 2384 | ||
2386 | static void mxser_release_res(struct mxser_board *brd, unsigned int irq) | 2385 | static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev, |
2386 | unsigned int irq) | ||
2387 | { | 2387 | { |
2388 | struct pci_dev *pdev = brd->pdev; | ||
2389 | |||
2390 | if (irq) | 2388 | if (irq) |
2391 | free_irq(brd->irq, brd); | 2389 | free_irq(brd->irq, brd); |
2392 | if (pdev != NULL) { /* PCI */ | 2390 | if (pdev != NULL) { /* PCI */ |
@@ -2399,7 +2397,8 @@ static void mxser_release_res(struct mxser_board *brd, unsigned int irq) | |||
2399 | } | 2397 | } |
2400 | } | 2398 | } |
2401 | 2399 | ||
2402 | static int __devinit mxser_initbrd(struct mxser_board *brd) | 2400 | static int __devinit mxser_initbrd(struct mxser_board *brd, |
2401 | struct pci_dev *pdev) | ||
2403 | { | 2402 | { |
2404 | struct mxser_port *info; | 2403 | struct mxser_port *info; |
2405 | unsigned int i; | 2404 | unsigned int i; |
@@ -2450,7 +2449,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd) | |||
2450 | "conflict with another device.\n", | 2449 | "conflict with another device.\n", |
2451 | brd->info->name, brd->irq); | 2450 | brd->info->name, brd->irq); |
2452 | /* We hold resources, we need to release them. */ | 2451 | /* We hold resources, we need to release them. */ |
2453 | mxser_release_res(brd, 0); | 2452 | mxser_release_res(brd, pdev, 0); |
2454 | return retval; | 2453 | return retval; |
2455 | } | 2454 | } |
2456 | return 0; | 2455 | return 0; |
@@ -2552,20 +2551,43 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) | |||
2552 | return brd->info->nports; | 2551 | return brd->info->nports; |
2553 | } | 2552 | } |
2554 | 2553 | ||
2555 | static int __init mxser_get_PCI_conf(const struct pci_device_id *ent, | 2554 | static int __devinit mxser_probe(struct pci_dev *pdev, |
2556 | struct mxser_board *brd, struct pci_dev *pdev) | 2555 | const struct pci_device_id *ent) |
2557 | { | 2556 | { |
2557 | struct mxser_board *brd; | ||
2558 | unsigned int i, j; | 2558 | unsigned int i, j; |
2559 | unsigned long ioaddress; | 2559 | unsigned long ioaddress; |
2560 | int retval; | 2560 | int retval = -EINVAL; |
2561 | |||
2562 | for (i = 0; i < MXSER_BOARDS; i++) | ||
2563 | if (mxser_boards[i].info == NULL) | ||
2564 | break; | ||
2565 | |||
2566 | if (i >= MXSER_BOARDS) { | ||
2567 | printk(KERN_ERR "Too many Smartio/Industio family boards found " | ||
2568 | "(maximum %d), board not configured\n", MXSER_BOARDS); | ||
2569 | goto err; | ||
2570 | } | ||
2571 | |||
2572 | brd = &mxser_boards[i]; | ||
2573 | brd->idx = i * MXSER_PORTS_PER_BOARD; | ||
2574 | printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n", | ||
2575 | mxser_cards[ent->driver_data].name, | ||
2576 | pdev->bus->number, PCI_SLOT(pdev->devfn)); | ||
2577 | |||
2578 | retval = pci_enable_device(pdev); | ||
2579 | if (retval) { | ||
2580 | printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n"); | ||
2581 | goto err; | ||
2582 | } | ||
2561 | 2583 | ||
2562 | /* io address */ | 2584 | /* io address */ |
2563 | brd->info = &mxser_cards[ent->driver_data]; | ||
2564 | ioaddress = pci_resource_start(pdev, 2); | 2585 | ioaddress = pci_resource_start(pdev, 2); |
2565 | retval = pci_request_region(pdev, 2, "mxser(IO)"); | 2586 | retval = pci_request_region(pdev, 2, "mxser(IO)"); |
2566 | if (retval) | 2587 | if (retval) |
2567 | goto err; | 2588 | goto err; |
2568 | 2589 | ||
2590 | brd->info = &mxser_cards[ent->driver_data]; | ||
2569 | for (i = 0; i < brd->info->nports; i++) | 2591 | for (i = 0; i < brd->info->nports; i++) |
2570 | brd->ports[i].ioaddr = ioaddress + 8 * i; | 2592 | brd->ports[i].ioaddr = ioaddress + 8 * i; |
2571 | 2593 | ||
@@ -2612,20 +2634,50 @@ static int __init mxser_get_PCI_conf(const struct pci_device_id *ent, | |||
2612 | brd->vector_mask |= (1 << i); | 2634 | brd->vector_mask |= (1 << i); |
2613 | brd->ports[i].baud_base = 921600; | 2635 | brd->ports[i].baud_base = 921600; |
2614 | } | 2636 | } |
2637 | |||
2638 | /* mxser_initbrd will hook ISR. */ | ||
2639 | if (mxser_initbrd(brd, pdev) < 0) | ||
2640 | goto err_relvec; | ||
2641 | |||
2642 | for (i = 0; i < brd->info->nports; i++) | ||
2643 | tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev); | ||
2644 | |||
2645 | pci_set_drvdata(pdev, brd); | ||
2646 | |||
2615 | return 0; | 2647 | return 0; |
2648 | err_relvec: | ||
2649 | pci_release_region(pdev, 3); | ||
2616 | err_relio: | 2650 | err_relio: |
2617 | pci_release_region(pdev, 2); | 2651 | pci_release_region(pdev, 2); |
2652 | brd->info = NULL; | ||
2618 | err: | 2653 | err: |
2619 | return retval; | 2654 | return retval; |
2620 | } | 2655 | } |
2621 | 2656 | ||
2657 | static void __devexit mxser_remove(struct pci_dev *pdev) | ||
2658 | { | ||
2659 | struct mxser_board *brd = pci_get_drvdata(pdev); | ||
2660 | unsigned int i; | ||
2661 | |||
2662 | for (i = 0; i < brd->info->nports; i++) | ||
2663 | tty_unregister_device(mxvar_sdriver, brd->idx + i); | ||
2664 | |||
2665 | mxser_release_res(brd, pdev, 1); | ||
2666 | } | ||
2667 | |||
2668 | static struct pci_driver mxser_driver = { | ||
2669 | .name = "mxser", | ||
2670 | .id_table = mxser_pcibrds, | ||
2671 | .probe = mxser_probe, | ||
2672 | .remove = __devexit_p(mxser_remove) | ||
2673 | }; | ||
2674 | |||
2622 | static int __init mxser_module_init(void) | 2675 | static int __init mxser_module_init(void) |
2623 | { | 2676 | { |
2624 | struct pci_dev *pdev = NULL; | ||
2625 | struct mxser_board *brd; | 2677 | struct mxser_board *brd; |
2626 | unsigned long cap; | 2678 | unsigned long cap; |
2627 | unsigned int i, m, isaloop; | 2679 | unsigned int i, m, isaloop; |
2628 | int retval, b, n; | 2680 | int retval, b; |
2629 | 2681 | ||
2630 | pr_debug("Loading module mxser ...\n"); | 2682 | pr_debug("Loading module mxser ...\n"); |
2631 | 2683 | ||
@@ -2696,87 +2748,31 @@ static int __init mxser_module_init(void) | |||
2696 | printk(KERN_ERR "Invalid I/O address, " | 2748 | printk(KERN_ERR "Invalid I/O address, " |
2697 | "board not configured\n"); | 2749 | "board not configured\n"); |
2698 | 2750 | ||
2751 | brd->info = NULL; | ||
2699 | continue; | 2752 | continue; |
2700 | } | 2753 | } |
2701 | 2754 | ||
2702 | brd->pdev = NULL; | ||
2703 | |||
2704 | /* mxser_initbrd will hook ISR. */ | 2755 | /* mxser_initbrd will hook ISR. */ |
2705 | if (mxser_initbrd(brd) < 0) | 2756 | if (mxser_initbrd(brd, NULL) < 0) { |
2706 | continue; | 2757 | brd->info = NULL; |
2707 | |||
2708 | for (i = 0; i < brd->info->nports; i++) | ||
2709 | tty_register_device(mxvar_sdriver, | ||
2710 | m * MXSER_PORTS_PER_BOARD + i, NULL); | ||
2711 | |||
2712 | m++; | ||
2713 | } | ||
2714 | |||
2715 | /* start finding PCI board here */ | ||
2716 | n = ARRAY_SIZE(mxser_pcibrds) - 1; | ||
2717 | b = 0; | ||
2718 | while (b < n) { | ||
2719 | pdev = pci_get_device(mxser_pcibrds[b].vendor, | ||
2720 | mxser_pcibrds[b].device, pdev); | ||
2721 | if (pdev == NULL) { | ||
2722 | b++; | ||
2723 | continue; | ||
2724 | } | ||
2725 | printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n", | ||
2726 | mxser_cards[mxser_pcibrds[b].driver_data].name, | ||
2727 | pdev->bus->number, PCI_SLOT(pdev->devfn)); | ||
2728 | if (m >= MXSER_BOARDS) | ||
2729 | printk(KERN_ERR | ||
2730 | "Too many Smartio/Industio family boards find " | ||
2731 | "(maximum %d), board not configured\n", | ||
2732 | MXSER_BOARDS); | ||
2733 | else { | ||
2734 | if (pci_enable_device(pdev)) { | ||
2735 | printk(KERN_ERR "Moxa SmartI/O PCI enable " | ||
2736 | "fail !\n"); | ||
2737 | continue; | ||
2738 | } | ||
2739 | brd = &mxser_boards[m]; | ||
2740 | brd->pdev = pdev; | ||
2741 | retval = mxser_get_PCI_conf(&mxser_pcibrds[b], | ||
2742 | brd, pdev); | ||
2743 | if (retval < 0) { | ||
2744 | if (retval == MXSER_ERR_IRQ) | ||
2745 | printk(KERN_ERR | ||
2746 | "Invalid interrupt number, " | ||
2747 | "board not configured\n"); | ||
2748 | else if (retval == MXSER_ERR_IRQ_CONFLIT) | ||
2749 | printk(KERN_ERR | ||
2750 | "Invalid interrupt number, " | ||
2751 | "board not configured\n"); | ||
2752 | else if (retval == MXSER_ERR_VECTOR) | ||
2753 | printk(KERN_ERR | ||
2754 | "Invalid interrupt vector, " | ||
2755 | "board not configured\n"); | ||
2756 | else if (retval == MXSER_ERR_IOADDR) | ||
2757 | printk(KERN_ERR | ||
2758 | "Invalid I/O address, " | ||
2759 | "board not configured\n"); | ||
2760 | continue; | 2758 | continue; |
2761 | } | 2759 | } |
2762 | /* mxser_initbrd will hook ISR. */ | 2760 | |
2763 | if (mxser_initbrd(brd) < 0) | 2761 | brd->idx = m * MXSER_PORTS_PER_BOARD; |
2764 | continue; | ||
2765 | for (i = 0; i < brd->info->nports; i++) | 2762 | for (i = 0; i < brd->info->nports; i++) |
2766 | tty_register_device(mxvar_sdriver, | 2763 | tty_register_device(mxvar_sdriver, brd->idx + i, |
2767 | m * MXSER_PORTS_PER_BOARD + i, | 2764 | NULL); |
2768 | &pdev->dev); | ||
2769 | 2765 | ||
2770 | m++; | 2766 | m++; |
2771 | /* Keep an extra reference if we succeeded. It will | ||
2772 | be returned at unload time */ | ||
2773 | pci_dev_get(pdev); | ||
2774 | } | 2767 | } |
2775 | } | ||
2776 | 2768 | ||
2777 | if (!m) { | 2769 | retval = pci_register_driver(&mxser_driver); |
2778 | retval = -ENODEV; | 2770 | if (retval) { |
2779 | goto err_unr; | 2771 | printk(KERN_ERR "Can't register pci driver\n"); |
2772 | if (!m) { | ||
2773 | retval = -ENODEV; | ||
2774 | goto err_unr; | ||
2775 | } /* else: we have some ISA cards under control */ | ||
2780 | } | 2776 | } |
2781 | 2777 | ||
2782 | pr_debug("Done.\n"); | 2778 | pr_debug("Done.\n"); |
@@ -2791,18 +2787,23 @@ err_put: | |||
2791 | 2787 | ||
2792 | static void __exit mxser_module_exit(void) | 2788 | static void __exit mxser_module_exit(void) |
2793 | { | 2789 | { |
2794 | unsigned int i; | 2790 | unsigned int i, j; |
2795 | 2791 | ||
2796 | pr_debug("Unloading module mxser ...\n"); | 2792 | pr_debug("Unloading module mxser ...\n"); |
2797 | 2793 | ||
2798 | for (i = 0; i < MXSER_PORTS; i++) | 2794 | pci_unregister_driver(&mxser_driver); |
2799 | tty_unregister_device(mxvar_sdriver, i); | 2795 | |
2796 | for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */ | ||
2797 | if (mxser_boards[i].info != NULL) | ||
2798 | for (j = 0; j < mxser_boards[i].info->nports; j++) | ||
2799 | tty_unregister_device(mxvar_sdriver, | ||
2800 | mxser_boards[i].idx + j); | ||
2800 | tty_unregister_driver(mxvar_sdriver); | 2801 | tty_unregister_driver(mxvar_sdriver); |
2801 | put_tty_driver(mxvar_sdriver); | 2802 | put_tty_driver(mxvar_sdriver); |
2802 | 2803 | ||
2803 | for (i = 0; i < MXSER_BOARDS; i++) | 2804 | for (i = 0; i < MXSER_BOARDS; i++) |
2804 | if (mxser_boards[i].info != NULL) | 2805 | if (mxser_boards[i].info != NULL) |
2805 | mxser_release_res(&mxser_boards[i], 1); | 2806 | mxser_release_res(&mxser_boards[i], NULL, 1); |
2806 | 2807 | ||
2807 | pr_debug("Done.\n"); | 2808 | pr_debug("Done.\n"); |
2808 | } | 2809 | } |