brintos

brintos / linux-shallow public Read only

0
0
Text · 22.0 KiB · 3644997 Raw
787 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Support for common PCI multi-I/O cards (which is most of them)4 *5 * Copyright (C) 2001  Tim Waugh <twaugh@redhat.com>6 *7 * Multi-function PCI cards are supposed to present separate logical8 * devices on the bus.  A common thing to do seems to be to just use9 * one logical device with lots of base address registers for both10 * parallel ports and serial ports.  This driver is for dealing with11 * that.12 */13 14#include <linux/interrupt.h>15#include <linux/module.h>16#include <linux/parport.h>17#include <linux/parport_pc.h>18#include <linux/pci.h>19#include <linux/slab.h>20#include <linux/types.h>21 22#include <linux/8250_pci.h>23 24enum parport_pc_pci_cards {25	titan_110l = 0,26	titan_210l,27	netmos_9xx5_combo,28	netmos_9855,29	netmos_9855_2p,30	netmos_9900,31	netmos_9900_2p,32	netmos_99xx_1p,33	avlab_1s1p,34	avlab_1s2p,35	avlab_2s1p,36	siig_1s1p_10x,37	siig_2s1p_10x,38	siig_2p1s_20x,39	siig_1s1p_20x,40	siig_2s1p_20x,41	timedia_4078a,42	timedia_4079h,43	timedia_4085h,44	timedia_4088a,45	timedia_4089a,46	timedia_4095a,47	timedia_4096a,48	timedia_4078u,49	timedia_4079a,50	timedia_4085u,51	timedia_4079r,52	timedia_4079s,53	timedia_4079d,54	timedia_4079e,55	timedia_4079f,56	timedia_9079a,57	timedia_9079b,58	timedia_9079c,59	wch_ch353_1s1p,60	wch_ch353_2s1p,61	wch_ch382_0s1p,62	wch_ch382_2s1p,63	brainboxes_5s1p,64	sunix_4008a,65	sunix_5069a,66	sunix_5079a,67	sunix_5099a,68	brainboxes_uc257,69	brainboxes_is300,70	brainboxes_uc414,71	brainboxes_px263,72};73 74/* each element directly indexed from enum list, above */75struct parport_pc_pci {76	int numports;77	struct { /* BAR (base address registers) numbers in the config78                    space header */79		int lo;80		int hi; /* -1 if not there, >6 for offset-method (max81                           BAR is 6) */82	} addr[4];83 84	/* If set, this is called immediately after pci_enable_device.85	 * If it returns non-zero, no probing will take place and the86	 * ports will not be used. */87	int (*preinit_hook) (struct pci_dev *pdev, struct parport_pc_pci *card,88				int autoirq, int autodma);89 90	/* If set, this is called after probing for ports.  If 'failed'91	 * is non-zero we couldn't use any of the ports. */92	void (*postinit_hook) (struct pci_dev *pdev,93				struct parport_pc_pci *card, int failed);94};95 96static int netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *par,97				int autoirq, int autodma)98{99	/* the rule described below doesn't hold for this device */100	if (dev->device == PCI_DEVICE_ID_NETMOS_9835 &&101			dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&102			dev->subsystem_device == 0x0299)103		return -ENODEV;104 105	if (dev->device == PCI_DEVICE_ID_NETMOS_9912) {106		par->numports = 1;107	} else {108		/*109		 * Netmos uses the subdevice ID to indicate the number of parallel110		 * and serial ports.  The form is 0x00PS, where <P> is the number of111		 * parallel ports and <S> is the number of serial ports.112		 */113		par->numports = (dev->subsystem_device & 0xf0) >> 4;114		if (par->numports > ARRAY_SIZE(par->addr))115			par->numports = ARRAY_SIZE(par->addr);116	}117 118	return 0;119}120 121static struct parport_pc_pci cards[] = {122	/* titan_110l */		{ 1, { { 3, -1 }, } },123	/* titan_210l */		{ 1, { { 3, -1 }, } },124	/* netmos_9xx5_combo */		{ 1, { { 2, -1 }, }, netmos_parallel_init },125	/* netmos_9855 */		{ 1, { { 0, -1 }, }, netmos_parallel_init },126	/* netmos_9855_2p */		{ 2, { { 0, -1 }, { 2, -1 }, } },127	/* netmos_9900 */		{1, { { 3, 4 }, }, netmos_parallel_init },128	/* netmos_9900_2p */		{2, { { 0, 1 }, { 3, 4 }, } },129	/* netmos_99xx_1p */		{1, { { 0, 1 }, } },130	/* avlab_1s1p     */		{ 1, { { 1, 2}, } },131	/* avlab_1s2p     */		{ 2, { { 1, 2}, { 3, 4 },} },132	/* avlab_2s1p     */		{ 1, { { 2, 3}, } },133	/* siig_1s1p_10x */		{ 1, { { 3, 4 }, } },134	/* siig_2s1p_10x */		{ 1, { { 4, 5 }, } },135	/* siig_2p1s_20x */		{ 2, { { 1, 2 }, { 3, 4 }, } },136	/* siig_1s1p_20x */		{ 1, { { 1, 2 }, } },137	/* siig_2s1p_20x */		{ 1, { { 2, 3 }, } },138	/* timedia_4078a */		{ 1, { { 2, -1 }, } },139	/* timedia_4079h */             { 1, { { 2, 3 }, } },140	/* timedia_4085h */             { 2, { { 2, -1 }, { 4, -1 }, } },141	/* timedia_4088a */             { 2, { { 2, 3 }, { 4, 5 }, } },142	/* timedia_4089a */             { 2, { { 2, 3 }, { 4, 5 }, } },143	/* timedia_4095a */             { 2, { { 2, 3 }, { 4, 5 }, } },144	/* timedia_4096a */             { 2, { { 2, 3 }, { 4, 5 }, } },145	/* timedia_4078u */             { 1, { { 2, -1 }, } },146	/* timedia_4079a */             { 1, { { 2, 3 }, } },147	/* timedia_4085u */             { 2, { { 2, -1 }, { 4, -1 }, } },148	/* timedia_4079r */             { 1, { { 2, 3 }, } },149	/* timedia_4079s */             { 1, { { 2, 3 }, } },150	/* timedia_4079d */             { 1, { { 2, 3 }, } },151	/* timedia_4079e */             { 1, { { 2, 3 }, } },152	/* timedia_4079f */             { 1, { { 2, 3 }, } },153	/* timedia_9079a */             { 1, { { 2, 3 }, } },154	/* timedia_9079b */             { 1, { { 2, 3 }, } },155	/* timedia_9079c */             { 1, { { 2, 3 }, } },156	/* wch_ch353_1s1p*/             { 1, { { 1, -1}, } },157	/* wch_ch353_2s1p*/             { 1, { { 2, -1}, } },158	/* wch_ch382_0s1p*/		{ 1, { { 2, -1}, } },159	/* wch_ch382_2s1p*/             { 1, { { 2, -1}, } },160	/* brainboxes_5s1p */           { 1, { { 3, -1 }, } },161	/* sunix_4008a */		{ 1, { { 1, 2 }, } },162	/* sunix_5069a */		{ 1, { { 1, 2 }, } },163	/* sunix_5079a */		{ 1, { { 1, 2 }, } },164	/* sunix_5099a */		{ 1, { { 1, 2 }, } },165	/* brainboxes_uc257 */	{ 1, { { 3, -1 }, } },166	/* brainboxes_is300 */	{ 1, { { 3, -1 }, } },167	/* brainboxes_uc414 */  { 1, { { 3, -1 }, } },168	/* brainboxes_px263 */	{ 1, { { 3, -1 }, } },169};170 171static struct pci_device_id parport_serial_pci_tbl[] = {172	/* PCI cards */173	{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L,174	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l },175	{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L,176	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l },177	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735,178	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },179	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9745,180	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },181	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,182	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },183	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845,184	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },185	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,186	  0x1000, 0x0020, 0, 0, netmos_9855_2p },187	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,188	  0x1000, 0x0022, 0, 0, netmos_9855_2p },189	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,190	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 },191	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,192	  0xA000, 0x3011, 0, 0, netmos_9900 },193	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,194	  0xA000, 0x3012, 0, 0, netmos_9900 },195	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,196	  0xA000, 0x3020, 0, 0, netmos_9900_2p },197	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912,198	  0xA000, 0x2000, 0, 0, netmos_99xx_1p },199	/* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/200	{ PCI_VENDOR_ID_AFAVLAB, 0x2110,201	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p },202	{ PCI_VENDOR_ID_AFAVLAB, 0x2111,203	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p },204	{ PCI_VENDOR_ID_AFAVLAB, 0x2112,205	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p },206	{ PCI_VENDOR_ID_AFAVLAB, 0x2140,207	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p },208	{ PCI_VENDOR_ID_AFAVLAB, 0x2141,209	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p },210	{ PCI_VENDOR_ID_AFAVLAB, 0x2142,211	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p },212	{ PCI_VENDOR_ID_AFAVLAB, 0x2160,213	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p },214	{ PCI_VENDOR_ID_AFAVLAB, 0x2161,215	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p },216	{ PCI_VENDOR_ID_AFAVLAB, 0x2162,217	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p },218	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,219	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },220	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,221	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },222	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,223	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },224	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,225	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },226	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,227	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },228	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,229	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },230	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,231	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },232	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,233	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },234	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,235	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },236	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,237	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },238	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,239	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },240	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,241	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },242	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,243	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },244	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,245	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },246	{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,247	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },248	/* PCI_VENDOR_ID_TIMEDIA/SUNIX has many differing cards ...*/249	{ 0x1409, 0x7168, 0x1409, 0x4078, 0, 0, timedia_4078a },250	{ 0x1409, 0x7168, 0x1409, 0x4079, 0, 0, timedia_4079h },251	{ 0x1409, 0x7168, 0x1409, 0x4085, 0, 0, timedia_4085h },252	{ 0x1409, 0x7168, 0x1409, 0x4088, 0, 0, timedia_4088a },253	{ 0x1409, 0x7168, 0x1409, 0x4089, 0, 0, timedia_4089a },254	{ 0x1409, 0x7168, 0x1409, 0x4095, 0, 0, timedia_4095a },255	{ 0x1409, 0x7168, 0x1409, 0x4096, 0, 0, timedia_4096a },256	{ 0x1409, 0x7168, 0x1409, 0x5078, 0, 0, timedia_4078u },257	{ 0x1409, 0x7168, 0x1409, 0x5079, 0, 0, timedia_4079a },258	{ 0x1409, 0x7168, 0x1409, 0x5085, 0, 0, timedia_4085u },259	{ 0x1409, 0x7168, 0x1409, 0x6079, 0, 0, timedia_4079r },260	{ 0x1409, 0x7168, 0x1409, 0x7079, 0, 0, timedia_4079s },261	{ 0x1409, 0x7168, 0x1409, 0x8079, 0, 0, timedia_4079d },262	{ 0x1409, 0x7168, 0x1409, 0x9079, 0, 0, timedia_4079e },263	{ 0x1409, 0x7168, 0x1409, 0xa079, 0, 0, timedia_4079f },264	{ 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a },265	{ 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b },266	{ 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },267 268	/* WCH CARDS */269	{ 0x4348, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, wch_ch353_1s1p},270	{ 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},271	{ 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382_0s1p},272	{ 0x1c00, 0x3250, 0x1c00, 0x3250, 0, 0, wch_ch382_2s1p},273 274	/* BrainBoxes PX272/PX306 MIO card */275	{ PCI_VENDOR_ID_INTASHIELD, 0x4100,276	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_5s1p },277 278	/* Sunix boards */279	{ PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,280	  0x0100, 0, 0, sunix_4008a },281	{ PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,282	  0x0101, 0, 0, sunix_5069a },283	{ PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,284	  0x0102, 0, 0, sunix_5079a },285	{ PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,286	  0x0104, 0, 0, sunix_5099a },287 288	/* Brainboxes UC-203 */289	{ PCI_VENDOR_ID_INTASHIELD, 0x0bc1,290	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },291	{ PCI_VENDOR_ID_INTASHIELD, 0x0bc2,292	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },293 294	/* Brainboxes UC-257 */295	{ PCI_VENDOR_ID_INTASHIELD, 0x0861,296	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },297	{ PCI_VENDOR_ID_INTASHIELD, 0x0862,298	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },299	{ PCI_VENDOR_ID_INTASHIELD, 0x0863,300	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },301 302	/* Brainboxes UC-414 */303	{ PCI_VENDOR_ID_INTASHIELD, 0x0e61,304	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc414 },305 306	/* Brainboxes UC-475 */307	{ PCI_VENDOR_ID_INTASHIELD, 0x0981,308	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },309	{ PCI_VENDOR_ID_INTASHIELD, 0x0982,310	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },311 312	/* Brainboxes IS-300/IS-500 */313	{ PCI_VENDOR_ID_INTASHIELD, 0x0da0,314	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_is300 },315 316	/* Brainboxes PX-263/PX-295 */317	{ PCI_VENDOR_ID_INTASHIELD, 0x402c,318	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_px263 },319 320	{ 0, } /* terminate list */321};322MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);323 324/*325 * This table describes the serial "geometry" of these boards.  Any326 * quirks for these can be found in drivers/serial/8250_pci.c327 *328 * Cards not tested are marked n/t329 * If you have one of these cards and it works for you, please tell me..330 */331static struct pciserial_board pci_parport_serial_boards[] = {332	[titan_110l] = {333		.flags		= FL_BASE1 | FL_BASE_BARS,334		.num_ports	= 1,335		.base_baud	= 921600,336		.uart_offset	= 8,337	},338	[titan_210l] = {339		.flags		= FL_BASE1 | FL_BASE_BARS,340		.num_ports	= 2,341		.base_baud	= 921600,342		.uart_offset	= 8,343	},344	[netmos_9xx5_combo] = {345		.flags		= FL_BASE0 | FL_BASE_BARS,346		.num_ports	= 1,347		.base_baud	= 115200,348		.uart_offset	= 8,349	},350	[netmos_9855] = {351		.flags		= FL_BASE2 | FL_BASE_BARS,352		.num_ports	= 1,353		.base_baud	= 115200,354		.uart_offset	= 8,355	},356	[netmos_9855_2p] = {357		.flags		= FL_BASE4 | FL_BASE_BARS,358		.num_ports	= 1,359		.base_baud	= 115200,360		.uart_offset	= 8,361	},362	[netmos_9900] = { /* n/t */363		.flags		= FL_BASE0 | FL_BASE_BARS,364		.num_ports	= 1,365		.base_baud	= 115200,366		.uart_offset	= 8,367	},368	[netmos_9900_2p] = { /* parallel only */ /* n/t */369		.flags		= FL_BASE0,370		.num_ports	= 0,371		.base_baud	= 115200,372		.uart_offset	= 8,373	},374	[netmos_99xx_1p] = { /* parallel only */ /* n/t */375		.flags		= FL_BASE0,376		.num_ports	= 0,377		.base_baud	= 115200,378		.uart_offset	= 8,379	},380	[avlab_1s1p] = { /* n/t */381		.flags		= FL_BASE0 | FL_BASE_BARS,382		.num_ports	= 1,383		.base_baud	= 115200,384		.uart_offset	= 8,385	},386	[avlab_1s2p] = { /* n/t */387		.flags		= FL_BASE0 | FL_BASE_BARS,388		.num_ports	= 1,389		.base_baud	= 115200,390		.uart_offset	= 8,391	},392	[avlab_2s1p] = { /* n/t */393		.flags		= FL_BASE0 | FL_BASE_BARS,394		.num_ports	= 2,395		.base_baud	= 115200,396		.uart_offset	= 8,397	},398	[siig_1s1p_10x] = {399		.flags		= FL_BASE2,400		.num_ports	= 1,401		.base_baud	= 460800,402		.uart_offset	= 8,403	},404	[siig_2s1p_10x] = {405		.flags		= FL_BASE2,406		.num_ports	= 1,407		.base_baud	= 921600,408		.uart_offset	= 8,409	},410	[siig_2p1s_20x] = {411		.flags		= FL_BASE0,412		.num_ports	= 1,413		.base_baud	= 921600,414		.uart_offset	= 8,415	},416	[siig_1s1p_20x] = {417		.flags		= FL_BASE0,418		.num_ports	= 1,419		.base_baud	= 921600,420		.uart_offset	= 8,421	},422	[siig_2s1p_20x] = {423		.flags		= FL_BASE0,424		.num_ports	= 1,425		.base_baud	= 921600,426		.uart_offset	= 8,427	},428	[timedia_4078a] = {429		.flags		= FL_BASE0|FL_BASE_BARS,430		.num_ports	= 1,431		.base_baud	= 921600,432		.uart_offset	= 8,433	},434	[timedia_4079h] = {435		.flags		= FL_BASE0|FL_BASE_BARS,436		.num_ports	= 1,437		.base_baud	= 921600,438		.uart_offset	= 8,439	},440	[timedia_4085h] = {441		.flags		= FL_BASE0|FL_BASE_BARS,442		.num_ports	= 1,443		.base_baud	= 921600,444		.uart_offset	= 8,445	},446	[timedia_4088a] = {447		.flags		= FL_BASE0|FL_BASE_BARS,448		.num_ports	= 1,449		.base_baud	= 921600,450		.uart_offset	= 8,451	},452	[timedia_4089a] = {453		.flags		= FL_BASE0|FL_BASE_BARS,454		.num_ports	= 1,455		.base_baud	= 921600,456		.uart_offset	= 8,457	},458	[timedia_4095a] = {459		.flags		= FL_BASE0|FL_BASE_BARS,460		.num_ports	= 1,461		.base_baud	= 921600,462		.uart_offset	= 8,463	},464	[timedia_4096a] = {465		.flags		= FL_BASE0|FL_BASE_BARS,466		.num_ports	= 1,467		.base_baud	= 921600,468		.uart_offset	= 8,469	},470	[timedia_4078u] = {471		.flags		= FL_BASE0|FL_BASE_BARS,472		.num_ports	= 1,473		.base_baud	= 921600,474		.uart_offset	= 8,475	},476	[timedia_4079a] = {477		.flags		= FL_BASE0|FL_BASE_BARS,478		.num_ports	= 1,479		.base_baud	= 921600,480		.uart_offset	= 8,481	},482	[timedia_4085u] = {483		.flags		= FL_BASE0|FL_BASE_BARS,484		.num_ports	= 1,485		.base_baud	= 921600,486		.uart_offset	= 8,487	},488	[timedia_4079r] = {489		.flags		= FL_BASE0|FL_BASE_BARS,490		.num_ports	= 1,491		.base_baud	= 921600,492		.uart_offset	= 8,493	},494	[timedia_4079s] = {495		.flags		= FL_BASE0|FL_BASE_BARS,496		.num_ports	= 1,497		.base_baud	= 921600,498		.uart_offset	= 8,499	},500	[timedia_4079d] = {501		.flags		= FL_BASE0|FL_BASE_BARS,502		.num_ports	= 1,503		.base_baud	= 921600,504		.uart_offset	= 8,505	},506	[timedia_4079e] = {507		.flags		= FL_BASE0|FL_BASE_BARS,508		.num_ports	= 1,509		.base_baud	= 921600,510		.uart_offset	= 8,511	},512	[timedia_4079f] = {513		.flags		= FL_BASE0|FL_BASE_BARS,514		.num_ports	= 1,515		.base_baud	= 921600,516		.uart_offset	= 8,517	},518	[timedia_9079a] = {519		.flags		= FL_BASE0|FL_BASE_BARS,520		.num_ports	= 1,521		.base_baud	= 921600,522		.uart_offset	= 8,523	},524	[timedia_9079b] = {525		.flags		= FL_BASE0|FL_BASE_BARS,526		.num_ports	= 1,527		.base_baud	= 921600,528		.uart_offset	= 8,529	},530	[timedia_9079c] = {531		.flags		= FL_BASE0|FL_BASE_BARS,532		.num_ports	= 1,533		.base_baud	= 921600,534		.uart_offset	= 8,535	},536	[wch_ch353_1s1p] = {537		.flags          = FL_BASE0|FL_BASE_BARS,538		.num_ports      = 1,539		.base_baud      = 115200,540		.uart_offset    = 8,541	},542	[wch_ch353_2s1p] = {543		.flags          = FL_BASE0|FL_BASE_BARS,544		.num_ports      = 2,545		.base_baud      = 115200,546		.uart_offset    = 8,547	},548	[wch_ch382_0s1p] = {549		.flags          = FL_BASE0,550		.num_ports      = 0,551		.base_baud      = 115200,552		.uart_offset    = 8,553	},554	[wch_ch382_2s1p] = {555		.flags          = FL_BASE0,556		.num_ports      = 2,557		.base_baud      = 115200,558		.uart_offset    = 8,559		.first_offset   = 0xC0,560	},561	[brainboxes_5s1p] = {562		.flags		= FL_BASE2,563		.num_ports	= 5,564		.base_baud	= 921600,565		.uart_offset	= 8,566	},567	[sunix_4008a] = {568		.num_ports	= 0,569	},570	[sunix_5069a] = {571		.num_ports	= 1,572		.base_baud      = 921600,573		.uart_offset	= 0x8,574	},575	[sunix_5079a] = {576		.num_ports	= 2,577		.base_baud      = 921600,578		.uart_offset	= 0x8,579	},580	[sunix_5099a] = {581		.num_ports	= 4,582		.base_baud      = 921600,583		.uart_offset	= 0x8,584	},585	[brainboxes_uc257] = {586		.flags		= FL_BASE2,587		.num_ports	= 2,588		.base_baud	= 115200,589		.uart_offset	= 8,590	},591	[brainboxes_is300] = {592		.flags		= FL_BASE2,593		.num_ports	= 1,594		.base_baud	= 115200,595		.uart_offset	= 8,596	},597	[brainboxes_uc414] = {598		.flags		= FL_BASE2,599		.num_ports	= 4,600		.base_baud	= 115200,601		.uart_offset	= 8,602	},603	[brainboxes_px263] = {604		.flags		= FL_BASE2,605		.num_ports	= 4,606		.base_baud	= 921600,607		.uart_offset	= 8,608	},609};610 611struct parport_serial_private {612	struct serial_private	*serial;613	int num_par;614	struct parport *port[PARPORT_MAX];615	struct parport_pc_pci par;616};617 618/* Register the serial port(s) of a PCI card. */619static int serial_register(struct pci_dev *dev, const struct pci_device_id *id)620{621	struct parport_serial_private *priv = pci_get_drvdata (dev);622	struct pciserial_board *board;623	struct serial_private *serial;624 625	board = &pci_parport_serial_boards[id->driver_data];626	if (board->num_ports == 0)627		return 0;628 629	serial = pciserial_init_ports(dev, board);630	if (IS_ERR(serial))631		return PTR_ERR(serial);632 633	priv->serial = serial;634	return 0;635}636 637/* Register the parallel port(s) of a PCI card. */638static int parport_register(struct pci_dev *dev, const struct pci_device_id *id)639{640	struct parport_pc_pci *card;641	struct parport_serial_private *priv = pci_get_drvdata (dev);642	int n, success = 0;643 644	priv->par = cards[id->driver_data];645	card = &priv->par;646	if (card->preinit_hook &&647	    card->preinit_hook (dev, card, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))648		return -ENODEV;649 650	for (n = 0; n < card->numports; n++) {651		struct parport *port;652		int lo = card->addr[n].lo;653		int hi = card->addr[n].hi;654		unsigned long io_lo, io_hi;655		int irq;656 657		if (priv->num_par == ARRAY_SIZE (priv->port)) {658			dev_warn(&dev->dev,659				 "only %zu parallel ports supported (%d reported)\n",660				 ARRAY_SIZE(priv->port), card->numports);661			break;662		}663 664		io_lo = pci_resource_start (dev, lo);665		io_hi = 0;666		if ((hi >= 0) && (hi <= 6))667			io_hi = pci_resource_start (dev, hi);668		else if (hi > 6)669			io_lo += hi; /* Reinterpret the meaning of670                                        "hi" as an offset (see SYBA671                                        def.) */672		/* TODO: test if sharing interrupts works */673		irq = pci_irq_vector(dev, 0);674		if (irq < 0)675			return irq;676		if (irq == 0)677			irq = PARPORT_IRQ_NONE;678		if (irq == PARPORT_IRQ_NONE) {679			dev_dbg(&dev->dev,680				"PCI parallel port detected: I/O at %#lx(%#lx)\n",681				io_lo, io_hi);682		} else {683			dev_dbg(&dev->dev,684				"PCI parallel port detected: I/O at %#lx(%#lx), IRQ %d\n",685				io_lo, io_hi, irq);686		}687		port = parport_pc_probe_port (io_lo, io_hi, irq,688			      PARPORT_DMA_NONE, &dev->dev, IRQF_SHARED);689		if (port) {690			priv->port[priv->num_par++] = port;691			success = 1;692		}693	}694 695	if (card->postinit_hook)696		card->postinit_hook (dev, card, !success);697 698	return 0;699}700 701static int parport_serial_pci_probe(struct pci_dev *dev,702				    const struct pci_device_id *id)703{704	struct parport_serial_private *priv;705	int err;706 707	priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);708	if (!priv)709		return -ENOMEM;710 711	pci_set_drvdata (dev, priv);712 713	err = pcim_enable_device(dev);714	if (err)715		return err;716 717	err = parport_register(dev, id);718	if (err)719		return err;720 721	err = serial_register(dev, id);722	if (err) {723		int i;724		for (i = 0; i < priv->num_par; i++)725			parport_pc_unregister_port (priv->port[i]);726		return err;727	}728 729	return 0;730}731 732static void parport_serial_pci_remove(struct pci_dev *dev)733{734	struct parport_serial_private *priv = pci_get_drvdata (dev);735	int i;736 737	// Serial ports738	if (priv->serial)739		pciserial_remove_ports(priv->serial);740 741	// Parallel ports742	for (i = 0; i < priv->num_par; i++)743		parport_pc_unregister_port (priv->port[i]);744 745	return;746}747 748static int __maybe_unused parport_serial_pci_suspend(struct device *dev)749{750	struct parport_serial_private *priv = dev_get_drvdata(dev);751 752	if (priv->serial)753		pciserial_suspend_ports(priv->serial);754 755	/* FIXME: What about parport? */756	return 0;757}758 759static int __maybe_unused parport_serial_pci_resume(struct device *dev)760{761	struct parport_serial_private *priv = dev_get_drvdata(dev);762 763	if (priv->serial)764		pciserial_resume_ports(priv->serial);765 766	/* FIXME: What about parport? */767	return 0;768}769 770static SIMPLE_DEV_PM_OPS(parport_serial_pm_ops,771			 parport_serial_pci_suspend, parport_serial_pci_resume);772 773static struct pci_driver parport_serial_pci_driver = {774	.name		= "parport_serial",775	.id_table	= parport_serial_pci_tbl,776	.probe		= parport_serial_pci_probe,777	.remove		= parport_serial_pci_remove,778	.driver         = {779		.pm     = &parport_serial_pm_ops,780	},781};782module_pci_driver(parport_serial_pci_driver);783 784MODULE_AUTHOR("Tim Waugh <twaugh@redhat.com>");785MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards");786MODULE_LICENSE("GPL");787