📄 sdla_chdlc.c
字号:
/* Check for which port the interrupt has been generated * Since Secondary Port is piggybacking on the Primary * the check must be done here. */ flags = card->u.c.flags; if (!flags->interrupt_info_struct.interrupt_type){ /* Check for a second port (piggybacking) */ if ((my_card = card->next)){ flags = my_card->u.c.flags; if (flags->interrupt_info_struct.interrupt_type){ card = my_card; card->isr(card); return; } } } flags = card->u.c.flags; card->in_isr = 1; dev = card->wandev.dev; /* If we get an interrupt with no network device, stop the interrupts * and issue an error */ if (!card->tty_opt && !dev && flags->interrupt_info_struct.interrupt_type != COMMAND_COMPLETE_APP_INT_PEND){ goto isr_done; } /* if critical due to peripheral operations * ie. update() or getstats() then reset the interrupt and * wait for the board to retrigger. */ if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "ISR CRIT TO PERI\n"); goto isr_done; } /* On a 508 Card, if critical due to if_send * Major Error !!! */ if(card->hw.type != SDLA_S514) { if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical while in ISR: %lx\n", card->devname, card->wandev.critical); card->in_isr = 0; flags->interrupt_info_struct.interrupt_type = 0; return; } } switch(flags->interrupt_info_struct.interrupt_type) { case RX_APP_INT_PEND: /* 0x01: receive interrupt */ rx_intr(card); break; case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_TX_FRAME; if (card->tty_opt){ wanpipe_tty_trigger_poll(card); break; } if (dev && netif_queue_stopped(dev)){ if (card->u.c.usedby == API){ netif_start_queue(dev); wakeup_sk_bh(dev); }else{ netif_wake_queue(dev); } } break; case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ ++ Intr_test_counter; break; case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ process_chdlc_exception(card); break; case GLOBAL_EXCEP_COND_APP_INT_PEND: process_global_exception(card); break; case TIMER_APP_INT_PEND: timer_intr(card); break; default: printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", card->devname, flags->interrupt_info_struct.interrupt_type); printk(KERN_INFO "Code name: "); for(i = 0; i < 4; i ++) printk(KERN_INFO "%c", flags->global_info_struct.codename[i]); printk(KERN_INFO "\nCode version: "); for(i = 0; i < 4; i ++) printk(KERN_INFO "%c", flags->global_info_struct.codeversion[i]); printk(KERN_INFO "\n"); break; }isr_done: card->in_isr = 0; flags->interrupt_info_struct.interrupt_type = 0; return;}/*============================================================================ * Receive interrupt handler. */static void rx_intr (sdla_t* card){ struct net_device *dev; chdlc_private_area_t *chdlc_priv_area; SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; struct sk_buff *skb; unsigned len; unsigned addr = rxbuf->ptr_data_bfr; void *buf; int i,udp_type; if (rxbuf->opp_flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", card->devname, (unsigned)rxbuf, rxbuf->opp_flag); printk(KERN_INFO "Code name: "); for(i = 0; i < 4; i ++) printk(KERN_INFO "%c", flags->global_info_struct.codename[i]); printk(KERN_INFO "\nCode version: "); for(i = 0; i < 4; i ++) printk(KERN_INFO "%c", flags->global_info_struct.codeversion[i]); printk(KERN_INFO "\n"); /* Bug Fix: Mar 6 2000 * If we get a corrupted mailbox, it measn that driver * is out of sync with the firmware. There is no recovery. * If we don't turn off all interrupts for this card * the machine will crash. */ printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); printk(KERN_INFO "Please contact Sangoma Technologies !\n"); chdlc_set_intr_mode(card,0); return; } len = rxbuf->frame_length; if (card->tty_opt){ if (rxbuf->error_flag){ goto rx_exit; } if (len <= CRC_LENGTH){ goto rx_exit; } if (!card->u.c.async_mode){ len -= CRC_LENGTH; } wanpipe_tty_receive(card,addr,len); goto rx_exit; } dev = card->wandev.dev; if (!dev){ goto rx_exit; } if (!netif_running(dev)) goto rx_exit; chdlc_priv_area = dev->priv; /* Allocate socket buffer */ skb = dev_alloc_skb(len); if (skb == NULL) { printk(KERN_INFO "%s: no socket buffers available!\n", card->devname); ++card->wandev.stats.rx_dropped; goto rx_exit; } /* Copy data to the socket buffer */ if((addr + len) > card->u.c.rx_top + 1) { unsigned tmp = card->u.c.rx_top - addr + 1; buf = skb_put(skb, tmp); sdla_peek(&card->hw, addr, buf, tmp); addr = card->u.c.rx_base; len -= tmp; } buf = skb_put(skb, len); sdla_peek(&card->hw, addr, buf, len); skb->protocol = htons(ETH_P_IP); card->wandev.stats.rx_packets ++; card->wandev.stats.rx_bytes += skb->len; udp_type = udp_pkt_type( skb, card ); if(udp_type == UDP_CPIPE_TYPE) { if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev, chdlc_priv_area)) { flags->interrupt_info_struct. interrupt_permission |= APP_INT_ON_TIMER; } } else if(card->u.c.usedby == API) { api_rx_hdr_t* api_rx_hdr; skb_push(skb, sizeof(api_rx_hdr_t)); api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; api_rx_hdr->error_flag = rxbuf->error_flag; api_rx_hdr->time_stamp = rxbuf->time_stamp; skb->protocol = htons(PVC_PROT); skb->mac.raw = skb->data; skb->dev = dev; skb->pkt_type = WAN_PACKET_DATA; bh_enqueue(dev, skb); if (!test_and_set_bit(0,&chdlc_priv_area->tq_working)) wanpipe_queue_work(&chdlc_priv_area->common.wanpipe_work); }else{ /* FIXME: we should check to see if the received packet is a multicast packet so that we can increment the multicast statistic ++ chdlc_priv_area->if_stats.multicast; */ /* Pass it up the protocol stack */ skb->dev = dev; skb->mac.raw = skb->data; netif_rx(skb); dev->last_rx = jiffies; }rx_exit: /* Release buffer element and calculate a pointer to the next one */ rxbuf->opp_flag = 0x00; card->u.c.rxmb = ++ rxbuf; if((void*)rxbuf > card->u.c.rxbuf_last){ card->u.c.rxmb = card->u.c.rxbuf_base; }}/*============================================================================ * Timer interrupt handler. * The timer interrupt is used for two purposes: * 1) Processing udp calls from 'cpipemon'. * 2) Reading board-level statistics for updating the proc file system. */void timer_intr(sdla_t *card){ struct net_device* dev; chdlc_private_area_t* chdlc_priv_area = NULL; SHARED_MEMORY_INFO_STRUCT* flags = NULL; if ((dev = card->wandev.dev)==NULL){ flags = card->u.c.flags; flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_TIMER; return; } chdlc_priv_area = dev->priv; if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { if (!config_chdlc(card)){ chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; } } /* process a udp call if pending */ if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { process_udp_mgmt_pkt(card, dev, chdlc_priv_area); chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; } /* read the communications statistics if required */ if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { update_comms_stats(card, chdlc_priv_area); if(!(-- chdlc_priv_area->update_comms_stats)) { chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; } } /* only disable the timer interrupt if there are no udp or statistic */ /* updates pending */ if(!chdlc_priv_area->timer_int_enabled) { flags = card->u.c.flags; flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_TIMER; }}/*------------------------------------------------------------------------------ Miscellaneous Functions - set_chdlc_config() used to set configuration options on the board------------------------------------------------------------------------------*/static int set_chdlc_config(sdla_t* card){ CHDLC_CONFIGURATION_STRUCT cfg; memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); if(card->wandev.clocking){ cfg.baud_rate = card->wandev.bps; } cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; cfg.modem_config_options = 0; cfg.modem_status_timer = 100; cfg.CHDLC_protocol_options = card->u.c.protocol_options; if (card->tty_opt){ cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; } cfg.percent_data_buffer_for_Tx = (card->u.c.receive_only) ? 0 : 50; cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | CHDLC_RX_DATA_BYTE_COUNT_STAT); if (card->tty_opt){ card->wandev.mtu = TTY_CHDLC_MAX_MTU; } cfg.max_CHDLC_data_field_length = card->wandev.mtu; cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; cfg.receive_keepalive_timer = card->u.c.kpalv_rx; cfg.keepalive_error_tolerance = card->u.c.kpalv_err; cfg.SLARP_request_timer = card->u.c.slarp_timer; if (cfg.SLARP_request_timer) { cfg.IP_address = 0; cfg.IP_netmask = 0; }else if (card->wandev.dev){ struct net_device *dev = card->wandev.dev; chdlc_private_area_t *chdlc_priv_area = dev->priv; struct in_device *in_dev = dev->ip_ptr; if(in_dev != NULL) { struct in_ifaddr *ifa = in_dev->ifa_list; if (ifa != NULL ) { cfg.IP_address = ntohl(ifa->ifa_local); cfg.IP_netmask = ntohl(ifa->ifa_mask); chdlc_priv_area->IP_address = ntohl(ifa->ifa_local); chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); } } /* FIXME: We must re-think this message in next release if((cfg.IP_address & 0x000000FF) > 2) { printk(KERN_WARNING "\n"); printk(KERN_WARNING " WARNING:%s configured with an\n", card->devname); printk(KERN_WARNING " invalid local IP address.\n"); printk(KERN_WARNING " Slarp pragmatics will fail.\n"); printk(KERN_WARNING " IP address should be of the\n"); printk(KERN_WARNING " format A.B.C.1 or A.B.C.2.\n"); } */ } return chdlc_configure(card, &cfg);}/*----------------------------------------------------------------------------- set_asy_config() used to set asynchronous configuration options on the board------------------------------------------------------------------------------*/static int set_asy_config(sdla_t* card){ ASY_CONFIGURATION_STRUCT cfg; CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; int err; memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); if(card->wandev.clocking) cfg.baud_rate = card->wandev.bps; cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; cfg.modem_config_options = 0; cfg.asy_API_options = card->u.c.api_options; cfg.asy_protocol_options = card->u.c.protocol_options; cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; cfg.stop_bits = card->u.c.stop_bits; cfg.parity = card->u.c.parity; cfg.break_timer = card->u.c.break_timer; cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer; cfg.asy_Rx_complete_length = card->u.c.rx_complete_length; cfg.XON_char = card->u.c.xon_char; cfg.XOFF_char = card->u.c.xoff_char; cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | CHDLC_RX_DATA_BYTE_COUNT_STAT); mailbox->buffer_length = sizeof(ASY_CONFIGURATION_STRUCT); memcpy(mailbox->data, &cfg, mailbox->buffer_length); mailbox->command = SET_ASY_CONFIGURATION; err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; if (err != COMMAND_OK) chdlc_error (card, err, mailbox); return err;}/*============================================================================ * Enable asynchronous communications. */static int asy_comm_enable (sdla_t* card){ int err; CHDLC_MAILBOX_STRUCT* mb = card->mbox; mb->buffer_len
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -