patch-2.3.48 linux/drivers/parport/parport_pc.c

Next file: linux/drivers/parport/probe.c
Previous file: linux/drivers/parport/daisy.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.47/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
@@ -681,6 +681,7 @@
 
 	/* Set up parallel port FIFO mode.*/
 	parport_pc_data_forward (port); /* Must be in PS2 mode */
+	parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0);
 	change_mode (port, ECR_PPF); /* Parallel port FIFO */
 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 
@@ -747,6 +748,10 @@
 
 	/* Set up ECP parallel port mode.*/
 	parport_pc_data_forward (port); /* Must be in PS2 mode */
+	parport_pc_frob_control (port,
+				 PARPORT_CONTROL_STROBE |
+				 PARPORT_CONTROL_AUTOFD,
+				 0);
 	change_mode (port, ECR_ECP); /* ECP FIFO */
 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 
@@ -850,6 +855,10 @@
 
 	/* Set up ECP parallel port mode.*/
 	parport_pc_data_reverse (port); /* Must be in PS2 mode */
+	parport_pc_frob_control (port,
+				 PARPORT_CONTROL_STROBE |
+				 PARPORT_CONTROL_AUTOFD,
+				 0);
 	change_mode (port, ECR_ECP); /* ECP FIFO */
 	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
 
@@ -989,7 +998,7 @@
 /*
  * Checks for port existence, all ports support SPP MODE
  */
