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_1s2p, 351da177e4SLinus Torvalds avlab_2s1p, 361da177e4SLinus Torvalds siig_1s1p_10x, 371da177e4SLinus Torvalds siig_2s1p_10x, 381da177e4SLinus Torvalds siig_2p1s_20x, 391da177e4SLinus Torvalds siig_1s1p_20x, 401da177e4SLinus Torvalds siig_2s1p_20x, 411da177e4SLinus Torvalds }; 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds /* each element directly indexed from enum list, above */ 441da177e4SLinus Torvalds struct parport_pc_pci { 451da177e4SLinus Torvalds int numports; 461da177e4SLinus Torvalds struct { /* BAR (base address registers) numbers in the config 471da177e4SLinus Torvalds space header */ 481da177e4SLinus Torvalds int lo; 491da177e4SLinus Torvalds int hi; /* -1 if not there, >6 for offset-method (max 501da177e4SLinus Torvalds BAR is 6) */ 511da177e4SLinus Torvalds } addr[4]; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds /* If set, this is called immediately after pci_enable_device. 541da177e4SLinus Torvalds * If it returns non-zero, no probing will take place and the 551da177e4SLinus Torvalds * ports will not be used. */ 561da177e4SLinus Torvalds int (*preinit_hook) (struct pci_dev *pdev, struct parport_pc_pci *card, 571da177e4SLinus Torvalds int autoirq, int autodma); 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds /* If set, this is called after probing for ports. If 'failed' 601da177e4SLinus Torvalds * is non-zero we couldn't use any of the ports. */ 611da177e4SLinus Torvalds void (*postinit_hook) (struct pci_dev *pdev, 621da177e4SLinus Torvalds struct parport_pc_pci *card, int failed); 631da177e4SLinus Torvalds }; 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *card, int autoirq, int autodma) 661da177e4SLinus Torvalds { 671da177e4SLinus Torvalds /* 681da177e4SLinus Torvalds * Netmos uses the subdevice ID to indicate the number of parallel 691da177e4SLinus Torvalds * and serial ports. The form is 0x00PS, where <P> is the number of 701da177e4SLinus Torvalds * parallel ports and <S> is the number of serial ports. 711da177e4SLinus Torvalds */ 721da177e4SLinus Torvalds card->numports = (dev->subsystem_device & 0xf0) >> 4; 731da177e4SLinus Torvalds return 0; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds static struct parport_pc_pci cards[] __devinitdata = { 771da177e4SLinus Torvalds /* titan_110l */ { 1, { { 3, -1 }, } }, 781da177e4SLinus Torvalds /* titan_210l */ { 1, { { 3, -1 }, } }, 791da177e4SLinus Torvalds /* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init }, 8044e58a6aSMartin Schitter /* netmos_9855 */ { 1, { { 0, -1 }, }, netmos_parallel_init }, 811da177e4SLinus Torvalds /* avlab_1s1p */ { 1, { { 1, 2}, } }, 821da177e4SLinus Torvalds /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} }, 831da177e4SLinus Torvalds /* avlab_2s1p */ { 1, { { 2, 3}, } }, 841da177e4SLinus Torvalds /* siig_1s1p_10x */ { 1, { { 3, 4 }, } }, 851da177e4SLinus Torvalds /* siig_2s1p_10x */ { 1, { { 4, 5 }, } }, 861da177e4SLinus Torvalds /* siig_2p1s_20x */ { 2, { { 1, 2 }, { 3, 4 }, } }, 871da177e4SLinus Torvalds /* siig_1s1p_20x */ { 1, { { 1, 2 }, } }, 881da177e4SLinus Torvalds /* siig_2s1p_20x */ { 1, { { 2, 3 }, } }, 891da177e4SLinus Torvalds }; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds static struct pci_device_id parport_serial_pci_tbl[] = { 921da177e4SLinus Torvalds /* PCI cards */ 931da177e4SLinus Torvalds { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L, 941da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l }, 951da177e4SLinus Torvalds { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L, 961da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l }, 971da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735, 981da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 991da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9745, 1001da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1011da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, 1021da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1031da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845, 1041da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, 1051da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, 10644e58a6aSMartin Schitter PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 }, 1071da177e4SLinus Torvalds /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ 10891bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2110, 10991bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p }, 11091bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2111, 11191bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p }, 11291bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2112, 11391bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p }, 11491bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2140, 11591bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p }, 11691bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2141, 11791bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p }, 11891bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2142, 11991bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p }, 12091bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2160, 12191bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p }, 12291bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2161, 12391bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p }, 12491bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2162, 12591bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p }, 1261da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, 1271da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, 1281da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, 1291da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, 1301da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, 1311da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, 1321da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, 1331da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, 1341da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, 1351da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, 1361da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, 1371da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, 1381da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, 1391da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, 1401da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, 1411da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, 1421da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, 1431da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, 1441da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, 1451da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1461da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, 1471da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x }, 1481da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, 1491da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x }, 1501da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, 1511da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1521da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, 1531da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1541da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, 1551da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds { 0, } /* terminate list */ 1581da177e4SLinus Torvalds }; 1591da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* 16205caac58SRussell King * This table describes the serial "geometry" of these boards. Any 16305caac58SRussell King * quirks for these can be found in drivers/serial/8250_pci.c 16405caac58SRussell King * 16505caac58SRussell King * Cards not tested are marked n/t 16605caac58SRussell King * If you have one of these cards and it works for you, please tell me.. 1671da177e4SLinus Torvalds */ 16805caac58SRussell King static struct pciserial_board pci_parport_serial_boards[] __devinitdata = { 16905caac58SRussell King [titan_110l] = { 17005caac58SRussell King .flags = FL_BASE1 | FL_BASE_BARS, 17105caac58SRussell King .num_ports = 1, 17205caac58SRussell King .base_baud = 921600, 17305caac58SRussell King .uart_offset = 8, 17405caac58SRussell King }, 17505caac58SRussell King [titan_210l] = { 17605caac58SRussell King .flags = FL_BASE1 | FL_BASE_BARS, 17705caac58SRussell King .num_ports = 2, 17805caac58SRussell King .base_baud = 921600, 17905caac58SRussell King .uart_offset = 8, 18005caac58SRussell King }, 18105caac58SRussell King [netmos_9xx5_combo] = { 18205caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 18305caac58SRussell King .num_ports = 1, 18405caac58SRussell King .base_baud = 115200, 18505caac58SRussell King .uart_offset = 8, 18605caac58SRussell King }, 18705caac58SRussell King [netmos_9855] = { 18805caac58SRussell King .flags = FL_BASE2 | FL_BASE_BARS, 18905caac58SRussell King .num_ports = 1, 19005caac58SRussell King .base_baud = 115200, 19105caac58SRussell King .uart_offset = 8, 19205caac58SRussell King }, 19305caac58SRussell King [avlab_1s1p] = { /* n/t */ 19405caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 19505caac58SRussell King .num_ports = 1, 19605caac58SRussell King .base_baud = 115200, 19705caac58SRussell King .uart_offset = 8, 19805caac58SRussell King }, 19905caac58SRussell King [avlab_1s2p] = { /* n/t */ 20005caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 20105caac58SRussell King .num_ports = 1, 20205caac58SRussell King .base_baud = 115200, 20305caac58SRussell King .uart_offset = 8, 20405caac58SRussell King }, 20505caac58SRussell King [avlab_2s1p] = { /* n/t */ 20605caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS, 20705caac58SRussell King .num_ports = 2, 20805caac58SRussell King .base_baud = 115200, 20905caac58SRussell King .uart_offset = 8, 21005caac58SRussell King }, 21105caac58SRussell King [siig_1s1p_10x] = { 21205caac58SRussell King .flags = FL_BASE2, 21305caac58SRussell King .num_ports = 1, 21405caac58SRussell King .base_baud = 460800, 21505caac58SRussell King .uart_offset = 8, 21605caac58SRussell King }, 21705caac58SRussell King [siig_2s1p_10x] = { 21805caac58SRussell King .flags = FL_BASE2, 21905caac58SRussell King .num_ports = 1, 22005caac58SRussell King .base_baud = 921600, 22105caac58SRussell King .uart_offset = 8, 22205caac58SRussell King }, 22305caac58SRussell King [siig_2p1s_20x] = { 22405caac58SRussell King .flags = FL_BASE0, 22505caac58SRussell King .num_ports = 1, 22605caac58SRussell King .base_baud = 921600, 22705caac58SRussell King .uart_offset = 8, 22805caac58SRussell King }, 22905caac58SRussell King [siig_1s1p_20x] = { 23005caac58SRussell King .flags = FL_BASE0, 23105caac58SRussell King .num_ports = 1, 23205caac58SRussell King .base_baud = 921600, 23305caac58SRussell King .uart_offset = 8, 23405caac58SRussell King }, 23505caac58SRussell King [siig_2s1p_20x] = { 23605caac58SRussell King .flags = FL_BASE0, 23705caac58SRussell King .num_ports = 1, 23805caac58SRussell King .base_baud = 921600, 23905caac58SRussell King .uart_offset = 8, 24005caac58SRussell King }, 2411da177e4SLinus Torvalds }; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds struct parport_serial_private { 24405caac58SRussell King struct serial_private *serial; 2451da177e4SLinus Torvalds int num_par; 2461da177e4SLinus Torvalds struct parport *port[PARPORT_MAX]; 2471da177e4SLinus Torvalds struct parport_pc_pci par; 2481da177e4SLinus Torvalds }; 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* Register the serial port(s) of a PCI card. */ 2511da177e4SLinus Torvalds static int __devinit serial_register (struct pci_dev *dev, 2521da177e4SLinus Torvalds const struct pci_device_id *id) 2531da177e4SLinus Torvalds { 2541da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev); 25505caac58SRussell King struct pciserial_board *board; 25605caac58SRussell King struct serial_private *serial; 2571da177e4SLinus Torvalds 25805caac58SRussell King board = &pci_parport_serial_boards[id->driver_data]; 25905caac58SRussell King serial = pciserial_init_ports(dev, board); 2601da177e4SLinus Torvalds 26105caac58SRussell King if (IS_ERR(serial)) 26205caac58SRussell King return PTR_ERR(serial); 2631da177e4SLinus Torvalds 26405caac58SRussell King priv->serial = serial; 26505caac58SRussell King return 0; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds /* Register the parallel port(s) of a PCI card. */ 2691da177e4SLinus Torvalds static int __devinit parport_register (struct pci_dev *dev, 2701da177e4SLinus Torvalds const struct pci_device_id *id) 2711da177e4SLinus Torvalds { 2721da177e4SLinus Torvalds struct parport_pc_pci *card; 2731da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev); 2747a171cdcSRussell King int n, success = 0; 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds priv->par = cards[id->driver_data]; 2771da177e4SLinus Torvalds card = &priv->par; 2781da177e4SLinus Torvalds if (card->preinit_hook && 2791da177e4SLinus Torvalds card->preinit_hook (dev, card, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) 2801da177e4SLinus Torvalds return -ENODEV; 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds for (n = 0; n < card->numports; n++) { 2831da177e4SLinus Torvalds struct parport *port; 2841da177e4SLinus Torvalds int lo = card->addr[n].lo; 2851da177e4SLinus Torvalds int hi = card->addr[n].hi; 2861da177e4SLinus Torvalds unsigned long io_lo, io_hi; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds if (priv->num_par == ARRAY_SIZE (priv->port)) { 2891da177e4SLinus Torvalds printk (KERN_WARNING 290f4f64e9dSAndrew Morton "parport_serial: %s: only %zu parallel ports " 2911da177e4SLinus Torvalds "supported (%d reported)\n", pci_name (dev), 2921da177e4SLinus Torvalds ARRAY_SIZE(priv->port), card->numports); 2931da177e4SLinus Torvalds break; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds io_lo = pci_resource_start (dev, lo); 2971da177e4SLinus Torvalds io_hi = 0; 2981da177e4SLinus Torvalds if ((hi >= 0) && (hi <= 6)) 2991da177e4SLinus Torvalds io_hi = pci_resource_start (dev, hi); 3001da177e4SLinus Torvalds else if (hi > 6) 3011da177e4SLinus Torvalds io_lo += hi; /* Reinterpret the meaning of 3021da177e4SLinus Torvalds "hi" as an offset (see SYBA 3031da177e4SLinus Torvalds def.) */ 3041da177e4SLinus Torvalds /* TODO: test if sharing interrupts works */ 3057a171cdcSRussell King dev_dbg(&dev->dev, "PCI parallel port detected: I/O at " 3067a171cdcSRussell King "%#lx(%#lx)\n", io_lo, io_hi); 3071da177e4SLinus Torvalds port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, 308c15a3837SDavid Brownell PARPORT_DMA_NONE, &dev->dev); 3091da177e4SLinus Torvalds if (port) { 3101da177e4SLinus Torvalds priv->port[priv->num_par++] = port; 3111da177e4SLinus Torvalds success = 1; 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds if (card->postinit_hook) 3161da177e4SLinus Torvalds card->postinit_hook (dev, card, !success); 3171da177e4SLinus Torvalds 3187a171cdcSRussell King return 0; 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds static int __devinit parport_serial_pci_probe (struct pci_dev *dev, 3221da177e4SLinus Torvalds const struct pci_device_id *id) 3231da177e4SLinus Torvalds { 3241da177e4SLinus Torvalds struct parport_serial_private *priv; 3251da177e4SLinus Torvalds int err; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds priv = kmalloc (sizeof *priv, GFP_KERNEL); 3281da177e4SLinus Torvalds if (!priv) 3291da177e4SLinus Torvalds return -ENOMEM; 33005caac58SRussell King memset(priv, 0, sizeof(struct parport_serial_private)); 3311da177e4SLinus Torvalds pci_set_drvdata (dev, priv); 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds err = pci_enable_device (dev); 3341da177e4SLinus Torvalds if (err) { 3351da177e4SLinus Torvalds pci_set_drvdata (dev, NULL); 3361da177e4SLinus Torvalds kfree (priv); 3371da177e4SLinus Torvalds return err; 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds if (parport_register (dev, id)) { 3411da177e4SLinus Torvalds pci_set_drvdata (dev, NULL); 3421da177e4SLinus Torvalds kfree (priv); 3431da177e4SLinus Torvalds return -ENODEV; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds if (serial_register (dev, id)) { 3471da177e4SLinus Torvalds int i; 3481da177e4SLinus Torvalds for (i = 0; i < priv->num_par; i++) 3491da177e4SLinus Torvalds parport_pc_unregister_port (priv->port[i]); 3501da177e4SLinus Torvalds pci_set_drvdata (dev, NULL); 3511da177e4SLinus Torvalds kfree (priv); 3521da177e4SLinus Torvalds return -ENODEV; 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds return 0; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds static void __devexit parport_serial_pci_remove (struct pci_dev *dev) 3591da177e4SLinus Torvalds { 3601da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev); 3611da177e4SLinus Torvalds int i; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds pci_set_drvdata(dev, NULL); 3641da177e4SLinus Torvalds 36505caac58SRussell King // Serial ports 36605caac58SRussell King if (priv->serial) 36705caac58SRussell King pciserial_remove_ports(priv->serial); 36805caac58SRussell King 3691da177e4SLinus Torvalds // Parallel ports 3701da177e4SLinus Torvalds for (i = 0; i < priv->num_par; i++) 3711da177e4SLinus Torvalds parport_pc_unregister_port (priv->port[i]); 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds kfree (priv); 3741da177e4SLinus Torvalds return; 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 3777dd7d691SAlexey Dobriyan #ifdef CONFIG_PM 37805caac58SRussell King static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state) 37905caac58SRussell King { 38005caac58SRussell King struct parport_serial_private *priv = pci_get_drvdata(dev); 38105caac58SRussell King 38205caac58SRussell King if (priv->serial) 38305caac58SRussell King pciserial_suspend_ports(priv->serial); 38405caac58SRussell King 38505caac58SRussell King /* FIXME: What about parport? */ 38605caac58SRussell King 38705caac58SRussell King pci_save_state(dev); 38805caac58SRussell King pci_set_power_state(dev, pci_choose_state(dev, state)); 38905caac58SRussell King return 0; 39005caac58SRussell King } 39105caac58SRussell King 39205caac58SRussell King static int parport_serial_pci_resume(struct pci_dev *dev) 39305caac58SRussell King { 39405caac58SRussell King struct parport_serial_private *priv = pci_get_drvdata(dev); 39510f8a598SRandy Dunlap int err; 39605caac58SRussell King 39705caac58SRussell King pci_set_power_state(dev, PCI_D0); 39805caac58SRussell King pci_restore_state(dev); 39905caac58SRussell King 40005caac58SRussell King /* 40105caac58SRussell King * The device may have been disabled. Re-enable it. 40205caac58SRussell King */ 40310f8a598SRandy Dunlap err = pci_enable_device(dev); 40410f8a598SRandy Dunlap if (err) { 40510f8a598SRandy Dunlap printk(KERN_ERR "parport_serial: %s: error enabling " 40610f8a598SRandy Dunlap "device for resume (%d)\n", pci_name(dev), err); 40710f8a598SRandy Dunlap return err; 40810f8a598SRandy Dunlap } 40905caac58SRussell King 41005caac58SRussell King if (priv->serial) 41105caac58SRussell King pciserial_resume_ports(priv->serial); 41205caac58SRussell King 41305caac58SRussell King /* FIXME: What about parport? */ 41405caac58SRussell King 41505caac58SRussell King return 0; 41605caac58SRussell King } 4177dd7d691SAlexey Dobriyan #endif 41805caac58SRussell King 4191da177e4SLinus Torvalds static struct pci_driver parport_serial_pci_driver = { 4201da177e4SLinus Torvalds .name = "parport_serial", 4211da177e4SLinus Torvalds .id_table = parport_serial_pci_tbl, 4221da177e4SLinus Torvalds .probe = parport_serial_pci_probe, 4231da177e4SLinus Torvalds .remove = __devexit_p(parport_serial_pci_remove), 4247dd7d691SAlexey Dobriyan #ifdef CONFIG_PM 42505caac58SRussell King .suspend = parport_serial_pci_suspend, 42605caac58SRussell King .resume = parport_serial_pci_resume, 4277dd7d691SAlexey Dobriyan #endif 4281da177e4SLinus Torvalds }; 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds static int __init parport_serial_init (void) 4321da177e4SLinus Torvalds { 43393b47684SRichard Knutsson return pci_register_driver (&parport_serial_pci_driver); 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds static void __exit parport_serial_exit (void) 4371da177e4SLinus Torvalds { 4381da177e4SLinus Torvalds pci_unregister_driver (&parport_serial_pci_driver); 4391da177e4SLinus Torvalds return; 4401da177e4SLinus Torvalds } 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds MODULE_AUTHOR("Tim Waugh <twaugh@redhat.com>"); 4431da177e4SLinus Torvalds MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards"); 4441da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds module_init(parport_serial_init); 4471da177e4SLinus Torvalds module_exit(parport_serial_exit); 448