Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Support for common PCI multi-I/O cards (which is most of them)
0004  *
0005  * Copyright (C) 2001  Tim Waugh <twaugh@redhat.com>
0006  *
0007  * Multi-function PCI cards are supposed to present separate logical
0008  * devices on the bus.  A common thing to do seems to be to just use
0009  * one logical device with lots of base address registers for both
0010  * parallel ports and serial ports.  This driver is for dealing with
0011  * that.
0012  */
0013 
0014 #include <linux/interrupt.h>
0015 #include <linux/module.h>
0016 #include <linux/parport.h>
0017 #include <linux/parport_pc.h>
0018 #include <linux/pci.h>
0019 #include <linux/slab.h>
0020 #include <linux/types.h>
0021 
0022 #include <linux/8250_pci.h>
0023 
0024 enum parport_pc_pci_cards {
0025     titan_110l = 0,
0026     titan_210l,
0027     netmos_9xx5_combo,
0028     netmos_9855,
0029     netmos_9855_2p,
0030     netmos_9900,
0031     netmos_9900_2p,
0032     netmos_99xx_1p,
0033     avlab_1s1p,
0034     avlab_1s2p,
0035     avlab_2s1p,
0036     siig_1s1p_10x,
0037     siig_2s1p_10x,
0038     siig_2p1s_20x,
0039     siig_1s1p_20x,
0040     siig_2s1p_20x,
0041     timedia_4078a,
0042     timedia_4079h,
0043     timedia_4085h,
0044     timedia_4088a,
0045     timedia_4089a,
0046     timedia_4095a,
0047     timedia_4096a,
0048     timedia_4078u,
0049     timedia_4079a,
0050     timedia_4085u,
0051     timedia_4079r,
0052     timedia_4079s,
0053     timedia_4079d,
0054     timedia_4079e,
0055     timedia_4079f,
0056     timedia_9079a,
0057     timedia_9079b,
0058     timedia_9079c,
0059     wch_ch353_1s1p,
0060     wch_ch353_2s1p,
0061     wch_ch382_0s1p,
0062     wch_ch382_2s1p,
0063     brainboxes_5s1p,
0064     sunix_4008a,
0065     sunix_5069a,
0066     sunix_5079a,
0067     sunix_5099a,
0068 };
0069 
0070 /* each element directly indexed from enum list, above */
0071 struct parport_pc_pci {
0072     int numports;
0073     struct { /* BAR (base address registers) numbers in the config
0074                     space header */
0075         int lo;
0076         int hi; /* -1 if not there, >6 for offset-method (max
0077                            BAR is 6) */
0078     } addr[4];
0079 
0080     /* If set, this is called immediately after pci_enable_device.
0081      * If it returns non-zero, no probing will take place and the
0082      * ports will not be used. */
0083     int (*preinit_hook) (struct pci_dev *pdev, struct parport_pc_pci *card,
0084                 int autoirq, int autodma);
0085 
0086     /* If set, this is called after probing for ports.  If 'failed'
0087      * is non-zero we couldn't use any of the ports. */
0088     void (*postinit_hook) (struct pci_dev *pdev,
0089                 struct parport_pc_pci *card, int failed);
0090 };
0091 
0092 static int netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *par,
0093                 int autoirq, int autodma)
0094 {
0095     /* the rule described below doesn't hold for this device */
0096     if (dev->device == PCI_DEVICE_ID_NETMOS_9835 &&
0097             dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
0098             dev->subsystem_device == 0x0299)
0099         return -ENODEV;
0100 
0101     if (dev->device == PCI_DEVICE_ID_NETMOS_9912) {
0102         par->numports = 1;
0103     } else {
0104         /*
0105          * Netmos uses the subdevice ID to indicate the number of parallel
0106          * and serial ports.  The form is 0x00PS, where <P> is the number of
0107          * parallel ports and <S> is the number of serial ports.
0108          */
0109         par->numports = (dev->subsystem_device & 0xf0) >> 4;
0110         if (par->numports > ARRAY_SIZE(par->addr))
0111             par->numports = ARRAY_SIZE(par->addr);
0112     }
0113 
0114     return 0;
0115 }
0116 
0117 static struct parport_pc_pci cards[] = {
0118     /* titan_110l */        { 1, { { 3, -1 }, } },
0119     /* titan_210l */        { 1, { { 3, -1 }, } },
0120     /* netmos_9xx5_combo */     { 1, { { 2, -1 }, }, netmos_parallel_init },
0121     /* netmos_9855 */       { 1, { { 0, -1 }, }, netmos_parallel_init },
0122     /* netmos_9855_2p */        { 2, { { 0, -1 }, { 2, -1 }, } },
0123     /* netmos_9900 */       {1, { { 3, 4 }, }, netmos_parallel_init },
0124     /* netmos_9900_2p */        {2, { { 0, 1 }, { 3, 4 }, } },
0125     /* netmos_99xx_1p */        {1, { { 0, 1 }, } },
0126     /* avlab_1s1p     */        { 1, { { 1, 2}, } },
0127     /* avlab_1s2p     */        { 2, { { 1, 2}, { 3, 4 },} },
0128     /* avlab_2s1p     */        { 1, { { 2, 3}, } },
0129     /* siig_1s1p_10x */     { 1, { { 3, 4 }, } },
0130     /* siig_2s1p_10x */     { 1, { { 4, 5 }, } },
0131     /* siig_2p1s_20x */     { 2, { { 1, 2 }, { 3, 4 }, } },
0132     /* siig_1s1p_20x */     { 1, { { 1, 2 }, } },
0133     /* siig_2s1p_20x */     { 1, { { 2, 3 }, } },
0134     /* timedia_4078a */     { 1, { { 2, -1 }, } },
0135     /* timedia_4079h */             { 1, { { 2, 3 }, } },
0136     /* timedia_4085h */             { 2, { { 2, -1 }, { 4, -1 }, } },
0137     /* timedia_4088a */             { 2, { { 2, 3 }, { 4, 5 }, } },
0138     /* timedia_4089a */             { 2, { { 2, 3 }, { 4, 5 }, } },
0139     /* timedia_4095a */             { 2, { { 2, 3 }, { 4, 5 }, } },
0140     /* timedia_4096a */             { 2, { { 2, 3 }, { 4, 5 }, } },
0141     /* timedia_4078u */             { 1, { { 2, -1 }, } },
0142     /* timedia_4079a */             { 1, { { 2, 3 }, } },
0143     /* timedia_4085u */             { 2, { { 2, -1 }, { 4, -1 }, } },
0144     /* timedia_4079r */             { 1, { { 2, 3 }, } },
0145     /* timedia_4079s */             { 1, { { 2, 3 }, } },
0146     /* timedia_4079d */             { 1, { { 2, 3 }, } },
0147     /* timedia_4079e */             { 1, { { 2, 3 }, } },
0148     /* timedia_4079f */             { 1, { { 2, 3 }, } },
0149     /* timedia_9079a */             { 1, { { 2, 3 }, } },
0150     /* timedia_9079b */             { 1, { { 2, 3 }, } },
0151     /* timedia_9079c */             { 1, { { 2, 3 }, } },
0152     /* wch_ch353_1s1p*/             { 1, { { 1, -1}, } },
0153     /* wch_ch353_2s1p*/             { 1, { { 2, -1}, } },
0154     /* wch_ch382_0s1p*/     { 1, { { 2, -1}, } },
0155     /* wch_ch382_2s1p*/             { 1, { { 2, -1}, } },
0156     /* brainboxes_5s1p */           { 1, { { 3, -1 }, } },
0157     /* sunix_4008a */       { 1, { { 1, 2 }, } },
0158     /* sunix_5069a */       { 1, { { 1, 2 }, } },
0159     /* sunix_5079a */       { 1, { { 1, 2 }, } },
0160     /* sunix_5099a */       { 1, { { 1, 2 }, } },
0161 };
0162 
0163 static struct pci_device_id parport_serial_pci_tbl[] = {
0164     /* PCI cards */
0165     { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L,
0166       PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l },
0167     { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L,
0168       PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l },
0169     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735,
0170       PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
0171     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9745,
0172       PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
0173     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
0174       PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
0175     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845,
0176       PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
0177     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
0178       0x1000, 0x0020, 0, 0, netmos_9855_2p },
0179     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
0180       0x1000, 0x0022, 0, 0, netmos_9855_2p },
0181     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
0182       PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 },
0183     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
0184       0xA000, 0x3011, 0, 0, netmos_9900 },
0185     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
0186       0xA000, 0x3012, 0, 0, netmos_9900 },
0187     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
0188       0xA000, 0x3020, 0, 0, netmos_9900_2p },
0189     { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912,
0190       0xA000, 0x2000, 0, 0, netmos_99xx_1p },
0191     /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
0192     { PCI_VENDOR_ID_AFAVLAB, 0x2110,
0193       PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p },
0194     { PCI_VENDOR_ID_AFAVLAB, 0x2111,
0195       PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p },
0196     { PCI_VENDOR_ID_AFAVLAB, 0x2112,
0197       PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p },
0198     { PCI_VENDOR_ID_AFAVLAB, 0x2140,
0199       PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p },
0200     { PCI_VENDOR_ID_AFAVLAB, 0x2141,
0201       PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p },
0202     { PCI_VENDOR_ID_AFAVLAB, 0x2142,
0203       PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p },
0204     { PCI_VENDOR_ID_AFAVLAB, 0x2160,
0205       PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p },
0206     { PCI_VENDOR_ID_AFAVLAB, 0x2161,
0207       PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p },
0208     { PCI_VENDOR_ID_AFAVLAB, 0x2162,
0209       PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p },
0210     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
0211       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
0212     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
0213       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
0214     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
0215       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
0216     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
0217       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
0218     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
0219       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
0220     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
0221       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
0222     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
0223       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
0224     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
0225       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
0226     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
0227       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
0228     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
0229       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
0230     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
0231       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },
0232     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
0233       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },
0234     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
0235       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
0236     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
0237       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
0238     { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
0239       PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
0240     /* PCI_VENDOR_ID_TIMEDIA/SUNIX has many differing cards ...*/
0241     { 0x1409, 0x7168, 0x1409, 0x4078, 0, 0, timedia_4078a },
0242     { 0x1409, 0x7168, 0x1409, 0x4079, 0, 0, timedia_4079h },
0243     { 0x1409, 0x7168, 0x1409, 0x4085, 0, 0, timedia_4085h },
0244     { 0x1409, 0x7168, 0x1409, 0x4088, 0, 0, timedia_4088a },
0245     { 0x1409, 0x7168, 0x1409, 0x4089, 0, 0, timedia_4089a },
0246     { 0x1409, 0x7168, 0x1409, 0x4095, 0, 0, timedia_4095a },
0247     { 0x1409, 0x7168, 0x1409, 0x4096, 0, 0, timedia_4096a },
0248     { 0x1409, 0x7168, 0x1409, 0x5078, 0, 0, timedia_4078u },
0249     { 0x1409, 0x7168, 0x1409, 0x5079, 0, 0, timedia_4079a },
0250     { 0x1409, 0x7168, 0x1409, 0x5085, 0, 0, timedia_4085u },
0251     { 0x1409, 0x7168, 0x1409, 0x6079, 0, 0, timedia_4079r },
0252     { 0x1409, 0x7168, 0x1409, 0x7079, 0, 0, timedia_4079s },
0253     { 0x1409, 0x7168, 0x1409, 0x8079, 0, 0, timedia_4079d },
0254     { 0x1409, 0x7168, 0x1409, 0x9079, 0, 0, timedia_4079e },
0255     { 0x1409, 0x7168, 0x1409, 0xa079, 0, 0, timedia_4079f },
0256     { 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a },
0257     { 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b },
0258     { 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
0259 
0260     /* WCH CARDS */
0261     { 0x4348, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, wch_ch353_1s1p},
0262     { 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
0263     { 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382_0s1p},
0264     { 0x1c00, 0x3250, 0x1c00, 0x3250, 0, 0, wch_ch382_2s1p},
0265 
0266     /* BrainBoxes PX272/PX306 MIO card */
0267     { PCI_VENDOR_ID_INTASHIELD, 0x4100,
0268       PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_5s1p },
0269 
0270     /* Sunix boards */
0271     { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
0272       0x0100, 0, 0, sunix_4008a },
0273     { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
0274       0x0101, 0, 0, sunix_5069a },
0275     { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
0276       0x0102, 0, 0, sunix_5079a },
0277     { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
0278       0x0104, 0, 0, sunix_5099a },
0279 
0280     { 0, } /* terminate list */
0281 };
0282 MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
0283 
0284 /*
0285  * This table describes the serial "geometry" of these boards.  Any
0286  * quirks for these can be found in drivers/serial/8250_pci.c
0287  *
0288  * Cards not tested are marked n/t
0289  * If you have one of these cards and it works for you, please tell me..
0290  */
0291 static struct pciserial_board pci_parport_serial_boards[] = {
0292     [titan_110l] = {
0293         .flags      = FL_BASE1 | FL_BASE_BARS,
0294         .num_ports  = 1,
0295         .base_baud  = 921600,
0296         .uart_offset    = 8,
0297     },
0298     [titan_210l] = {
0299         .flags      = FL_BASE1 | FL_BASE_BARS,
0300         .num_ports  = 2,
0301         .base_baud  = 921600,
0302         .uart_offset    = 8,
0303     },
0304     [netmos_9xx5_combo] = {
0305         .flags      = FL_BASE0 | FL_BASE_BARS,
0306         .num_ports  = 1,
0307         .base_baud  = 115200,
0308         .uart_offset    = 8,
0309     },
0310     [netmos_9855] = {
0311         .flags      = FL_BASE2 | FL_BASE_BARS,
0312         .num_ports  = 1,
0313         .base_baud  = 115200,
0314         .uart_offset    = 8,
0315     },
0316     [netmos_9855_2p] = {
0317         .flags      = FL_BASE4 | FL_BASE_BARS,
0318         .num_ports  = 1,
0319         .base_baud  = 115200,
0320         .uart_offset    = 8,
0321     },
0322     [netmos_9900] = { /* n/t */
0323         .flags      = FL_BASE0 | FL_BASE_BARS,
0324         .num_ports  = 1,
0325         .base_baud  = 115200,
0326         .uart_offset    = 8,
0327     },
0328     [netmos_9900_2p] = { /* parallel only */ /* n/t */
0329         .flags      = FL_BASE0,
0330         .num_ports  = 0,
0331         .base_baud  = 115200,
0332         .uart_offset    = 8,
0333     },
0334     [netmos_99xx_1p] = { /* parallel only */ /* n/t */
0335         .flags      = FL_BASE0,
0336         .num_ports  = 0,
0337         .base_baud  = 115200,
0338         .uart_offset    = 8,
0339     },
0340     [avlab_1s1p] = { /* n/t */
0341         .flags      = FL_BASE0 | FL_BASE_BARS,
0342         .num_ports  = 1,
0343         .base_baud  = 115200,
0344         .uart_offset    = 8,
0345     },
0346     [avlab_1s2p] = { /* n/t */
0347         .flags      = FL_BASE0 | FL_BASE_BARS,
0348         .num_ports  = 1,
0349         .base_baud  = 115200,
0350         .uart_offset    = 8,
0351     },
0352     [avlab_2s1p] = { /* n/t */
0353         .flags      = FL_BASE0 | FL_BASE_BARS,
0354         .num_ports  = 2,
0355         .base_baud  = 115200,
0356         .uart_offset    = 8,
0357     },
0358     [siig_1s1p_10x] = {
0359         .flags      = FL_BASE2,
0360         .num_ports  = 1,
0361         .base_baud  = 460800,
0362         .uart_offset    = 8,
0363     },
0364     [siig_2s1p_10x] = {
0365         .flags      = FL_BASE2,
0366         .num_ports  = 1,
0367         .base_baud  = 921600,
0368         .uart_offset    = 8,
0369     },
0370     [siig_2p1s_20x] = {
0371         .flags      = FL_BASE0,
0372         .num_ports  = 1,
0373         .base_baud  = 921600,
0374         .uart_offset    = 8,
0375     },
0376     [siig_1s1p_20x] = {
0377         .flags      = FL_BASE0,
0378         .num_ports  = 1,
0379         .base_baud  = 921600,
0380         .uart_offset    = 8,
0381     },
0382     [siig_2s1p_20x] = {
0383         .flags      = FL_BASE0,
0384         .num_ports  = 1,
0385         .base_baud  = 921600,
0386         .uart_offset    = 8,
0387     },
0388     [timedia_4078a] = {
0389         .flags      = FL_BASE0|FL_BASE_BARS,
0390         .num_ports  = 1,
0391         .base_baud  = 921600,
0392         .uart_offset    = 8,
0393     },
0394     [timedia_4079h] = {
0395         .flags      = FL_BASE0|FL_BASE_BARS,
0396         .num_ports  = 1,
0397         .base_baud  = 921600,
0398         .uart_offset    = 8,
0399     },
0400     [timedia_4085h] = {
0401         .flags      = FL_BASE0|FL_BASE_BARS,
0402         .num_ports  = 1,
0403         .base_baud  = 921600,
0404         .uart_offset    = 8,
0405     },
0406     [timedia_4088a] = {
0407         .flags      = FL_BASE0|FL_BASE_BARS,
0408         .num_ports  = 1,
0409         .base_baud  = 921600,
0410         .uart_offset    = 8,
0411     },
0412     [timedia_4089a] = {
0413         .flags      = FL_BASE0|FL_BASE_BARS,
0414         .num_ports  = 1,
0415         .base_baud  = 921600,
0416         .uart_offset    = 8,
0417     },
0418     [timedia_4095a] = {
0419         .flags      = FL_BASE0|FL_BASE_BARS,
0420         .num_ports  = 1,
0421         .base_baud  = 921600,
0422         .uart_offset    = 8,
0423     },
0424     [timedia_4096a] = {
0425         .flags      = FL_BASE0|FL_BASE_BARS,
0426         .num_ports  = 1,
0427         .base_baud  = 921600,
0428         .uart_offset    = 8,
0429     },
0430     [timedia_4078u] = {
0431         .flags      = FL_BASE0|FL_BASE_BARS,
0432         .num_ports  = 1,
0433         .base_baud  = 921600,
0434         .uart_offset    = 8,
0435     },
0436     [timedia_4079a] = {
0437         .flags      = FL_BASE0|FL_BASE_BARS,
0438         .num_ports  = 1,
0439         .base_baud  = 921600,
0440         .uart_offset    = 8,
0441     },
0442     [timedia_4085u] = {
0443         .flags      = FL_BASE0|FL_BASE_BARS,
0444         .num_ports  = 1,
0445         .base_baud  = 921600,
0446         .uart_offset    = 8,
0447     },
0448     [timedia_4079r] = {
0449         .flags      = FL_BASE0|FL_BASE_BARS,
0450         .num_ports  = 1,
0451         .base_baud  = 921600,
0452         .uart_offset    = 8,
0453     },
0454     [timedia_4079s] = {
0455         .flags      = FL_BASE0|FL_BASE_BARS,
0456         .num_ports  = 1,
0457         .base_baud  = 921600,
0458         .uart_offset    = 8,
0459     },
0460     [timedia_4079d] = {
0461         .flags      = FL_BASE0|FL_BASE_BARS,
0462         .num_ports  = 1,
0463         .base_baud  = 921600,
0464         .uart_offset    = 8,
0465     },
0466     [timedia_4079e] = {
0467         .flags      = FL_BASE0|FL_BASE_BARS,
0468         .num_ports  = 1,
0469         .base_baud  = 921600,
0470         .uart_offset    = 8,
0471     },
0472     [timedia_4079f] = {
0473         .flags      = FL_BASE0|FL_BASE_BARS,
0474         .num_ports  = 1,
0475         .base_baud  = 921600,
0476         .uart_offset    = 8,
0477     },
0478     [timedia_9079a] = {
0479         .flags      = FL_BASE0|FL_BASE_BARS,
0480         .num_ports  = 1,
0481         .base_baud  = 921600,
0482         .uart_offset    = 8,
0483     },
0484     [timedia_9079b] = {
0485         .flags      = FL_BASE0|FL_BASE_BARS,
0486         .num_ports  = 1,
0487         .base_baud  = 921600,
0488         .uart_offset    = 8,
0489     },
0490     [timedia_9079c] = {
0491         .flags      = FL_BASE0|FL_BASE_BARS,
0492         .num_ports  = 1,
0493         .base_baud  = 921600,
0494         .uart_offset    = 8,
0495     },
0496     [wch_ch353_1s1p] = {
0497         .flags          = FL_BASE0|FL_BASE_BARS,
0498         .num_ports      = 1,
0499         .base_baud      = 115200,
0500         .uart_offset    = 8,
0501     },
0502     [wch_ch353_2s1p] = {
0503         .flags          = FL_BASE0|FL_BASE_BARS,
0504         .num_ports      = 2,
0505         .base_baud      = 115200,
0506         .uart_offset    = 8,
0507     },
0508     [wch_ch382_0s1p] = {
0509         .flags          = FL_BASE0,
0510         .num_ports      = 0,
0511         .base_baud      = 115200,
0512         .uart_offset    = 8,
0513     },
0514     [wch_ch382_2s1p] = {
0515         .flags          = FL_BASE0,
0516         .num_ports      = 2,
0517         .base_baud      = 115200,
0518         .uart_offset    = 8,
0519         .first_offset   = 0xC0,
0520     },
0521     [brainboxes_5s1p] = {
0522         .flags      = FL_BASE2,
0523         .num_ports  = 5,
0524         .base_baud  = 921600,
0525         .uart_offset    = 8,
0526     },
0527     [sunix_4008a] = {
0528         .num_ports  = 0,
0529     },
0530     [sunix_5069a] = {
0531         .num_ports  = 1,
0532         .base_baud      = 921600,
0533         .uart_offset    = 0x8,
0534     },
0535     [sunix_5079a] = {
0536         .num_ports  = 2,
0537         .base_baud      = 921600,
0538         .uart_offset    = 0x8,
0539     },
0540     [sunix_5099a] = {
0541         .num_ports  = 4,
0542         .base_baud      = 921600,
0543         .uart_offset    = 0x8,
0544     },
0545 };
0546 
0547 struct parport_serial_private {
0548     struct serial_private   *serial;
0549     int num_par;
0550     struct parport *port[PARPORT_MAX];
0551     struct parport_pc_pci par;
0552 };
0553 
0554 /* Register the serial port(s) of a PCI card. */
0555 static int serial_register(struct pci_dev *dev, const struct pci_device_id *id)
0556 {
0557     struct parport_serial_private *priv = pci_get_drvdata (dev);
0558     struct pciserial_board *board;
0559     struct serial_private *serial;
0560 
0561     board = &pci_parport_serial_boards[id->driver_data];
0562     if (board->num_ports == 0)
0563         return 0;
0564 
0565     serial = pciserial_init_ports(dev, board);
0566     if (IS_ERR(serial))
0567         return PTR_ERR(serial);
0568 
0569     priv->serial = serial;
0570     return 0;
0571 }
0572 
0573 /* Register the parallel port(s) of a PCI card. */
0574 static int parport_register(struct pci_dev *dev, const struct pci_device_id *id)
0575 {
0576     struct parport_pc_pci *card;
0577     struct parport_serial_private *priv = pci_get_drvdata (dev);
0578     int n, success = 0;
0579 
0580     priv->par = cards[id->driver_data];
0581     card = &priv->par;
0582     if (card->preinit_hook &&
0583         card->preinit_hook (dev, card, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
0584         return -ENODEV;
0585 
0586     for (n = 0; n < card->numports; n++) {
0587         struct parport *port;
0588         int lo = card->addr[n].lo;
0589         int hi = card->addr[n].hi;
0590         unsigned long io_lo, io_hi;
0591         int irq;
0592 
0593         if (priv->num_par == ARRAY_SIZE (priv->port)) {
0594             dev_warn(&dev->dev,
0595                  "only %zu parallel ports supported (%d reported)\n",
0596                  ARRAY_SIZE(priv->port), card->numports);
0597             break;
0598         }
0599 
0600         io_lo = pci_resource_start (dev, lo);
0601         io_hi = 0;
0602         if ((hi >= 0) && (hi <= 6))
0603             io_hi = pci_resource_start (dev, hi);
0604         else if (hi > 6)
0605             io_lo += hi; /* Reinterpret the meaning of
0606                                         "hi" as an offset (see SYBA
0607                                         def.) */
0608         /* TODO: test if sharing interrupts works */
0609         irq = pci_irq_vector(dev, 0);
0610         if (irq < 0)
0611             return irq;
0612         if (irq == 0)
0613             irq = PARPORT_IRQ_NONE;
0614         if (irq == PARPORT_IRQ_NONE) {
0615             dev_dbg(&dev->dev,
0616                 "PCI parallel port detected: I/O at %#lx(%#lx)\n",
0617                 io_lo, io_hi);
0618         } else {
0619             dev_dbg(&dev->dev,
0620                 "PCI parallel port detected: I/O at %#lx(%#lx), IRQ %d\n",
0621                 io_lo, io_hi, irq);
0622         }
0623         port = parport_pc_probe_port (io_lo, io_hi, irq,
0624                   PARPORT_DMA_NONE, &dev->dev, IRQF_SHARED);
0625         if (port) {
0626             priv->port[priv->num_par++] = port;
0627             success = 1;
0628         }
0629     }
0630 
0631     if (card->postinit_hook)
0632         card->postinit_hook (dev, card, !success);
0633 
0634     return 0;
0635 }
0636 
0637 static int parport_serial_pci_probe(struct pci_dev *dev,
0638                     const struct pci_device_id *id)
0639 {
0640     struct parport_serial_private *priv;
0641     int err;
0642 
0643     priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
0644     if (!priv)
0645         return -ENOMEM;
0646 
0647     pci_set_drvdata (dev, priv);
0648 
0649     err = pcim_enable_device(dev);
0650     if (err)
0651         return err;
0652 
0653     err = parport_register(dev, id);
0654     if (err)
0655         return err;
0656 
0657     err = serial_register(dev, id);
0658     if (err) {
0659         int i;
0660         for (i = 0; i < priv->num_par; i++)
0661             parport_pc_unregister_port (priv->port[i]);
0662         return err;
0663     }
0664 
0665     return 0;
0666 }
0667 
0668 static void parport_serial_pci_remove(struct pci_dev *dev)
0669 {
0670     struct parport_serial_private *priv = pci_get_drvdata (dev);
0671     int i;
0672 
0673     // Serial ports
0674     if (priv->serial)
0675         pciserial_remove_ports(priv->serial);
0676 
0677     // Parallel ports
0678     for (i = 0; i < priv->num_par; i++)
0679         parport_pc_unregister_port (priv->port[i]);
0680 
0681     return;
0682 }
0683 
0684 static int __maybe_unused parport_serial_pci_suspend(struct device *dev)
0685 {
0686     struct parport_serial_private *priv = dev_get_drvdata(dev);
0687 
0688     if (priv->serial)
0689         pciserial_suspend_ports(priv->serial);
0690 
0691     /* FIXME: What about parport? */
0692     return 0;
0693 }
0694 
0695 static int __maybe_unused parport_serial_pci_resume(struct device *dev)
0696 {
0697     struct parport_serial_private *priv = dev_get_drvdata(dev);
0698 
0699     if (priv->serial)
0700         pciserial_resume_ports(priv->serial);
0701 
0702     /* FIXME: What about parport? */
0703     return 0;
0704 }
0705 
0706 static SIMPLE_DEV_PM_OPS(parport_serial_pm_ops,
0707              parport_serial_pci_suspend, parport_serial_pci_resume);
0708 
0709 static struct pci_driver parport_serial_pci_driver = {
0710     .name       = "parport_serial",
0711     .id_table   = parport_serial_pci_tbl,
0712     .probe      = parport_serial_pci_probe,
0713     .remove     = parport_serial_pci_remove,
0714     .driver         = {
0715         .pm     = &parport_serial_pm_ops,
0716     },
0717 };
0718 module_pci_driver(parport_serial_pci_driver);
0719 
0720 MODULE_AUTHOR("Tim Waugh <twaugh@redhat.com>");
0721 MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards");
0722 MODULE_LICENSE("GPL");