📄 serial.c
字号:
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 + -