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 + -
显示快捷键?