示例#1
0
static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
{
	struct orinoco_private *priv = pci_get_drvdata(pdev);
	struct net_device *dev = &priv->ndev;

	TRACE_ENTER("orinoco_plx");

	if (!priv)
		BUG();

	orinoco_proc_dev_cleanup(priv);

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

	release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));

	pci_disable_device(pdev);

	TRACE_EXIT("orinoco_plx");
}
示例#2
0
static void
orinoco_cs_release(u_long arg)
{
	dev_link_t *link = (dev_link_t *) arg;
	struct orinoco_private *priv = link->priv;

	TRACE_ENTER(link->dev->dev_name);

	/*
	   If the device is currently in use, we won't release until it
	   is actually closed, because until then, we can't be sure that
	   no one will try to access the device or its data structures.
	 */
	if (link->open) {
		DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n",
		      link->dev->dev_name);
		link->state |= DEV_STALE_CONFIG;
		return;
	}

	/* Unregister proc entry */
	orinoco_proc_dev_cleanup(priv);

	/* Don't bother checking to see if these succeed or not */
	CardServices(ReleaseConfiguration, link->handle);
	if (link->io.NumPorts1)
		CardServices(ReleaseIO, link->handle, &link->io);
	if (link->irq.AssignedIRQ)
		CardServices(ReleaseIRQ, link->handle, &link->irq);
	link->state &= ~DEV_CONFIG;

	TRACE_EXIT(link->dev->dev_name);
}				/* orinoco_cs_release */
示例#3
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;
}