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