[ltp] Re: [PATCH] 2.6.16 ThinkPad T43/R52/*60 PnP IrDA support (try 2)

Henrique de Moraes Holschuh linux-thinkpad@linux-thinkpad.org
Sun, 4 Jun 2006 11:38:24 -0300


This is the patch against stock 2.6.16.19.

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh


diff -u 2.6.16/nsc-ircc.c 2.6.16-oldpnp-t43-fix/nsc-ircc.c
--- 2.6.16/drivers/net/irda/nsc-ircc.c	2006-06-02 11:34:36.000000000 -0300
+++ 2.6.16-thinkpad/drivers/net/irda/nsc-ircc.c	2006-06-03 12:35:03.000000000 -0300
@@ -12,6 +12,7 @@
  *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
  *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
  *     Copyright (c) 1998 Actisys Corp., www.actisys.com
+ *     Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com>
  *     All Rights Reserved
  *      
  *     This program is free software; you can redistribute it and/or 
@@ -53,6 +54,7 @@
 #include <linux/init.h>
 #include <linux/rtnetlink.h>
 #include <linux/dma-mapping.h>
+#include <linux/pnp.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -87,6 +89,7 @@
 static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info);
+static int __devinit nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id);
 
 /* These are the known NSC chips */
 static nsc_chip_t chips[] = {
@@ -101,6 +104,12 @@
 	/* Contributed by Jan Frey - IBM A30/A31 */
 	{ "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, 
 	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
+	/* IBM ThinkPads using PC8738x (T60/X60/Z60) */
+	{ "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
+	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
+	/* IBM ThinkPads using PC8394T (T43/R52/?) */
+	{ "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff,
+	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
 	{ NULL }
 };
 
@@ -126,8 +135,23 @@
 	"No dongle connected",
 };
 
+/* PNP probing */
+static const struct pnp_device_id nsc_ircc_pnp_table[] = {
+	{ .id = "NSC6001", .driver_data = 0 },
+	{ .id = "IBM0071", .driver_data = 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table);
+
+static struct pnp_driver nsc_ircc_pnp_driver = {
+	.name = "nsc-ircc",
+	.id_table = nsc_ircc_pnp_table,
+	.probe = nsc_ircc_pnp_probe,
+};
+
 /* Some prototypes */
-static int  nsc_ircc_open(int i, chipio_t *info);
+static int  nsc_ircc_open(chipio_t *info);
 static int  nsc_ircc_close(struct nsc_ircc_cb *self);
 static int  nsc_ircc_setup(chipio_t *info);
 static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
@@ -148,6 +172,9 @@
 static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev);
 static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
 
+/* Globals */
+static int pnp_registered_port;
+
 /*
  * Function nsc_ircc_init ()
  *
@@ -163,6 +190,14 @@
 	int cfg, id;
 	int reg;
 	int i = 0;
+	int r;
+
+	/* Register with PnP subsystem to detect disabled ports */
+	r = pnp_register_driver(&nsc_ircc_pnp_driver);
+	if (r >= 0) {
+		pnp_registered_port = 1;
+		ret = 0;
+	}
 
 	/* Probe for all the NSC chipsets we know about */
 	for (chip=chips; chip->name ; chip++) {
@@ -204,7 +239,7 @@
 				} else
 					chip->probe(chip, &info);
 
-				if (nsc_ircc_open(i, &info) == 0)
+				if (nsc_ircc_open(&info) == 0)
 					ret = 0;
 				i++;
 			} else {
@@ -229,6 +264,9 @@
 
 	pm_unregister_all(nsc_ircc_pmproc);
 
+	if (pnp_registered_port)
+		pnp_unregister_driver(&nsc_ircc_pnp_driver);
+
 	for (i=0; i < 4; i++) {
 		if (dev_self[i])
 			nsc_ircc_close(dev_self[i]);
@@ -241,16 +279,26 @@
  *    Open driver instance
  *
  */
-static int __init nsc_ircc_open(int i, chipio_t *info)
+static int __devinit nsc_ircc_open(chipio_t *info)
 {
 	struct net_device *dev;
 	struct nsc_ircc_cb *self;
         struct pm_dev *pmdev;
 	void *ret;
 	int err;
+	int i;
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
+ 	for (i=0; i < 4; i++) {
+		if (!dev_self[i])
+			break;
+	}
+	if (i == 4) {
+		IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
 	IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
 		     info->cfg_base);
 
@@ -389,7 +437,7 @@
  *    Close driver instance
  *
  */
-static int __exit nsc_ircc_close(struct nsc_ircc_cb *self)
+static int __devexit nsc_ircc_close(struct nsc_ircc_cb *self)
 {
 	int iobase;
 
@@ -806,6 +854,40 @@
 	return 0;
 }
 
+/* PNP probing */
+static int __devinit
+nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
+{
+	chipio_t info;
+
+	memset(&info, 0, sizeof(chipio_t));
+	info.irq = -1;
+	info.dma = -1;
+
+	/* There don't seem to be any way to get the cfg_base.
+	 * On my box, cfg_base is in the PnP descriptor of the
+	 * motherboard. Oh well... Jean II */
+
+	if (pnp_port_valid(dev, 0) &&
+		!(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED))
+		info.fir_base = pnp_port_start(dev, 0);
+
+	if (pnp_irq_valid(dev, 0) &&
+		!(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED))
+		info.irq = pnp_irq(dev, 0);
+
+	if (pnp_dma_valid(dev, 0) &&
+		!(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED))
+		info.dma = pnp_dma(dev, 0);
+
+	IRDA_DEBUG(0, "%s() : Found cfg_base 0x%03X ; firbase 0x%03X ; irq %d ; dma %d.\n", __FUNCTION__, info.cfg_base, info.fir_base, info.irq, info.dma);
+	IRDA_DEBUG(0, "%s() : Please load this driver with parameters: io=0x%03X irq=%d dma=%d\n",  __FUNCTION__, info.fir_base, info.irq, info.dma);
+
+	/* We are only a helper for nsc_ircc_init, so 
+	 * don't start the device, nor disable it! */
+	return 0;
+}
+
 /*
  * Function nsc_ircc_setup (info)
  *