📄 synclink_gt.c
字号:
info->rbuf_index = 0; free_rbufs(info, end, end); if (++end == info->rbuf_count) end = 0; /* if entire list searched then no frame available */ if (end == start) break; } if (tty && chars) tty_flip_buffer_push(tty);}/* * return next bottom half action to perform */static int bh_action(struct slgt_info *info){ unsigned long flags; int rc; spin_lock_irqsave(&info->lock,flags); if (info->pending_bh & BH_RECEIVE) { info->pending_bh &= ~BH_RECEIVE; rc = BH_RECEIVE; } else if (info->pending_bh & BH_TRANSMIT) { info->pending_bh &= ~BH_TRANSMIT; rc = BH_TRANSMIT; } else if (info->pending_bh & BH_STATUS) { info->pending_bh &= ~BH_STATUS; rc = BH_STATUS; } else { /* Mark BH routine as complete */ info->bh_running = 0; info->bh_requested = 0; rc = 0; } spin_unlock_irqrestore(&info->lock,flags); return rc;}/* * perform bottom half processing */static void bh_handler(struct work_struct *work){ struct slgt_info *info = container_of(work, struct slgt_info, task); int action; if (!info) return; info->bh_running = 1; while((action = bh_action(info))) { switch (action) { case BH_RECEIVE: DBGBH(("%s bh receive\n", info->device_name)); switch(info->params.mode) { case MGSL_MODE_ASYNC: rx_async(info); break; case MGSL_MODE_HDLC: while(rx_get_frame(info)); break; case MGSL_MODE_RAW: case MGSL_MODE_MONOSYNC: case MGSL_MODE_BISYNC: while(rx_get_buf(info)); break; } /* restart receiver if rx DMA buffers exhausted */ if (info->rx_restart) rx_start(info); break; case BH_TRANSMIT: bh_transmit(info); break; case BH_STATUS: DBGBH(("%s bh status\n", info->device_name)); info->ri_chkcount = 0; info->dsr_chkcount = 0; info->dcd_chkcount = 0; info->cts_chkcount = 0; break; default: DBGBH(("%s unknown action\n", info->device_name)); break; } } DBGBH(("%s bh_handler exit\n", info->device_name));}static void bh_transmit(struct slgt_info *info){ struct tty_struct *tty = info->tty; DBGBH(("%s bh_transmit\n", info->device_name)); if (tty) tty_wakeup(tty);}static void dsr_change(struct slgt_info *info){ get_signals(info); DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_DSR); return; } info->icount.dsr++; if (info->signals & SerialSignal_DSR) info->input_signal_events.dsr_up++; else info->input_signal_events.dsr_down++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS;}static void cts_change(struct slgt_info *info){ get_signals(info); DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_CTS); return; } info->icount.cts++; if (info->signals & SerialSignal_CTS) info->input_signal_events.cts_up++; else info->input_signal_events.cts_down++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; if (info->flags & ASYNC_CTS_FLOW) { if (info->tty) { if (info->tty->hw_stopped) { if (info->signals & SerialSignal_CTS) { info->tty->hw_stopped = 0; info->pending_bh |= BH_TRANSMIT; return; } } else { if (!(info->signals & SerialSignal_CTS)) info->tty->hw_stopped = 1; } } }}static void dcd_change(struct slgt_info *info){ get_signals(info); DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_DCD); return; } info->icount.dcd++; if (info->signals & SerialSignal_DCD) { info->input_signal_events.dcd_up++; } else { info->input_signal_events.dcd_down++; }#if SYNCLINK_GENERIC_HDLC if (info->netcount) { if (info->signals & SerialSignal_DCD) netif_carrier_on(info->netdev); else netif_carrier_off(info->netdev); }#endif wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; if (info->flags & ASYNC_CHECK_CD) { if (info->signals & SerialSignal_DCD) wake_up_interruptible(&info->open_wait); else { if (info->tty) tty_hangup(info->tty); } }}static void ri_change(struct slgt_info *info){ get_signals(info); DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_RI); return; } info->icount.dcd++; if (info->signals & SerialSignal_RI) { info->input_signal_events.ri_up++; } else { info->input_signal_events.ri_down++; } wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS;}static void isr_serial(struct slgt_info *info){ unsigned short status = rd_reg16(info, SSR); DBGISR(("%s isr_serial status=%04X\n", info->device_name, status)); wr_reg16(info, SSR, status); /* clear pending */ info->irq_occurred = 1; if (info->params.mode == MGSL_MODE_ASYNC) { if (status & IRQ_TXIDLE) { if (info->tx_count) isr_txeom(info, status); } if ((status & IRQ_RXBREAK) && (status & RXBREAK)) { info->icount.brk++; /* process break detection if tty control allows */ if (info->tty) { if (!(status & info->ignore_status_mask)) { if (info->read_status_mask & MASK_BREAK) { tty_insert_flip_char(info->tty, 0, TTY_BREAK); if (info->flags & ASYNC_SAK) do_SAK(info->tty); } } } } } else { if (status & (IRQ_TXIDLE + IRQ_TXUNDER)) isr_txeom(info, status); if (status & IRQ_RXIDLE) { if (status & RXIDLE) info->icount.rxidle++; else info->icount.exithunt++; wake_up_interruptible(&info->event_wait_q); } if (status & IRQ_RXOVER) rx_start(info); } if (status & IRQ_DSR) dsr_change(info); if (status & IRQ_CTS) cts_change(info); if (status & IRQ_DCD) dcd_change(info); if (status & IRQ_RI) ri_change(info);}static void isr_rdma(struct slgt_info *info){ unsigned int status = rd_reg32(info, RDCSR); DBGISR(("%s isr_rdma status=%08x\n", info->device_name, status)); /* RDCSR (rx DMA control/status) * * 31..07 reserved * 06 save status byte to DMA buffer * 05 error * 04 eol (end of list) * 03 eob (end of buffer) * 02 IRQ enable * 01 reset * 00 enable */ wr_reg32(info, RDCSR, status); /* clear pending */ if (status & (BIT5 + BIT4)) { DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name)); info->rx_restart = 1; } info->pending_bh |= BH_RECEIVE;}static void isr_tdma(struct slgt_info *info){ unsigned int status = rd_reg32(info, TDCSR); DBGISR(("%s isr_tdma status=%08x\n", info->device_name, status)); /* TDCSR (tx DMA control/status) * * 31..06 reserved * 05 error * 04 eol (end of list) * 03 eob (end of buffer) * 02 IRQ enable * 01 reset * 00 enable */ wr_reg32(info, TDCSR, status); /* clear pending */ if (status & (BIT5 + BIT4 + BIT3)) { // another transmit buffer has completed // run bottom half to get more send data from user info->pending_bh |= BH_TRANSMIT; }}static void isr_txeom(struct slgt_info *info, unsigned short status){ DBGISR(("%s txeom status=%04x\n", info->device_name, status)); slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); tdma_reset(info); reset_tbufs(info); if (status & IRQ_TXUNDER) { unsigned short val = rd_reg16(info, TCR); wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ wr_reg16(info, TCR, val); /* clear reset bit */ } if (info->tx_active) { if (info->params.mode != MGSL_MODE_ASYNC) { if (status & IRQ_TXUNDER) info->icount.txunder++; else if (status & IRQ_TXIDLE) info->icount.txok++; } info->tx_active = 0; info->tx_count = 0; del_timer(&info->tx_timer); if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) { info->signals &= ~SerialSignal_RTS; info->drop_rts_on_tx_done = 0; set_signals(info); }#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_tx_done(info); else#endif { if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { tx_stop(info); return; } info->pending_bh |= BH_TRANSMIT; } }}static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int state){ struct cond_wait *w, *prev; /* wake processes waiting for specific transitions */ for (w = info->gpio_wait_q, prev = NULL ; w != NULL ; w = w->next) { if (w->data & changed) { w->data = state; wake_up_interruptible(&w->q); if (prev != NULL) prev->next = w->next; else info->gpio_wait_q = w->next; } else prev = w; }}/* interrupt service routine * * irq interrupt number * dev_id device ID supplied during interrupt registration */static irqreturn_t slgt_interrupt(int irq, void *dev_id){ struct slgt_info *info; unsigned int gsr; unsigned int i; DBGISR(("slgt_interrupt irq=%d entry\n", irq)); info = dev_id; if (!info) return IRQ_NONE; spin_lock(&info->lock); while((gsr = rd_reg32(info, GSR) & 0xffffff00)) { DBGISR(("%s gsr=%08x\n", info->device_name, gsr)); info->irq_occurred = 1; for(i=0; i < info->port_count ; i++) { if (info->port_array[i] == NULL) continue; if (gsr & (BIT8 << i)) isr_serial(info->port_array[i]); if (gsr & (BIT16 << (i*2))) isr_rdma(info->port_array[i]); if (gsr & (BIT17 << (i*2))) isr_tdma(info->port_array[i]); } } if (info->gpio_present) { unsigned int state; unsigned int changed; while ((changed = rd_reg32(info, IOSR)) != 0) { DBGISR(("%s iosr=%08x\n", info->device_name, changed)); /* read latched state of GPIO signals */ state = rd_reg32(info, IOVR); /* clear pending GPIO interrupt bits */ wr_reg32(info, IOSR, changed); for (i=0 ; i < info->port_count ; i++) { if (info->port_array[i] != NULL) isr_gpio(info->port_array[i], changed, state); } } } for(i=0; i < info->port_count ; i++) { struct slgt_info *port = info->port_array[i]; if (port && (port->count || port->netcount) && port->pending_bh && !port->bh_running && !port->bh_requested) { DBGISR(("%s bh queued\n", port->device_name)); schedule_work(&port->task); port->bh_requested = 1; } } spin_unlock(&info->lock); DBGISR(("slgt_interrupt irq=%d exit\n", irq)); return IRQ_HANDLED;}static int startup(struct slgt_info *info){ DBGINFO(("%s startup\n", info->device_name)); if (info->flags & ASYNC_INITIALIZED) return 0; if (!info->tx_buf) { info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); if (!info->tx_buf) { DBGERR(("%s can't allocate tx buffer\n", info->device_name)); return -ENOMEM; } } info->pending_bh = 0; memset(&info->icount, 0, sizeof(info->icount)); /* program hardware for current parameters */ change_params(info); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->flags |= ASYNC_INITIALIZED; return 0;}/* *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -