synclinkmp.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,458 行 · 第 1/5 页
C
2,458 行
memcpy(skb_put(skb, size),buf,size); skb->dev = info->netdev; skb->mac.raw = skb->data; skb->protocol = hdlc_type_trans(skb, skb->dev); stats->rx_packets++; stats->rx_bytes += size; netif_rx(skb); info->netdev->last_rx = jiffies;}/** * called by device driver when adding device instance * do generic HDLC initialization * * info pointer to device instance information * * returns 0 if success, otherwise error code */static int hdlcdev_init(SLMP_INFO *info){ int rc; struct net_device *dev; hdlc_device *hdlc; /* allocate and initialize network and HDLC layer objects */ if (!(dev = alloc_hdlcdev(info))) { printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); return -ENOMEM; } /* for network layer reporting purposes only */ dev->mem_start = info->phys_sca_base; dev->mem_end = info->phys_sca_base + SCA_BASE_SIZE - 1; dev->irq = info->irq_level; /* network layer callbacks and settings */ dev->do_ioctl = hdlcdev_ioctl; dev->open = hdlcdev_open; dev->stop = hdlcdev_close; dev->tx_timeout = hdlcdev_tx_timeout; dev->watchdog_timeo = 10*HZ; dev->tx_queue_len = 50; /* generic HDLC layer callbacks and settings */ hdlc = dev_to_hdlc(dev); hdlc->attach = hdlcdev_attach; hdlc->xmit = hdlcdev_xmit; /* register objects with HDLC layer */ if ((rc = register_hdlc_device(dev))) { printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); free_netdev(dev); return rc; } info->netdev = dev; return 0;}/** * called by device driver when removing device instance * do generic HDLC cleanup * * info pointer to device instance information */static void hdlcdev_exit(SLMP_INFO *info){ unregister_hdlc_device(info->netdev); free_netdev(info->netdev); info->netdev = NULL;}#endif /* CONFIG_HDLC *//* Return next bottom half action to perform. * Return Value: BH action code or 0 if nothing to do. */int bh_action(SLMP_INFO *info){ unsigned long flags; int rc = 0; spin_lock_irqsave(&info->lock,flags); if (info->pending_bh & BH_RECEIVE) { info->pending_bh &= ~BH_RECEIVE; rc = BH_RECEIVE; } else if (info->pending_bh & BH_TRANSMIT) { info->pending_bh &= ~BH_TRANSMIT; rc = BH_TRANSMIT; } else if (info->pending_bh & BH_STATUS) { info->pending_bh &= ~BH_STATUS; rc = BH_STATUS; } if (!rc) { /* Mark BH routine as complete */ info->bh_running = 0; info->bh_requested = 0; } spin_unlock_irqrestore(&info->lock,flags); return rc;}/* Perform bottom half processing of work items queued by ISR. */void bh_handler(void* Context){ SLMP_INFO *info = (SLMP_INFO*)Context; int action; if (!info) return; if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_handler() entry\n", __FILE__,__LINE__,info->device_name); info->bh_running = 1; while((action = bh_action(info)) != 0) { /* Process work item */ if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_handler() work item action=%d\n", __FILE__,__LINE__,info->device_name, action); switch (action) { case BH_RECEIVE: bh_receive(info); break; case BH_TRANSMIT: bh_transmit(info); break; case BH_STATUS: bh_status(info); break; default: /* unknown work item ID */ printk("%s(%d):%s Unknown work item ID=%08X!\n", __FILE__,__LINE__,info->device_name,action); break; } } if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_handler() exit\n", __FILE__,__LINE__,info->device_name);}void bh_receive(SLMP_INFO *info){ if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_receive()\n", __FILE__,__LINE__,info->device_name); while( rx_get_frame(info) );}void bh_transmit(SLMP_INFO *info){ struct tty_struct *tty = info->tty; if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_transmit() entry\n", __FILE__,__LINE__,info->device_name); if (tty) { tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); }}void bh_status(SLMP_INFO *info){ if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_status() entry\n", __FILE__,__LINE__,info->device_name); info->ri_chkcount = 0; info->dsr_chkcount = 0; info->dcd_chkcount = 0; info->cts_chkcount = 0;}void isr_timer(SLMP_INFO * info){ unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0; /* IER2<7..4> = timer<3..0> interrupt enables (0=disabled) */ write_reg(info, IER2, 0); /* TMCS, Timer Control/Status Register * * 07 CMF, Compare match flag (read only) 1=match * 06 ECMI, CMF Interrupt Enable: 0=disabled * 05 Reserved, must be 0 * 04 TME, Timer Enable * 03..00 Reserved, must be 0 * * 0000 0000 */ write_reg(info, (unsigned char)(timer + TMCS), 0); info->irq_occurred = TRUE; if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_timer()\n", __FILE__,__LINE__,info->device_name);}void isr_rxint(SLMP_INFO * info){ struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; unsigned char status = read_reg(info, SR1) & info->ie1_value & (FLGD + IDLD + CDCD + BRKD); unsigned char status2 = read_reg(info, SR2) & info->ie2_value & OVRN; /* clear status bits */ if (status) write_reg(info, SR1, status); if (status2) write_reg(info, SR2, status2); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_rxint status=%02X %02x\n", __FILE__,__LINE__,info->device_name,status,status2); if (info->params.mode == MGSL_MODE_ASYNC) { if (status & BRKD) { icount->brk++; /* process break detection if tty control * is not set to ignore it */ if ( tty ) { if (!(status & info->ignore_status_mask1)) { if (info->read_status_mask1 & BRKD) { *tty->flip.flag_buf_ptr = TTY_BREAK; if (info->flags & ASYNC_SAK) do_SAK(tty); } } } } } else { if (status & (FLGD|IDLD)) { if (status & FLGD) info->icount.exithunt++; else if (status & IDLD) info->icount.rxidle++; wake_up_interruptible(&info->event_wait_q); } } if (status & CDCD) { /* simulate a common modem status change interrupt * for our handler */ get_signals( info ); isr_io_pin(info, MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD)); }}/* * handle async rx data interrupts */void isr_rxrdy(SLMP_INFO * info){ u16 status; unsigned char DataByte; struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_rxrdy\n", __FILE__,__LINE__,info->device_name); while((status = read_reg(info,CST0)) & BIT0) { DataByte = read_reg(info,TRB); if ( tty ) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) continue; *tty->flip.char_buf_ptr = DataByte; *tty->flip.flag_buf_ptr = 0; } icount->rx++; if ( status & (PE + FRME + OVRN) ) { printk("%s(%d):%s rxerr=%04X\n", __FILE__,__LINE__,info->device_name,status); /* update error statistics */ if (status & PE) icount->parity++; else if (status & FRME) icount->frame++; else if (status & OVRN) icount->overrun++; /* discard char if tty control flags say so */ if (status & info->ignore_status_mask2) continue; status &= info->read_status_mask2; if ( tty ) { if (status & PE) *tty->flip.flag_buf_ptr = TTY_PARITY; else if (status & FRME) *tty->flip.flag_buf_ptr = TTY_FRAME; if (status & OVRN) { /* Overrun is special, since it's * reported immediately, and doesn't * affect the current character */ if (tty->flip.count < TTY_FLIPBUF_SIZE) { tty->flip.count++; tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; *tty->flip.flag_buf_ptr = TTY_OVERRUN; } } } } /* end of if (error) */ if ( tty ) { tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; } } if ( debug_level >= DEBUG_LEVEL_ISR ) { printk("%s(%d):%s isr_rxrdy() flip count=%d\n", __FILE__,__LINE__,info->device_name, tty ? tty->flip.count : 0); printk("%s(%d):%s rx=%d brk=%d parity=%d frame=%d overrun=%d\n", __FILE__,__LINE__,info->device_name, icount->rx,icount->brk,icount->parity, icount->frame,icount->overrun); } if ( tty && tty->flip.count ) tty_flip_buffer_push(tty);}void isr_txeom(SLMP_INFO * info, unsigned char status){ if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_txeom status=%02x\n", __FILE__,__LINE__,info->device_name,status); write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ if (status & UDRN) { write_reg(info, CMD, TXRESET); write_reg(info, CMD, TXENABLE); } else write_reg(info, CMD, TXBUFCLR); /* disable and clear tx interrupts */ info->ie0_value &= ~TXRDYE; info->ie1_value &= ~(IDLE + UDRN); write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); write_reg(info, SR1, (unsigned char)(UDRN + IDLE)); if ( info->tx_active ) { if (info->params.mode != MGSL_MODE_ASYNC) { if (status & UDRN) info->icount.txunder++; else if (status & IDLE) info->icount.txok++; } info->tx_active = 0; info->tx_count = info->tx_put = info->tx_get = 0; del_timer(&info->tx_timer); if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done ) { info->serial_signals &= ~SerialSignal_RTS; info->drop_rts_on_tx_done = 0; set_signals(info); }#ifdef CONFIG_HDLC if (info->netcount) hdlcdev_tx_done(info); else#endif { if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { tx_stop(info); return; } info->pending_bh |= BH_TRANSMIT; } }}/* * handle tx status interrupts */void isr_txint(SLMP_INFO * info){ unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS); /* clear status bits */ write_reg(info, SR1, status); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_txint status=%02x\n", __FILE__,__LINE__,info->device_name,status); if (status & (UDRN + IDLE)) isr_txeom(info, status); if (status & CCTS) { /* simulate a common modem status change interrupt * for our handler */ get_signals( info ); isr_io_pin(info, MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS)); }}/* * handle async tx data interrupts */void isr_txrdy(SLMP_INFO * info){ if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_txrdy() tx_count=%d\n", __FILE__,__LINE__,info->device_name,info->tx_count); if (info->params.mode != MGSL_MODE_ASYNC) { /* disable TXRDY IRQ, enable IDLE IRQ */ info->ie0_value &= ~TXRDYE; info->ie1_value |= IDLE; write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); return; } if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { tx_stop(info); return; } if ( info->tx_count ) tx_load_fifo( info ); else { info->tx_active = 0; info->ie0_value &= ~TXRDYE; write_reg(info, IE0, info->ie0_value); } if (info->tx_count < WAKEUP_CHARS) info->pending_bh |= BH_TRANSMIT;}void isr_rxdmaok(SLMP_INFO * info){ /* BIT7 = EOT (end of transfer) * BIT6 = EOM (end of message/frame) */ unsigned char status = read_reg(info,RXDMA + DSR) & 0xc0; /* clear IRQ (BIT0 must be
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?