-static int __maybe_init parport_SPP_supported(struct parport *pb)
+static int __devinit parport_SPP_supported(struct parport *pb)
 {
 	unsigned char r, w;
 
@@ -1066,7 +1075,7 @@
  * two bits of ECR aren't writable, so we check by writing ECR and
  * reading it back to see if it's what we expect.
  */
-static int __maybe_init parport_ECR_present(struct parport *pb)
+static int __devinit parport_ECR_present(struct parport *pb)
 {
 	struct parport_pc_private *priv = pb->private_data;
 	unsigned char r = 0xc;
@@ -1118,7 +1127,7 @@
  * be misdetected here is rather academic. 
  */
 
-static int __maybe_init parport_PS2_supported(struct parport *pb)
+static int __devinit parport_PS2_supported(struct parport *pb)
 {
 	int ok = 0;
   
@@ -1146,7 +1155,7 @@
 	return ok;
 }
 
-static int __maybe_init parport_ECP_supported(struct parport *pb)
+static int __devinit parport_ECP_supported(struct parport *pb)
 {
 	int i;
 	int config;
@@ -1257,7 +1266,7 @@
 	return 1;
 }
 
-static int __maybe_init parport_ECPPS2_supported(struct parport *pb)
+static int __devinit parport_ECPPS2_supported(struct parport *pb)
 {
 	const struct parport_pc_private *priv = pb->private_data;
 	int result;
@@ -1277,7 +1286,7 @@
 
 /* EPP mode detection  */
 
-static int __maybe_init parport_EPP_supported(struct parport *pb)
+static int __devinit parport_EPP_supported(struct parport *pb)
 {
 	const struct parport_pc_private *priv = pb->private_data;
 
@@ -1320,7 +1329,7 @@
 	return 1;
 }
 
-static int __maybe_init parport_ECPEPP_supported(struct parport *pb)
+static int __devinit parport_ECPEPP_supported(struct parport *pb)
 {
 	struct parport_pc_private *priv = pb->private_data;
 	int result;
@@ -1351,18 +1360,18 @@
 #else /* No IEEE 1284 support */
 
 /* Don't bother probing for modes we know we won't use. */
-static int __maybe_init parport_PS2_supported(struct parport *pb) { return 0; }
-static int __maybe_init parport_ECP_supported(struct parport *pb) { return 0; }
-static int __maybe_init parport_EPP_supported(struct parport *pb) { return 0; }
-static int __maybe_init parport_ECPEPP_supported(struct parport *pb){return 0;}
-static int __maybe_init parport_ECPPS2_supported(struct parport *pb){return 0;}
+static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
+static int __devinit parport_ECP_supported(struct parport *pb) { return 0; }
+static int __devinit parport_EPP_supported(struct parport *pb) { return 0; }
+static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;}
+static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}
 
 #endif /* No IEEE 1284 support */
 
 /* --- IRQ detection -------------------------------------- */
 
 /* Only if supports ECP mode */
-static int __maybe_init programmable_irq_support(struct parport *pb)
+static int __devinit programmable_irq_support(struct parport *pb)
 {
 	int irq, intrLine;
 	unsigned char oecr = inb (ECONTROL (pb));
@@ -1379,7 +1388,7 @@
 	return irq;
 }
 
-static int __maybe_init irq_probe_ECP(struct parport *pb)
+static int __devinit irq_probe_ECP(struct parport *pb)
 {
 	int i;
 	unsigned long irqs;
@@ -1408,7 +1417,7 @@
  * This detection seems that only works in National Semiconductors
  * This doesn't work in SMC, LGS, and Winbond 
  */
-static int __maybe_init irq_probe_EPP(struct parport *pb)
+static int __devinit irq_probe_EPP(struct parport *pb)
 {
 #ifndef ADVANCED_DETECT
 	return PARPORT_IRQ_NONE;
@@ -1448,7 +1457,7 @@
 #endif /* Advanced detection */
 }
 
-static int __maybe_init irq_probe_SPP(struct parport *pb)
+static int __devinit irq_probe_SPP(struct parport *pb)
 {
 	/* Don't even try to do this. */
 	return PARPORT_IRQ_NONE;
@@ -1461,7 +1470,7 @@
  * When ECP is available we can autoprobe for IRQs.
  * NOTE: If we can autoprobe it, we can register the IRQ.
  */
-static int __maybe_init parport_irq_probe(struct parport *pb)
+static int __devinit parport_irq_probe(struct parport *pb)
 {
 	const struct parport_pc_private *priv = pb->private_data;
 
@@ -1495,7 +1504,7 @@
 /* --- DMA detection -------------------------------------- */
 
 /* Only if supports ECP mode */
-static int __maybe_init programmable_dma_support (struct parport *p)
+static int __devinit programmable_dma_support (struct parport *p)
 {
 	unsigned char oecr = inb (ECONTROL (p));
 	int dma;
@@ -1510,7 +1519,7 @@
 	return dma;
 }
 
-static int __maybe_init parport_dma_probe (struct parport *p)
+static int __devinit parport_dma_probe (struct parport *p)
 {
 	const struct parport_pc_private *priv = p->private_data;
 	if (priv->ecr)
@@ -1521,7 +1530,7 @@
 
 /* --- Initialisation code -------------------------------- */
 
-struct parport *__maybe_init parport_pc_probe_port (unsigned long int base,
+struct parport *__devinit parport_pc_probe_port (unsigned long int base,
 						    unsigned long int base_hi,
 						    int irq, int dma,
 						    struct pci_dev *dev)
@@ -1693,9 +1702,7 @@
 #endif /* CONFIG_PARPORT_PC_FIFO */
 	}
 
-	/* Done probing.  Now put the port into a sensible start-up state.
-	 * SELECT | INIT also puts IEEE1284-compliant devices into
-	 * compatibility mode. */
+	/* Done probing.  Now put the port into a sensible start-up state. */
 	if (priv->ecr)
 		/*
 		 * Put the ECP detected port in PS2 mode.
@@ -1714,9 +1721,143 @@
 	return p;
 }
 
+
+static int __devinit sio_via_686a_probe (struct pci_dev *pdev)
+{
+	u8 dma, irq, tmp;
+	unsigned port1, port2, have_eppecp;
+
+	/*
+	 * unlock super i/o configuration, set 0x85_1
+	 */
+	pci_read_config_byte (pdev, 0x85, &tmp);
+	tmp |= (1 << 1);
+	pci_write_config_byte (pdev, 0x85, tmp);
+	
+	/* 
+	 * Super I/O configuration, index port == 3f0h, data port == 3f1h
+	 */
+	
+	/* 0xE2_1-0: Parallel Port Mode / Enable */
+	outb (0xE2, 0x3F0);
+	tmp = inb (0x3F1);
+	
+	if ((tmp & 0x03) == 0x03) {
+		printk (KERN_INFO "parport_pc: Via 686A parallel port disabled in BIOS\n");
+		return 0;
+	}
+	
+	/* 0xE6: Parallel Port I/O Base Address, bits 9-2 */
+	outb (0xE6, 0x3F0);
+	port1 = inb (0x3F1) << 2;
+	
+	switch (port1) {
+	case 0x3bc: port2 = 0x7bc; break;
+	case 0x378: port2 = 0x778; break;
+	case 0x278: port2 = 0x678; break;
+	default:
+		printk (KERN_INFO "parport_pc: Via 686A weird parport base 0x%X, ignoring\n",
+			port1);
+		return 0;
+	}
+
+	/* 0xF0_5: EPP+ECP enable */
+	outb (0xF0, 0x3F0);
+	have_eppecp = (inb (0x3F1) & (1 << 5));
+	
+	/*
+	 * lock super i/o configuration, clear 0x85_1
+	 */
+	pci_read_config_byte (pdev, 0x85, &tmp);
+	tmp &= ~(1 << 1);
+	pci_write_config_byte (pdev, 0x85, tmp);
+
+	/*
+	 * Get DMA and IRQ from PCI->ISA bridge PCI config registers
+	 */
+
+	/* 0x50_3-2: PnP Routing for Parallel Port DRQ */
+	pci_read_config_byte (pdev, 0x50, &dma);
+	dma = ((dma >> 2) & 0x03);
+	
+	/* 0x51_7-4: PnP Routing for Parallel Port IRQ */
+	pci_read_config_byte (pdev, 0x51, &irq);
+	irq = ((irq >> 4) & 0x0F);
+
+	/* filter bogus IRQs */
+	switch (irq) {
+	case 0:
+	case 2:
+	case 8:
+	case 13:
+		irq = PARPORT_IRQ_NONE;
+		break;
+
+	default: /* do nothing */
+		break;
+	}
+
+	/* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */
+	if (!have_eppecp)
+		dma = PARPORT_DMA_NONE;
+
+	/* finally, do the probe with values obtained */
+	if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) {
+		printk (KERN_INFO "parport_pc: Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n",
+			port1, irq, dma);
+		return 1;
+	}
+	
+	printk (KERN_WARNING "parport_pc: Strange, can't probe Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n",
+		port1, irq, dma);
+	return 0;
+}
+
+
+enum parport_pc_sio_types {
+	sio_via_686a = 0,	/* Via VT82C686A motherboard Super I/O */
+};
+
+
+/* each element directly indexed from enum list, above */
+static struct parport_pc_superio {
+	int (*probe) (struct pci_dev *pdev);
+} parport_pc_superio_info[] __devinitdata = {
+	{ sio_via_686a_probe, },
+};
+
+
+static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = {
+	{ 0x1106, 0x0686, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_686a },
+	{ 0, }, /* terminate list */
+};
+
+
+static int __devinit parport_pc_init_superio(void)
+{
+	const struct pci_device_id *id;
+	struct pci_dev *pdev;
+	
+	pci_for_each_dev(pdev) {
+		id = pci_match_device (parport_pc_pci_tbl, pdev);
+		if (id == NULL)
+			continue;
+		
+		return parport_pc_superio_info[id->driver_data].probe (pdev);
+	}
+	
+	return 0; /* zero devices found */
+}
+
+
 /* Look for PCI parallel port cards. */
 static int __init parport_pc_init_pci (int irq, int dma)
 {
+#ifndef PCI_VENDOR_ID_AFAVLAB
+#define PCI_VENDOR_ID_AFAVLAB		0x14db
+#define PCI_DEVICE_ID_AFAVLAB_TK9902	0x2120
+#endif
+
 	struct {
 		unsigned int vendor;
 		unsigned int device;
@@ -1800,6 +1941,9 @@
 		{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 		  PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014,
 		  2, { { 4, -1 }, { 5, -1 }, } },
+		{ PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902,
+		  PCI_ANY_ID, PCI_ANY_ID,
+		  1, { { 0, 1 }, } },
 		{ 0, }
 	};
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)