void cleanup_devs (void) { hdw_info_t *hi; int i; for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { if (hi->pci_slot == 0xff || !hi->ndev) break; c4_stopwd(netdev_priv(hi->ndev)); #ifdef CONFIG_PROC_FS sbecom_proc_brd_cleanup(netdev_priv(hi->ndev)); #endif unregister_netdev (hi->ndev); free_irq (hi->pdev[0]->irq, hi->ndev); #ifdef CONFIG_SBE_PMCC4_NCOMM free_irq (hi->pdev[1]->irq, hi->ndev); #endif OS_kfree (hi->ndev); } }
struct net_device *__init c4_add_dev (hdw_info_t * hi, int brdno, unsigned long f0, unsigned long f1, int irq0, int irq1) { struct net_device *ndev; ci_t *ci; ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, c4_setup); if (!ndev) { pr_warning("%s: no memory for struct net_device !\n", hi->devname); error_flag = ENOMEM; return 0; } ci = (ci_t *)(netdev_priv(ndev)); ndev->irq = irq0; ci->hdw_info = hi; ci->state = C_INIT; /* mark as hardware not available */ ci->next = c4_list; c4_list = ci; ci->brdno = ci->next ? ci->next->brdno + 1 : 0; if (CI == 0) CI = ci; /* DEBUG, only board 0 usage */ strcpy (ci->devname, hi->devname); ci->release = &pmcc4_OSSI_release[0]; /* tasklet */ #if defined(SBE_ISR_TASKLET) tasklet_init (&ci->ci_musycc_isr_tasklet, (void (*) (unsigned long)) musycc_intr_bh_tasklet, (unsigned long) ci); if (atomic_read (&ci->ci_musycc_isr_tasklet.count) == 0) tasklet_disable_nosync (&ci->ci_musycc_isr_tasklet); #elif defined(SBE_ISR_IMMEDIATE) ci->ci_musycc_isr_tq.routine = (void *) (unsigned long) musycc_intr_bh_tasklet; ci->ci_musycc_isr_tq.data = ci; #endif if (register_netdev (ndev) || (c4_init (ci, (u_char *) f0, (u_char *) f1) != SBE_DRVR_SUCCESS)) { OS_kfree (netdev_priv(ndev)); OS_kfree (ndev); error_flag = ENODEV; return 0; } /************************************************************* * int request_irq(unsigned int irq, * void (*handler)(int, void *, struct pt_regs *), * unsigned long flags, const char *dev_name, void *dev_id); * wherein: * irq -> The interrupt number that is being requested. * handler -> Pointer to handling function being installed. * flags -> A bit mask of options related to interrupt management. * dev_name -> String used in /proc/interrupts to show owner of interrupt. * dev_id -> Pointer (for shared interrupt lines) to point to its own * private data area (to identify which device is interrupting). * * extern void free_irq(unsigned int irq, void *dev_id); **************************************************************/ if (request_irq (irq0, &c4_linux_interrupt, IRQF_SHARED, ndev->name, ndev)) { pr_warning("%s: MUSYCC could not get irq: %d\n", ndev->name, irq0); unregister_netdev (ndev); OS_kfree (netdev_priv(ndev)); OS_kfree (ndev); error_flag = EIO; return 0; } #ifdef CONFIG_SBE_PMCC4_NCOMM if (request_irq (irq1, &c4_ebus_interrupt, IRQF_SHARED, ndev->name, ndev)) { pr_warning("%s: EBUS could not get irq: %d\n", hi->devname, irq1); unregister_netdev (ndev); free_irq (irq0, ndev); OS_kfree (netdev_priv(ndev)); OS_kfree (ndev); error_flag = EIO; return 0; } #endif /* setup board identification information */ { u_int32_t tmp; hdw_sn_get (hi, brdno); /* also sets PROM format type (promfmt) * for later usage */ switch (hi->promfmt) { case PROM_FORMAT_TYPE1: memcpy (ndev->dev_addr, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); memcpy (&tmp, (FLD_TYPE1 *) (hi->mfg_info.pft1.Id), 4); /* unaligned data * acquisition */ ci->brd_id = cpu_to_be32 (tmp); break; case PROM_FORMAT_TYPE2: memcpy (ndev->dev_addr, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); memcpy (&tmp, (FLD_TYPE2 *) (hi->mfg_info.pft2.Id), 4); /* unaligned data * acquisition */ ci->brd_id = cpu_to_be32 (tmp); break; default: ci->brd_id = 0; memset (ndev->dev_addr, 0, 6); break; } #if 1 sbeid_set_hdwbid (ci); /* requires bid to be preset */ #else sbeid_set_bdtype (ci); /* requires hdw_bid to be preset */ #endif } #ifdef CONFIG_PROC_FS sbecom_proc_brd_init (ci); #endif #if defined(SBE_ISR_TASKLET) tasklet_enable (&ci->ci_musycc_isr_tasklet); #endif if ((error_flag = c4_init2 (ci)) != SBE_DRVR_SUCCESS) { #ifdef CONFIG_PROC_FS sbecom_proc_brd_cleanup (ci); #endif unregister_netdev (ndev); free_irq (irq1, ndev); free_irq (irq0, ndev); OS_kfree (netdev_priv(ndev)); OS_kfree (ndev); return 0; /* failure, error_flag is set */ } return ndev; }