static dldwd_priv_t* airport_attach(struct device_node* of_node) { dldwd_priv_t *priv; struct net_device *ndev; dldwd_card_t* card; hermes_t *hw; TRACE_ENTER("dldwd"); if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); return NULL; } /* Allocate space for private device-specific data */ card = kmalloc(sizeof(*card), GFP_KERNEL); if (!card) { printk(KERN_ERR "airport: can't allocate device datas\n"); return NULL; } memset(card, 0, sizeof(*card)); priv = &(card->priv); priv->card = card; ndev = &priv->ndev; hw = &priv->hw; card->node = of_node; /* Setup the common part */ if (dldwd_setup(priv) < 0) { kfree(card); return NULL; } /* Overrides */ ndev->init = airport_init; ndev->open = airport_open; ndev->stop = airport_stop; /* Setup interrupts & base address */ ndev->irq = of_node->intrs[0].line; ndev->base_addr = (unsigned long)ioremap(of_node->addrs[0].address, 0x1000) - _IO_BASE; hermes_struct_init(hw, ndev->base_addr); /* Power up card */ feature_set_airport_power(card->node, 1); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ); /* Reset it before we get the interrupt */ hermes_reset(hw); if (request_irq(ndev->irq, dldwd_interrupt, 0, "Airport", (void *)priv)) { printk(KERN_ERR "airport: Couldn't get IRQ %d\n", ndev->irq); goto failed; } card->irq_requested = 1; /* 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 "airport: register_netdev() failed\n"); goto failed; } printk(KERN_DEBUG "airport: card registered for interface %s\n", ndev->name); card->ndev_registered = 1; SET_MODULE_OWNER(ndev); /* And give us the proc nodes for debugging */ if (dldwd_proc_dev_init(priv) != 0) printk(KERN_ERR "airport: Failed to create /proc node for %s\n", ndev->name); #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&airport_sleep_notifier); #endif return priv; failed: airport_detach(priv); return NULL; } /* airport_attach */
static dev_link_t * dldwd_cs_attach(void) { dldwd_card_t *card; dldwd_priv_t *priv; dev_link_t *link; struct net_device *ndev; client_reg_t client_reg; int ret, i; TRACE_ENTER("dldwd"); /* 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; card->instance = num_instances++; /* FIXME: Racy? */ link = &card->link; ndev = &priv->ndev; link->priv = priv; /* Initialize the dev_link_t structure */ link->release.function = &dldwd_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(dldwd_setup(priv) < 0) { kfree(card); return NULL; } /* Overrides */ ndev->open = dldwd_cs_open; ndev->stop = dldwd_cs_stop; priv->card_reset_handler = dldwd_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 = &dldwd_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); dldwd_cs_detach(link); link = NULL; goto out; } out: TRACE_EXIT("dldwd"); return link; } /* dldwd_cs_attach */