📄 sdlamain.c
字号:
if (err){ release_hw(card); return err; } /* Reserve I/O region and schedule background task */ if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) request_region(card->hw.port, card->hw.io_range, wandev->name); if (++active == 1) { MOD_INC_USE_COUNT; if (schedule_task(&sdla_tq) == 0) MOD_DEC_USE_COUNT; } wandev->critical = 0; 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 (wan_device_t* wandev){ sdla_t *card; /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; if (wandev->state == WAN_UNCONFIGURED) return 0; /* If we are in a critical section we lose */ if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN; card = wandev->private; wandev->state = WAN_UNCONFIGURED; if (--active == 0) schedule(); /* stop background thread */ /* 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)); } } wandev->critical = 0; return 0;}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\n", nxt_card->devname); 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; }}/*============================================================================ * 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 (wan_device_t* 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; if(card->hw.type != SDLA_S514){ disable_irq(card->hw.irq); } if (test_and_set_bit(0, (void*)&wandev->critical)) { if(card->hw.type != SDLA_S514){ enable_irq(card->hw.irq); } return -EAGAIN; } switch (cmd) { case WANPIPE_DUMP: err = ioctl_dump(wandev->private, (void*)arg); break; case WANPIPE_EXEC: err = ioctl_exec(wandev->private, (void*)arg); break; default: err = -EINVAL; } clear_bit(0, (void*)&wandev->critical); if(card->hw.type != SDLA_S514){ enable_irq(card->hw.irq); } return err;}/****** Driver IOCTL Handlers ***********************************************//*============================================================================ * Dump adapter memory to user buffer. * o verify request structure * o copy request structure to kernel data space * o verify length/offset * o verify user buffer * o copy adapter memory image to user buffer * * Note: when dumping memory, this routine switches curent dual-port memory * vector, so care must be taken to avoid racing conditions. */static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump){ sdla_dump_t dump; unsigned winsize; unsigned long oldvec; /* DPM window vector */ unsigned long flags; int err = 0; if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) return -EFAULT; if ((dump.magic != WANPIPE_MAGIC) || (dump.offset + dump.length > card->hw.memory)) return -EINVAL; winsize = card->hw.dpmsize; save_flags(flags); cli(); /* >>> critical section start <<< */ if(card->hw.type != SDLA_S514) { oldvec = card->hw.vector; while (dump.length) { /* current offset */ unsigned pos = dump.offset % winsize; /* current vector */ unsigned long vec = dump.offset - pos; unsigned len = (dump.length > (winsize - pos)) ? (winsize - pos) : dump.length; /* relocate window */ if (sdla_mapmem(&card->hw, vec) != 0) { err = -EIO; break; } /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ sti(); /* Not ideal but tough we have to do this */ if(copy_to_user((void *)dump.ptr, (u8 *)card->hw.dpmbase + pos, len)) return -EFAULT; cli(); dump.length -= len; dump.offset += len; (char*)dump.ptr += len; } sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ } else { /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ sti(); /* Not ideal but tough we have to do this */ if(copy_to_user((void *)dump.ptr, (u8 *)card->hw.dpmbase + dump.offset, dump.length)) return -EFAULT; cli(); } restore_flags(flags); /* >>> critical section end <<< */ return err;}/*============================================================================ * Execute adapter firmware command. * o verify request structure * o copy request structure to kernel data space * o call protocol-specific 'exec' function */static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec){ sdla_exec_t exec; if (card->exec == NULL) return -ENODEV; if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) return -EFAULT; if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) return -EINVAL; return card->exec(card, exec.cmd, exec.data);}/******* Miscellaneous ******************************************************//*============================================================================ * SDLA Interrupt Service Routine. * o acknowledge SDLA hardware interrupt. * o call protocol-specific interrupt service routine, if any. */STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs){#define card ((sdla_t*)dev_id) if(card->hw.type == SDLA_S514) { /* handle interrrupt on S514 */ u32 int_status; unsigned char CPU_no = card->hw.S514_cpu_no[0]; unsigned char card_found_for_IRQ; u8 IRQ_count = 0; for(;;) { read_S514_int_stat(&card->hw, &int_status); /* check if the interrupt is for this device */ if(!((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B))) return; /* if the IRQ is for both CPUs on the same adapter, */ /* then alter the interrupt status so as to handle */ /* one CPU at a time */ if(((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B)) == (IRQ_CPU_A | IRQ_CPU_B)) { int_status &= (CPU_no == S514_CPU_A) ? ~IRQ_CPU_B : ~IRQ_CPU_A; } card_found_for_IRQ = 0; /* check to see that the CPU number for this device */ /* corresponds to the interrupt status read */ switch (CPU_no) { case S514_CPU_A: if((unsigned char)int_status & IRQ_CPU_A) card_found_for_IRQ = 1; break; case S514_CPU_B: if((unsigned char)int_status & IRQ_CPU_B) card_found_for_IRQ = 1; break; } /* exit if the interrupt is for another CPU on the */ /* same IRQ */ if(!card_found_for_IRQ) return; if (!card || (card->wandev.state == WAN_UNCONFIGURED && !card->configured)){ printk(KERN_INFO "Received IRQ %d for CPU #%c\n", irq, CPU_no); printk(KERN_INFO "IRQ for unconfigured adapter\n"); S514_intack(&card->hw, int_status); return; } if (card->in_isr) { printk(KERN_INFO "%s: interrupt re-entrancy on IRQ %d\n", card->devname, card->wandev.irq); S514_intack(&card->hw, int_status); return; } S514_intack(&card->hw, int_status); if (card->isr) card->isr(card); /* handle a maximum of two interrupts (one for each */ /* CPU on the adapter) before returning */ if((++ IRQ_count) == 2) return; } } else { /* handle interrupt on S508 adapter */ if (!card || ((card->wandev.state == WAN_UNCONFIGURED) && !card->configured)) return; if (card->in_isr) { printk(KERN_INFO "%s: interrupt re-entrancy on IRQ %d!\n", card->devname, card->wandev.irq); return; } /* Use spin lock only for S508 */#ifdef CONFIG_SMP spin_lock(&card->lock);#endif sdla_intack(&card->hw); if (card->isr) card->isr(card);#ifdef CONFIG_SMP spin_unlock(&card->lock);#endif } #undef card}/*============================================================================ * SDLA polling routine. * This routine simulates kernel thread to perform various housekeeping job. * * o for each configured device call its poll() routine * o if there is at least one active card, then reschedule itself once again */STATIC void sdla_poll (void* data){ int i; for (i = 0; i < ncards; ++i) { sdla_t* card = &card_array[i]; if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll && !card->wandev.critical) { card->poll(card); } } if (active) { MOD_INC_USE_COUNT; if (schedule_task(&sdla_tq) == 0) /* Surely not? */ MOD_DEC_USE_COUNT; } MOD_DEC_USE_COUNT;}/*============================================================================ * This routine is called by the protocol-specific modules when network * interface is being open. The only reason we need this, is because we * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's * defined more than once into the same kernel module. */void wanpipe_open (sdla_t* card){ ++card->open_cnt; MOD_INC_USE_COUNT;}/*============================================================================ * This routine is called by the protocol-specific modules when network * interface is being closed. The only reason we need this, is because we * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's * defined more than once into the same kernel module. */void wanpipe_close (sdla_t* card){ --card->open_cnt; MOD_DEC_USE_COUNT;}/*============================================================================ * Set WAN device state. */void wanpipe_set_state (sdla_t* card, int state){ unsigned long flags; save_flags(flags); cli(); if (card->wandev.state != state) { switch (state) { case WAN_CONNECTED: printk (KERN_INFO "%s: link connected!\n", card->devname); break; case WAN_CONNECTING: printk (KERN_INFO "%s: link connecting...\n", card->devname); break; case WAN_DISCONNECTED: printk (KERN_INFO "%s: link disconnected!\n", card->devname); break; } card->wandev.state = state; } card->state_tick = jiffies; restore_flags(flags);}/****** End *****************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -