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; }
static dev_link_t * orinoco_cs_attach(void) { struct orinoco_pccard *card; struct orinoco_private *priv; dev_link_t *link; struct net_device *ndev; client_reg_t client_reg; int ret, i; TRACE_ENTER("orinoco"); /* A bit of cleanup */ flush_stale_links(); /* Allocate space for private device-specific data */ card = kmalloc(sizeof(*card), GFP_KERNEL); if (! card) { link = NULL; goto out; } memset(card, 0, sizeof(*card)); /* Link both structure together */ priv = &(card->priv); priv->card = card; link = &card->link; ndev = &priv->ndev; link->priv = priv; /* Initialize the dev_link_t structure */ link->release.function = &orinoco_cs_release; link->release.data = (u_long) link; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; 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 = NULL; /* General socket configuration defaults can go here. In this client, we assume very little, and rely on the CIS for almost everything. In most clients, many details (i.e., number, sizes, and attributes of IO windows) are fixed by the nature of the device, and can be hard-wired here. */ link->conf.Attributes = 0; link->conf.IntType = INT_MEMORY_AND_IO; /* Setup the common part */ if(orinoco_setup(priv) < 0) { kfree(card); return NULL; } /* Overrides */ ndev->open = orinoco_cs_open; ndev->stop = orinoco_cs_stop; priv->card_reset_handler = orinoco_cs_cor_reset; /* Register with Card Services */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = &orinoco_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); orinoco_cs_detach(link); link = NULL; goto out; } out: TRACE_EXIT("orinoco"); return link; } /* orinoco_cs_attach */