Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec4f32d5 authored by Jean Tourrilhes's avatar Jean Tourrilhes Committed by David S. Miller
Browse files

[IRDA]: nsc-ircc: ISAPnP support



This enables PnP support for the nsc-ircc chipset.
Since we can't fetch the chipset cfg_base from the PnP layer, we just use
the PnP information as one more hint when probing the chip.

Signed-off-by: default avatarJean Tourrilhes <jt@hpl.hp.com>
Signed-off-by: default avatarSamuel Ortiz <samuel.ortiz@nokia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4277a083
Loading
Loading
Loading
Loading
+151 −34
Original line number Diff line number Diff line
@@ -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>
@@ -78,8 +80,8 @@ static int dongle_id;

/* Use BIOS settions by default, but user may supply module parameters */
static unsigned int io[]  = { ~0, ~0, ~0, ~0 };
static unsigned int irq[] = { 0, 0, 0, 0, 0 };
static unsigned int dma[] = { 0, 0, 0, 0, 0 };
static unsigned int irq[] = {  0,  0,  0,  0 };
static unsigned int dma[] = {  0,  0,  0,  0 };

static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info);
@@ -87,6 +89,7 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info);
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 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[] = {
@@ -104,7 +107,6 @@ static nsc_chip_t chips[] = {
	{ NULL }
};

/* Max 4 instances for now */
static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };

