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

📄 serial.c

📁 该文件是rt_linux
💻 C
📖 第 1 页 / 共 5 页
字号:
	buffer->length = 1;	buffer->error = flag;	buffer->buffer[0] = data;		append_recv_buffer(info, buffer);	info->icount.rx++;	return 1;}static _INLINE_ unsigned inthandle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl){	struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;	if (info->recv_cnt + recvl > 65536) {		printk(__FUNCTION__ ": Too much pending incoming serial data! Dropping %u bytes.\n", recvl);		return 0;	}	buffer->length = recvl;	if (info->errorcode == ERRCODE_SET_BREAK)		buffer->error = TTY_BREAK;	info->errorcode = 0;	append_recv_buffer(info, buffer);	if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))		panic(__FUNCTION__ ": Failed to allocate memory for receive buffer!\n");	descr->buf = virt_to_phys(buffer->buffer);		return recvl;}static _INLINE_ unsigned inthandle_all_descr_data(struct e100_serial *info){	struct etrax_dma_descr *descr;	unsigned int recvl;	unsigned int ret = 0;	while (1)	{		descr = &info->rec_descr[info->cur_rec_descr];		if (descr == phys_to_virt(*info->idescradr))			break;		if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)			info->cur_rec_descr = 0;			/* find out how many bytes were read */		/* if the eop bit was not set, all data has been received */		if (!(descr->status & d_eop)) {			recvl = descr->sw_len;		} else {			/* otherwise we find the amount of data received here */			recvl = descr->hw_len;		}		/* Reset the status information */		descr->status = 0;		DEBUG_LOG(info->line, "recvl %lu\n", recvl);		/* update stats */		info->icount.rx += recvl;		ret += handle_descr_data(info, descr, recvl);	}	return ret;}static _INLINE_ void receive_chars(struct e100_serial *info){	struct tty_struct *tty;	unsigned char rstat;#ifdef CONFIG_SVINTO_SIM	/* No receive in the simulator.  Will probably be when the rest of	 * the serial interface works, and this piece will just be removed.	 */	return;#endif	/* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */	*info->iclrintradr =		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);	tty = info->tty;	if (!tty) /* Something wrong... */		return;#ifdef SERIAL_HANDLE_EARLY_ERRORS	e100_enable_serial_data_irq(info);#endif		if (info->errorcode == ERRCODE_INSERT_BREAK)		add_char_and_flag(info, '\0', TTY_BREAK);	handle_all_descr_data(info);	/* Read the status register to detect errors */	rstat = info->port[REG_STATUS];	if (rstat & SER_ERROR_MASK) {		/* If we got an error, we must reset it by reading the		 * data_in field		 */		unsigned char data = info->port[REG_DATA];		PROCSTAT(ser_stat[info->line].errors_cnt++);		DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",			  ((rstat & SER_ERROR_MASK) << 8) | data);		if (rstat & SER_PAR_ERR_MASK)			add_char_and_flag(info, data, TTY_PARITY);		else if (rstat & SER_OVERRUN_MASK)			add_char_and_flag(info, data, TTY_OVERRUN);		else if (rstat & SER_FRAMING_ERR_MASK)			add_char_and_flag(info, data, TTY_FRAME);	}	START_FLUSH_FAST_TIMER(info, "receive_chars");	/* Restart the receiving DMA */	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);}static _INLINE_ intstart_recv_dma(struct e100_serial *info){	struct etrax_dma_descr *descr = info->rec_descr;	struct etrax_recv_buffer *buffer;        int i;	/* Set up the receiving descriptors */	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {		if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))			panic(__FUNCTION__ ": Failed to allocate memory for receive buffer!\n");		descr[i].ctrl = d_int;		descr[i].buf = virt_to_phys(buffer->buffer);		descr[i].sw_len = SERIAL_DESCR_BUF_SIZE;		descr[i].hw_len = 0;		descr[i].status = 0;		descr[i].next = virt_to_phys(&descr[i+1]);	}	/* Link the last descriptor to the first */	descr[i-1].next = virt_to_phys(&descr[0]);	/* Start with the first descriptor in the list */	info->cur_rec_descr = 0;	/* Start the DMA */	*info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]);	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);	/* Input DMA should be running now */	return 1;}static void start_receive(struct e100_serial *info){#ifdef CONFIG_SVINTO_SIM	/* No receive in the simulator.  Will probably be when the rest of	 * the serial interface works, and this piece will just be removed.	 */	return;#endif	/* reset the input dma channel to be sure it works */	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);	while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==	       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));	info->tty->flip.count = 0;	start_recv_dma(info);	#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST	start_flush_timer();#endif}static _INLINE_ void status_handle(struct e100_serial *info, unsigned short status){}/* the bits in the MASK2 register are laid out like this:   DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR   where I is the input channel and O is the output channel for the port.   info->irq is the bit number for the DMAO_DESCR so to check the others we   shift info->irq to the left.*//* dma output channel interrupt handler   this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or   DMA8(ser1) when they have finished a descriptor with the intr flag set.*/static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct e100_serial *info;	unsigned long ireg;	int i;	#ifdef CONFIG_SVINTO_SIM	/* No receive in the simulator.  Will probably be when the rest of	 * the serial interface works, and this piece will just be removed.	 */	{		const char *s = "What? tr_interrupt in simulator??\n";		SIMCOUT(s,strlen(s));	}	return;#endif		/* find out the line that caused this irq and get it from rs_table */		ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */		for (i = 0; i < NR_PORTS; i++) {		info = rs_table + i;		if (!info->uses_dma) 			continue; 		/* check for dma_descr (don't need to check for dma_eop in output dma for serial */		if (ireg & info->irq) {  			/* we can send a new dma bunch. make it so. */			DEBUG_LOG(info->line, "tr_interrupt %i\n", i);			/* Read jiffies_usec first, 			 * we want this time to be as late as possible			 */ 			PROCSTAT(ser_stat[info->line].tx_dma_ints++);			info->last_tx_active_usec = GET_JIFFIES_USEC();			info->last_tx_active = jiffies;			transmit_chars(info);		}				/* FIXME: here we should really check for a change in the		   status lines and if so call status_handle(info) */	}}/* dma input channel interrupt handler */static void rec_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct e100_serial *info;	unsigned long ireg;	int i;#ifdef CONFIG_SVINTO_SIM	/* No receive in the simulator.  Will probably be when the rest of	 * the serial interface works, and this piece will just be removed.	 */	{		const char *s = "What? rec_interrupt in simulator??\n";		SIMCOUT(s,strlen(s));	}	return;#endif		/* find out the line that caused this irq and get it from rs_table */		ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */		for (i = 0; i < NR_PORTS; i++) {		info = rs_table + i;		if (!info->uses_dma) 			continue; 		/* check for both dma_eop and dma_descr for the input dma channel */		if (ireg & ((info->irq << 2) | (info->irq << 3))) {			/* we have received something */			receive_chars(info);		}				/* FIXME: here we should really check for a change in the		   status lines and if so call status_handle(info) */	}}static _INLINE_ intforce_eop_if_needed(struct e100_serial *info){	/* We check data_avail bit to determine if data has 	 * arrived since last time	 */ 	unsigned char rstat = info->port[REG_STATUS];	/* error or datavail? */	if (rstat & SER_ERROR_MASK) { 		/* Some error has occurred. If there has been valid data, an		 * EOP interrupt will be made automatically. If no data, the		 * normal ser_interrupt should be enabled and handle it.		 * So do nothing!		 */		DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n",		          rstat | (info->line << 8));		return 0;	}	if (rstat & SER_DATA_AVAIL_MASK) { 		/* Ok data, no error, count it */		TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n",		          rstat | (info->line << 8)));		/* Read data to clear status flags */		(void)info->port[REG_DATA];		info->forced_eop = 0;		START_FLUSH_FAST_TIMER(info, "magic");		return 0;	}	/* hit the timeout, force an EOP for the input	 * dma channel if we haven't already	 */	if (!info->forced_eop) {		info->forced_eop = 1;		PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);		DEBUG_LOG(info->line, "timeout EOP %i\n", info->line);		FORCE_EOP(info);	}	return 1;}static _INLINE_ voidflush_to_flip_buffer(struct e100_serial *info){	struct tty_struct *tty = info->tty;	struct etrax_recv_buffer *buffer;	unsigned int length;	unsigned long flags;	if (!info->first_recv_buffer)		return;	save_flags(flags);	cli();	length = tty->flip.count;	while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) {		unsigned int count = buffer->length;		if (length + count > TTY_FLIPBUF_SIZE)			count = TTY_FLIPBUF_SIZE - length;		memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count);		memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count);		tty->flip.flag_buf_ptr[length] = buffer->error;		length += count;		info->recv_cnt -= count;		if (count == buffer->length) {			info->first_recv_buffer = buffer->next;			kfree(buffer);		} else {			buffer->length -= count;			memmove(buffer->buffer, buffer->buffer + count, buffer->length);			buffer->error = TTY_NORMAL;		}	}	if (!info->first_recv_buffer)		info->last_recv_buffer = NULL;	tty->flip.count = length;	restore_flags(flags);#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,66)	/* this includes a check for low-latency */	tty_flip_buffer_push(tty);#else	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);#endif}static _INLINE_ voidcheck_flush_timeout(struct e100_serial *info){	force_eop_if_needed(info);	flush_to_flip_buffer(info);	if (info->first_recv_buffer)		START_FLUSH_FAST_TIMER(info, "flip");}#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMERstatic void flush_timeout_function(unsigned long data){	struct e100_serial *info = (struct e100_serial *)data;	fast_timers[info->line].function = NULL;	serial_fast_timer_expired++;	TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line));	TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired));	check_flush_timeout(info);}#elif defined(CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST)static void timeout_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct e100_serial *info;	int i;	#ifdef CONFIG_SVINTO_SIM	/* No receive in the simulator.  Will probably be when the rest of	 * the serial interface works, and this piece will just be removed.	 */	{		const char *s = "What? timeout_interrupt in simulator??\n";		SIMCOUT(s,strlen(s));	}	return;#endif	/* acknowledge the timer1 irq */	*R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr);	PROCSTAT(fast_timer_ints++);		for (i = 0; i < NR_PORTS; i++) {		info = rs_table + i;		if (info->uses_dma) 

⌨️ 快捷键说明

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