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