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> 231da177e4SLinus Torvalds #include <linux/pci.h> 241da177e4SLinus Torvalds #include <linux/parport.h> 251da177e4SLinus Torvalds #include <linux/parport_pc.h> 261da177e4SLinus Torvalds #include <linux/8250_pci.h> 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds enum parport_pc_pci_cards { 291da177e4SLinus Torvalds titan_110l = 0, 301da177e4SLinus Torvalds titan_210l, 311da177e4SLinus Torvalds netmos_9xx5_combo, 3244e58a6aSMartin Schitter netmos_9855, 331da177e4SLinus Torvalds avlab_1s1p, 341da177e4SLinus Torvalds avlab_1s1p_650, 351da177e4SLinus Torvalds avlab_1s1p_850, 361da177e4SLinus Torvalds avlab_1s2p, 371da177e4SLinus Torvalds avlab_1s2p_650, 381da177e4SLinus Torvalds avlab_1s2p_850, 391da177e4SLinus Torvalds avlab_2s1p, 401da177e4SLinus Torvalds avlab_2s1p_650, 411da177e4SLinus Torvalds avlab_2s1p_850, 421da177e4SLinus Torvalds siig_1s1p_10x, 431da177e4SLinus Torvalds siig_2s1p_10x, 441da177e4SLinus Torvalds siig_2p1s_20x, 451da177e4SLinus Torvalds siig_1s1p_20x, 461da177e4SLinus Torvalds siig_2s1p_20x, 471da177e4SLinus Torvalds }; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds /* each element directly indexed from enum list, above */ 501da177e4SLinus Torvalds struct parport_pc_pci { 511da177e4SLinus Torvalds int numports; 521da177e4SLinus Torvalds struct { /* BAR (base address registers) numbers in the config 531da177e4SLinus Torvalds space header */ 541da177e4SLinus Torvalds int lo; 551da177e4SLinus Torvalds int hi; /* -1 if not there, >6 for offset-method (max 561da177e4SLinus Torvalds BAR is 6) */ 571da177e4SLinus Torvalds } addr[4]; 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds /* If set, this is called immediately after pci_enable_device. 601da177e4SLinus Torvalds * If it returns non-zero, no probing will take place and the 611da177e4SLinus Torvalds * ports will not be used. */ 621da177e4SLinus Torvalds int (*preinit_hook) (struct pci_dev *pdev, struct parport_pc_pci *card, 631da177e4SLinus Torvalds int autoirq, int autodma); 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds /* If set, this is called after probing for ports. If 'failed' 661da177e4SLinus Torvalds * is non-zero we couldn't use any of the ports. */ 671da177e4SLinus Torvalds void (*postinit_hook) (struct pci_dev *pdev, 681da177e4SLinus Torvalds struct parport_pc_pci *card, int failed); 691da177e4SLinus Torvalds }; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *card, int autoirq, int autodma) 721da177e4SLinus Torvalds { 731da177e4SLinus Torvalds /* 741da177e4SLinus Torvalds * Netmos uses the subdevice ID to indicate the number of parallel 751da177e4SLinus Torvalds * and serial ports. The form is 0x00PS, where <P> is the number of 761da177e4SLinus Torvalds * parallel ports and <S> is the number of serial ports. 771da177e4SLinus Torvalds */ 781da177e4SLinus Torvalds card->numports = (dev->subsystem_device & 0xf0) >> 4; 791da177e4SLinus Torvalds return 0; 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds static struct parport_pc_pci cards[] __devinitdata = { 831da177e4SLinus Torvalds /* titan_110l */ { 1, { { 3, -1 }, } }, 841da177e4SLinus Torvalds /* titan_210l */ { 1, { { 3, -1 }, } }, 851da177e4SLinus Torvalds /* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init }, 8644e58a6aSMartin Schitter /* netmos_9855 */ { 1, { { 0, -1 }, }, netmos_parallel_init }, 871da177e4SLinus Torvalds /* avlab_1s1p */ { 1, { { 1, 2}, } }, 881da177e4SLinus Torvalds /* avlab_1s1p_650 */ { 1, { { 1, 2}, } }, 891da177e4SLinus Torvalds /* avlab_1s1p_850 */ { 1, { { 1, 2}, } }, 901da177e4SLinus Torvalds /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} }, 911da177e4SLinus Torvalds /* avlab_1s2p_650 */ { 2, { { 1, 2}, { 3, 4 },} }, 921da177e4SLinus Torvalds /* avlab_1s2p_850 */ { 2, { { 1, 2}, { 3, 4 },} }, 931da177e4SLinus Torvalds /* avlab_2s1p */ { 1, { { 2, 3}, } }, 941da177e4SLinus Torvalds /* avlab_2s1p_650 */ { 1, { { 2, 3}, } }, 951da177e4SLinus Torvalds /* avlab_2s1p_850 */ { 1, { { 2, 3}, } }, 961da177e4SLinus Torvalds /* siig_1s1p_10x */ { 1, { { 3, 4 }, } }, 971da177e4SLinus Torvalds /* siig_2s1p_10x */ { 1, { { 4, 5 }, } }, 981da177e4SLinus Torvalds /* siig_2p1s_20x */ { 2, { { 1, 2 }, { 3, 4 }, } }, 991da177e4SLinus Torvalds /* siig_1s1p_20x */ { 1, { { 1, 2 }, } }, 1001da177e4SLinus Torvalds /* siig_2s1p_20x */ { 1, { { 2, 3 }, } }, 1011da177e4SLinus Torvalds }; 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds static struct pci_device_id parport_serial_pci_tbl[] = { 1041da177e4SLinus Torvalds /* PCI cards */ 1051da177e4SLinus Torvalds { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L, 1061da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l }, 1071da177e4SLinus Torvalds { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L, 1081da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l }, 1091da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735, 1101da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1111da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9745, 1121da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1131da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, 1141da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1151da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, 1161da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1171da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845, 1181da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1191da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, 12044e58a6aSMartin Schitter PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 }, 1211da177e4SLinus Torvalds /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ 1221da177e4SLinus Torvalds { 0x14db, 0x2110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p}, 1231da177e4SLinus Torvalds { 0x14db, 0x2111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_650}, 1241da177e4SLinus Torvalds { 0x14db, 0x2112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_850}, 1251da177e4SLinus Torvalds { 0x14db, 0x2140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p}, 1261da177e4SLinus Torvalds { 0x14db, 0x2141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_650}, 1271da177e4SLinus Torvalds { 0x14db, 0x2142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_850}, 1281da177e4SLinus Torvalds { 0x14db, 0x2160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p}, 1291da177e4SLinus Torvalds { 0x14db, 0x2161, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_650}, 1301da177e4SLinus Torvalds { 0x14db, 0x2162, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_850}, 1311da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, 1321da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, 1331da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, 1341da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, 1351da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, 1361da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, 1371da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, 1381da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, 1391da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, 1401da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, 1411da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, 1421da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, 1431da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, 1441da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, 1451da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, 1461da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, 1471da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, 1481da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, 1491da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, 1501da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1511da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, 1521da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x }, 1531da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, 1541da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x }, 1551da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, 1561da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1571da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, 1581da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1591da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, 1601da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds { 0, } /* terminate list */ 1631da177e4SLinus Torvalds }; 1641da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds /* 16705caac58SRussell King * This table describes the serial "geometry" of these boards. Any 16805caac58SRussell King * quirks for these can be found in drivers/serial/8250_pci.c 16905caac58SRussell King * 17005caac58SRussell King * Cards not tested are marked n/t 17105caac58SRussell King * If you have one of these cards and it works for you, please tell me.. 1721da177e4SLinus Torvalds */ 17305caac58SRussell King static struct pciserial_board pci_parport_serial_boards[] __devinitdata = { 17405caac58SRussell King [titan_110l] = { 17505caac58SRussell King .flags = FL_BASE1 | FL_BASE_BARS, 17605caac58SRussell King .num_ports = 1, 17705caac58SRussell King .base_baud = 921600, 17805caac58SRussell King .uart_offset = 8, 17905caac58SRussell King }, 18005caac58SRussell King [titan_210l] = { 18105caac58SRussell King .flags = FL_BASE1 | FL_BASE_BARS, 18205caac58SRussell King .num_ports = 2, 18305caac58SRussell King .base_baud = 921600, 18405caac58SRussell King .uart_offset = 8, 18505caac58SRussell King }, 18605caac58SRussell King [netmos_9xx5_combo] = { 18705caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 18805caac58SRussell King .num_ports = 1, 18905caac58SRussell King .base_baud = 115200, 19005caac58SRussell King .uart_offset = 8, 19105caac58SRussell King }, 19205caac58SRussell King [netmos_9855] = { 19305caac58SRussell King .flags = FL_BASE2 | FL_BASE_BARS, 19405caac58SRussell King .num_ports = 1, 19505caac58SRussell King .base_baud = 115200, 19605caac58SRussell King .uart_offset = 8, 19705caac58SRussell King }, 19805caac58SRussell King [avlab_1s1p] = { /* n/t */ 19905caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 20005caac58SRussell King .num_ports = 1, 20105caac58SRussell King .base_baud = 115200, 20205caac58SRussell King .uart_offset = 8, 20305caac58SRussell King }, 20405caac58SRussell King [avlab_1s1p_650] = { /* nt */ 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 [avlab_1s1p_850] = { /* nt */ 21105caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 21205caac58SRussell King .num_ports = 1, 21305caac58SRussell King .base_baud = 115200, 21405caac58SRussell King .uart_offset = 8, 21505caac58SRussell King }, 21605caac58SRussell King [avlab_1s2p] = { /* n/t */ 21705caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 21805caac58SRussell King .num_ports = 1, 21905caac58SRussell King .base_baud = 115200, 22005caac58SRussell King .uart_offset = 8, 22105caac58SRussell King }, 22205caac58SRussell King [avlab_1s2p_650] = { /* nt */ 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_850] = { /* nt */ 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 [avlab_2s1p_650] = { /* nt */ 24105caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 24205caac58SRussell King .num_ports = 2, 24305caac58SRussell King .base_baud = 115200, 24405caac58SRussell King .uart_offset = 8, 24505caac58SRussell King }, 24605caac58SRussell King [avlab_2s1p_850] = { /* nt */ 24705caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 24805caac58SRussell King .num_ports = 2, 24905caac58SRussell King .base_baud = 115200, 25005caac58SRussell King .uart_offset = 8, 25105caac58SRussell King }, 25205caac58SRussell King [siig_1s1p_10x] = { 25305caac58SRussell King .flags = FL_BASE2, 25405caac58SRussell King .num_ports = 1, 25505caac58SRussell King .base_baud = 460800, 25605caac58SRussell King .uart_offset = 8, 25705caac58SRussell King }, 25805caac58SRussell King [siig_2s1p_10x] = { 25905caac58SRussell King .flags = FL_BASE2, 26005caac58SRussell King .num_ports = 1, 26105caac58SRussell King .base_baud = 921600, 26205caac58SRussell King .uart_offset = 8, 26305caac58SRussell King }, 26405caac58SRussell King [siig_2p1s_20x] = { 26505caac58SRussell King .flags = FL_BASE0, 26605caac58SRussell King .num_ports = 1, 26705caac58SRussell King .base_baud = 921600, 26805caac58SRussell King .uart_offset = 8, 26905caac58SRussell King }, 27005caac58SRussell King [siig_1s1p_20x] = { 27105caac58SRussell King .flags = FL_BASE0, 27205caac58SRussell King .num_ports = 1, 27305caac58SRussell King .base_baud = 921600, 27405caac58SRussell King .uart_offset = 8, 27505caac58SRussell King }, 27605caac58SRussell King [siig_2s1p_20x] = { 27705caac58SRussell King .flags = FL_BASE0, 27805caac58SRussell King .num_ports = 1, 27905caac58SRussell King .base_baud = 921600, 28005caac58SRussell King .uart_offset = 8, 28105caac58SRussell King }, 2821da177e4SLinus Torvalds }; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds struct parport_serial_private { 28505caac58SRussell King struct serial_private *serial; 2861da177e4SLinus Torvalds int num_par; 2871da177e4SLinus Torvalds struct parport *port[PARPORT_MAX]; 2881da177e4SLinus Torvalds struct parport_pc_pci par; 2891da177e4SLinus Torvalds }; 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /* Register the serial port(s) of a PCI card. */ 2921da177e4SLinus Torvalds static int __devinit serial_register (struct pci_dev *dev, 2931da177e4SLinus Torvalds const struct pci_device_id *id) 2941da177e4SLinus Torvalds { 2951da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev); 29605caac58SRussell King struct pciserial_board *board; 29705caac58SRussell King struct serial_private *serial; 2981da177e4SLinus Torvalds 29905caac58SRussell King board = &pci_parport_serial_boards[id->driver_data]; 30005caac58SRussell King serial = pciserial_init_ports(dev, board); 3011da177e4SLinus Torvalds 30205caac58SRussell King if (IS_ERR(serial)) 30305caac58SRussell King return PTR_ERR(serial); 3041da177e4SLinus Torvalds 30505caac58SRussell King priv->serial = serial; 30605caac58SRussell King return 0; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds /* Register the parallel port(s) of a PCI card. */ 3101da177e4SLinus Torvalds static int __devinit parport_register (struct pci_dev *dev, 3111da177e4SLinus Torvalds const struct pci_device_id *id) 3121da177e4SLinus Torvalds { 3131da177e4SLinus Torvalds struct parport_pc_pci *card; 3141da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev); 3151da177e4SLinus Torvalds int i = id->driver_data, n; 3161da177e4SLinus Torvalds int success = 0; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds priv->par = cards[id->driver_data]; 3191da177e4SLinus Torvalds card = &priv->par; 3201da177e4SLinus Torvalds if (card->preinit_hook && 3211da177e4SLinus Torvalds card->preinit_hook (dev, card, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) 3221da177e4SLinus Torvalds return -ENODEV; 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds for (n = 0; n < card->numports; n++) { 3251da177e4SLinus Torvalds struct parport *port; 3261da177e4SLinus Torvalds int lo = card->addr[n].lo; 3271da177e4SLinus Torvalds int hi = card->addr[n].hi; 3281da177e4SLinus Torvalds unsigned long io_lo, io_hi; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds if (priv->num_par == ARRAY_SIZE (priv->port)) { 3311da177e4SLinus Torvalds printk (KERN_WARNING 332f4f64e9dSAndrew Morton "parport_serial: %s: only %zu parallel ports " 3331da177e4SLinus Torvalds "supported (%d reported)\n", pci_name (dev), 3341da177e4SLinus Torvalds ARRAY_SIZE(priv->port), card->numports); 3351da177e4SLinus Torvalds break; 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds io_lo = pci_resource_start (dev, lo); 3391da177e4SLinus Torvalds io_hi = 0; 3401da177e4SLinus Torvalds if ((hi >= 0) && (hi <= 6)) 3411da177e4SLinus Torvalds io_hi = pci_resource_start (dev, hi); 3421da177e4SLinus Torvalds else if (hi > 6) 3431da177e4SLinus Torvalds io_lo += hi; /* Reinterpret the meaning of 3441da177e4SLinus Torvalds "hi" as an offset (see SYBA 3451da177e4SLinus Torvalds def.) */ 3461da177e4SLinus Torvalds /* TODO: test if sharing interrupts works */ 3471da177e4SLinus Torvalds printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, " 3481da177e4SLinus Torvalds "I/O at %#lx(%#lx)\n", 3491da177e4SLinus Torvalds parport_serial_pci_tbl[i].vendor, 3501da177e4SLinus Torvalds parport_serial_pci_tbl[i].device, io_lo, io_hi); 3511da177e4SLinus Torvalds port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, 3521da177e4SLinus Torvalds PARPORT_DMA_NONE, dev); 3531da177e4SLinus Torvalds if (port) { 3541da177e4SLinus Torvalds priv->port[priv->num_par++] = port; 3551da177e4SLinus Torvalds success = 1; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds if (card->postinit_hook) 3601da177e4SLinus Torvalds card->postinit_hook (dev, card, !success); 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds return success ? 0 : 1; 3631da177e4SLinus Torvalds } 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds static int __devinit parport_serial_pci_probe (struct pci_dev *dev, 3661da177e4SLinus Torvalds const struct pci_device_id *id) 3671da177e4SLinus Torvalds { 3681da177e4SLinus Torvalds struct parport_serial_private *priv; 3691da177e4SLinus Torvalds int err; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds priv = kmalloc (sizeof *priv, GFP_KERNEL); 3721da177e4SLinus Torvalds if (!priv) 3731da177e4SLinus Torvalds return -ENOMEM; 37405caac58SRussell King memset(priv, 0, sizeof(struct parport_serial_private)); 3751da177e4SLinus Torvalds pci_set_drvdata (dev, priv); 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds err = pci_enable_device (dev); 3781da177e4SLinus Torvalds if (err) { 3791da177e4SLinus Torvalds pci_set_drvdata (dev, NULL); 3801da177e4SLinus Torvalds kfree (priv); 3811da177e4SLinus Torvalds return err; 3821da177e4SLinus Torvalds } 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds if (parport_register (dev, id)) { 3851da177e4SLinus Torvalds pci_set_drvdata (dev, NULL); 3861da177e4SLinus Torvalds kfree (priv); 3871da177e4SLinus Torvalds return -ENODEV; 3881da177e4SLinus Torvalds } 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds if (serial_register (dev, id)) { 3911da177e4SLinus Torvalds int i; 3921da177e4SLinus Torvalds for (i = 0; i < priv->num_par; i++) 3931da177e4SLinus Torvalds parport_pc_unregister_port (priv->port[i]); 3941da177e4SLinus Torvalds pci_set_drvdata (dev, NULL); 3951da177e4SLinus Torvalds kfree (priv); 3961da177e4SLinus Torvalds return -ENODEV; 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds return 0; 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds static void __devexit parport_serial_pci_remove (struct pci_dev *dev) 4031da177e4SLinus Torvalds { 4041da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev); 4051da177e4SLinus Torvalds int i; 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds pci_set_drvdata(dev, NULL); 4081da177e4SLinus Torvalds 40905caac58SRussell King // Serial ports 41005caac58SRussell King if (priv->serial) 41105caac58SRussell King pciserial_remove_ports(priv->serial); 41205caac58SRussell King 4131da177e4SLinus Torvalds // Parallel ports 4141da177e4SLinus Torvalds for (i = 0; i < priv->num_par; i++) 4151da177e4SLinus Torvalds parport_pc_unregister_port (priv->port[i]); 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds kfree (priv); 4181da177e4SLinus Torvalds return; 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds 42105caac58SRussell King static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state) 42205caac58SRussell King { 42305caac58SRussell King struct parport_serial_private *priv = pci_get_drvdata(dev); 42405caac58SRussell King 42505caac58SRussell King if (priv->serial) 42605caac58SRussell King pciserial_suspend_ports(priv->serial); 42705caac58SRussell King 42805caac58SRussell King /* FIXME: What about parport? */ 42905caac58SRussell King 43005caac58SRussell King pci_save_state(dev); 43105caac58SRussell King pci_set_power_state(dev, pci_choose_state(dev, state)); 43205caac58SRussell King return 0; 43305caac58SRussell King } 43405caac58SRussell King 43505caac58SRussell King static int parport_serial_pci_resume(struct pci_dev *dev) 43605caac58SRussell King { 43705caac58SRussell King struct parport_serial_private *priv = pci_get_drvdata(dev); 43805caac58SRussell King 43905caac58SRussell King pci_set_power_state(dev, PCI_D0); 44005caac58SRussell King pci_restore_state(dev); 44105caac58SRussell King 44205caac58SRussell King /* 44305caac58SRussell King * The device may have been disabled. Re-enable it. 44405caac58SRussell King */ 44505caac58SRussell King pci_enable_device(dev); 44605caac58SRussell King 44705caac58SRussell King if (priv->serial) 44805caac58SRussell King pciserial_resume_ports(priv->serial); 44905caac58SRussell King 45005caac58SRussell King /* FIXME: What about parport? */ 45105caac58SRussell King 45205caac58SRussell King return 0; 45305caac58SRussell King } 45405caac58SRussell King 4551da177e4SLinus Torvalds static struct pci_driver parport_serial_pci_driver = { 4561da177e4SLinus Torvalds .name = "parport_serial", 4571da177e4SLinus Torvalds .id_table = parport_serial_pci_tbl, 4581da177e4SLinus Torvalds .probe = parport_serial_pci_probe, 4591da177e4SLinus Torvalds .remove = __devexit_p(parport_serial_pci_remove), 46005caac58SRussell King .suspend = parport_serial_pci_suspend, 46105caac58SRussell King .resume = parport_serial_pci_resume, 4621da177e4SLinus Torvalds }; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds 4651da177e4SLinus Torvalds static int __init parport_serial_init (void) 4661da177e4SLinus Torvalds { 46793b47684SRichard Knutsson return pci_register_driver (&parport_serial_pci_driver); 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds static void __exit parport_serial_exit (void) 4711da177e4SLinus Torvalds { 4721da177e4SLinus Torvalds pci_unregister_driver (&parport_serial_pci_driver); 4731da177e4SLinus Torvalds return; 4741da177e4SLinus Torvalds } 4751da177e4SLinus Torvalds 4761da177e4SLinus Torvalds MODULE_AUTHOR("Tim Waugh <twaugh@redhat.com>"); 4771da177e4SLinus Torvalds MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards"); 4781da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds module_init(parport_serial_init); 4811da177e4SLinus Torvalds module_exit(parport_serial_exit); 482