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

📄 serial.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 5 页
字号:
	queue_task(&info->tqueue, &tq_serial);	mark_bh(SERIAL_BH);}/* The output DMA channel is free - use it to send as many chars as possible * NOTES: *   We don't pay attention to info->x_char, which means if the TTY wants to *   use XON/XOFF it will set info->x_char but we won't send any X char! *  *   To implement this, we'd just start a DMA send of 1 byte pointing at a *   buffer containing the X char, and skip updating xmit. We'd also have to *   check if the last sent char was the X char when we enter this function *   the next time, to avoid updating xmit with the sent X value. */static void transmit_chars(struct e100_serial *info){	unsigned int c, sentl;	struct etrax_dma_descr *descr;#ifdef CONFIG_SVINTO_SIM	/* This will output too little if tail is not 0 always since	 * we don't reloop to send the other part. Anyway this SHOULD be a	 * no-op - transmit_chars would never really be called during sim	 * since rs_write does not write into the xmit buffer then.	 */	if (info->xmit.tail)		printk("Error in serial.c:transmit_chars(), tail!=0\n");	if (info->xmit.head != info->xmit.tail) {		SIMCOUT(info->xmit.buf + info->xmit.tail,			CIRC_CNT(info->xmit.head,				 info->xmit.tail,				 SERIAL_XMIT_SIZE));		info->xmit.head = info->xmit.tail;  /* move back head */		info->tr_running = 0;	}	return;#endif	/* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */	*info->oclrintradr =		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);#ifdef SERIAL_DEBUG_INTR	if (info->line == SERIAL_DEBUG_LINE)		printk("tc\n");#endif	if (!info->tr_running) {		/* weirdo... we shouldn't get here! */		printk("Achtung: transmit_chars with !tr_running\n");		return;	}	descr = &info->tr_descr;	/* first get the amount of bytes sent during the last DMA transfer,	   and update xmit accordingly */	/* if the stop bit was not set, all data has been sent */	if (!(descr->status & d_stop)) {		sentl = descr->sw_len;	} else 		/* otherwise we find the amount of data sent here */		sentl = descr->hw_len;	/* update stats */	info->icount.tx += sentl;	/* update xmit buffer */	info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1);	/* if there is only a few chars left in the buf, wake up the blocked	   write if any */	if (CIRC_CNT(info->xmit.head,		     info->xmit.tail,		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);	/* find out the largest amount of consecutive bytes we want to send now */	c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);	if (c <= 0) {		/* our job here is done, don't schedule any new DMA transfer */		info->tr_running = 0;#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)		if (info->rs485.enabled) {			/* Set a short timer to toggle RTS */			start_one_shot_timer(&fast_timers_rs485[info->line],			                     rs485_toggle_rts_timer_function,			                     (unsigned long)info,			                     info->char_time_usec*2,			                     "RS-485");		}#endif /* RS485 */		return;	}	/* ok we can schedule a dma send of c chars starting at info->xmit.tail */	/* set up the descriptor correctly for output */	descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */	descr->sw_len = c;	descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail);	descr->status = 0;	*info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */	*info->ocmdadr = 1;       /* dma command start -> R_DMAx_CMD */		/* DMA is now running (hopefully) */} /* transmit_chars */static void start_transmit(struct e100_serial *info){#if 0	if (info->line == SERIAL_DEBUG_LINE)		printk("x\n");#endif	info->tr_descr.sw_len = 0;	info->tr_descr.hw_len = 0;	info->tr_descr.status = 0;	info->tr_running = 1;	transmit_chars(info);} /* start_transmit */#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMERstatic int serial_fast_timer_started = 0;static int serial_fast_timer_expired = 0;static void flush_timeout_function(unsigned long data);#define START_FLUSH_FAST_TIMER(info, string) {\  unsigned long timer_flags; \  save_flags(timer_flags); \  cli(); \  if (fast_timers[info->line].function == NULL) { \    serial_fast_timer_started++; \    TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \    TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \    start_one_shot_timer(&fast_timers[info->line], \                         flush_timeout_function, \                         (unsigned long)info, \                         info->char_time_usec*4, \                         string); \  } \  else { \    TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \  } \  restore_flags(timer_flags); \}#else#define START_FLUSH_FAST_TIMER(info, string)#endifstatic struct etrax_recv_buffer *alloc_recv_buffer(unsigned int size){	struct etrax_recv_buffer *buffer;	if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))		return NULL;	buffer->next = NULL;	buffer->length = 0;	buffer->error = TTY_NORMAL;	return buffer;}static voidappend_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer){	unsigned long flags;	save_flags(flags);	cli();	if (!info->first_recv_buffer)		info->first_recv_buffer = buffer;	else		info->last_recv_buffer->next = buffer;	info->last_recv_buffer = buffer;	info->recv_cnt += buffer->length;	if (info->recv_cnt > info->max_recv_cnt)		info->max_recv_cnt = info->recv_cnt;	restore_flags(flags);}static intadd_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag){	struct etrax_recv_buffer *buffer;	if (!(buffer = alloc_recv_buffer(4)))		return 0;	buffer->length = 1;	buffer->error = flag;	buffer->buffer[0] = data;		append_recv_buffer(info, buffer);	info->icount.rx++;	return 1;}extern _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 */

⌨️ 快捷键说明

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