Пример #1
0
static int orinoco_plx_init_one(struct pci_dev *pdev,
				const struct pci_device_id *ent)
{
	int err = 0;
	u16 *attr_mem = NULL;
	u32 reg, addr;
	struct orinoco_private *priv = NULL;
	unsigned long pccard_ioaddr = 0;
	unsigned long pccard_iolen = 0;
	struct net_device *dev = NULL;
	int netdev_registered = 0;
	int i;

	TRACE_ENTER("orinoco_plx");

	err = pci_enable_device(pdev);
	if (err)
		return -EIO;

	/* Resource 2 is mapped to the PCMCIA space */
	attr_mem = ioremap(pci_resource_start(pdev, 2), PAGE_SIZE);
	if (! attr_mem)
		goto fail;

	printk(KERN_DEBUG "orinoco_plx: CIS: ");
	for (i = 0; i < 16; i++) {
		printk("%02X:", (int)attr_mem[i]);
	}
	printk("\n");

	/* Verify whether PC card is present */
	/* FIXME: we probably need to be smarted about this */
	if (memcmp(attr_mem, cis_magic, sizeof(cis_magic)) != 0) {
		printk(KERN_ERR "orinoco_plx: The CIS value of Prism2 PC card is invalid.\n");
		err = -EIO;
		goto fail;
	}

	/* PCMCIA COR is the first byte following CIS: this write should
	 * enable I/O mode and select level-triggered interrupts */
	attr_mem[COR_OFFSET] = COR_VALUE;
	mdelay(1);
	reg = attr_mem[COR_OFFSET];
	if (reg != COR_VALUE) {
		printk(KERN_ERR "orinoco_plx: Error setting COR value (reg=%x)\n", reg);
		goto fail;
	}			

	iounmap(attr_mem);
	attr_mem = NULL; /* done with this now, it seems */

	/* bjoern: We need to tell the card to enable interrupts, in
	   case the serial eprom didn't do this already. See the
	   PLX9052 data book, p8-1 and 8-24 for reference. */
	addr = pci_resource_start(pdev, 1);
	reg = 0;
	reg = inl(addr+PLX_INTCSR);
	if(reg & PLX_INTCSR_INTEN)
		printk(KERN_DEBUG "orinoco_plx: "
		       "Local Interrupt already enabled\n");
	else {
		reg |= PLX_INTCSR_INTEN;
		outl(reg, addr+PLX_INTCSR);
		reg = inl(addr+PLX_INTCSR);
		if(!(reg & PLX_INTCSR_INTEN)) {
			printk(KERN_ERR "orinoco_plx: "
			       "Couldn't enable Local Interrupts\n");
			goto fail;
		}
	}

	/* and 3 to the PCMCIA slot I/O address space */
	pccard_ioaddr = pci_resource_start(pdev, 3);
	pccard_iolen = pci_resource_len(pdev, 3);
	if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) {
		printk(KERN_ERR "orinoco_plx: I/O resource 0x%lx @ 0x%lx busy\n",
		       pccard_iolen, pccard_ioaddr);
		pccard_ioaddr = 0;
		err = -EBUSY;
		goto fail;
	}

	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
	if (! priv) {
		err = -ENOMEM;
		goto fail;
	}
	memset(priv, 0, sizeof(*priv));

	dev = &priv->ndev;

	err = orinoco_setup(priv);
	if (err)
		goto fail;
	dev->base_addr = pccard_ioaddr;
	dev->open = orinoco_plx_open;
	dev->stop = orinoco_plx_stop;
	priv->card_reset_handler = NULL; /* We have no reset handler */
	SET_MODULE_OWNER(dev);

	printk(KERN_DEBUG
	       "Detected Orinoco/Prism2 PLX device at %s irq:%d, io addr:0x%lx\n",
	       pdev->slot_name, pdev->irq, pccard_ioaddr);

	hermes_struct_init(&(priv->hw), dev->base_addr);
	pci_set_drvdata(pdev, priv);

	err = request_irq(pdev->irq, orinoco_plx_interrupt, SA_SHIRQ, dev->name, priv);
	if (err) {
		printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq);
		err = -EBUSY;
		goto fail;
	}
	dev->irq = pdev->irq;

	err = register_netdev(dev);
	if (err)
		goto fail;
	netdev_registered = 1;

	err = orinoco_proc_dev_init(priv);
	if (err)
		goto fail;

	priv->hw_ready = 1;

	TRACE_EXIT("orinoco_plx");

	return 0;		/* succeeded */

 fail:	
	printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n");

	if (priv) {
		orinoco_proc_dev_cleanup(priv);

		if (netdev_registered)
			unregister_netdev(dev);
		
		if (dev->irq)
			free_irq(dev->irq, priv);
		
		kfree(priv);
	}

	if (pccard_ioaddr)
		release_region(pccard_ioaddr, pccard_iolen);

	if (attr_mem)
		iounmap(attr_mem);

	pci_disable_device(pdev);

	TRACE_EXIT("orinoco_plx");
	
	return err;
}
Пример #2
0
static void
orinoco_cs_config(dev_link_t * link)
{
	client_handle_t handle = link->handle;
	struct orinoco_private *priv = link->priv;
	struct orinoco_pccard *card = (struct orinoco_pccard *)priv->card;
	hermes_t *hw = &priv->hw;
	struct net_device *ndev = &priv->ndev;
	tuple_t tuple;
	cisparse_t parse;
	int last_fn, last_ret;
	u_char buf[64];
	config_info_t conf;
	cistpl_cftable_entry_t dflt = { 0 };
	cisinfo_t info;

	TRACE_ENTER("orinoco");

	CS_CHECK(ValidateCIS, handle, &info);

	/*
	   This reads the card's CONFIG tuple to find its configuration
	   registers.
	 */
	tuple.DesiredTuple = CISTPL_CONFIG;
	tuple.Attributes = 0;
	tuple.TupleData = buf;
	tuple.TupleDataMax = sizeof(buf);
	tuple.TupleOffset = 0;
	CS_CHECK(GetFirstTuple, handle, &tuple);
	CS_CHECK(GetTupleData, handle, &tuple);
	CS_CHECK(ParseTuple, handle, &tuple, &parse);
	link->conf.ConfigBase = parse.config.base;
	link->conf.Present = parse.config.rmask[0];

	/* Configure card */
	link->state |= DEV_CONFIG;

	/* Look up the current Vcc */
	CS_CHECK(GetConfigurationInfo, handle, &conf);
	link->conf.Vcc = conf.Vcc;

	DEBUG(0, "orinoco_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", 
	      link->conf.ConfigBase, link->conf.Vcc);

	/*
	   In this loop, we scan the CIS for configuration table entries,
	   each of which describes a valid card configuration, including
	   voltage, IO window, memory window, and interrupt settings.

	   We make no assumptions about the card to be configured: we use
	   just the information available in the CIS.  In an ideal world,
	   this would work for any PCMCIA card, but it requires a complete
	   and accurate CIS.  In practice, a driver usually "knows" most of
	   these things without consulting the CIS, and most client drivers
	   will only use the CIS to fill in implementation-defined details.
	 */
	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
	CS_CHECK(GetFirstTuple, handle, &tuple);
	while (1) {
		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
		CFG_CHECK(GetTupleData, handle, &tuple);
		CFG_CHECK(ParseTuple, handle, &tuple, &parse);

		DEBUG(0, "orinoco_cs_config: index = 0x%x, flags = 0x%x\n",
		      cfg->index, cfg->flags);

		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
			dflt = *cfg;
		if (cfg->index == 0)
			goto next_entry;
		link->conf.ConfigIndex = cfg->index;

		/* Does this card need audio output? */
		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
			link->conf.Attributes |= CONF_ENABLE_SPKR;
			link->conf.Status = CCSR_AUDIO_ENA;
		}

		/* Use power settings for Vcc and Vpp if present */
		/*  Note that the CIS values need to be rescaled */
		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
			if (conf.Vcc !=
			    cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
				if(!ignore_cis_vcc)
					goto next_entry;
			}
		} else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
			if (conf.Vcc !=
			    dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
				if(!ignore_cis_vcc)
					goto next_entry;
			}
		}

		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
			link->conf.Vpp1 = link->conf.Vpp2 =
			    cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
		else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
			link->conf.Vpp1 = link->conf.Vpp2 =
			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
		
		DEBUG(0, "orinoco_cs_config: We seem to have configured Vcc and Vpp\n");

		/* Do we need to allocate an interrupt? */
		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
			link->conf.Attributes |= CONF_ENABLE_IRQ;

		/* IO window settings */
		link->io.NumPorts1 = link->io.NumPorts2 = 0;
		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
			cistpl_io_t *io =
			    (cfg->io.nwin) ? &cfg->io : &dflt.io;
			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
			if (!(io->flags & CISTPL_IO_8BIT))
				link->io.Attributes1 =
				    IO_DATA_PATH_WIDTH_16;
			if (!(io->flags & CISTPL_IO_16BIT))
				link->io.Attributes1 =
				    IO_DATA_PATH_WIDTH_8;
			link->io.IOAddrLines =
			    io->flags & CISTPL_IO_LINES_MASK;
			link->io.BasePort1 = io->win[0].base;
			link->io.NumPorts1 = io->win[0].len;
			if (io->nwin > 1) {
				link->io.Attributes2 =
				    link->io.Attributes1;
				link->io.BasePort2 = io->win[1].base;
				link->io.NumPorts2 = io->win[1].len;
			}

			/* This reserves IO space but doesn't actually enable it */
			CFG_CHECK(RequestIO, link->handle, &link->io);
		}


		/* If we got this far, we're cool! */

		break;
		
	next_entry:
		if (link->io.NumPorts1)
			CardServices(ReleaseIO, link->handle, &link->io);
		CS_CHECK(GetNextTuple, handle, &tuple);
	}

	/*
	   Allocate an interrupt line.  Note that this does not assign a
	   handler to the interrupt, unless the 'Handler' member of the
	   irq structure is initialized.
	 */
	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
		int i;

		link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
		link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
		if (irq_list[0] == -1)
			link->irq.IRQInfo2 = irq_mask;
		else
			for (i=0; i<4; i++)
				link->irq.IRQInfo2 |= 1 << irq_list[i];
		
  		link->irq.Handler = orinoco_interrupt; 
  		link->irq.Instance = priv; 
		
		CS_CHECK(RequestIRQ, link->handle, &link->irq);
	}

	/* We initialize the hermes structure before completing PCMCIA
	   configuration just in case the interrupt handler gets
	   called. */
	hermes_struct_init(hw, link->io.BasePort1);

	/*
	   This actually configures the PCMCIA socket -- setting up
	   the I/O windows and the interrupt mapping, and putting the
	   card and host interface into "Memory and IO" mode.
	 */
	CS_CHECK(RequestConfiguration, link->handle, &link->conf);

	ndev->base_addr = link->io.BasePort1;
	ndev->irq = link->irq.AssignedIRQ;

	/* register_netdev will give us an ethX name */
	ndev->name[0] = '\0';
	/* Tell the stack we exist */
	if (register_netdev(ndev) != 0) {
		printk(KERN_ERR "orinoco_cs: register_netdev() failed\n");
		goto failed;
	}
	strcpy(card->node.dev_name, ndev->name);

	/* Finally, report what we've done */
	printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d",
	       ndev->name, link->conf.ConfigIndex,
	       link->conf.Vcc / 10, link->conf.Vcc % 10);
	if (link->conf.Vpp1)
		printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
		       link->conf.Vpp1 % 10);
	if (link->conf.Attributes & CONF_ENABLE_IRQ)
		printk(", irq %d", link->irq.AssignedIRQ);
	if (link->io.NumPorts1)
		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
		       link->io.BasePort1 + link->io.NumPorts1 - 1);
	if (link->io.NumPorts2)
		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
		       link->io.BasePort2 + link->io.NumPorts2 - 1);
	printk("\n");

	/* And give us the proc nodes for debugging */
	if (orinoco_proc_dev_init(priv) != 0) {
		printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n",
		       ndev->name);
		goto failed;
	}
	
	/* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */
	SET_MODULE_OWNER(ndev);
	
	/* Allow cor_reset, /proc & ioctls to act */
	priv->hw_ready = 1;
	
	/* Do a Pcmcia soft reset of the card (optional) */
	if(reset_cor)
		orinoco_cs_cor_reset(priv);

	/*
	   At this point, the dev_node_t structure(s) need to be
	   initialized and arranged in a linked list at link->dev.
	 */
	card->node.major = card->node.minor = 0;
	link->dev = &card->node;
	link->state &= ~DEV_CONFIG_PENDING;

	TRACE_EXIT("orinoco");

	return;

 cs_failed:
	cs_error(link->handle, last_fn, last_ret);
 failed:
	orinoco_cs_release((u_long) link);

	TRACE_EXIT("orinoco");
}				/* orinoco_cs_config */