static char *dongle_types[] = {
@@ -126,8 +128,24 @@ static char *dongle_types[] = {
	"No dongle connected",
};

/* PNP probing */
static chipio_t pnp_info;
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 +166,10 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd
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;
static int pnp_succeeded;

/*
 * Function nsc_ircc_init ()
 *
@@ -158,29 +180,31 @@ static int __init nsc_ircc_init(void)
{
	chipio_t info;
	nsc_chip_t *chip;
	int ret = -ENODEV;
	int ret;
	int cfg_base;
	int cfg, id;
	int reg;
	int i = 0;

 	/* Register with PnP subsystem to detect disable ports */
	ret = pnp_register_driver(&nsc_ircc_pnp_driver);

 	if (ret >= 0)
 		pnp_registered = 1;

	ret = -ENODEV;

	/* Probe for all the NSC chipsets we know about */
	for (chip = chips; chip->name ; chip++) {
		IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__,
			   chip->name);
		
		/* Try all config registers for this chip */
		for (cfg=0; cfg<3; cfg++) {
		for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) {
			cfg_base = chip->cfg[cfg];
			if (!cfg_base)
				continue;

			memset(&info, 0, sizeof(chipio_t));
			info.cfg_base = cfg_base;
			info.fir_base = io[i];
			info.dma = dma[i];
			info.irq = irq[i];

			/* Read index register */
			reg = inb(cfg_base);
			if (reg == 0xff) {
@@ -194,6 +218,41 @@ static int __init nsc_ircc_init(void)
			if ((id & chip->cid_mask) == chip->cid_value) {
				IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n",
					   __FUNCTION__, chip->name, id & ~chip->cid_mask);

				/*
				 * If we found a correct PnP setting,
				 * we first try it.
				 */
				if (pnp_succeeded) {
					memset(&info, 0, sizeof(chipio_t));
					info.cfg_base = cfg_base;
					info.fir_base = pnp_info.fir_base;
					info.dma = pnp_info.dma;
					info.irq = pnp_info.irq;

					if (info.fir_base < 0x2000) {
						IRDA_MESSAGE("%s, chip->init\n", driver_name);
						chip->init(chip, &info);
					} else
						chip->probe(chip, &info);

					if (nsc_ircc_open(&info) >= 0)
						ret = 0;
				}

				/*
				 * Opening based on PnP values failed.
				 * Let's fallback to user values, or probe
				 * the chip.
				 */
				if (ret) {
					IRDA_DEBUG(2, "%s, PnP init failed\n", driver_name);
					memset(&info, 0, sizeof(chipio_t));
					info.cfg_base = cfg_base;
					info.fir_base = io[i];
					info.dma = dma[i];
					info.irq = irq[i];

					/*
					 * If the user supplies the base address, then
					 * we init the chip, if not we probe the values
@@ -204,14 +263,19 @@ static int __init nsc_ircc_init(void)
					} else
						chip->probe(chip, &info);

				if (nsc_ircc_open(i, &info) == 0)
					if (nsc_ircc_open(&info) >= 0)
						ret = 0;
				}
				i++;
			} else {
				IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id);
			}
		} 
	}

	if (ret) {
		pnp_unregister_driver(&nsc_ircc_pnp_driver);
		pnp_registered = 0;
	}

	return ret;
@@ -229,10 +293,15 @@ static void __exit nsc_ircc_cleanup(void)

	pm_unregister_all(nsc_ircc_pmproc);

	for (i=0; i < 4; i++) {
	for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
		if (dev_self[i])
			nsc_ircc_close(dev_self[i]);
	}

	if (pnp_registered)
 		pnp_unregister_driver(&nsc_ircc_pnp_driver);

	pnp_registered = 0;
}

/*
@@ -241,16 +310,27 @@ static void __exit nsc_ircc_cleanup(void)
 *    Open driver instance
 *
 */
static int __init nsc_ircc_open(int i, chipio_t *info)
static int __init nsc_ircc_open(chipio_t *info)
{
	struct net_device *dev;
	struct nsc_ircc_cb *self;
	struct pm_dev *pmdev;
	void *ret;
	int err;
	int err, chip_index;

	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);


 	for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) {
		if (!dev_self[chip_index])
			break;
	}

	if (chip_index == ARRAY_SIZE(dev_self)) {
		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);

@@ -271,8 +351,8 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
	spin_lock_init(&self->lock);
   
	/* Need to store self somewhere */
	dev_self[i] = self;
	self->index = i;
	dev_self[chip_index] = self;
	self->index = chip_index;

	/* Initialize IO */
	self->io.cfg_base  = info->cfg_base;
@@ -351,7 +431,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info)

	/* Check if user has supplied a valid dongle id or not */
	if ((dongle_id <= 0) ||
	    (dongle_id >= (sizeof(dongle_types) / sizeof(dongle_types[0]))) ) {
	    (dongle_id >= ARRAY_SIZE(dongle_types))) {
		dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
		
		IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name,
@@ -368,7 +448,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
        if (pmdev)
                pmdev->data = self;

	return 0;
	return chip_index;
 out4:
	dma_free_coherent(NULL, self->tx_buff.truesize,
			  self->tx_buff.head, self->tx_buff_dma);
@@ -379,7 +459,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
	release_region(self->io.fir_base, self->io.fir_ext);
 out1:
	free_netdev(dev);
	dev_self[i] = NULL;
	dev_self[chip_index] = NULL;
	return err;
}

@@ -806,6 +886,43 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info)
	return 0;
}

/* PNP probing */
static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
{
	memset(&pnp_info, 0, sizeof(chipio_t));
	pnp_info.irq = -1;
	pnp_info.dma = -1;
	pnp_succeeded = 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))
		pnp_info.fir_base = pnp_port_start(dev, 0);

	if (pnp_irq_valid(dev, 0) &&
		!(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED))
		pnp_info.irq = pnp_irq(dev, 0);

	if (pnp_dma_valid(dev, 0) &&
		!(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED))
		pnp_info.dma = pnp_dma(dev, 0);

	IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n",
		   __FUNCTION__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma);

	if((pnp_info.fir_base == 0) ||
	   (pnp_info.irq == -1) || (pnp_info.dma == -1)) {
		/* Returning an error will disable the device. Yuck ! */
		//return -EINVAL;
		pnp_succeeded = 0;
	}

	return 0;
}

/*
 * Function nsc_ircc_setup (info)
 *