📄 sdlamain.c
字号:
return err; } if(card->hw.type != SDLA_S514) irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ else irq = card->hw.irq; /* request an interrupt vector - note that interrupts may be shared */ /* when using the S514 PCI adapter */ if(request_irq(irq, sdla_isr, (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, wandev->name, card)){ printk(KERN_INFO "%s: Can't reserve IRQ %d!\n", wandev->name, irq); return -EINVAL; } }else{ printk(KERN_INFO "%s: Card Configured %lu or Piggybacking %i!\n", wandev->name,card->configured,card->wandev.piggyback); } if (!card->configured){ /* Initialize the Spin lock */ printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name); /* Piggyback spin lock has already been initialized, * in check_s514/s508_conflicts() */ if (!card->wandev.piggyback){ spin_lock_init(&card->wandev.lock); } /* Intialize WAN device data space */ wandev->irq = irq; wandev->dma = 0; if(card->hw.type != SDLA_S514){ wandev->ioport = card->hw.port; }else{ wandev->S514_cpu_no[0] = card->hw.S514_cpu_no[0]; wandev->S514_slot_no = card->hw.S514_slot_no; } wandev->maddr = (unsigned long)card->hw.dpmbase; wandev->msize = card->hw.dpmsize; wandev->hw_opt[0] = card->hw.type; wandev->hw_opt[1] = card->hw.pclk; wandev->hw_opt[2] = card->hw.memory; wandev->hw_opt[3] = card->hw.fwid; } /* Protocol-specific initialization */ switch (card->hw.fwid) { case SFID_X25_502: case SFID_X25_508: printk(KERN_INFO "%s: Starting X.25 Protocol Init.\n", card->devname); err = wpx_init(card, conf); break; case SFID_FR502: case SFID_FR508: printk(KERN_INFO "%s: Starting Frame Relay Protocol Init.\n", card->devname); err = wpf_init(card, conf); break; case SFID_PPP502: case SFID_PPP508: printk(KERN_INFO "%s: Starting PPP Protocol Init.\n", card->devname); err = wpp_init(card, conf); break; case SFID_CHDLC508: case SFID_CHDLC514: if (conf->ft1){ printk(KERN_INFO "%s: Starting FT1 CSU/DSU Config Driver.\n", card->devname); err = wpft1_init(card, conf); break; }else if (conf->config_id == WANCONFIG_MPPP){ printk(KERN_INFO "%s: Starting Multi-Port PPP Protocol Init.\n", card->devname); err = wsppp_init(card,conf); break; }else{ printk(KERN_INFO "%s: Starting CHDLC Protocol Init.\n", card->devname); err = wpc_init(card, conf); break; } default: printk(KERN_INFO "%s: Error, Firmware is not supported %X %X!\n", wandev->name,card->hw.fwid,SFID_CHDLC508); err = -EPROTONOSUPPORT; } if (err != 0){ if (err == -EPROTONOSUPPORT){ printk(KERN_INFO "%s: Error, Protocol selected has not been compiled!\n", card->devname); printk(KERN_INFO "%s: Re-configure the kernel and re-build the modules!\n", card->devname); } release_hw(card); wandev->state = WAN_UNCONFIGURED; return err; } /* Reserve I/O region and schedule background task */ if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) if (!request_region(card->hw.port, card->hw.io_range, wandev->name)) { printk(KERN_WARNING "port 0x%04x busy\n", card->hw.port); release_hw(card); wandev->state = WAN_UNCONFIGURED; return -EBUSY; } /* Only use the polling routine for the X25 protocol */ card->wandev.critical=0; return 0;}/*================================================================== * configure_s508_card * * For a S508 adapter, check for a possible configuration error in that * we are loading an adapter in the same IO port as a previously loaded S508 * card. */ static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq){ unsigned long smp_flags; int i; if (conf->ioport <= 0) { printk(KERN_INFO "%s: can't configure without I/O port address!\n", card->wandev.name); return -EINVAL; } if (conf->irq <= 0) { printk(KERN_INFO "%s: can't configure without IRQ!\n", card->wandev.name); return -EINVAL; } if (test_bit(0,&card->configured)) return 0; /* Check for already loaded card with the same IO port and IRQ * If found, copy its hardware configuration and use its * resources (i.e. piggybacking) */ for (i = 0; i < ncards; i++) { sdla_t *nxt_card = &card_array[i]; /* Skip the current card ptr */ if (nxt_card == card) continue; /* Find a card that is already configured with the * same IO Port */ if ((nxt_card->hw.type == SDLA_S508) && (nxt_card->hw.port == conf->ioport) && (nxt_card->next == NULL)){ /* We found a card the card that has same configuration * as us. This means, that we must setup this card in * piggibacking mode. However, only CHDLC and MPPP protocol * support this setup */ if ((conf->config_id == WANCONFIG_CHDLC || conf->config_id == WANCONFIG_MPPP) && (nxt_card->wandev.config_id == WANCONFIG_CHDLC || nxt_card->wandev.config_id == WANCONFIG_MPPP)){ *irq = nxt_card->hw.irq; memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); /* The master could already be running, we must * set this as a critical area */ lock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); nxt_card->next = card; card->next = nxt_card; card->wandev.piggyback = WANOPT_YES; /* We must initialise the piggiback spin lock here * since isr will try to lock card->next if it * exists */ spin_lock_init(&card->wandev.lock); unlock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); break; }else{ /* Trying to run piggibacking with a wrong protocol */ printk(KERN_INFO "%s: ERROR: Resource busy, ioport: 0x%x\n" "%s: This protocol doesn't support\n" "%s: multi-port operation!\n", card->devname,nxt_card->hw.port, card->devname,card->devname); return -EEXIST; } } } /* Make sure I/O port region is available only if we are the * master device. If we are running in piggybacking mode, * we will use the resources of the master card. */ if (!card->wandev.piggyback) { struct resource *rr = request_region(conf->ioport, SDLA_MAXIORANGE, "sdlamain"); release_region(conf->ioport, SDLA_MAXIORANGE); if (!rr) { printk(KERN_INFO "%s: I/O region 0x%X - 0x%X is in use!\n", card->wandev.name, conf->ioport, conf->ioport + SDLA_MAXIORANGE - 1); return -EINVAL; } } return 0;}/*================================================================== * configure_s514_card * * For a S514 adapter, check for a possible configuration error in that * we are loading an adapter in the same slot as a previously loaded S514 * card. */ static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq){ unsigned long smp_flags; int i; if (test_bit(0,&card->configured)) return 0; /* Check for already loaded card with the same IO port and IRQ * If found, copy its hardware configuration and use its * resources (i.e. piggybacking) */ for (i = 0; i < ncards; i ++) { sdla_t* nxt_card = &card_array[i]; if(nxt_card == card) continue; if((nxt_card->hw.type == SDLA_S514) && (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& (nxt_card->next == NULL)){ if ((conf->config_id == WANCONFIG_CHDLC || conf->config_id == WANCONFIG_MPPP) && (nxt_card->wandev.config_id == WANCONFIG_CHDLC || nxt_card->wandev.config_id == WANCONFIG_MPPP)){ *irq = nxt_card->hw.irq; memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); /* The master could already be running, we must * set this as a critical area */ lock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); nxt_card->next = card; card->next = nxt_card; card->wandev.piggyback = WANOPT_YES; /* We must initialise the piggiback spin lock here * since isr will try to lock card->next if it * exists */ spin_lock_init(&card->wandev.lock); unlock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); }else{ /* Trying to run piggibacking with a wrong protocol */ printk(KERN_INFO "%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" "%s: This protocol doesn't support\n" "%s: multi-port operation!\n", card->devname, conf->S514_CPU_no[0],conf->PCI_slot_no, card->devname,card->devname); return -EEXIST; } } } return 0;}/*============================================================================ * Shut down WAN link driver. * o shut down adapter hardware * o release system resources. * * This function is called by the router when device is being unregistered or * when it handles ROUTER_DOWN IOCTL. */static int shutdown(struct wan_device* wandev){ sdla_t *card; int err=0; /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)){ return -EFAULT; } if (wandev->state == WAN_UNCONFIGURED){ return 0; } card = wandev->private; if (card->tty_opt){ if (card->tty_open){ printk(KERN_INFO "%s: Shutdown Failed: TTY is still open\n", card->devname); return -EBUSY; } } wandev->state = WAN_UNCONFIGURED; set_bit(PERI_CRIT,(void*)&wandev->critical); /* In case of piggibacking, make sure that * we never try to shutdown both devices at the same * time, because they depend on one another */ if (card->disable_comm){ card->disable_comm(card); } /* Release Resources */ release_hw(card); /* only free the allocated I/O range if not an S514 adapter */ if (wandev->hw_opt[0] != SDLA_S514 && !card->configured){ release_region(card->hw.port, card->hw.io_range); } if (!card->configured){ memset(&card->hw, 0, sizeof(sdlahw_t)); if (card->next){ memset(&card->next->hw, 0, sizeof(sdlahw_t)); } } clear_bit(PERI_CRIT,(void*)&wandev->critical); return err;}static void release_hw (sdla_t *card){ sdla_t *nxt_card; /* Check if next device exists */ if (card->next){ nxt_card = card->next; /* If next device is down then release resources */ if (nxt_card->wandev.state == WAN_UNCONFIGURED){ if (card->wandev.piggyback){ /* If this device is piggyback then use * information of the master device */ printk(KERN_INFO "%s: Piggyback shutting down\n",card->devname); sdla_down(&card->next->hw); free_irq(card->wandev.irq, card->next); card->configured = 0; card->next->configured = 0; card->wandev.piggyback = 0; }else{ /* Master device shutting down */ printk(KERN_INFO "%s: Master shutting down\n",card->devname); sdla_down(&card->hw); free_irq(card->wandev.irq, card); card->configured = 0; card->next->configured = 0; } }else{ printk(KERN_INFO "%s: Device still running %i\n", nxt_card->devname,nxt_card->wandev.state); card->configured = 1; } }else{ printk(KERN_INFO "%s: Master shutting down\n",card->devname); sdla_down(&card->hw); free_irq(card->wandev.irq, card); card->configured = 0; } return;}/*============================================================================ * Driver I/O control. * o verify arguments * o perform requested action * * This function is called when router handles one of the reserved user * IOCTLs. Note that 'arg' stil points to user address space. */static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg){ sdla_t* card; int err; /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; card = wandev->private;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -