18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/************************************************************************
38c2ecf20Sopenharmony_ci * Copyright 2003 Digi International (www.digi.com)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2004 IBM Corporation. All rights reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Contact Information:
88c2ecf20Sopenharmony_ci * Scott H Kilau <Scott_Kilau@digi.com>
98c2ecf20Sopenharmony_ci * Wendy Xiong   <wendyx@us.ibm.com>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci ***********************************************************************/
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/pci.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "jsm.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Digi International, https://www.digi.com");
208c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line");
218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
228c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("jsm");
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define JSM_DRIVER_NAME "jsm"
258c2ecf20Sopenharmony_ci#define NR_PORTS	32
268c2ecf20Sopenharmony_ci#define JSM_MINOR_START	0
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct uart_driver jsm_uart_driver = {
298c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
308c2ecf20Sopenharmony_ci	.driver_name	= JSM_DRIVER_NAME,
318c2ecf20Sopenharmony_ci	.dev_name	= "ttyn",
328c2ecf20Sopenharmony_ci	.major		= 0,
338c2ecf20Sopenharmony_ci	.minor		= JSM_MINOR_START,
348c2ecf20Sopenharmony_ci	.nr		= NR_PORTS,
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
388c2ecf20Sopenharmony_ci					pci_channel_state_t state);
398c2ecf20Sopenharmony_cistatic pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
408c2ecf20Sopenharmony_cistatic void jsm_io_resume(struct pci_dev *pdev);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic const struct pci_error_handlers jsm_err_handler = {
438c2ecf20Sopenharmony_ci	.error_detected = jsm_io_error_detected,
448c2ecf20Sopenharmony_ci	.slot_reset = jsm_io_slot_reset,
458c2ecf20Sopenharmony_ci	.resume = jsm_io_resume,
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciint jsm_debug;
498c2ecf20Sopenharmony_cimodule_param(jsm_debug, int, 0);
508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(jsm_debug, "Driver debugging level");
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	int rc = 0;
558c2ecf20Sopenharmony_ci	struct jsm_board *brd;
568c2ecf20Sopenharmony_ci	static int adapter_count;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	rc = pci_enable_device(pdev);
598c2ecf20Sopenharmony_ci	if (rc) {
608c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Device enable FAILED\n");
618c2ecf20Sopenharmony_ci		goto out;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	rc = pci_request_regions(pdev, JSM_DRIVER_NAME);
658c2ecf20Sopenharmony_ci	if (rc) {
668c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "pci_request_region FAILED\n");
678c2ecf20Sopenharmony_ci		goto out_disable_device;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	brd = kzalloc(sizeof(*brd), GFP_KERNEL);
718c2ecf20Sopenharmony_ci	if (!brd) {
728c2ecf20Sopenharmony_ci		rc = -ENOMEM;
738c2ecf20Sopenharmony_ci		goto out_release_regions;
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	/* store the info for the board we've found */
778c2ecf20Sopenharmony_ci	brd->boardnum = adapter_count++;
788c2ecf20Sopenharmony_ci	brd->pci_dev = pdev;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	switch (pdev->device) {
818c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_2DB9:
828c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_2DB9PRI:
838c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_2RJ45:
848c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_2RJ45PRI:
858c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_2_422_485:
868c2ecf20Sopenharmony_ci		brd->maxports = 2;
878c2ecf20Sopenharmony_ci		break;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_4:
908c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_4_422:
918c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_4:
928c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_NEO_4:
938c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_NEO_4RJ45:
948c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_NEO_4_IBM:
958c2ecf20Sopenharmony_ci		brd->maxports = 4;
968c2ecf20Sopenharmony_ci		break;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_8:
998c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_8_422:
1008c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_DIGI_NEO_8:
1018c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_NEO_8:
1028c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_NEO_8RJ45:
1038c2ecf20Sopenharmony_ci		brd->maxports = 8;
1048c2ecf20Sopenharmony_ci		break;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	default:
1078c2ecf20Sopenharmony_ci		brd->maxports = 1;
1088c2ecf20Sopenharmony_ci		break;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	spin_lock_init(&brd->bd_intr_lock);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* store which revision we have */
1148c2ecf20Sopenharmony_ci	brd->rev = pdev->revision;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	brd->irq = pdev->irq;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	switch (pdev->device) {
1198c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_4:
1208c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_4_422:
1218c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_8:
1228c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_8_422:
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		jsm_dbg(INIT, &brd->pci_dev,
1258c2ecf20Sopenharmony_ci			"jsm_found_board - Classic adapter\n");
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci		/*
1288c2ecf20Sopenharmony_ci		 * For PCI ClassicBoards
1298c2ecf20Sopenharmony_ci		 * PCI Local Address (.i.e. "resource" number) space
1308c2ecf20Sopenharmony_ci		 * 0	PLX Memory Mapped Config
1318c2ecf20Sopenharmony_ci		 * 1	PLX I/O Mapped Config
1328c2ecf20Sopenharmony_ci		 * 2	I/O Mapped UARTs and Status
1338c2ecf20Sopenharmony_ci		 * 3	Memory Mapped VPD
1348c2ecf20Sopenharmony_ci		 * 4	Memory Mapped UARTs and Status
1358c2ecf20Sopenharmony_ci		 */
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci		/* Get the PCI Base Address Registers */
1388c2ecf20Sopenharmony_ci		brd->membase = pci_resource_start(pdev, 4);
1398c2ecf20Sopenharmony_ci		brd->membase_end = pci_resource_end(pdev, 4);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci		if (brd->membase & 0x1)
1428c2ecf20Sopenharmony_ci			brd->membase &= ~0x3;
1438c2ecf20Sopenharmony_ci		else
1448c2ecf20Sopenharmony_ci			brd->membase &= ~0xF;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci		brd->iobase = pci_resource_start(pdev, 1);
1478c2ecf20Sopenharmony_ci		brd->iobase_end = pci_resource_end(pdev, 1);
1488c2ecf20Sopenharmony_ci		brd->iobase = ((unsigned int)(brd->iobase)) & 0xFFFE;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci		/* Assign the board_ops struct */
1518c2ecf20Sopenharmony_ci		brd->bd_ops = &jsm_cls_ops;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci		brd->bd_uart_offset = 0x8;
1548c2ecf20Sopenharmony_ci		brd->bd_dividend = 921600;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		brd->re_map_membase = ioremap(brd->membase,
1578c2ecf20Sopenharmony_ci						pci_resource_len(pdev, 4));
1588c2ecf20Sopenharmony_ci		if (!brd->re_map_membase) {
1598c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
1608c2ecf20Sopenharmony_ci				"Card has no PCI Memory resources, failing board.\n");
1618c2ecf20Sopenharmony_ci			rc = -ENOMEM;
1628c2ecf20Sopenharmony_ci			goto out_kfree_brd;
1638c2ecf20Sopenharmony_ci		}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		/*
1668c2ecf20Sopenharmony_ci		 * Enable Local Interrupt 1			(0x1),
1678c2ecf20Sopenharmony_ci		 * Local Interrupt 1 Polarity Active high	(0x2),
1688c2ecf20Sopenharmony_ci		 * Enable PCI interrupt				(0x43)
1698c2ecf20Sopenharmony_ci		 */
1708c2ecf20Sopenharmony_ci		outb(0x43, brd->iobase + 0x4c);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_2DB9:
1758c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_2DB9PRI:
1768c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_2RJ45:
1778c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_2RJ45PRI:
1788c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_2_422_485:
1798c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_NEO_4:
1808c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_NEO_4:
1818c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_NEO_4RJ45:
1828c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_NEO_4_IBM:
1838c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_DIGI_NEO_8:
1848c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_NEO_8:
1858c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_NEO_8RJ45:
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		jsm_dbg(INIT, &brd->pci_dev, "jsm_found_board - NEO adapter\n");
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci		/* get the PCI Base Address Registers */
1908c2ecf20Sopenharmony_ci		brd->membase	= pci_resource_start(pdev, 0);
1918c2ecf20Sopenharmony_ci		brd->membase_end = pci_resource_end(pdev, 0);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci		if (brd->membase & 1)
1948c2ecf20Sopenharmony_ci			brd->membase &= ~0x3;
1958c2ecf20Sopenharmony_ci		else
1968c2ecf20Sopenharmony_ci			brd->membase &= ~0xF;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		/* Assign the board_ops struct */
1998c2ecf20Sopenharmony_ci		brd->bd_ops = &jsm_neo_ops;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		brd->bd_uart_offset = 0x200;
2028c2ecf20Sopenharmony_ci		brd->bd_dividend = 921600;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		brd->re_map_membase = ioremap(brd->membase,
2058c2ecf20Sopenharmony_ci						pci_resource_len(pdev, 0));
2068c2ecf20Sopenharmony_ci		if (!brd->re_map_membase) {
2078c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
2088c2ecf20Sopenharmony_ci				"Card has no PCI Memory resources, failing board.\n");
2098c2ecf20Sopenharmony_ci			rc = -ENOMEM;
2108c2ecf20Sopenharmony_ci			goto out_kfree_brd;
2118c2ecf20Sopenharmony_ci		}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		break;
2148c2ecf20Sopenharmony_ci	default:
2158c2ecf20Sopenharmony_ci		rc = -ENXIO;
2168c2ecf20Sopenharmony_ci		goto out_kfree_brd;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	rc = request_irq(brd->irq, brd->bd_ops->intr, IRQF_SHARED, "JSM", brd);
2208c2ecf20Sopenharmony_ci	if (rc) {
2218c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev, "Failed to hook IRQ %d\n", brd->irq);
2228c2ecf20Sopenharmony_ci		goto out_iounmap;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	rc = jsm_tty_init(brd);
2268c2ecf20Sopenharmony_ci	if (rc < 0) {
2278c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc);
2288c2ecf20Sopenharmony_ci		rc = -ENXIO;
2298c2ecf20Sopenharmony_ci		goto out_free_irq;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	rc = jsm_uart_port_init(brd);
2338c2ecf20Sopenharmony_ci	if (rc < 0) {
2348c2ecf20Sopenharmony_ci		/* XXX: leaking all resources from jsm_tty_init here! */
2358c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc);
2368c2ecf20Sopenharmony_ci		rc = -ENXIO;
2378c2ecf20Sopenharmony_ci		goto out_free_irq;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* Log the information about the board */
2418c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "board %d: Digi Classic/Neo (rev %d), irq %d\n",
2428c2ecf20Sopenharmony_ci			adapter_count, brd->rev, brd->irq);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, brd);
2458c2ecf20Sopenharmony_ci	pci_save_state(pdev);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return 0;
2488c2ecf20Sopenharmony_ci out_free_irq:
2498c2ecf20Sopenharmony_ci	jsm_remove_uart_port(brd);
2508c2ecf20Sopenharmony_ci	free_irq(brd->irq, brd);
2518c2ecf20Sopenharmony_ci out_iounmap:
2528c2ecf20Sopenharmony_ci	iounmap(brd->re_map_membase);
2538c2ecf20Sopenharmony_ci out_kfree_brd:
2548c2ecf20Sopenharmony_ci	kfree(brd);
2558c2ecf20Sopenharmony_ci out_release_regions:
2568c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
2578c2ecf20Sopenharmony_ci out_disable_device:
2588c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
2598c2ecf20Sopenharmony_ci out:
2608c2ecf20Sopenharmony_ci	return rc;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic void jsm_remove_one(struct pci_dev *pdev)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	struct jsm_board *brd = pci_get_drvdata(pdev);
2668c2ecf20Sopenharmony_ci	int i = 0;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	switch (pdev->device) {
2698c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_4:
2708c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_4_422:
2718c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_8:
2728c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_CLASSIC_8_422:
2738c2ecf20Sopenharmony_ci		/* Tell card not to interrupt anymore. */
2748c2ecf20Sopenharmony_ci		outb(0x0, brd->iobase + 0x4c);
2758c2ecf20Sopenharmony_ci		break;
2768c2ecf20Sopenharmony_ci	default:
2778c2ecf20Sopenharmony_ci		break;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	jsm_remove_uart_port(brd);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	free_irq(brd->irq, brd);
2838c2ecf20Sopenharmony_ci	iounmap(brd->re_map_membase);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* Free all allocated channels structs */
2868c2ecf20Sopenharmony_ci	for (i = 0; i < brd->maxports; i++) {
2878c2ecf20Sopenharmony_ci		if (brd->channels[i]) {
2888c2ecf20Sopenharmony_ci			kfree(brd->channels[i]->ch_rqueue);
2898c2ecf20Sopenharmony_ci			kfree(brd->channels[i]->ch_equeue);
2908c2ecf20Sopenharmony_ci			kfree(brd->channels[i]);
2918c2ecf20Sopenharmony_ci		}
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
2958c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
2968c2ecf20Sopenharmony_ci	kfree(brd);
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic const struct pci_device_id jsm_pci_tbl[] = {
3008c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 },
3018c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
3028c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
3038c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
3048c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
3058c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 },
3068c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_4), 0, 0, 6 },
3078c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_1_422), 0, 0, 7 },
3088c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_1_422_485), 0, 0, 8 },
3098c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2_422_485), 0, 0, 9 },
3108c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8), 0, 0, 10 },
3118c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4), 0, 0, 11 },
3128c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4RJ45), 0, 0, 12 },
3138c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8RJ45), 0, 0, 13 },
3148c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_4), 0, 0, 14 },
3158c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_4_422), 0, 0, 15 },
3168c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_8), 0, 0, 16 },
3178c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_8_422), 0, 0, 17 },
3188c2ecf20Sopenharmony_ci	{ 0, }
3198c2ecf20Sopenharmony_ci};
3208c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic struct pci_driver jsm_driver = {
3238c2ecf20Sopenharmony_ci	.name		= JSM_DRIVER_NAME,
3248c2ecf20Sopenharmony_ci	.id_table	= jsm_pci_tbl,
3258c2ecf20Sopenharmony_ci	.probe		= jsm_probe_one,
3268c2ecf20Sopenharmony_ci	.remove		= jsm_remove_one,
3278c2ecf20Sopenharmony_ci	.err_handler    = &jsm_err_handler,
3288c2ecf20Sopenharmony_ci};
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
3318c2ecf20Sopenharmony_ci					pci_channel_state_t state)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct jsm_board *brd = pci_get_drvdata(pdev);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	jsm_remove_uart_port(brd);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	return PCI_ERS_RESULT_NEED_RESET;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	int rc;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	rc = pci_enable_device(pdev);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (rc)
3478c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	pci_set_master(pdev);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return PCI_ERS_RESULT_RECOVERED;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic void jsm_io_resume(struct pci_dev *pdev)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct jsm_board *brd = pci_get_drvdata(pdev);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	pci_restore_state(pdev);
3598c2ecf20Sopenharmony_ci	pci_save_state(pdev);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	jsm_uart_port_init(brd);
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic int __init jsm_init_module(void)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	int rc;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	rc = uart_register_driver(&jsm_uart_driver);
3698c2ecf20Sopenharmony_ci	if (!rc) {
3708c2ecf20Sopenharmony_ci		rc = pci_register_driver(&jsm_driver);
3718c2ecf20Sopenharmony_ci		if (rc)
3728c2ecf20Sopenharmony_ci			uart_unregister_driver(&jsm_uart_driver);
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci	return rc;
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic void __exit jsm_exit_module(void)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	pci_unregister_driver(&jsm_driver);
3808c2ecf20Sopenharmony_ci	uart_unregister_driver(&jsm_uart_driver);
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cimodule_init(jsm_init_module);
3848c2ecf20Sopenharmony_cimodule_exit(jsm_exit_module);
385