11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Support for common PCI multi-I/O cards (which is most of them) 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001 Tim Waugh <twaugh@redhat.com> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Multi-function PCI cards are supposed to present separate logical 131da177e4SLinus Torvalds * devices on the bus. A common thing to do seems to be to just use 141da177e4SLinus Torvalds * one logical device with lots of base address registers for both 151da177e4SLinus Torvalds * parallel ports and serial ports. This driver is for dealing with 161da177e4SLinus Torvalds * that. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds */ 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds #include <linux/types.h> 211da177e4SLinus Torvalds #include <linux/module.h> 221da177e4SLinus Torvalds #include <linux/init.h> 235a0e3ad6STejun Heo #include <linux/slab.h> 241da177e4SLinus Torvalds #include <linux/pci.h> 2551dcdfecSAlan Cox #include <linux/interrupt.h> 261da177e4SLinus Torvalds #include <linux/parport.h> 271da177e4SLinus Torvalds #include <linux/parport_pc.h> 281da177e4SLinus Torvalds #include <linux/8250_pci.h> 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds enum parport_pc_pci_cards { 311da177e4SLinus Torvalds titan_110l = 0, 321da177e4SLinus Torvalds titan_210l, 331da177e4SLinus Torvalds netmos_9xx5_combo, 3444e58a6aSMartin Schitter netmos_9855, 3550db9d8eSPhilippe De Muyter netmos_9855_2p, 361da177e4SLinus Torvalds avlab_1s1p, 371da177e4SLinus Torvalds avlab_1s2p, 381da177e4SLinus Torvalds avlab_2s1p, 391da177e4SLinus Torvalds siig_1s1p_10x, 401da177e4SLinus Torvalds siig_2s1p_10x, 411da177e4SLinus Torvalds siig_2p1s_20x, 421da177e4SLinus Torvalds siig_1s1p_20x, 431da177e4SLinus Torvalds siig_2s1p_20x, 441da177e4SLinus Torvalds }; 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds /* each element directly indexed from enum list, above */ 471da177e4SLinus Torvalds struct parport_pc_pci { 481da177e4SLinus Torvalds int numports; 491da177e4SLinus Torvalds struct { /* BAR (base address registers) numbers in the config 501da177e4SLinus Torvalds space header */ 511da177e4SLinus Torvalds int lo; 521da177e4SLinus Torvalds int hi; /* -1 if not there, >6 for offset-method (max 531da177e4SLinus Torvalds BAR is 6) */ 541da177e4SLinus Torvalds } addr[4]; 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* If set, this is called immediately after pci_enable_device. 571da177e4SLinus Torvalds * If it returns non-zero, no probing will take place and the 581da177e4SLinus Torvalds * ports will not be used. */ 591da177e4SLinus Torvalds int (*preinit_hook) (struct pci_dev *pdev, struct parport_pc_pci *card, 601da177e4SLinus Torvalds int autoirq, int autodma); 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds /* If set, this is called after probing for ports. If 'failed' 631da177e4SLinus Torvalds * is non-zero we couldn't use any of the ports. */ 641da177e4SLinus Torvalds void (*postinit_hook) (struct pci_dev *pdev, 651da177e4SLinus Torvalds struct parport_pc_pci *card, int failed); 661da177e4SLinus Torvalds }; 671da177e4SLinus Torvalds 6850db9d8eSPhilippe De Muyter static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *par, int autoirq, int autodma) 691da177e4SLinus Torvalds { 703abdbf90SJiri Slaby /* the rule described below doesn't hold for this device */ 713abdbf90SJiri Slaby if (dev->device == PCI_DEVICE_ID_NETMOS_9835 && 723abdbf90SJiri Slaby dev->subsystem_vendor == PCI_VENDOR_ID_IBM && 733abdbf90SJiri Slaby dev->subsystem_device == 0x0299) 743abdbf90SJiri Slaby return -ENODEV; 751da177e4SLinus Torvalds /* 761da177e4SLinus Torvalds * Netmos uses the subdevice ID to indicate the number of parallel 771da177e4SLinus Torvalds * and serial ports. The form is 0x00PS, where <P> is the number of 781da177e4SLinus Torvalds * parallel ports and <S> is the number of serial ports. 791da177e4SLinus Torvalds */ 8050db9d8eSPhilippe De Muyter par->numports = (dev->subsystem_device & 0xf0) >> 4; 8150db9d8eSPhilippe De Muyter if (par->numports > ARRAY_SIZE(par->addr)) 8250db9d8eSPhilippe De Muyter par->numports = ARRAY_SIZE(par->addr); 8350db9d8eSPhilippe De Muyter /* 8450db9d8eSPhilippe De Muyter * This function is currently only called for cards with up to 8550db9d8eSPhilippe De Muyter * one parallel port. 8650db9d8eSPhilippe De Muyter * Parallel port BAR is either before or after serial ports BARS; 8750db9d8eSPhilippe De Muyter * hence, lo should be either 0 or equal to the number of serial ports. 8850db9d8eSPhilippe De Muyter */ 8950db9d8eSPhilippe De Muyter if (par->addr[0].lo != 0) 9050db9d8eSPhilippe De Muyter par->addr[0].lo = dev->subsystem_device & 0xf; 911da177e4SLinus Torvalds return 0; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds static struct parport_pc_pci cards[] __devinitdata = { 951da177e4SLinus Torvalds /* titan_110l */ { 1, { { 3, -1 }, } }, 961da177e4SLinus Torvalds /* titan_210l */ { 1, { { 3, -1 }, } }, 971da177e4SLinus Torvalds /* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init }, 9850db9d8eSPhilippe De Muyter /* netmos_9855 */ { 1, { { 0, -1 }, }, netmos_parallel_init }, 9950db9d8eSPhilippe De Muyter /* netmos_9855_2p */ { 2, { { 0, -1 }, { 2, -1 }, } }, 1001da177e4SLinus Torvalds /* avlab_1s1p */ { 1, { { 1, 2}, } }, 1011da177e4SLinus Torvalds /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} }, 1021da177e4SLinus Torvalds /* avlab_2s1p */ { 1, { { 2, 3}, } }, 1031da177e4SLinus Torvalds /* siig_1s1p_10x */ { 1, { { 3, 4 }, } }, 1041da177e4SLinus Torvalds /* siig_2s1p_10x */ { 1, { { 4, 5 }, } }, 1051da177e4SLinus Torvalds /* siig_2p1s_20x */ { 2, { { 1, 2 }, { 3, 4 }, } }, 1061da177e4SLinus Torvalds /* siig_1s1p_20x */ { 1, { { 1, 2 }, } }, 1071da177e4SLinus Torvalds /* siig_2s1p_20x */ { 1, { { 2, 3 }, } }, 1081da177e4SLinus Torvalds }; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds static struct pci_device_id parport_serial_pci_tbl[] = { 1111da177e4SLinus Torvalds /* PCI cards */ 1121da177e4SLinus Torvalds { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L, 1131da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l }, 1141da177e4SLinus Torvalds { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L, 1151da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l }, 1161da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735, 1171da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1181da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9745, 1191da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1201da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, 1211da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1221da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845, 1231da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1241da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, 12550db9d8eSPhilippe De Muyter 0x1000, 0x0020, 0, 0, netmos_9855_2p }, 12650db9d8eSPhilippe De Muyter { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, 12750db9d8eSPhilippe De Muyter 0x1000, 0x0022, 0, 0, netmos_9855_2p }, 12850db9d8eSPhilippe De Muyter { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, 12944e58a6aSMartin Schitter PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 }, 1301da177e4SLinus Torvalds /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ 13191bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2110, 13291bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p }, 13391bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2111, 13491bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p }, 13591bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2112, 13691bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p }, 13791bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2140, 13891bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p }, 13991bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2141, 14091bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p }, 14191bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2142, 14291bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p }, 14391bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2160, 14491bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p }, 14591bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2161, 14691bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p }, 14791bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2162, 14891bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p }, 1491da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, 1501da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, 1511da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, 1521da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, 1531da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, 1541da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, 1551da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, 1561da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, 1571da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, 1581da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, 1591da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, 1601da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, 1611da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, 1621da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, 1631da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, 1641da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, 1651da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, 1661da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, 1671da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, 1681da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1691da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, 1701da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x }, 1711da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, 1721da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x }, 1731da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, 1741da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1751da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, 1761da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1771da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, 1781da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds { 0, } /* terminate list */ 1811da177e4SLinus Torvalds }; 1821da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds /* 18505caac58SRussell King * This table describes the serial "geometry" of these boards. Any 18605caac58SRussell King * quirks for these can be found in drivers/serial/8250_pci.c 18705caac58SRussell King * 18805caac58SRussell King * Cards not tested are marked n/t 18905caac58SRussell King * If you have one of these cards and it works for you, please tell me.. 1901da177e4SLinus Torvalds */ 19105caac58SRussell King static struct pciserial_board pci_parport_serial_boards[] __devinitdata = { 19205caac58SRussell King [titan_110l] = { 19305caac58SRussell King .flags = FL_BASE1 | FL_BASE_BARS, 19405caac58SRussell King .num_ports = 1, 19505caac58SRussell King .base_baud = 921600, 19605caac58SRussell King .uart_offset = 8, 19705caac58SRussell King }, 19805caac58SRussell King [titan_210l] = { 19905caac58SRussell King .flags = FL_BASE1 | FL_BASE_BARS, 20005caac58SRussell King .num_ports = 2, 20105caac58SRussell King .base_baud = 921600, 20205caac58SRussell King .uart_offset = 8, 20305caac58SRussell King }, 20405caac58SRussell King [netmos_9xx5_combo] = { 20505caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 20605caac58SRussell King .num_ports = 1, 20705caac58SRussell King .base_baud = 115200, 20805caac58SRussell King .uart_offset = 8, 20905caac58SRussell King }, 21005caac58SRussell King [netmos_9855] = { 21150db9d8eSPhilippe De Muyter .flags = FL_BASE2 | FL_BASE_BARS, 21250db9d8eSPhilippe De Muyter .num_ports = 1, 21350db9d8eSPhilippe De Muyter .base_baud = 115200, 21450db9d8eSPhilippe De Muyter .uart_offset = 8, 21550db9d8eSPhilippe De Muyter }, 21650db9d8eSPhilippe De Muyter [netmos_9855_2p] = { 217c01106e5SChristian Pellegrin .flags = FL_BASE4 | FL_BASE_BARS, 21805caac58SRussell King .num_ports = 1, 21905caac58SRussell King .base_baud = 115200, 22005caac58SRussell King .uart_offset = 8, 22105caac58SRussell King }, 22205caac58SRussell King [avlab_1s1p] = { /* n/t */ 22305caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 22405caac58SRussell King .num_ports = 1, 22505caac58SRussell King .base_baud = 115200, 22605caac58SRussell King .uart_offset = 8, 22705caac58SRussell King }, 22805caac58SRussell King [avlab_1s2p] = { /* n/t */ 22905caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 23005caac58SRussell King .num_ports = 1, 23105caac58SRussell King .base_baud = 115200, 23205caac58SRussell King .uart_offset = 8, 23305caac58SRussell King }, 23405caac58SRussell King [avlab_2s1p] = { /* n/t */ 23505caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 23605caac58SRussell King .num_ports = 2, 23705caac58SRussell King .base_baud = 115200, 23805caac58SRussell King .uart_offset = 8, 23905caac58SRussell King }, 24005caac58SRussell King [siig_1s1p_10x] = { 24105caac58SRussell King .flags = FL_BASE2, 24205caac58SRussell King .num_ports = 1, 24305caac58SRussell King .base_baud = 460800, 24405caac58SRussell King .uart_offset = 8, 24505caac58SRussell King }, 24605caac58SRussell King [siig_2s1p_10x] = { 24705caac58SRussell King .flags = FL_BASE2, 24805caac58SRussell King .num_ports = 1, 24905caac58SRussell King .base_baud = 921600, 25005caac58SRussell King .uart_offset = 8, 25105caac58SRussell King }, 25205caac58SRussell King [siig_2p1s_20x] = { 25305caac58SRussell King .flags = FL_BASE0, 25405caac58SRussell King .num_ports = 1, 25505caac58SRussell King .base_baud = 921600, 25605caac58SRussell King .uart_offset = 8, 25705caac58SRussell King }, 25805caac58SRussell King [siig_1s1p_20x] = { 25905caac58SRussell King .flags = FL_BASE0, 26005caac58SRussell King .num_ports = 1, 26105caac58SRussell King .base_baud = 921600, 26205caac58SRussell King .uart_offset = 8, 26305caac58SRussell King }, 26405caac58SRussell King [siig_2s1p_20x] = { 26505caac58SRussell King .flags = FL_BASE0, 26605caac58SRussell King .num_ports = 1, 26705caac58SRussell King .base_baud = 921600, 26805caac58SRussell King .uart_offset = 8, 26905caac58SRussell King }, 2701da177e4SLinus Torvalds }; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds struct parport_serial_private { 27305caac58SRussell King struct serial_private *serial; 2741da177e4SLinus Torvalds int num_par; 2751da177e4SLinus Torvalds struct parport *port[PARPORT_MAX]; 2761da177e4SLinus Torvalds struct parport_pc_pci par; 2771da177e4SLinus Torvalds }; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds /* Register the serial port(s) of a PCI card. */ 2801da177e4SLinus Torvalds static int __devinit serial_register (struct pci_dev *dev, 2811da177e4SLinus Torvalds const struct pci_device_id *id) 2821da177e4SLinus Torvalds { 2831da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev); 28405caac58SRussell King struct pciserial_board *board; 28505caac58SRussell King struct serial_private *serial; 2861da177e4SLinus Torvalds 28705caac58SRussell King board = &pci_parport_serial_boards[id->driver_data]; 28805caac58SRussell King serial = pciserial_init_ports(dev, board); 2891da177e4SLinus Torvalds 29005caac58SRussell King if (IS_ERR(serial)) 29105caac58SRussell King return PTR_ERR(serial); 2921da177e4SLinus Torvalds 29305caac58SRussell King priv->serial = serial; 29405caac58SRussell King return 0; 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds /* Register the parallel port(s) of a PCI card. */ 2981da177e4SLinus Torvalds static int __devinit parport_register (struct pci_dev *dev, 2991da177e4SLinus Torvalds const struct pci_device_id *id) 3001da177e4SLinus Torvalds { 3011da177e4SLinus Torvalds struct parport_pc_pci *card; 3021da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev); 3037a171cdcSRussell King int n, success = 0; 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds priv->par = cards[id->driver_data]; 3061da177e4SLinus Torvalds card = &priv->par; 3071da177e4SLinus Torvalds if (card->preinit_hook && 3081da177e4SLinus Torvalds card->preinit_hook (dev, card, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) 3091da177e4SLinus Torvalds return -ENODEV; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds for (n = 0; n < card->numports; n++) { 3121da177e4SLinus Torvalds struct parport *port; 3131da177e4SLinus Torvalds int lo = card->addr[n].lo; 3141da177e4SLinus Torvalds int hi = card->addr[n].hi; 3151da177e4SLinus Torvalds unsigned long io_lo, io_hi; 31651dcdfecSAlan Cox int irq; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds if (priv->num_par == ARRAY_SIZE (priv->port)) { 3191da177e4SLinus Torvalds printk (KERN_WARNING 320f4f64e9dSAndrew Morton "parport_serial: %s: only %zu parallel ports " 3211da177e4SLinus Torvalds "supported (%d reported)\n", pci_name (dev), 3221da177e4SLinus Torvalds ARRAY_SIZE(priv->port), card->numports); 3231da177e4SLinus Torvalds break; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds io_lo = pci_resource_start (dev, lo); 3271da177e4SLinus Torvalds io_hi = 0; 3281da177e4SLinus Torvalds if ((hi >= 0) && (hi <= 6)) 3291da177e4SLinus Torvalds io_hi = pci_resource_start (dev, hi); 3301da177e4SLinus Torvalds else if (hi > 6) 3311da177e4SLinus Torvalds io_lo += hi; /* Reinterpret the meaning of 3321da177e4SLinus Torvalds "hi" as an offset (see SYBA 3331da177e4SLinus Torvalds def.) */ 3341da177e4SLinus Torvalds /* TODO: test if sharing interrupts works */ 33551dcdfecSAlan Cox irq = dev->irq; 33651dcdfecSAlan Cox if (irq == IRQ_NONE) { 33751dcdfecSAlan Cox dev_dbg(&dev->dev, 33851dcdfecSAlan Cox "PCI parallel port detected: I/O at %#lx(%#lx)\n", 33951dcdfecSAlan Cox io_lo, io_hi); 34051dcdfecSAlan Cox irq = PARPORT_IRQ_NONE; 34151dcdfecSAlan Cox } else { 34251dcdfecSAlan Cox dev_dbg(&dev->dev, 34351dcdfecSAlan Cox "PCI parallel port detected: I/O at %#lx(%#lx), IRQ %d\n", 34451dcdfecSAlan Cox io_lo, io_hi, irq); 34551dcdfecSAlan Cox irq = PARPORT_IRQ_NONE; 34651dcdfecSAlan Cox } 34751dcdfecSAlan Cox port = parport_pc_probe_port (io_lo, io_hi, irq, 34851dcdfecSAlan Cox PARPORT_DMA_NONE, &dev->dev, IRQF_SHARED); 3491da177e4SLinus Torvalds if (port) { 3501da177e4SLinus Torvalds priv->port[priv->num_par++] = port; 3511da177e4SLinus Torvalds success = 1; 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds if (card->postinit_hook) 3561da177e4SLinus Torvalds card->postinit_hook (dev, card, !success); 3571da177e4SLinus Torvalds 3587a171cdcSRussell King return 0; 3591da177e4SLinus Torvalds } 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds static int __devinit parport_serial_pci_probe (struct pci_dev *dev, 3621da177e4SLinus Torvalds const struct pci_device_id *id) 3631da177e4SLinus Torvalds { 3641da177e4SLinus Torvalds struct parport_serial_private *priv; 3651da177e4SLinus Torvalds int err; 3661da177e4SLinus Torvalds 367dd00cc48SYoann Padioleau priv = kzalloc (sizeof *priv, GFP_KERNEL); 3681da177e4SLinus Torvalds if (!priv) 3691da177e4SLinus Torvalds return -ENOMEM; 3701da177e4SLinus Torvalds pci_set_drvdata (dev, priv); 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds err = pci_enable_device (dev); 3731da177e4SLinus Torvalds if (err) { 3741da177e4SLinus Torvalds pci_set_drvdata (dev, NULL); 3751da177e4SLinus Torvalds kfree (priv); 3761da177e4SLinus Torvalds return err; 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds if (parport_register (dev, id)) { 3801da177e4SLinus Torvalds pci_set_drvdata (dev, NULL); 3811da177e4SLinus Torvalds kfree (priv); 3821da177e4SLinus Torvalds return -ENODEV; 3831da177e4SLinus Torvalds } 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds if (serial_register (dev, id)) { 3861da177e4SLinus Torvalds int i; 3871da177e4SLinus Torvalds for (i = 0; i < priv->num_par; i++) 3881da177e4SLinus Torvalds parport_pc_unregister_port (priv->port[i]); 3891da177e4SLinus Torvalds pci_set_drvdata (dev, NULL); 3901da177e4SLinus Torvalds kfree (priv); 3911da177e4SLinus Torvalds return -ENODEV; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds return 0; 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds static void __devexit parport_serial_pci_remove (struct pci_dev *dev) 3981da177e4SLinus Torvalds { 3991da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev); 4001da177e4SLinus Torvalds int i; 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds pci_set_drvdata(dev, NULL); 4031da177e4SLinus Torvalds 40405caac58SRussell King // Serial ports 40505caac58SRussell King if (priv->serial) 40605caac58SRussell King pciserial_remove_ports(priv->serial); 40705caac58SRussell King 4081da177e4SLinus Torvalds // Parallel ports 4091da177e4SLinus Torvalds for (i = 0; i < priv->num_par; i++) 4101da177e4SLinus Torvalds parport_pc_unregister_port (priv->port[i]); 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds kfree (priv); 4131da177e4SLinus Torvalds return; 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds 4167dd7d691SAlexey Dobriyan #ifdef CONFIG_PM 41705caac58SRussell King static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state) 41805caac58SRussell King { 41905caac58SRussell King struct parport_serial_private *priv = pci_get_drvdata(dev); 42005caac58SRussell King 42105caac58SRussell King if (priv->serial) 42205caac58SRussell King pciserial_suspend_ports(priv->serial); 42305caac58SRussell King 42405caac58SRussell King /* FIXME: What about parport? */ 42505caac58SRussell King 42605caac58SRussell King pci_save_state(dev); 42705caac58SRussell King pci_set_power_state(dev, pci_choose_state(dev, state)); 42805caac58SRussell King return 0; 42905caac58SRussell King } 43005caac58SRussell King 43105caac58SRussell King static int parport_serial_pci_resume(struct pci_dev *dev) 43205caac58SRussell King { 43305caac58SRussell King struct parport_serial_private *priv = pci_get_drvdata(dev); 43410f8a598SRandy Dunlap int err; 43505caac58SRussell King 43605caac58SRussell King pci_set_power_state(dev, PCI_D0); 43705caac58SRussell King pci_restore_state(dev); 43805caac58SRussell King 43905caac58SRussell King /* 44005caac58SRussell King * The device may have been disabled. Re-enable it. 44105caac58SRussell King */ 44210f8a598SRandy Dunlap err = pci_enable_device(dev); 44310f8a598SRandy Dunlap if (err) { 44410f8a598SRandy Dunlap printk(KERN_ERR "parport_serial: %s: error enabling " 44510f8a598SRandy Dunlap "device for resume (%d)\n", pci_name(dev), err); 44610f8a598SRandy Dunlap return err; 44710f8a598SRandy Dunlap } 44805caac58SRussell King 44905caac58SRussell King if (priv->serial) 45005caac58SRussell King pciserial_resume_ports(priv->serial); 45105caac58SRussell King 45205caac58SRussell King /* FIXME: What about parport? */ 45305caac58SRussell King 45405caac58SRussell King return 0; 45505caac58SRussell King } 4567dd7d691SAlexey Dobriyan #endif 45705caac58SRussell King 4581da177e4SLinus Torvalds static struct pci_driver parport_serial_pci_driver = { 4591da177e4SLinus Torvalds .name = "parport_serial", 4601da177e4SLinus Torvalds .id_table = parport_serial_pci_tbl, 4611da177e4SLinus Torvalds .probe = parport_serial_pci_probe, 4621da177e4SLinus Torvalds .remove = __devexit_p(parport_serial_pci_remove), 4637dd7d691SAlexey Dobriyan #ifdef CONFIG_PM 46405caac58SRussell King .suspend = parport_serial_pci_suspend, 46505caac58SRussell King .resume = parport_serial_pci_resume, 4667dd7d691SAlexey Dobriyan #endif 4671da177e4SLinus Torvalds }; 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds static int __init parport_serial_init (void) 4711da177e4SLinus Torvalds { 47293b47684SRichard Knutsson return pci_register_driver (&parport_serial_pci_driver); 4731da177e4SLinus Torvalds } 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds static void __exit parport_serial_exit (void) 4761da177e4SLinus Torvalds { 4771da177e4SLinus Torvalds pci_unregister_driver (&parport_serial_pci_driver); 4781da177e4SLinus Torvalds return; 4791da177e4SLinus Torvalds } 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds MODULE_AUTHOR("Tim Waugh <twaugh@redhat.com>"); 4821da177e4SLinus Torvalds MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards"); 4831da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds module_init(parport_serial_init); 4861da177e4SLinus Torvalds module_exit(parport_serial_exit); 487