⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pc300_tty.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (!tty || !tty->driver_data ) {	   	CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n");			return -ENODEV; 	}	cpc_tty = (st_cpc_tty_area *) tty->driver_data; 	if (set & TIOCM_RTS)		cpc_tty_signal_on(cpc_tty->pc300dev, CTL_RTS);	if (set & TIOCM_DTR)		cpc_tty_signal_on(cpc_tty->pc300dev, CTL_DTR);	if (clear & TIOCM_RTS)		cpc_tty_signal_off(cpc_tty->pc300dev, CTL_RTS);	if (clear & TIOCM_DTR)		cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR);	return 0;}static int pc300_tiocmget(struct tty_struct *tty, struct file *file){	unsigned int result;	unsigned char status;	unsigned long flags;	st_cpc_tty_area  *cpc_tty = (st_cpc_tty_area *) tty->driver_data;	pc300dev_t *pc300dev = cpc_tty->pc300dev;	pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan;	pc300_t *card = (pc300_t *) pc300chan->card;	int ch = pc300chan->channel;	cpc_tty = (st_cpc_tty_area *) tty->driver_data;	CPC_TTY_DBG("%s-tty: tiocmget\n",		((struct net_device*)(pc300dev->hdlc))->name);	CPC_TTY_LOCK(card, flags);	status = cpc_readb(card->hw.scabase+M_REG(CTL,ch));	CPC_TTY_UNLOCK(card,flags);	result = ((status & CTL_DTR) ? TIOCM_DTR : 0) |		 ((status & CTL_RTS) ? TIOCM_RTS : 0);	return result;}/* * PC300 TTY Flush Buffer routine * * This routine resets the transmission buffer  */static void cpc_tty_flush_buffer(struct tty_struct *tty){ 	st_cpc_tty_area    *cpc_tty; 		if (!tty || !tty->driver_data ) {	   	CPC_TTY_DBG("hdlcX-tty: no TTY to flush buffer\n");			return; 	}	cpc_tty = (st_cpc_tty_area *) tty->driver_data; 	if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { 		CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);		return; 	}	CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name);	tty_wakeup(tty);		return; } /* * PC300 TTY Hangup routine * * This routine is called by the tty driver to hangup the interface  * o clear DTR signal */static void cpc_tty_hangup(struct tty_struct *tty){ 	st_cpc_tty_area    *cpc_tty; 	int res;	if (!tty || !tty->driver_data ) {		CPC_TTY_DBG("hdlcX-tty: no TTY to hangup\n");			return ; 	}	cpc_tty = (st_cpc_tty_area *) tty->driver_data; 	if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) {		CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);		return ;	}	if (!serial_drv.refcount && cpc_tty_unreg_flag) {		cpc_tty_unreg_flag = 0;		CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name);		if ((res=tty_unregister_driver(&serial_drv))) { 			CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",							cpc_tty->name,res);		}	}	cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR);}/* * PC300 TTY RX work routine * This routine treats RX work * o verify read buffer * o call the line disc. read * o free memory */static void cpc_tty_rx_work(void * data){	unsigned long port;	int i, j;	st_cpc_tty_area *cpc_tty; 	volatile st_cpc_rx_buf *buf;	char flags=0,flg_rx=1; 	struct tty_ldisc *ld;	if (cpc_tty_cnt == 0) return;		for (i=0; (i < 4) && flg_rx ; i++) {		flg_rx = 0;		port = (unsigned long)data;		for (j=0; j < CPC_TTY_NPORTS; j++) {			cpc_tty = &cpc_tty_area[port];					if ((buf=cpc_tty->buf_rx.first) != 0) {				if (cpc_tty->tty) {					ld = tty_ldisc_ref(cpc_tty->tty);					if (ld) {						if (ld->receive_buf) {							CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name);							ld->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size);						}						tty_ldisc_deref(ld);					}				}					cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next;				kfree(buf);				buf = cpc_tty->buf_rx.first;				flg_rx = 1;			}			if (++port == CPC_TTY_NPORTS) port = 0;		}	}} /* * PC300 TTY RX work routine * * This routine treats RX interrupt.  * o read all frames in card * o verify the frame size * o read the frame in rx buffer */static void cpc_tty_rx_disc_frame(pc300ch_t *pc300chan){	volatile pcsca_bd_t __iomem * ptdescr; 	volatile unsigned char status; 	pc300_t *card = (pc300_t *)pc300chan->card; 	int ch = pc300chan->channel; 	/* dma buf read */ 	ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + 				RX_BD_ADDR(ch, pc300chan->rx_first_bd)); 	while (pc300chan->rx_first_bd != pc300chan->rx_last_bd) { 		status = cpc_readb(&ptdescr->status); 		cpc_writeb(&ptdescr->status, 0); 		cpc_writeb(&ptdescr->len, 0); 		pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) & 					(N_DMA_RX_BUF - 1); 		if (status & DST_EOM) { 			break; /* end of message */		}		ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + cpc_readl(&ptdescr->next)); 	}}void cpc_tty_receive(pc300dev_t *pc300dev){	st_cpc_tty_area *cpc_tty; 	pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; 	pc300_t *card = (pc300_t *)pc300chan->card; 	int ch = pc300chan->channel; 	volatile pcsca_bd_t  __iomem * ptdescr; 	struct net_device_stats *stats = hdlc_stats(pc300dev->dev);	int rx_len, rx_aux; 	volatile unsigned char status; 	unsigned short first_bd = pc300chan->rx_first_bd;	st_cpc_rx_buf *new = NULL;	unsigned char dsr_rx;	if (pc300dev->cpc_tty == NULL) { 		return; 	}	dsr_rx = cpc_readb(card->hw.scabase + DSR_RX(ch));	cpc_tty = (st_cpc_tty_area *)pc300dev->cpc_tty; 	while (1) { 		rx_len = 0;		ptdescr = (pcsca_bd_t  __iomem *)(card->hw.rambase + RX_BD_ADDR(ch, first_bd));		while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {			rx_len += cpc_readw(&ptdescr->len);			first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1);			if (status & DST_EOM) {				break;			}			ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase+cpc_readl(&ptdescr->next));		}					if (!rx_len) { 			if (dsr_rx & DSR_BOF) {				/* update EDA */ 				cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), 						RX_BD_ADDR(ch, pc300chan->rx_last_bd)); 			}			kfree(new);			return; 		}				if (rx_len > CPC_TTY_MAX_MTU) { 			/* Free RX descriptors */ 			CPC_TTY_DBG("%s: frame size is invalid.\n",cpc_tty->name);			stats->rx_errors++; 			stats->rx_frame_errors++; 			cpc_tty_rx_disc_frame(pc300chan);			continue;		} 				new = (st_cpc_rx_buf *)kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC);		if (new == 0) {			cpc_tty_rx_disc_frame(pc300chan);			continue;		}				/* dma buf read */ 		ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + 				RX_BD_ADDR(ch, pc300chan->rx_first_bd)); 		rx_len = 0;	/* counter frame size */				while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {			rx_aux = cpc_readw(&ptdescr->len);			if ((status & (DST_OVR | DST_CRC | DST_RBIT |  DST_SHRT | DST_ABT))				|| (rx_aux > BD_DEF_LEN)) {				CPC_TTY_DBG("%s: reception error\n", cpc_tty->name);				stats->rx_errors++; 				if (status & DST_OVR) { 					stats->rx_fifo_errors++; 				}				if (status & DST_CRC) { 					stats->rx_crc_errors++; 				}				if ((status & (DST_RBIT | DST_SHRT | DST_ABT)) ||					(rx_aux > BD_DEF_LEN))	{ 					stats->rx_frame_errors++; 				} 				/* discard remainig descriptors used by the bad frame */ 				CPC_TTY_DBG("%s: reception error - discard descriptors",						cpc_tty->name);				cpc_tty_rx_disc_frame(pc300chan);				rx_len = 0;				kfree(new);				new = NULL;				break; /* read next frame - while(1) */			}			if (cpc_tty->state != CPC_TTY_ST_OPEN) {				/* Free RX descriptors */ 				cpc_tty_rx_disc_frame(pc300chan);				stats->rx_dropped++; 				rx_len = 0; 				kfree(new);				new = NULL;				break; /* read next frame - while(1) */			}			/* read the segment of the frame */			if (rx_aux != 0) {				memcpy_fromio((new->data + rx_len), 					(void __iomem *)(card->hw.rambase + 					 cpc_readl(&ptdescr->ptbuf)), rx_aux);				rx_len += rx_aux; 			}			cpc_writeb(&ptdescr->status,0); 			cpc_writeb(&ptdescr->len, 0); 			pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) & 					(N_DMA_RX_BUF -1); 			if (status & DST_EOM)break;						ptdescr = (pcsca_bd_t __iomem *) (card->hw.rambase + 					cpc_readl(&ptdescr->next)); 		}		/* update pointer */ 		pc300chan->rx_last_bd = (pc300chan->rx_first_bd - 1) & 					(N_DMA_RX_BUF - 1) ; 		if (!(dsr_rx & DSR_BOF)) {			/* update EDA */ 			cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), 					RX_BD_ADDR(ch, pc300chan->rx_last_bd)); 		}		if (rx_len != 0) { 			stats->rx_bytes += rx_len; 					if (pc300dev->trace_on) { 				cpc_tty_trace(pc300dev, new->data,rx_len, 'R'); 			} 			new->size = rx_len;			new->next = NULL;			if (cpc_tty->buf_rx.first == 0) {				cpc_tty->buf_rx.first = new;				cpc_tty->buf_rx.last = new;			} else {				cpc_tty->buf_rx.last->next = new;				cpc_tty->buf_rx.last = new;			}			schedule_work(&(cpc_tty->tty_rx_work));			stats->rx_packets++;		}	} } /* * PC300 TTY TX work routine *  * This routine treats TX interrupt.  * o if need call line discipline wakeup * o call wake_up_interruptible */static void cpc_tty_tx_work(void *data){	st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *) data; 	struct tty_struct *tty; 	CPC_TTY_DBG("%s: cpc_tty_tx_work init\n",cpc_tty->name);		if ((tty = cpc_tty->tty) == 0) { 		CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name);		return; 	}	tty_wakeup(tty);}/* * PC300 TTY send to card routine *  * This routine send data to card.  * o clear descriptors * o write data to DMA buffers * o start the transmission */static int cpc_tty_send_to_card(pc300dev_t *dev,void* buf, int len){	pc300ch_t *chan = (pc300ch_t *)dev->chan; 	pc300_t *card = (pc300_t *)chan->card; 	int ch = chan->channel; 	struct net_device_stats *stats = hdlc_stats(dev->dev);	unsigned long flags; 	volatile pcsca_bd_t __iomem *ptdescr; 	int i, nchar;	int tosend = len;	int nbuf = ((len - 1)/BD_DEF_LEN) + 1;	unsigned char *pdata=buf;	CPC_TTY_DBG("%s:cpc_tty_send_to_cars len=%i", 			(st_cpc_tty_area *)dev->cpc_tty->name,len);		if (nbuf >= card->chan[ch].nfree_tx_bd) {		return 1;	}		/* write buffer to DMA buffers */ 	CPC_TTY_DBG("%s: call dma_buf_write\n",			(st_cpc_tty_area *)dev->cpc_tty->name);		for (i = 0 ; i < nbuf ; i++) {		ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + 			TX_BD_ADDR(ch, card->chan[ch].tx_next_bd));		nchar = (BD_DEF_LEN > tosend) ? tosend : BD_DEF_LEN;		if (cpc_readb(&ptdescr->status) & DST_OSB) {			memcpy_toio((void __iomem *)(card->hw.rambase + 				cpc_readl(&ptdescr->ptbuf)), 				&pdata[len - tosend], 				nchar);			card->chan[ch].nfree_tx_bd--;			if ((i + 1) == nbuf) {				/* This must be the last BD to be used */				cpc_writeb(&ptdescr->status, DST_EOM);			} else {				cpc_writeb(&ptdescr->status, 0);			}			cpc_writew(&ptdescr->len, nchar);		} else {			CPC_TTY_DBG("%s: error in dma_buf_write\n",					(st_cpc_tty_area *)dev->cpc_tty->name);				stats->tx_dropped++;			return 1; 		}		tosend -= nchar;		card->chan[ch].tx_next_bd = 			(card->chan[ch].tx_next_bd + 1) & (N_DMA_TX_BUF - 1);	}	if (dev->trace_on) { 		cpc_tty_trace(dev, buf, len,'T'); 	}	/* start transmission */ 	CPC_TTY_DBG("%s: start transmission\n",		(st_cpc_tty_area *)dev->cpc_tty->name);			CPC_TTY_LOCK(card, flags); 	cpc_writeb(card->hw.scabase + DTX_REG(EDAL, ch), 			TX_BD_ADDR(ch, chan->tx_next_bd)); 	cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_ENA); 	cpc_writeb(card->hw.scabase + DSR_TX(ch), DSR_DE); 	if (card->hw.type == PC300_TE) { 		cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, 			cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) |			(CPLD_REG2_FALC_LED1 << (2 * ch))); 	}	CPC_TTY_UNLOCK(card, flags); 	return 0; } /* *	PC300 TTY trace routine * *  This routine send trace of connection to application.  *  o clear descriptors *  o write data to DMA buffers *  o start the transmission */static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx){	struct sk_buff *skb; 	if ((skb = dev_alloc_skb(10 + len)) == NULL) { 		/* out of memory */ 		CPC_TTY_DBG("%s: tty_trace - out of memory\n", dev->dev->name);		return; 	}	skb_put (skb, 10 + len); 	skb->dev = dev->dev; 	skb->protocol = htons(ETH_P_CUST); 	skb->mac.raw = skb->data; 	skb->pkt_type = PACKET_HOST; 	skb->len = 10 + len; 	memcpy(skb->data,dev->dev->name,5);	skb->data[5] = '['; 	skb->data[6] = rxtx; 	skb->data[7] = ']'; 	skb->data[8] = ':'; 	skb->data[9] = ' '; 	memcpy(&skb->data[10], buf, len); 	netif_rx(skb); } 	/* *	PC300 TTY unregister service routine * *	This routine unregister one interface.  */void cpc_tty_unregister_service(pc300dev_t *pc300dev){	st_cpc_tty_area *cpc_tty; 	ulong flags;	int res;	if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == 0) { 		CPC_TTY_DBG("%s: interface is not TTY\n", pc300dev->dev->name);		return; 	}	CPC_TTY_DBG("%s: cpc_tty_unregister_service", cpc_tty->name);	if (cpc_tty->pc300dev != pc300dev) { 		CPC_TTY_DBG("%s: invalid tty ptr=%s\n", 		pc300dev->dev->name, cpc_tty->name);		return; 	}	if (--cpc_tty_cnt == 0) { 		if (serial_drv.refcount) {			CPC_TTY_DBG("%s: unregister is not possible, refcount=%d",							cpc_tty->name, serial_drv.refcount);			cpc_tty_cnt++;			cpc_tty_unreg_flag = 1;			return;		} else { 			CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name);			if ((res=tty_unregister_driver(&serial_drv))) { 				CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",								cpc_tty->name,res);			}		}	}	CPC_TTY_LOCK(pc300dev->chan->card,flags);	cpc_tty->tty = NULL; 	CPC_TTY_UNLOCK(pc300dev->chan->card, flags);	cpc_tty->tty_minor = 0; 	cpc_tty->state = CPC_TTY_ST_IDLE; } /* * PC300 TTY trigger poll routine * This routine is called by pc300driver to treats Tx interrupt.  */void cpc_tty_trigger_poll(pc300dev_t *pc300dev){	st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *)pc300dev->cpc_tty; 	if (!cpc_tty) {		return;	}	schedule_work(&(cpc_tty->tty_tx_work)); } /* * PC300 TTY reset var routine * This routine is called by pc300driver to init the TTY area.  */void cpc_tty_reset_var(void){	int i ; 	CPC_TTY_DBG("hdlcX-tty: reset variables\n");	/* reset  the tty_driver structure - serial_drv */ 	memset(&serial_drv, 0, sizeof(struct tty_driver));	for (i=0; i < CPC_TTY_NPORTS; i++){		memset(&cpc_tty_area[i],0, sizeof(st_cpc_tty_area)); 	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -