1fecae16eSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Support for common PCI multi-I/O cards (which is most of them)
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 2001 Tim Waugh <twaugh@redhat.com>
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Multi-function PCI cards are supposed to present separate logical
81da177e4SLinus Torvalds * devices on the bus. A common thing to do seems to be to just use
91da177e4SLinus Torvalds * one logical device with lots of base address registers for both
101da177e4SLinus Torvalds * parallel ports and serial ports. This driver is for dealing with
111da177e4SLinus Torvalds * that.
121da177e4SLinus Torvalds */
131da177e4SLinus Torvalds
1451dcdfecSAlan Cox #include <linux/interrupt.h>
154af5781aSAndy Shevchenko #include <linux/module.h>
161da177e4SLinus Torvalds #include <linux/parport.h>
171da177e4SLinus Torvalds #include <linux/parport_pc.h>
184af5781aSAndy Shevchenko #include <linux/pci.h>
194af5781aSAndy Shevchenko #include <linux/slab.h>
204af5781aSAndy Shevchenko #include <linux/types.h>
214af5781aSAndy Shevchenko
221da177e4SLinus Torvalds #include <linux/8250_pci.h>
231da177e4SLinus Torvalds
241da177e4SLinus Torvalds enum parport_pc_pci_cards {
251da177e4SLinus Torvalds titan_110l = 0,
261da177e4SLinus Torvalds titan_210l,
271da177e4SLinus Torvalds netmos_9xx5_combo,
2844e58a6aSMartin Schitter netmos_9855,
2950db9d8eSPhilippe De Muyter netmos_9855_2p,
307808edcdSNicos Gollan netmos_9900,
317808edcdSNicos Gollan netmos_9900_2p,
327808edcdSNicos Gollan netmos_99xx_1p,
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,
41b9b24558SFrédéric Brière timedia_4078a,
42b9b24558SFrédéric Brière timedia_4079h,
43b9b24558SFrédéric Brière timedia_4085h,
44b9b24558SFrédéric Brière timedia_4088a,
45b9b24558SFrédéric Brière timedia_4089a,
46b9b24558SFrédéric Brière timedia_4095a,
47b9b24558SFrédéric Brière timedia_4096a,
48b9b24558SFrédéric Brière timedia_4078u,
49b9b24558SFrédéric Brière timedia_4079a,
50b9b24558SFrédéric Brière timedia_4085u,
51b9b24558SFrédéric Brière timedia_4079r,
52b9b24558SFrédéric Brière timedia_4079s,
53b9b24558SFrédéric Brière timedia_4079d,
54b9b24558SFrédéric Brière timedia_4079e,
55b9b24558SFrédéric Brière timedia_4079f,
56b9b24558SFrédéric Brière timedia_9079a,
57b9b24558SFrédéric Brière timedia_9079b,
58b9b24558SFrédéric Brière timedia_9079c,
59feb58142SEzequiel Garcia wch_ch353_1s1p,
606971c635SGuainluca Anzolin wch_ch353_2s1p,
61c9a104e2SColin Ian King wch_ch382_0s1p,
622fdd8c8cSSergej Pupykin wch_ch382_2s1p,
63ec8e3893SAndy Shevchenko brainboxes_5s1p,
64c6c94eecSKai-Heng Feng sunix_4008a,
65c6c94eecSKai-Heng Feng sunix_5069a,
66c6c94eecSKai-Heng Feng sunix_5079a,
67c6c94eecSKai-Heng Feng sunix_5099a,
6803427e7fSCameron Williams brainboxes_uc257,
6903427e7fSCameron Williams brainboxes_is300,
7003427e7fSCameron Williams brainboxes_uc414,
7103427e7fSCameron Williams brainboxes_px263,
721da177e4SLinus Torvalds };
731da177e4SLinus Torvalds
741da177e4SLinus Torvalds /* each element directly indexed from enum list, above */
751da177e4SLinus Torvalds struct parport_pc_pci {
761da177e4SLinus Torvalds int numports;
771da177e4SLinus Torvalds struct { /* BAR (base address registers) numbers in the config
781da177e4SLinus Torvalds space header */
791da177e4SLinus Torvalds int lo;
801da177e4SLinus Torvalds int hi; /* -1 if not there, >6 for offset-method (max
811da177e4SLinus Torvalds BAR is 6) */
821da177e4SLinus Torvalds } addr[4];
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds /* If set, this is called immediately after pci_enable_device.
851da177e4SLinus Torvalds * If it returns non-zero, no probing will take place and the
861da177e4SLinus Torvalds * ports will not be used. */
871da177e4SLinus Torvalds int (*preinit_hook) (struct pci_dev *pdev, struct parport_pc_pci *card,
881da177e4SLinus Torvalds int autoirq, int autodma);
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds /* If set, this is called after probing for ports. If 'failed'
911da177e4SLinus Torvalds * is non-zero we couldn't use any of the ports. */
921da177e4SLinus Torvalds void (*postinit_hook) (struct pci_dev *pdev,
931da177e4SLinus Torvalds struct parport_pc_pci *card, int failed);
941da177e4SLinus Torvalds };
951da177e4SLinus Torvalds
netmos_parallel_init(struct pci_dev * dev,struct parport_pc_pci * par,int autoirq,int autodma)96312facafSGreg Kroah-Hartman static int netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *par,
97312facafSGreg Kroah-Hartman int autoirq, int autodma)
981da177e4SLinus Torvalds {
993abdbf90SJiri Slaby /* the rule described below doesn't hold for this device */
1003abdbf90SJiri Slaby if (dev->device == PCI_DEVICE_ID_NETMOS_9835 &&
1013abdbf90SJiri Slaby dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
1023abdbf90SJiri Slaby dev->subsystem_device == 0x0299)
1033abdbf90SJiri Slaby return -ENODEV;
1047808edcdSNicos Gollan
1057808edcdSNicos Gollan if (dev->device == PCI_DEVICE_ID_NETMOS_9912) {
1067808edcdSNicos Gollan par->numports = 1;
1077808edcdSNicos Gollan } else {
1081da177e4SLinus Torvalds /*
1091da177e4SLinus Torvalds * Netmos uses the subdevice ID to indicate the number of parallel
1101da177e4SLinus Torvalds * and serial ports. The form is 0x00PS, where <P> is the number of
1111da177e4SLinus Torvalds * parallel ports and <S> is the number of serial ports.
1121da177e4SLinus Torvalds */
11350db9d8eSPhilippe De Muyter par->numports = (dev->subsystem_device & 0xf0) >> 4;
11450db9d8eSPhilippe De Muyter if (par->numports > ARRAY_SIZE(par->addr))
11550db9d8eSPhilippe De Muyter par->numports = ARRAY_SIZE(par->addr);
1167808edcdSNicos Gollan }
1177808edcdSNicos Gollan
1181da177e4SLinus Torvalds return 0;
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds
121312facafSGreg Kroah-Hartman static struct parport_pc_pci cards[] = {
1221da177e4SLinus Torvalds /* titan_110l */ { 1, { { 3, -1 }, } },
1231da177e4SLinus Torvalds /* titan_210l */ { 1, { { 3, -1 }, } },
1241da177e4SLinus Torvalds /* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init },
12550db9d8eSPhilippe De Muyter /* netmos_9855 */ { 1, { { 0, -1 }, }, netmos_parallel_init },
12650db9d8eSPhilippe De Muyter /* netmos_9855_2p */ { 2, { { 0, -1 }, { 2, -1 }, } },
1277808edcdSNicos Gollan /* netmos_9900 */ {1, { { 3, 4 }, }, netmos_parallel_init },
1287808edcdSNicos Gollan /* netmos_9900_2p */ {2, { { 0, 1 }, { 3, 4 }, } },
1297808edcdSNicos Gollan /* netmos_99xx_1p */ {1, { { 0, 1 }, } },
1301da177e4SLinus Torvalds /* avlab_1s1p */ { 1, { { 1, 2}, } },
1311da177e4SLinus Torvalds /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} },
1321da177e4SLinus Torvalds /* avlab_2s1p */ { 1, { { 2, 3}, } },
1331da177e4SLinus Torvalds /* siig_1s1p_10x */ { 1, { { 3, 4 }, } },
1341da177e4SLinus Torvalds /* siig_2s1p_10x */ { 1, { { 4, 5 }, } },
1351da177e4SLinus Torvalds /* siig_2p1s_20x */ { 2, { { 1, 2 }, { 3, 4 }, } },
1361da177e4SLinus Torvalds /* siig_1s1p_20x */ { 1, { { 1, 2 }, } },
1371da177e4SLinus Torvalds /* siig_2s1p_20x */ { 1, { { 2, 3 }, } },
138b9b24558SFrédéric Brière /* timedia_4078a */ { 1, { { 2, -1 }, } },
139b9b24558SFrédéric Brière /* timedia_4079h */ { 1, { { 2, 3 }, } },
140b9b24558SFrédéric Brière /* timedia_4085h */ { 2, { { 2, -1 }, { 4, -1 }, } },
141b9b24558SFrédéric Brière /* timedia_4088a */ { 2, { { 2, 3 }, { 4, 5 }, } },
142b9b24558SFrédéric Brière /* timedia_4089a */ { 2, { { 2, 3 }, { 4, 5 }, } },
143b9b24558SFrédéric Brière /* timedia_4095a */ { 2, { { 2, 3 }, { 4, 5 }, } },
144b9b24558SFrédéric Brière /* timedia_4096a */ { 2, { { 2, 3 }, { 4, 5 }, } },
145b9b24558SFrédéric Brière /* timedia_4078u */ { 1, { { 2, -1 }, } },
146b9b24558SFrédéric Brière /* timedia_4079a */ { 1, { { 2, 3 }, } },
147b9b24558SFrédéric Brière /* timedia_4085u */ { 2, { { 2, -1 }, { 4, -1 }, } },
148b9b24558SFrédéric Brière /* timedia_4079r */ { 1, { { 2, 3 }, } },
149b9b24558SFrédéric Brière /* timedia_4079s */ { 1, { { 2, 3 }, } },
150b9b24558SFrédéric Brière /* timedia_4079d */ { 1, { { 2, 3 }, } },
151b9b24558SFrédéric Brière /* timedia_4079e */ { 1, { { 2, 3 }, } },
152b9b24558SFrédéric Brière /* timedia_4079f */ { 1, { { 2, 3 }, } },
153b9b24558SFrédéric Brière /* timedia_9079a */ { 1, { { 2, 3 }, } },
154b9b24558SFrédéric Brière /* timedia_9079b */ { 1, { { 2, 3 }, } },
155b9b24558SFrédéric Brière /* timedia_9079c */ { 1, { { 2, 3 }, } },
156feb58142SEzequiel Garcia /* wch_ch353_1s1p*/ { 1, { { 1, -1}, } },
1576971c635SGuainluca Anzolin /* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
158c9a104e2SColin Ian King /* wch_ch382_0s1p*/ { 1, { { 2, -1}, } },
1592fdd8c8cSSergej Pupykin /* wch_ch382_2s1p*/ { 1, { { 2, -1}, } },
160ec8e3893SAndy Shevchenko /* brainboxes_5s1p */ { 1, { { 3, -1 }, } },
161c6c94eecSKai-Heng Feng /* sunix_4008a */ { 1, { { 1, 2 }, } },
162c6c94eecSKai-Heng Feng /* sunix_5069a */ { 1, { { 1, 2 }, } },
163c6c94eecSKai-Heng Feng /* sunix_5079a */ { 1, { { 1, 2 }, } },
164c6c94eecSKai-Heng Feng /* sunix_5099a */ { 1, { { 1, 2 }, } },
16503427e7fSCameron Williams /* brainboxes_uc257 */ { 1, { { 3, -1 }, } },
16603427e7fSCameron Williams /* brainboxes_is300 */ { 1, { { 3, -1 }, } },
16703427e7fSCameron Williams /* brainboxes_uc414 */ { 1, { { 3, -1 }, } },
16803427e7fSCameron Williams /* brainboxes_px263 */ { 1, { { 3, -1 }, } },
1691da177e4SLinus Torvalds };
1701da177e4SLinus Torvalds
1711da177e4SLinus Torvalds static struct pci_device_id parport_serial_pci_tbl[] = {
1721da177e4SLinus Torvalds /* PCI cards */
1731da177e4SLinus Torvalds { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L,
1741da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l },
1751da177e4SLinus Torvalds { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L,
1761da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l },
1771da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735,
1781da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
1791da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9745,
1801da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
1811da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
1821da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
1831da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845,
1841da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
1851da177e4SLinus Torvalds { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
18650db9d8eSPhilippe De Muyter 0x1000, 0x0020, 0, 0, netmos_9855_2p },
18750db9d8eSPhilippe De Muyter { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
18850db9d8eSPhilippe De Muyter 0x1000, 0x0022, 0, 0, netmos_9855_2p },
18950db9d8eSPhilippe De Muyter { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
19044e58a6aSMartin Schitter PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 },
1917808edcdSNicos Gollan { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
1927808edcdSNicos Gollan 0xA000, 0x3011, 0, 0, netmos_9900 },
1937808edcdSNicos Gollan { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
1947808edcdSNicos Gollan 0xA000, 0x3012, 0, 0, netmos_9900 },
1957808edcdSNicos Gollan { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
1967808edcdSNicos Gollan 0xA000, 0x3020, 0, 0, netmos_9900_2p },
1977808edcdSNicos Gollan { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912,
1987808edcdSNicos Gollan 0xA000, 0x2000, 0, 0, netmos_99xx_1p },
1991da177e4SLinus Torvalds /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
20091bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2110,
20191bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p },
20291bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2111,
20391bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p },
20491bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2112,
20591bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p },
20691bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2140,
20791bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p },
20891bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2141,
20991bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p },
21091bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2142,
21191bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p },
21291bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2160,
21391bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p },
21491bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2161,
21591bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p },
21691bca4b3SRussell King { PCI_VENDOR_ID_AFAVLAB, 0x2162,
21791bca4b3SRussell King PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p },
2181da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
2191da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
2201da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
2211da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
2221da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
2231da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
2241da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
2251da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
2261da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
2271da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
2281da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
2291da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
2301da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
2311da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
2321da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
2331da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
2341da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
2351da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
2361da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
2371da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
2381da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
2391da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },
2401da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
2411da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },
2421da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
2431da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
2441da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
2451da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
2461da177e4SLinus Torvalds { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
2471da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
248b9b24558SFrédéric Brière /* PCI_VENDOR_ID_TIMEDIA/SUNIX has many differing cards ...*/
249b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x4078, 0, 0, timedia_4078a },
250b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x4079, 0, 0, timedia_4079h },
251b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x4085, 0, 0, timedia_4085h },
252b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x4088, 0, 0, timedia_4088a },
253b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x4089, 0, 0, timedia_4089a },
254b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x4095, 0, 0, timedia_4095a },
255b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x4096, 0, 0, timedia_4096a },
256b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x5078, 0, 0, timedia_4078u },
257b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x5079, 0, 0, timedia_4079a },
258b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x5085, 0, 0, timedia_4085u },
259b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x6079, 0, 0, timedia_4079r },
260b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x7079, 0, 0, timedia_4079s },
261b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x8079, 0, 0, timedia_4079d },
262b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0x9079, 0, 0, timedia_4079e },
263b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0xa079, 0, 0, timedia_4079f },
264b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a },
265b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b },
266b9b24558SFrédéric Brière { 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
267abd7bacaSStephen Chivers
2686971c635SGuainluca Anzolin /* WCH CARDS */
269feb58142SEzequiel Garcia { 0x4348, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, wch_ch353_1s1p},
2706971c635SGuainluca Anzolin { 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
271c9a104e2SColin Ian King { 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382_0s1p},
2722fdd8c8cSSergej Pupykin { 0x1c00, 0x3250, 0x1c00, 0x3250, 0, 0, wch_ch382_2s1p},
273abd7bacaSStephen Chivers
274ec8e3893SAndy Shevchenko /* BrainBoxes PX272/PX306 MIO card */
275ec8e3893SAndy Shevchenko { PCI_VENDOR_ID_INTASHIELD, 0x4100,
276ec8e3893SAndy Shevchenko PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_5s1p },
277ec8e3893SAndy Shevchenko
278c6c94eecSKai-Heng Feng /* Sunix boards */
279abd7bacaSStephen Chivers { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
280c6c94eecSKai-Heng Feng 0x0100, 0, 0, sunix_4008a },
281c6c94eecSKai-Heng Feng { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
282c6c94eecSKai-Heng Feng 0x0101, 0, 0, sunix_5069a },
283c6c94eecSKai-Heng Feng { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
284c6c94eecSKai-Heng Feng 0x0102, 0, 0, sunix_5079a },
285c6c94eecSKai-Heng Feng { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
286c6c94eecSKai-Heng Feng 0x0104, 0, 0, sunix_5099a },
287abd7bacaSStephen Chivers
288*12786872SCameron Williams /* Brainboxes UC-203 */
289*12786872SCameron Williams { PCI_VENDOR_ID_INTASHIELD, 0x0bc1,
290*12786872SCameron Williams PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
291*12786872SCameron Williams { PCI_VENDOR_ID_INTASHIELD, 0x0bc2,
292*12786872SCameron Williams PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
293*12786872SCameron Williams
294*12786872SCameron Williams /* Brainboxes UC-257 */
295*12786872SCameron Williams { PCI_VENDOR_ID_INTASHIELD, 0x0861,
296*12786872SCameron Williams PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
297*12786872SCameron Williams { PCI_VENDOR_ID_INTASHIELD, 0x0862,
298*12786872SCameron Williams PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
299*12786872SCameron Williams { PCI_VENDOR_ID_INTASHIELD, 0x0863,
300*12786872SCameron Williams PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
301*12786872SCameron Williams
302*12786872SCameron Williams /* Brainboxes UC-414 */
303*12786872SCameron Williams { PCI_VENDOR_ID_INTASHIELD, 0x0e61,
304*12786872SCameron Williams PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc414 },
305*12786872SCameron Williams
306*12786872SCameron Williams /* Brainboxes UC-475 */
307*12786872SCameron Williams { PCI_VENDOR_ID_INTASHIELD, 0x0981,
308*12786872SCameron Williams PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
309*12786872SCameron Williams { PCI_VENDOR_ID_INTASHIELD, 0x0982,
310*12786872SCameron Williams PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
311*12786872SCameron Williams
312*12786872SCameron Williams /* Brainboxes IS-300/IS-500 */
313*12786872SCameron Williams { PCI_VENDOR_ID_INTASHIELD, 0x0da0,
314*12786872SCameron Williams PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_is300 },
315*12786872SCameron Williams
316*12786872SCameron Williams /* Brainboxes PX-263/PX-295 */
317*12786872SCameron Williams { PCI_VENDOR_ID_INTASHIELD, 0x402c,
318*12786872SCameron Williams PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_px263 },
319*12786872SCameron Williams
3201da177e4SLinus Torvalds { 0, } /* terminate list */
3211da177e4SLinus Torvalds };
3221da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
3231da177e4SLinus Torvalds
3241da177e4SLinus Torvalds /*
32505caac58SRussell King * This table describes the serial "geometry" of these boards. Any
32605caac58SRussell King * quirks for these can be found in drivers/serial/8250_pci.c
32705caac58SRussell King *
32805caac58SRussell King * Cards not tested are marked n/t
32905caac58SRussell King * If you have one of these cards and it works for you, please tell me..
3301da177e4SLinus Torvalds */
331312facafSGreg Kroah-Hartman static struct pciserial_board pci_parport_serial_boards[] = {
33205caac58SRussell King [titan_110l] = {
33305caac58SRussell King .flags = FL_BASE1 | FL_BASE_BARS,
33405caac58SRussell King .num_ports = 1,
33505caac58SRussell King .base_baud = 921600,
33605caac58SRussell King .uart_offset = 8,
33705caac58SRussell King },
33805caac58SRussell King [titan_210l] = {
33905caac58SRussell King .flags = FL_BASE1 | FL_BASE_BARS,
34005caac58SRussell King .num_ports = 2,
34105caac58SRussell King .base_baud = 921600,
34205caac58SRussell King .uart_offset = 8,
34305caac58SRussell King },
34405caac58SRussell King [netmos_9xx5_combo] = {
34505caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS,
34605caac58SRussell King .num_ports = 1,
34705caac58SRussell King .base_baud = 115200,
34805caac58SRussell King .uart_offset = 8,
34905caac58SRussell King },
35005caac58SRussell King [netmos_9855] = {
35150db9d8eSPhilippe De Muyter .flags = FL_BASE2 | FL_BASE_BARS,
35250db9d8eSPhilippe De Muyter .num_ports = 1,
35350db9d8eSPhilippe De Muyter .base_baud = 115200,
35450db9d8eSPhilippe De Muyter .uart_offset = 8,
35550db9d8eSPhilippe De Muyter },
35650db9d8eSPhilippe De Muyter [netmos_9855_2p] = {
357c01106e5SChristian Pellegrin .flags = FL_BASE4 | FL_BASE_BARS,
35805caac58SRussell King .num_ports = 1,
35905caac58SRussell King .base_baud = 115200,
36005caac58SRussell King .uart_offset = 8,
36105caac58SRussell King },
3627808edcdSNicos Gollan [netmos_9900] = { /* n/t */
3637808edcdSNicos Gollan .flags = FL_BASE0 | FL_BASE_BARS,
3647808edcdSNicos Gollan .num_ports = 1,
3657808edcdSNicos Gollan .base_baud = 115200,
3667808edcdSNicos Gollan .uart_offset = 8,
3677808edcdSNicos Gollan },
3687808edcdSNicos Gollan [netmos_9900_2p] = { /* parallel only */ /* n/t */
3697808edcdSNicos Gollan .flags = FL_BASE0,
3707808edcdSNicos Gollan .num_ports = 0,
3717808edcdSNicos Gollan .base_baud = 115200,
3727808edcdSNicos Gollan .uart_offset = 8,
3737808edcdSNicos Gollan },
3747808edcdSNicos Gollan [netmos_99xx_1p] = { /* parallel only */ /* n/t */
3757808edcdSNicos Gollan .flags = FL_BASE0,
3767808edcdSNicos Gollan .num_ports = 0,
3777808edcdSNicos Gollan .base_baud = 115200,
3787808edcdSNicos Gollan .uart_offset = 8,
3797808edcdSNicos Gollan },
38005caac58SRussell King [avlab_1s1p] = { /* n/t */
38105caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS,
38205caac58SRussell King .num_ports = 1,
38305caac58SRussell King .base_baud = 115200,
38405caac58SRussell King .uart_offset = 8,
38505caac58SRussell King },
38605caac58SRussell King [avlab_1s2p] = { /* n/t */
38705caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS,
38805caac58SRussell King .num_ports = 1,
38905caac58SRussell King .base_baud = 115200,
39005caac58SRussell King .uart_offset = 8,
39105caac58SRussell King },
39205caac58SRussell King [avlab_2s1p] = { /* n/t */
39305caac58SRussell King .flags = FL_BASE0 | FL_BASE_BARS,
39405caac58SRussell King .num_ports = 2,
39505caac58SRussell King .base_baud = 115200,
39605caac58SRussell King .uart_offset = 8,
39705caac58SRussell King },
39805caac58SRussell King [siig_1s1p_10x] = {
39905caac58SRussell King .flags = FL_BASE2,
40005caac58SRussell King .num_ports = 1,
40105caac58SRussell King .base_baud = 460800,
40205caac58SRussell King .uart_offset = 8,
40305caac58SRussell King },
40405caac58SRussell King [siig_2s1p_10x] = {
40505caac58SRussell King .flags = FL_BASE2,
40605caac58SRussell King .num_ports = 1,
40705caac58SRussell King .base_baud = 921600,
40805caac58SRussell King .uart_offset = 8,
40905caac58SRussell King },
41005caac58SRussell King [siig_2p1s_20x] = {
41105caac58SRussell King .flags = FL_BASE0,
41205caac58SRussell King .num_ports = 1,
41305caac58SRussell King .base_baud = 921600,
41405caac58SRussell King .uart_offset = 8,
41505caac58SRussell King },
41605caac58SRussell King [siig_1s1p_20x] = {
41705caac58SRussell King .flags = FL_BASE0,
41805caac58SRussell King .num_ports = 1,
41905caac58SRussell King .base_baud = 921600,
42005caac58SRussell King .uart_offset = 8,
42105caac58SRussell King },
42205caac58SRussell King [siig_2s1p_20x] = {
42305caac58SRussell King .flags = FL_BASE0,
42405caac58SRussell King .num_ports = 1,
42505caac58SRussell King .base_baud = 921600,
42605caac58SRussell King .uart_offset = 8,
42705caac58SRussell King },
428b9b24558SFrédéric Brière [timedia_4078a] = {
429b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
430b9b24558SFrédéric Brière .num_ports = 1,
431b9b24558SFrédéric Brière .base_baud = 921600,
432b9b24558SFrédéric Brière .uart_offset = 8,
433b9b24558SFrédéric Brière },
434b9b24558SFrédéric Brière [timedia_4079h] = {
435b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
436b9b24558SFrédéric Brière .num_ports = 1,
437b9b24558SFrédéric Brière .base_baud = 921600,
438b9b24558SFrédéric Brière .uart_offset = 8,
439b9b24558SFrédéric Brière },
440b9b24558SFrédéric Brière [timedia_4085h] = {
441b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
442b9b24558SFrédéric Brière .num_ports = 1,
443b9b24558SFrédéric Brière .base_baud = 921600,
444b9b24558SFrédéric Brière .uart_offset = 8,
445b9b24558SFrédéric Brière },
446b9b24558SFrédéric Brière [timedia_4088a] = {
447b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
448b9b24558SFrédéric Brière .num_ports = 1,
449b9b24558SFrédéric Brière .base_baud = 921600,
450b9b24558SFrédéric Brière .uart_offset = 8,
451b9b24558SFrédéric Brière },
452b9b24558SFrédéric Brière [timedia_4089a] = {
453b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
454b9b24558SFrédéric Brière .num_ports = 1,
455b9b24558SFrédéric Brière .base_baud = 921600,
456b9b24558SFrédéric Brière .uart_offset = 8,
457b9b24558SFrédéric Brière },
458b9b24558SFrédéric Brière [timedia_4095a] = {
459b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
460b9b24558SFrédéric Brière .num_ports = 1,
461b9b24558SFrédéric Brière .base_baud = 921600,
462b9b24558SFrédéric Brière .uart_offset = 8,
463b9b24558SFrédéric Brière },
464b9b24558SFrédéric Brière [timedia_4096a] = {
465b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
466b9b24558SFrédéric Brière .num_ports = 1,
467b9b24558SFrédéric Brière .base_baud = 921600,
468b9b24558SFrédéric Brière .uart_offset = 8,
469b9b24558SFrédéric Brière },
470b9b24558SFrédéric Brière [timedia_4078u] = {
471b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
472b9b24558SFrédéric Brière .num_ports = 1,
473b9b24558SFrédéric Brière .base_baud = 921600,
474b9b24558SFrédéric Brière .uart_offset = 8,
475b9b24558SFrédéric Brière },
476b9b24558SFrédéric Brière [timedia_4079a] = {
477b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
478b9b24558SFrédéric Brière .num_ports = 1,
479b9b24558SFrédéric Brière .base_baud = 921600,
480b9b24558SFrédéric Brière .uart_offset = 8,
481b9b24558SFrédéric Brière },
482b9b24558SFrédéric Brière [timedia_4085u] = {
483b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
484b9b24558SFrédéric Brière .num_ports = 1,
485b9b24558SFrédéric Brière .base_baud = 921600,
486b9b24558SFrédéric Brière .uart_offset = 8,
487b9b24558SFrédéric Brière },
488b9b24558SFrédéric Brière [timedia_4079r] = {
489b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
490b9b24558SFrédéric Brière .num_ports = 1,
491b9b24558SFrédéric Brière .base_baud = 921600,
492b9b24558SFrédéric Brière .uart_offset = 8,
493b9b24558SFrédéric Brière },
494b9b24558SFrédéric Brière [timedia_4079s] = {
495b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
496b9b24558SFrédéric Brière .num_ports = 1,
497b9b24558SFrédéric Brière .base_baud = 921600,
498b9b24558SFrédéric Brière .uart_offset = 8,
499b9b24558SFrédéric Brière },
500b9b24558SFrédéric Brière [timedia_4079d] = {
501b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
502b9b24558SFrédéric Brière .num_ports = 1,
503b9b24558SFrédéric Brière .base_baud = 921600,
504b9b24558SFrédéric Brière .uart_offset = 8,
505b9b24558SFrédéric Brière },
506b9b24558SFrédéric Brière [timedia_4079e] = {
507b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
508b9b24558SFrédéric Brière .num_ports = 1,
509b9b24558SFrédéric Brière .base_baud = 921600,
510b9b24558SFrédéric Brière .uart_offset = 8,
511b9b24558SFrédéric Brière },
512b9b24558SFrédéric Brière [timedia_4079f] = {
513b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
514b9b24558SFrédéric Brière .num_ports = 1,
515b9b24558SFrédéric Brière .base_baud = 921600,
516b9b24558SFrédéric Brière .uart_offset = 8,
517b9b24558SFrédéric Brière },
518b9b24558SFrédéric Brière [timedia_9079a] = {
519b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
520b9b24558SFrédéric Brière .num_ports = 1,
521b9b24558SFrédéric Brière .base_baud = 921600,
522b9b24558SFrédéric Brière .uart_offset = 8,
523b9b24558SFrédéric Brière },
524b9b24558SFrédéric Brière [timedia_9079b] = {
525b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
526b9b24558SFrédéric Brière .num_ports = 1,
527b9b24558SFrédéric Brière .base_baud = 921600,
528b9b24558SFrédéric Brière .uart_offset = 8,
529b9b24558SFrédéric Brière },
530b9b24558SFrédéric Brière [timedia_9079c] = {
531b9b24558SFrédéric Brière .flags = FL_BASE0|FL_BASE_BARS,
532b9b24558SFrédéric Brière .num_ports = 1,
533b9b24558SFrédéric Brière .base_baud = 921600,
534b9b24558SFrédéric Brière .uart_offset = 8,
535b9b24558SFrédéric Brière },
536feb58142SEzequiel Garcia [wch_ch353_1s1p] = {
537feb58142SEzequiel Garcia .flags = FL_BASE0|FL_BASE_BARS,
538feb58142SEzequiel Garcia .num_ports = 1,
539feb58142SEzequiel Garcia .base_baud = 115200,
540feb58142SEzequiel Garcia .uart_offset = 8,
541feb58142SEzequiel Garcia },
5426971c635SGuainluca Anzolin [wch_ch353_2s1p] = {
5436971c635SGuainluca Anzolin .flags = FL_BASE0|FL_BASE_BARS,
5446971c635SGuainluca Anzolin .num_ports = 2,
5456971c635SGuainluca Anzolin .base_baud = 115200,
5466971c635SGuainluca Anzolin .uart_offset = 8,
5476971c635SGuainluca Anzolin },
548c9a104e2SColin Ian King [wch_ch382_0s1p] = {
549c9a104e2SColin Ian King .flags = FL_BASE0,
550c9a104e2SColin Ian King .num_ports = 0,
551c9a104e2SColin Ian King .base_baud = 115200,
552c9a104e2SColin Ian King .uart_offset = 8,
553c9a104e2SColin Ian King },
5542fdd8c8cSSergej Pupykin [wch_ch382_2s1p] = {
5552fdd8c8cSSergej Pupykin .flags = FL_BASE0,
5562fdd8c8cSSergej Pupykin .num_ports = 2,
5572fdd8c8cSSergej Pupykin .base_baud = 115200,
5582fdd8c8cSSergej Pupykin .uart_offset = 8,
5592fdd8c8cSSergej Pupykin .first_offset = 0xC0,
5602fdd8c8cSSergej Pupykin },
561ec8e3893SAndy Shevchenko [brainboxes_5s1p] = {
562ec8e3893SAndy Shevchenko .flags = FL_BASE2,
563ec8e3893SAndy Shevchenko .num_ports = 5,
564ec8e3893SAndy Shevchenko .base_baud = 921600,
565ec8e3893SAndy Shevchenko .uart_offset = 8,
566ec8e3893SAndy Shevchenko },
567c6c94eecSKai-Heng Feng [sunix_4008a] = {
568c6c94eecSKai-Heng Feng .num_ports = 0,
569c6c94eecSKai-Heng Feng },
570c6c94eecSKai-Heng Feng [sunix_5069a] = {
571c6c94eecSKai-Heng Feng .num_ports = 1,
572c6c94eecSKai-Heng Feng .base_baud = 921600,
573c6c94eecSKai-Heng Feng .uart_offset = 0x8,
574c6c94eecSKai-Heng Feng },
575c6c94eecSKai-Heng Feng [sunix_5079a] = {
576abd7bacaSStephen Chivers .num_ports = 2,
577abd7bacaSStephen Chivers .base_baud = 921600,
578c6c94eecSKai-Heng Feng .uart_offset = 0x8,
579c6c94eecSKai-Heng Feng },
580c6c94eecSKai-Heng Feng [sunix_5099a] = {
581c6c94eecSKai-Heng Feng .num_ports = 4,
582c6c94eecSKai-Heng Feng .base_baud = 921600,
583c6c94eecSKai-Heng Feng .uart_offset = 0x8,
584abd7bacaSStephen Chivers },
585*12786872SCameron Williams [brainboxes_uc257] = {
586*12786872SCameron Williams .flags = FL_BASE2,
587*12786872SCameron Williams .num_ports = 2,
588*12786872SCameron Williams .base_baud = 115200,
589*12786872SCameron Williams .uart_offset = 8,
590*12786872SCameron Williams },
591*12786872SCameron Williams [brainboxes_is300] = {
592*12786872SCameron Williams .flags = FL_BASE2,
593*12786872SCameron Williams .num_ports = 1,
594*12786872SCameron Williams .base_baud = 115200,
595*12786872SCameron Williams .uart_offset = 8,
596*12786872SCameron Williams },
597*12786872SCameron Williams [brainboxes_uc414] = {
598*12786872SCameron Williams .flags = FL_BASE2,
599*12786872SCameron Williams .num_ports = 4,
600*12786872SCameron Williams .base_baud = 115200,
601*12786872SCameron Williams .uart_offset = 8,
602*12786872SCameron Williams },
603*12786872SCameron Williams [brainboxes_px263] = {
604*12786872SCameron Williams .flags = FL_BASE2,
605*12786872SCameron Williams .num_ports = 4,
606*12786872SCameron Williams .base_baud = 921600,
607*12786872SCameron Williams .uart_offset = 8,
608*12786872SCameron Williams },
6091da177e4SLinus Torvalds };
6101da177e4SLinus Torvalds
6111da177e4SLinus Torvalds struct parport_serial_private {
61205caac58SRussell King struct serial_private *serial;
6131da177e4SLinus Torvalds int num_par;
6141da177e4SLinus Torvalds struct parport *port[PARPORT_MAX];
6151da177e4SLinus Torvalds struct parport_pc_pci par;
6161da177e4SLinus Torvalds };
6171da177e4SLinus Torvalds
6181da177e4SLinus Torvalds /* Register the serial port(s) of a PCI card. */
serial_register(struct pci_dev * dev,const struct pci_device_id * id)619312facafSGreg Kroah-Hartman static int serial_register(struct pci_dev *dev, const struct pci_device_id *id)
6201da177e4SLinus Torvalds {
6211da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev);
62205caac58SRussell King struct pciserial_board *board;
62305caac58SRussell King struct serial_private *serial;
6241da177e4SLinus Torvalds
62505caac58SRussell King board = &pci_parport_serial_boards[id->driver_data];
6267808edcdSNicos Gollan if (board->num_ports == 0)
6277808edcdSNicos Gollan return 0;
6287808edcdSNicos Gollan
62905caac58SRussell King serial = pciserial_init_ports(dev, board);
63005caac58SRussell King if (IS_ERR(serial))
63105caac58SRussell King return PTR_ERR(serial);
6321da177e4SLinus Torvalds
63305caac58SRussell King priv->serial = serial;
63405caac58SRussell King return 0;
6351da177e4SLinus Torvalds }
6361da177e4SLinus Torvalds
6371da177e4SLinus Torvalds /* Register the parallel port(s) of a PCI card. */
parport_register(struct pci_dev * dev,const struct pci_device_id * id)638312facafSGreg Kroah-Hartman static int parport_register(struct pci_dev *dev, const struct pci_device_id *id)
6391da177e4SLinus Torvalds {
6401da177e4SLinus Torvalds struct parport_pc_pci *card;
6411da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev);
6427a171cdcSRussell King int n, success = 0;
6431da177e4SLinus Torvalds
6441da177e4SLinus Torvalds priv->par = cards[id->driver_data];
6451da177e4SLinus Torvalds card = &priv->par;
6461da177e4SLinus Torvalds if (card->preinit_hook &&
6471da177e4SLinus Torvalds card->preinit_hook (dev, card, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
6481da177e4SLinus Torvalds return -ENODEV;
6491da177e4SLinus Torvalds
6501da177e4SLinus Torvalds for (n = 0; n < card->numports; n++) {
6511da177e4SLinus Torvalds struct parport *port;
6521da177e4SLinus Torvalds int lo = card->addr[n].lo;
6531da177e4SLinus Torvalds int hi = card->addr[n].hi;
6541da177e4SLinus Torvalds unsigned long io_lo, io_hi;
65551dcdfecSAlan Cox int irq;
6561da177e4SLinus Torvalds
6571da177e4SLinus Torvalds if (priv->num_par == ARRAY_SIZE (priv->port)) {
65882dfabf1SAndy Shevchenko dev_warn(&dev->dev,
65982dfabf1SAndy Shevchenko "only %zu parallel ports supported (%d reported)\n",
6601da177e4SLinus Torvalds ARRAY_SIZE(priv->port), card->numports);
6611da177e4SLinus Torvalds break;
6621da177e4SLinus Torvalds }
6631da177e4SLinus Torvalds
6641da177e4SLinus Torvalds io_lo = pci_resource_start (dev, lo);
6651da177e4SLinus Torvalds io_hi = 0;
6661da177e4SLinus Torvalds if ((hi >= 0) && (hi <= 6))
6671da177e4SLinus Torvalds io_hi = pci_resource_start (dev, hi);
6681da177e4SLinus Torvalds else if (hi > 6)
6691da177e4SLinus Torvalds io_lo += hi; /* Reinterpret the meaning of
6701da177e4SLinus Torvalds "hi" as an offset (see SYBA
6711da177e4SLinus Torvalds def.) */
6721da177e4SLinus Torvalds /* TODO: test if sharing interrupts works */
673fa11c81cSAndy Shevchenko irq = pci_irq_vector(dev, 0);
674fa11c81cSAndy Shevchenko if (irq < 0)
675fa11c81cSAndy Shevchenko return irq;
67609b18f2fSAndy Shevchenko if (irq == 0)
67709b18f2fSAndy Shevchenko irq = PARPORT_IRQ_NONE;
67809b18f2fSAndy Shevchenko if (irq == PARPORT_IRQ_NONE) {
67951dcdfecSAlan Cox dev_dbg(&dev->dev,
68051dcdfecSAlan Cox "PCI parallel port detected: I/O at %#lx(%#lx)\n",
68151dcdfecSAlan Cox io_lo, io_hi);
68251dcdfecSAlan Cox } else {
68351dcdfecSAlan Cox dev_dbg(&dev->dev,
68451dcdfecSAlan Cox "PCI parallel port detected: I/O at %#lx(%#lx), IRQ %d\n",
68551dcdfecSAlan Cox io_lo, io_hi, irq);
68651dcdfecSAlan Cox }
68751dcdfecSAlan Cox port = parport_pc_probe_port (io_lo, io_hi, irq,
68851dcdfecSAlan Cox PARPORT_DMA_NONE, &dev->dev, IRQF_SHARED);
6891da177e4SLinus Torvalds if (port) {
6901da177e4SLinus Torvalds priv->port[priv->num_par++] = port;
6911da177e4SLinus Torvalds success = 1;
6921da177e4SLinus Torvalds }
6931da177e4SLinus Torvalds }
6941da177e4SLinus Torvalds
6951da177e4SLinus Torvalds if (card->postinit_hook)
6961da177e4SLinus Torvalds card->postinit_hook (dev, card, !success);
6971da177e4SLinus Torvalds
6987a171cdcSRussell King return 0;
6991da177e4SLinus Torvalds }
7001da177e4SLinus Torvalds
parport_serial_pci_probe(struct pci_dev * dev,const struct pci_device_id * id)701312facafSGreg Kroah-Hartman static int parport_serial_pci_probe(struct pci_dev *dev,
7021da177e4SLinus Torvalds const struct pci_device_id *id)
7031da177e4SLinus Torvalds {
7041da177e4SLinus Torvalds struct parport_serial_private *priv;
7051da177e4SLinus Torvalds int err;
7061da177e4SLinus Torvalds
707ad8ce834SAndy Shevchenko priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
7081da177e4SLinus Torvalds if (!priv)
7091da177e4SLinus Torvalds return -ENOMEM;
710ad8ce834SAndy Shevchenko
7111da177e4SLinus Torvalds pci_set_drvdata (dev, priv);
7121da177e4SLinus Torvalds
713ad8ce834SAndy Shevchenko err = pcim_enable_device(dev);
714ad8ce834SAndy Shevchenko if (err)
7151da177e4SLinus Torvalds return err;
7161da177e4SLinus Torvalds
71796edf537SAndy Shevchenko err = parport_register(dev, id);
71896edf537SAndy Shevchenko if (err)
71996edf537SAndy Shevchenko return err;
7201da177e4SLinus Torvalds
72196edf537SAndy Shevchenko err = serial_register(dev, id);
72296edf537SAndy Shevchenko if (err) {
7231da177e4SLinus Torvalds int i;
7241da177e4SLinus Torvalds for (i = 0; i < priv->num_par; i++)
7251da177e4SLinus Torvalds parport_pc_unregister_port (priv->port[i]);
72696edf537SAndy Shevchenko return err;
7271da177e4SLinus Torvalds }
7281da177e4SLinus Torvalds
7291da177e4SLinus Torvalds return 0;
7301da177e4SLinus Torvalds }
7311da177e4SLinus Torvalds
parport_serial_pci_remove(struct pci_dev * dev)732312facafSGreg Kroah-Hartman static void parport_serial_pci_remove(struct pci_dev *dev)
7331da177e4SLinus Torvalds {
7341da177e4SLinus Torvalds struct parport_serial_private *priv = pci_get_drvdata (dev);
7351da177e4SLinus Torvalds int i;
7361da177e4SLinus Torvalds
73705caac58SRussell King // Serial ports
73805caac58SRussell King if (priv->serial)
73905caac58SRussell King pciserial_remove_ports(priv->serial);
74005caac58SRussell King
7411da177e4SLinus Torvalds // Parallel ports
7421da177e4SLinus Torvalds for (i = 0; i < priv->num_par; i++)
7431da177e4SLinus Torvalds parport_pc_unregister_port (priv->port[i]);
7441da177e4SLinus Torvalds
7451da177e4SLinus Torvalds return;
7461da177e4SLinus Torvalds }
7471da177e4SLinus Torvalds
parport_serial_pci_suspend(struct device * dev)7481089c911SAndy Shevchenko static int __maybe_unused parport_serial_pci_suspend(struct device *dev)
74905caac58SRussell King {
7509e18a80cSChuhong Yuan struct parport_serial_private *priv = dev_get_drvdata(dev);
75105caac58SRussell King
75205caac58SRussell King if (priv->serial)
75305caac58SRussell King pciserial_suspend_ports(priv->serial);
75405caac58SRussell King
75505caac58SRussell King /* FIXME: What about parport? */
75605caac58SRussell King return 0;
75705caac58SRussell King }
75805caac58SRussell King
parport_serial_pci_resume(struct device * dev)7591089c911SAndy Shevchenko static int __maybe_unused parport_serial_pci_resume(struct device *dev)
76005caac58SRussell King {
7619e18a80cSChuhong Yuan struct parport_serial_private *priv = dev_get_drvdata(dev);
76205caac58SRussell King
76305caac58SRussell King if (priv->serial)
76405caac58SRussell King pciserial_resume_ports(priv->serial);
76505caac58SRussell King
76605caac58SRussell King /* FIXME: What about parport? */
76705caac58SRussell King return 0;
76805caac58SRussell King }
7691089c911SAndy Shevchenko
7701089c911SAndy Shevchenko static SIMPLE_DEV_PM_OPS(parport_serial_pm_ops,
7711089c911SAndy Shevchenko parport_serial_pci_suspend, parport_serial_pci_resume);
77205caac58SRussell King
7731da177e4SLinus Torvalds static struct pci_driver parport_serial_pci_driver = {
7741da177e4SLinus Torvalds .name = "parport_serial",
7751da177e4SLinus Torvalds .id_table = parport_serial_pci_tbl,
7761da177e4SLinus Torvalds .probe = parport_serial_pci_probe,
777312facafSGreg Kroah-Hartman .remove = parport_serial_pci_remove,
7781089c911SAndy Shevchenko .driver = {
7791089c911SAndy Shevchenko .pm = &parport_serial_pm_ops,
7801089c911SAndy Shevchenko },
7811da177e4SLinus Torvalds };
782b0b0a643SAndy Shevchenko module_pci_driver(parport_serial_pci_driver);
7831da177e4SLinus Torvalds
7841da177e4SLinus Torvalds MODULE_AUTHOR("Tim Waugh <twaugh@redhat.com>");
7851da177e4SLinus Torvalds MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards");
7861da177e4SLinus Torvalds MODULE_LICENSE("GPL");
787