static void bcm_uart_do_rx(struct uart_port *port) { struct tty_struct *tty; unsigned int max_count; max_count = 32; tty = port->state->port.tty; do { unsigned int iestat, c, cstat; char flag; iestat = bcm_uart_readl(port, UART_IR_REG); if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) { unsigned int val; val = bcm_uart_readl(port, UART_CTL_REG); val |= UART_CTL_RSTRXFIFO_MASK; bcm_uart_writel(port, val, UART_CTL_REG); port->icount.overrun++; tty_insert_flip_char(tty, 0, TTY_OVERRUN); } if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) break; cstat = c = bcm_uart_readl(port, UART_FIFO_REG); port->icount.rx++; flag = TTY_NORMAL; c &= 0xff; if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) { if (cstat & UART_FIFO_BRKDET_MASK) { port->icount.brk++; if (uart_handle_break(port)) continue; } if (cstat & UART_FIFO_PARERR_MASK) port->icount.parity++; if (cstat & UART_FIFO_FRAMEERR_MASK) port->icount.frame++; cstat &= port->read_status_mask; if (cstat & UART_FIFO_BRKDET_MASK) flag = TTY_BREAK; if (cstat & UART_FIFO_FRAMEERR_MASK) flag = TTY_FRAME; if (cstat & UART_FIFO_PARERR_MASK) flag = TTY_PARITY; } if (uart_handle_sysrq_char(port, c)) continue; if ((cstat & port->ignore_status_mask) == 0) tty_insert_flip_char(tty, c, flag); } while (--max_count); tty_flip_buffer_push(tty); }
static void handle_rx(struct uart_port *port, unsigned int misr) { struct tty_struct *tty = port->state->port.tty; unsigned int sr; int count = 0; struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); /* * Handle overrun. My understanding of the hardware is that overrun * is not tied to the RX buffer, so we handle the case out of band. */ if ((msm_hsl_read(port, UARTDM_SR_ADDR) & UARTDM_SR_OVERRUN_BMSK)) { port->icount.overrun++; tty_insert_flip_char(tty, 0, TTY_OVERRUN); msm_hsl_write(port, RESET_ERROR_STATUS, UARTDM_CR_ADDR); } if (misr & UARTDM_ISR_RXSTALE_BMSK) { count = msm_hsl_read(port, UARTDM_RX_TOTAL_SNAP_ADDR) - msm_hsl_port->old_snap_state; msm_hsl_port->old_snap_state = 0; } else { count = 4 * (msm_hsl_read(port, UARTDM_RFWR_ADDR)); msm_hsl_port->old_snap_state += count; } /* and now the main RX loop */ while (count > 0) { unsigned int c; char flag = TTY_NORMAL; sr = msm_hsl_read(port, UARTDM_SR_ADDR); if ((sr & UARTDM_SR_RXRDY_BMSK) == 0) { msm_hsl_port->old_snap_state -= count; break; } c = msm_hsl_read(port, UARTDM_RF_ADDR); if (sr & UARTDM_SR_RX_BREAK_BMSK) { port->icount.brk++; if (uart_handle_break(port)) continue; } else if (sr & UARTDM_SR_PAR_FRAME_BMSK) { port->icount.frame++; } else { port->icount.rx++; } /* Mask conditions we're ignorning. */ sr &= port->read_status_mask; if (sr & UARTDM_SR_RX_BREAK_BMSK) flag = TTY_BREAK; else if (sr & UARTDM_SR_PAR_FRAME_BMSK) flag = TTY_FRAME; /* TODO: handle sysrq */ /* if (!uart_handle_sysrq_char(port, c)) */ tty_insert_flip_string(tty, (char *) &c, (count > 4) ? 4 : count); count -= 4; } tty_flip_buffer_push(tty); }
/* * Receive characters */ static void cpm_uart_int_rx(struct uart_port *port) { int i; unsigned char ch; u8 *cp; struct tty_struct *tty = port->state->port.tty; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; cbd_t __iomem *bdp; u16 status; unsigned int flg; pr_debug("CPM uart[%d]:RX INT\n", port->line); /* Just loop through the closed BDs and copy the characters into * the buffer. */ bdp = pinfo->rx_cur; for (;;) { #ifdef CONFIG_CONSOLE_POLL if (unlikely(serial_polled)) { serial_polled = 0; return; } #endif /* get status */ status = in_be16(&bdp->cbd_sc); /* If this one is empty, return happy */ if (status & BD_SC_EMPTY) break; /* get number of characters, and check spce in flip-buffer */ i = in_be16(&bdp->cbd_datlen); /* If we have not enough room in tty flip buffer, then we try * later, which will be the next rx-interrupt or a timeout */ if(tty_buffer_request_room(tty, i) < i) { #ifdef CONFIG_DEBUG_PRINTK printk(KERN_WARNING "No room in flip buffer\n"); #else ; #endif return; } /* get pointer */ cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); /* loop through the buffer */ while (i-- > 0) { ch = *cp++; port->icount.rx++; flg = TTY_NORMAL; if (status & (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) goto handle_error; if (uart_handle_sysrq_char(port, ch)) continue; #ifdef CONFIG_CONSOLE_POLL if (unlikely(serial_polled)) { serial_polled = 0; return; } #endif error_return: tty_insert_flip_char(tty, ch, flg); } /* End while (i--) */ /* This BD is ready to be used again. Clear status. get next */ clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID); setbits16(&bdp->cbd_sc, BD_SC_EMPTY); if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = pinfo->rx_bd_base; else bdp++; } /* End for (;;) */ /* Write back buffer pointer */ pinfo->rx_cur = bdp; /* activate BH processing */ tty_flip_buffer_push(tty); return; /* Error processing */ handle_error: /* Statistics */ if (status & BD_SC_BR) port->icount.brk++; if (status & BD_SC_PR) port->icount.parity++; if (status & BD_SC_FR) port->icount.frame++; if (status & BD_SC_OV) port->icount.overrun++; /* Mask out ignored conditions */ status &= port->read_status_mask; /* Handle the remaining ones */ if (status & BD_SC_BR) flg = TTY_BREAK; else if (status & BD_SC_PR) flg = TTY_PARITY; else if (status & BD_SC_FR) flg = TTY_FRAME; /* overrun does not affect the current character ! */ if (status & BD_SC_OV) { ch = 0; flg = TTY_OVERRUN; /* We skip this buffer */ /* CHECK: Is really nothing senseful there */ /* ASSUMPTION: it contains nothing valid */ i = 0; } #ifdef SUPPORT_SYSRQ port->sysrq = 0; #endif goto error_return; }
static void ip3106_rx_chars(struct ip3106_port *sport, struct pt_regs *regs) { struct tty_struct *tty = sport->port.info->tty; unsigned int status, ch, flg, ignored = 0; status = FIFO_TO_SM(serial_in(sport, IP3106_FIFO)) | ISTAT_TO_SM(serial_in(sport, IP3106_ISTAT)); while (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFIFO)) { ch = serial_in(sport, IP3106_FIFO); if (tty->flip.count >= TTY_FLIPBUF_SIZE) goto ignore_char; sport->port.icount.rx++; flg = TTY_NORMAL; /* * note that the error handling code is * out of the main execution path */ if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFE | IP3106_UART_FIFO_RXPAR)) goto handle_error; if (uart_handle_sysrq_char(&sport->port, ch, regs)) goto ignore_char; error_return: tty_insert_flip_char(tty, ch, flg); ignore_char: serial_out(sport, IP3106_LCR, serial_in(sport, IP3106_LCR) | IP3106_UART_LCR_RX_NEXT); status = FIFO_TO_SM(serial_in(sport, IP3106_FIFO)) | ISTAT_TO_SM(serial_in(sport, IP3106_ISTAT)); } out: tty_flip_buffer_push(tty); return; handle_error: if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXPAR)) sport->port.icount.parity++; else if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFE)) sport->port.icount.frame++; if (status & ISTAT_TO_SM(IP3106_UART_INT_RXOVRN)) sport->port.icount.overrun++; if (status & sport->port.ignore_status_mask) { if (++ignored > 100) goto out; goto ignore_char; } // status &= sport->port.read_status_mask; if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXPAR)) flg = TTY_PARITY; else if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFE)) flg = TTY_FRAME; if (status & ISTAT_TO_SM(IP3106_UART_INT_RXOVRN)) { /* * overrun does *not* affect the character * we read from the FIFO */ tty_insert_flip_char(tty, ch, flg); ch = 0; flg = TTY_OVERRUN; } #ifdef SUPPORT_SYSRQ sport->port.sysrq = 0; #endif goto error_return; }
static void receive_chars(struct m68k_serial *info, unsigned short rx) { struct tty_struct *tty = info->tty; m68328_uart *uart = &uart_addr[info->line]; unsigned char ch, flag; /* * This do { } while() loop will get ALL chars out of Rx FIFO */ #ifndef CONFIG_XCOPILOT_BUGS do { #endif ch = GET_FIELD(rx, URX_RXDATA); if(info->is_cons) { if(URX_BREAK & rx) { /* whee, break received */ status_handle(info, rx); return; #ifdef CONFIG_MAGIC_SYSRQ } else if (ch == 0x10) { /* ^P */ show_state(); show_free_areas(); show_buffers(); /* show_net_buffers(); */ return; } else if (ch == 0x12) { /* ^R */ emergency_restart(); return; #endif /* CONFIG_MAGIC_SYSRQ */ } /* It is a 'keyboard interrupt' ;-) */ #ifdef CONFIG_CONSOLE wake_up(&keypress_wait); #endif } if(!tty) goto clear_and_exit; flag = TTY_NORMAL; if(rx & URX_PARITY_ERROR) { flag = TTY_PARITY; status_handle(info, rx); } else if(rx & URX_OVRUN) { flag = TTY_OVERRUN; status_handle(info, rx); } else if(rx & URX_FRAME_ERROR) { flag = TTY_FRAME; status_handle(info, rx); } tty_insert_flip_char(tty, ch, flag); #ifndef CONFIG_XCOPILOT_BUGS } while((rx = uart->urx.w) & URX_DATA_READY); #endif tty_schedule_flip(tty); clear_and_exit: return; }
static bool ntv2_serial_receive(struct ntv2_serial *ntv2_ser) { struct uart_port *port = &ntv2_ser->uart_port; struct tty_port *tport = &port->state->port; u32 valid = NTV2_FLD_MASK(ntv2_kona_fld_serial_rx_valid); u32 overrun = NTV2_FLD_MASK(ntv2_kona_fld_serial_error_overrun); u32 frame = NTV2_FLD_MASK(ntv2_kona_fld_serial_error_frame); u32 parity = NTV2_FLD_MASK(ntv2_kona_fld_serial_error_parity); u32 trigger = NTV2_FLD_MASK(ntv2_kona_fld_serial_rx_trigger); u32 active = NTV2_FLD_MASK(ntv2_kona_fld_serial_rx_active); u32 status; u32 rx = 0; int i; char flag = TTY_NORMAL; status = ntv2_reg_read(ntv2_ser->vid_reg, ntv2_kona_reg_serial_status, ntv2_ser->index); if ((status & (valid | overrun | frame)) == 0) return false; /* gather statistics */ if ((status & valid) != 0) { port->icount.rx++; /* trigger read of uart rx fifo */ ntv2_serial_control(ntv2_ser, 0, trigger); /* read rx data from pci */ for (i = 0; i < 10; i++) { rx = ntv2_reg_read(ntv2_ser->vid_reg, ntv2_kona_reg_serial_rx, ntv2_ser->index); if ((rx & active) == 0) break; } NTV2_MSG_SERIAL_STREAM("%s: uart rx %02x busy %d\n", ntv2_ser->name, (u8)rx, i); if ((status & parity) != 0) port->icount.parity++; } if ((status & overrun) != 0) port->icount.overrun++; if ((status & frame) != 0) port->icount.frame++; /* drop byte with parity error if IGNPAR specificed */ if ((status & port->ignore_status_mask & parity) != 0) status &= ~valid; status &= port->read_status_mask; if ((status & parity) != 0) flag = TTY_PARITY; status &= ~port->ignore_status_mask; if ((status & valid) != 0) tty_insert_flip_char(tport, (u8)rx, flag); if ((status & overrun) != 0) tty_insert_flip_char(tport, 0, TTY_OVERRUN); if ((status & frame) != 0) tty_insert_flip_char(tport, 0, TTY_FRAME); return true; }
/* * Interrupt routine, called from common io layer */ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) { struct raw3215_info *raw; struct raw3215_req *req; struct tty_struct *tty; int cstat, dstat; int count; raw = dev_get_drvdata(&cdev->dev); req = (struct raw3215_req *) intparm; tty = tty_port_tty_get(&raw->port); cstat = irb->scsw.cmd.cstat; dstat = irb->scsw.cmd.dstat; if (cstat != 0) raw3215_next_io(raw, tty); if (dstat & 0x01) { /* we got a unit exception */ dstat &= ~0x01; /* we can ignore it */ } switch (dstat) { case 0x80: if (cstat != 0) break; /* Attention interrupt, someone hit the enter key */ raw3215_mk_read_req(raw); raw3215_next_io(raw, tty); break; case 0x08: case 0x0C: /* Channel end interrupt. */ if ((raw = req->info) == NULL) goto put_tty; /* That shouldn't happen ... */ if (req->type == RAW3215_READ) { /* store residual count, then wait for device end */ req->residual = irb->scsw.cmd.count; } if (dstat == 0x08) break; case 0x04: /* Device end interrupt. */ if ((raw = req->info) == NULL) goto put_tty; /* That shouldn't happen ... */ if (req->type == RAW3215_READ && tty != NULL) { unsigned int cchar; count = 160 - req->residual; EBCASC(raw->inbuf, count); cchar = ctrlchar_handle(raw->inbuf, count, tty); switch (cchar & CTRLCHAR_MASK) { case CTRLCHAR_SYSRQ: break; case CTRLCHAR_CTRL: tty_insert_flip_char(&raw->port, cchar, TTY_NORMAL); tty_flip_buffer_push(&raw->port); break; case CTRLCHAR_NONE: if (count < 2 || (strncmp(raw->inbuf+count-2, "\252n", 2) && strncmp(raw->inbuf+count-2, "^n", 2)) ) { /* add the auto \n */ raw->inbuf[count] = '\n'; count++; } else count -= 2; tty_insert_flip_string(&raw->port, raw->inbuf, count); tty_flip_buffer_push(&raw->port); break; } } else if (req->type == RAW3215_WRITE) { raw->count -= req->len; raw->written -= req->len; } raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); /* check for empty wait */ if (waitqueue_active(&raw->empty_wait) && raw->queued_write == NULL && raw->queued_read == NULL) { wake_up_interruptible(&raw->empty_wait); } raw3215_next_io(raw, tty); break; default: /* Strange interrupt, I'll do my best to clean up */ if (req != NULL && req->type != RAW3215_FREE) { if (req->type == RAW3215_WRITE) { raw->count -= req->len; raw->written -= req->len; } raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); } raw3215_next_io(raw, tty); } put_tty: tty_kref_put(tty); }
/* * Helper Functions. */ static void put_queue(struct vc_data *vc, int ch) { tty_insert_flip_char(&vc->port, ch, 0); tty_schedule_flip(&vc->port); }
static inline void receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs) { struct tty_struct *tty = up->port.info->tty; unsigned int ch, flag; int max_count = 256; do { if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { if (tty->low_latency) tty_flip_buffer_push(tty); /* * If this failed then we will throw away the * bytes but must do so to clear interrupts */ } ch = serial_in(up, UART_RX); flag = TTY_NORMAL; up->port.icount.rx++; if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE))) { /* * For statistics only */ if (*status & UART_LSR_BI) { *status &= ~(UART_LSR_FE | UART_LSR_PE); up->port.icount.brk++; /* * We do the SysRQ and SAK checking * here because otherwise the break * may get masked by ignore_status_mask * or read_status_mask. */ if (uart_handle_break(&up->port)) goto ignore_char; } else if (*status & UART_LSR_PE) up->port.icount.parity++; else if (*status & UART_LSR_FE) up->port.icount.frame++; if (*status & UART_LSR_OE) up->port.icount.overrun++; /* * Mask off conditions which should be ignored. */ *status &= up->port.read_status_mask; #ifdef CONFIG_SERIAL_PXA_CONSOLE if (up->port.line == up->port.cons->index) { /* Recover the break flag from console xmit */ *status |= up->lsr_break_flag; up->lsr_break_flag = 0; } #endif if (*status & UART_LSR_BI) { flag = TTY_BREAK; } else if (*status & UART_LSR_PE) flag = TTY_PARITY; else if (*status & UART_LSR_FE) flag = TTY_FRAME; } if (uart_handle_sysrq_char(&up->port, ch, regs)) goto ignore_char; if ((*status & up->port.ignore_status_mask) == 0) { tty_insert_flip_char(tty, ch, flag); } if ((*status & UART_LSR_OE) && tty->flip.count < TTY_FLIPBUF_SIZE) { /* * Overrun is special, since it's reported * immediately, and doesn't affect the current * character. */ tty_insert_flip_char(tty, 0, TTY_OVERRUN); } ignore_char: *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); tty_flip_buffer_push(tty); }
static void uart00_rx_chars(struct uart_port *port, struct pt_regs *regs) { struct tty_struct *tty = port->info->tty; unsigned int status, ch, rds, flg, ignored = 0; status = UART_GET_RSR(port); while (UART_RX_DATA(status)) { /* * We need to read rds before reading the * character from the fifo */ rds = UART_GET_RDS(port); ch = UART_GET_CHAR(port); port->icount.rx++; if (tty->flip.count >= TTY_FLIPBUF_SIZE) goto ignore_char; flg = TTY_NORMAL; /* * Note that the error handling code is * out of the main execution path */ if (rds & (UART_RDS_BI_MSK |UART_RDS_FE_MSK| UART_RDS_PE_MSK |UART_RDS_PE_MSK)) goto handle_error; if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; error_return: tty_insert_flip_char(tty, ch, flg); ignore_char: status = UART_GET_RSR(port); } out: tty_flip_buffer_push(tty); return; handle_error: if (rds & UART_RDS_BI_MSK) { status &= ~(UART_RDS_FE_MSK | UART_RDS_PE_MSK); port->icount.brk++; if (uart_handle_break(port)) goto ignore_char; } else if (rds & UART_RDS_PE_MSK) port->icount.parity++; else if (rds & UART_RDS_FE_MSK) port->icount.frame++; if (rds & UART_RDS_OE_MSK) port->icount.overrun++; if (rds & port->ignore_status_mask) { if (++ignored > 100) goto out; goto ignore_char; } rds &= port->read_status_mask; if (rds & UART_RDS_BI_MSK) flg = TTY_BREAK; else if (rds & UART_RDS_PE_MSK) flg = TTY_PARITY; else if (rds & UART_RDS_FE_MSK) flg = TTY_FRAME; if (rds & UART_RDS_OE_MSK) { /* * CHECK: does overrun affect the current character? * ASSUMPTION: it does not. */ tty_insert_flip_char(tty, ch, flg); ch = 0; flg = TTY_OVERRUN; } #ifdef SUPPORT_SYSRQ port->sysrq = 0; #endif goto error_return; }
static void qt2_process_read_urb(struct urb *urb) { struct usb_serial *serial; struct qt2_serial_private *serial_priv; struct usb_serial_port *port; struct qt2_port_private *port_priv; bool escapeflag; unsigned char *ch; int i; unsigned char newport; int len = urb->actual_length; if (!len) return; ch = urb->transfer_buffer; serial = urb->context; serial_priv = usb_get_serial_data(serial); port = serial->port[serial_priv->current_port]; port_priv = usb_get_serial_port_data(port); for (i = 0; i < urb->actual_length; i++) { ch = (unsigned char *)urb->transfer_buffer + i; if ((i <= (len - 3)) && (*ch == QT2_CONTROL_BYTE) && (*(ch + 1) == QT2_CONTROL_BYTE)) { escapeflag = false; switch (*(ch + 2)) { case QT2_LINE_STATUS: case QT2_MODEM_STATUS: if (i > (len - 4)) { dev_warn(&port->dev, "%s - status message too short\n", __func__); break; } qt2_process_status(port, ch + 2); i += 3; escapeflag = true; break; case QT2_XMIT_HOLD: if (i > (len - 5)) { dev_warn(&port->dev, "%s - xmit_empty message too short\n", __func__); break; } qt2_process_xmit_empty(port, ch + 3); i += 4; escapeflag = true; break; case QT2_CHANGE_PORT: if (i > (len - 4)) { dev_warn(&port->dev, "%s - change_port message too short\n", __func__); break; } tty_flip_buffer_push(&port->port); newport = *(ch + 3); if (newport > serial->num_ports) { dev_err(&port->dev, "%s - port change to invalid port: %i\n", __func__, newport); break; } serial_priv->current_port = newport; port = serial->port[serial_priv->current_port]; port_priv = usb_get_serial_port_data(port); i += 3; escapeflag = true; break; case QT2_REC_FLUSH: case QT2_XMIT_FLUSH: qt2_process_flush(port, ch + 2); i += 2; escapeflag = true; break; case QT2_CONTROL_ESCAPE: tty_insert_flip_string(&port->port, ch, 2); i += 2; escapeflag = true; break; default: dev_warn(&port->dev, "%s - unsupported command %i\n", __func__, *(ch + 2)); break; } if (escapeflag) continue; } tty_insert_flip_char(&port->port, *ch, TTY_NORMAL); } tty_flip_buffer_push(&port->port); }
static int ipoctal_irq_handler(void *arg) { unsigned int channel; unsigned int block; unsigned char isr; unsigned char sr; unsigned char isrTxRdy, isrRxRdy; unsigned char value; struct ipoctal *ipoctal = (struct ipoctal *) arg; for (channel=0; channel<NR_CHANNELS; channel++) { /* The HW is organized in pair of channels. See which register we need to read from */ block = channel / 2; isr = ipoctal_read_io_reg(ipoctal, &ipoctal->block_regs[block].u.r.isr); sr = ipoctal_read_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.r.sr); if((channel % 2) == 1) { isrTxRdy = isr & ISR_TxRDY_B; isrRxRdy = isr & ISR_RxRDY_FFULL_B; } else { isrTxRdy = isr & ISR_TxRDY_A; isrRxRdy = isr & ISR_RxRDY_FFULL_A; } /* In case of RS-485, change from TX to RX. Half-duplex. */ if ((ipoctal->board_id == IP_OCTAL_485_ID) && (sr & SR_TX_EMPTY) && (ipoctal->nb_bytes[channel] == 0)) { ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, CR_DISABLE_TX); ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, CR_CMD_NEGATE_RTSN); ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, CR_ENABLE_RX); ipoctal->write = 1; wake_up_interruptible(&ipoctal->queue[channel]); } /* RX data */ if (isrRxRdy && (sr & SR_RX_READY) && (ipoctal->chan_status[channel] == CHAN_READ)) { value = ipoctal_read_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.r.rhr); tty_insert_flip_char(ipoctal->tty[channel], value, TTY_NORMAL); tty_flip_buffer_push(ipoctal->tty[channel]); } /* TX of each character */ if (isrTxRdy && (sr & SR_TX_READY) && (ipoctal->chan_status[channel] == CHAN_WRITE)) { unsigned int *pointer_write = &ipoctal->pointer_write[channel]; if(ipoctal->nb_bytes[channel] <= 0) { ipoctal->nb_bytes[channel] = 0; continue; } spin_lock(&ipoctal->lock[channel]); value = ipoctal->buffer[channel][*pointer_write]; ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.thr, value); ipoctal->chan_stats[channel].tx++; ipoctal->count_wr[channel]++; (*pointer_write)++; *pointer_write = *pointer_write % MAX_CHAR; ipoctal->nb_bytes[channel]--; spin_unlock(&ipoctal->lock[channel]); if ((ipoctal->nb_bytes[channel] == 0) && (waitqueue_active(&ipoctal->queue[channel]))){ if (ipoctal->board_id != IP_OCTAL_485_ID) { ipoctal->write = 1; wake_up_interruptible(&ipoctal->queue[channel]); } else { ipoctal->chan_status[channel] = CHAN_OPEN; } } } /* Error: count statistics */ if (sr & SR_ERROR) { ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, CR_CMD_RESET_ERR_STATUS); if (sr & SR_OVERRUN_ERROR){ ipoctal->error_flag[channel] |= UART_OVERRUN; ipoctal->chan_stats[channel].overrun_err++; } if (sr & SR_PARITY_ERROR){ ipoctal->error_flag[channel] |= UART_PARITY; ipoctal->chan_stats[channel].parity_err++; } if (sr & SR_FRAMING_ERROR){ ipoctal->error_flag[channel] |= UART_FRAMING; ipoctal->chan_stats[channel].framing_err++; } if (sr & SR_RECEIVED_BREAK){ ipoctal->error_flag[channel] |= UART_BREAK; ipoctal->chan_stats[channel].rcv_break++; } if (waitqueue_active(&ipoctal->queue[channel])){ ipoctal->chan_status[channel] = CHAN_OPEN; wake_up_interruptible(&ipoctal->queue[channel]); } } } return IRQ_HANDLED; }
/* * read all chars in rx fifo and send them to core */ static void bcm_uart_do_rx(struct uart_port *port) { struct tty_port *tty_port = &port->state->port; unsigned int max_count; /* limit number of char read in interrupt, should not be * higher than fifo size anyway since we're much faster than * serial port */ max_count = 32; do { unsigned int iestat, c, cstat; char flag; /* get overrun/fifo empty information from ier * register */ iestat = bcm_uart_readl(port, UART_IR_REG); if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) { unsigned int val; /* fifo reset is required to clear * interrupt */ val = bcm_uart_readl(port, UART_CTL_REG); val |= UART_CTL_RSTRXFIFO_MASK; bcm_uart_writel(port, val, UART_CTL_REG); port->icount.overrun++; tty_insert_flip_char(tty_port, 0, TTY_OVERRUN); } if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) break; cstat = c = bcm_uart_readl(port, UART_FIFO_REG); port->icount.rx++; flag = TTY_NORMAL; c &= 0xff; if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) { /* do stats first */ if (cstat & UART_FIFO_BRKDET_MASK) { port->icount.brk++; if (uart_handle_break(port)) continue; } if (cstat & UART_FIFO_PARERR_MASK) port->icount.parity++; if (cstat & UART_FIFO_FRAMEERR_MASK) port->icount.frame++; /* update flag wrt read_status_mask */ cstat &= port->read_status_mask; if (cstat & UART_FIFO_BRKDET_MASK) flag = TTY_BREAK; if (cstat & UART_FIFO_FRAMEERR_MASK) flag = TTY_FRAME; if (cstat & UART_FIFO_PARERR_MASK) flag = TTY_PARITY; } if (uart_handle_sysrq_char(port, c)) continue; if ((cstat & port->ignore_status_mask) == 0) tty_insert_flip_char(tty_port, c, flag); } while (--max_count); spin_unlock(&port->lock); tty_flip_buffer_push(tty_port); spin_lock(&port->lock); }
static ssize_t btport_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos) { struct uart_btlinux_port *btlinux_port; struct tty_struct *tty; int nCopy, nRemaining, dataOut; int access = 0; struct bt_diag_context *ctxt = &_context; unsigned int cmd_id = *user_buffer; int xfer; unsigned char *table = NULL; unsigned char tmp; dbg("%s -- %d bytes: %s", __func__, count, user_buffer); btlinux_port = (struct uart_btlinux_port *)file->private_data; if (btlinux_port == NULL) { err("BTLINUXPORT %s - error, can't find device", __func__); return -ENODEV; } /*BT SPP*/ if (btlinux_port->minor == 1) { if (!ctxt->ch) { err("btport_write %s: SMD channel is null\n", __func__); return 0; } else { /* check to verify that the incomign data is good */ access = !access_ok(VERIFY_READ, (void *)user_buffer, count); if (access) { err("BTLINUXPORT %s: buffer access verification failed", __func__); return 0; } if (count == 0) return 0; if (count > 8192) xfer = 8192; else xfer = count; dbg("cmd_id, xfer: %x, %x\n", cmd_id, xfer); /*Send data to DM router*/ if (cmd_id >= 0xfb && cmd_id <= 0xff) { send_to_dmrouter(user_buffer, xfer); return 0; } table = ctxt->id_table; while ((tmp = *table++)) { if (tmp == cmd_id) { dbg("cmd_id in table: %x\n", cmd_id); send_to_dmrouter(user_buffer, xfer); wake_up(&ctxt->read_wq); return 0; } } /*Sent data to ARM9*/ dataOut = smd_write(ctxt->ch, user_buffer, count); return dataOut; } } /*BT DUN*/ if (!btlinux_port->port_opened) { /* err("BTLINUXPORT %s - port not opened", __func__);*/ return -ENODEV; } if (!btlinux_port->is_open) return -EINVAL; if (count == 0) return 0; /* check to verify that the incomign data is good */ access = !access_ok(VERIFY_READ, (void *)user_buffer, count); if (access) { err("BTLINUXPORT %s: buffer access verification failed", __func__); return 0; } if (!btlinux_port->port.info) { err("btport_write - port info obtained"); return -EINVAL; } #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) tty = btlinux_port->port.info->port.tty; #else tty = btlinux_port->port.info->tty; #endif if (!tty) { err("btport_write - tty not obtained"); return -EINVAL; } dataOut = 0; if (!btlinux_port->rcv_full) { if (btlinux_port->rcv_data_tail >= btlinux_port->rcv_data_head) { nCopy = RX_BUFFERS_SIZE - btlinux_port->rcv_data_tail; nRemaining = btlinux_port->rcv_data_head; } else { nCopy = btlinux_port->rcv_data_head - btlinux_port->rcv_data_tail; nRemaining = 0; } if (nCopy >= count) nCopy = count; if (copy_from_user(&btlinux_port->rcv_data[btlinux_port->rcv_data_tail], (void *)user_buffer, nCopy)) { err("BTLINUXPORT %s: copy from user error", __func__); return -EINVAL; } dataOut = nCopy; btlinux_port->rcv_data_tail += nCopy; btlinux_port->rcv_data_tail &= (RX_BUFFERS_SIZE - 1); if (btlinux_port->rcv_data_tail == btlinux_port->rcv_data_head) { btlinux_port->rcv_full = 1; } else { if (nRemaining && nCopy < count) { int remData = count - nCopy; nCopy = nRemaining; if (nCopy >= remData) nCopy = remData; if (copy_from_user(&btlinux_port->rcv_data[btlinux_port->rcv_data_tail], (void *)(user_buffer+dataOut), nCopy)) { err("BTLINUXPORT %s: copy from user error", __func__); return -EINVAL; } dataOut += nCopy; btlinux_port->rcv_data_tail += nCopy; if (btlinux_port->rcv_data_tail == btlinux_port->rcv_data_head) btlinux_port->rcv_full = 1; } } } do { if (tty_buffer_request_room(tty, 1) == 0) { err("Flip buffer overflows"); break; } if (tty_insert_flip_char(tty, btlinux_port->rcv_data[btlinux_port->rcv_data_head], TTY_NORMAL) == 0) err("btlinux_write, flip buffer insert error"); btlinux_port->rcv_data_head++; btlinux_port->rcv_data_head &= (RX_BUFFERS_SIZE - 1); btlinux_port->port.icount.rx++; } while (btlinux_port->rcv_data_head != btlinux_port->rcv_data_tail); if (btlinux_port->rcv_data_tail != btlinux_port->rcv_data_head) btlinux_port->rcv_full = 0; tty->low_latency = 1; tty->icanon = 0; /*dbg("<<< push data to uart port>>>");*/ tty_flip_buffer_push(tty); /* let user know how much data we sent to transport */ return dataOut; }
static inline void sci_receive_chars(struct uart_port *port) { struct sci_port *sci_port = (struct sci_port *)port; struct tty_struct *tty = port->info->port.tty; int i, count, copied = 0; unsigned short status; unsigned char flag; status = sci_in(port, SCxSR); if (!(status & SCxSR_RDxF(port))) return; while (1) { #if !defined(SCI_ONLY) if (port->type == PORT_SCIF) count = scif_rxroom(port); else #endif count = sci_rxroom(port); /* Don't copy more bytes than there is room for in the buffer */ count = tty_buffer_request_room(tty, count); /* If for any reason we can't copy more data, we're done! */ if (count == 0) break; if (port->type == PORT_SCI) { char c = sci_in(port, SCxRDR); if (uart_handle_sysrq_char(port, c) || sci_port->break_flag) count = 0; else { tty_insert_flip_char(tty, c, TTY_NORMAL); } } else { for (i=0; i<count; i++) { char c = sci_in(port, SCxRDR); status = sci_in(port, SCxSR); #if defined(CONFIG_CPU_SH3) /* Skip "chars" during break */ if (sci_port->break_flag) { if ((c == 0) && (status & SCxSR_FER(port))) { count--; i--; continue; } /* Nonzero => end-of-break */ pr_debug("scif: debounce<%02x>\n", c); sci_port->break_flag = 0; if (STEPFN(c)) { count--; i--; continue; } } #endif /* CONFIG_CPU_SH3 */ if (uart_handle_sysrq_char(port, c)) { count--; i--; continue; } /* Store data and status */ if (status&SCxSR_FER(port)) { flag = TTY_FRAME; pr_debug("sci: frame error\n"); } else if (status&SCxSR_PER(port)) { flag = TTY_PARITY; pr_debug("sci: parity error\n"); } else flag = TTY_NORMAL; tty_insert_flip_char(tty, c, flag); } } sci_in(port, SCxSR); /* dummy read */ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); copied += count; port->icount.rx += count; } if (copied) { /* Tell the rest of the system the news. New characters! */ tty_flip_buffer_push(tty); } else { sci_in(port, SCxSR); /* dummy read */ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); } }
int atcmd_write_toatd(struct gdata_port *port, struct sk_buff *skb) { struct tty_struct *tty; unsigned char *ptr; int avail; char *cmd; int i; pr_debug("%s\n", __func__); tty = port->tty; if (!tty) return -ENODEV; avail = skb->len; if (avail == 0) return -EINVAL; ptr = skb->data + avail - 1; if (strncasecmp(skb->data, "AT", 2) || !(*ptr == '\r' || *ptr == '\n' || *ptr == '\0')) { return -EINVAL; } cmd = kstrdup(skb->data + 2, GFP_ATOMIC); if (!cmd) { pr_debug("%s: ENOMEM\n", __func__); return -ENOMEM; } if ((ptr = strchr(cmd, '=')) || (ptr = strchr(cmd, '?')) || (ptr = strchr(cmd, '\r')) ) { *ptr = '\0'; } if (*cmd != '\0') { for (i = 0; at_table[i] != NULL; i++) { if (!strcasecmp(cmd, at_table[i])) { kfree(cmd); if (!test_bit(CH_OPENED, &port->bridge_sts)) { /* signal TTY clients using TTY_BREAK */ tty_insert_flip_char(tty, 0x00, TTY_BREAK); tty_flip_buffer_push(tty); break; } else { avail = tty_prepare_flip_string(tty, &ptr, avail); if (avail <= 0) { return -EBUSY; } #ifdef VERBOSE_DEBUG print_hex_dump(KERN_DEBUG, "toatd:", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, 1); #endif memcpy(ptr, skb->data, avail); dev_kfree_skb_any(skb); tty_flip_buffer_push(tty); } /* XXX only when writable and necessary */ tty_wakeup(tty); return 0; } } } kfree(cmd); return -ENOENT; }
static irqreturn_t imx_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned int rx,flg,ignored = 0; struct tty_struct *tty = sport->port.info->tty; unsigned long flags; rx = URXD0((u32)sport->port.membase); spin_lock_irqsave(&sport->port.lock,flags); do { flg = TTY_NORMAL; sport->port.icount.rx++; if( USR2((u32)sport->port.membase) & USR2_BRCD ) { USR2((u32)sport->port.membase) |= USR2_BRCD; if(uart_handle_break(&sport->port)) goto ignore_char; } if (uart_handle_sysrq_char (&sport->port, (unsigned char)rx)) goto ignore_char; if( rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) goto handle_error; error_return: tty_insert_flip_char(tty, rx, flg); ignore_char: rx = URXD0((u32)sport->port.membase); } while(rx & URXD_CHARRDY); out: spin_unlock_irqrestore(&sport->port.lock,flags); tty_flip_buffer_push(tty); return IRQ_HANDLED; handle_error: if (rx & URXD_PRERR) sport->port.icount.parity++; else if (rx & URXD_FRMERR) sport->port.icount.frame++; if (rx & URXD_OVRRUN) sport->port.icount.overrun++; if (rx & sport->port.ignore_status_mask) { if (++ignored > 100) goto out; goto ignore_char; } rx &= sport->port.read_status_mask; if (rx & URXD_PRERR) flg = TTY_PARITY; else if (rx & URXD_FRMERR) flg = TTY_FRAME; if (rx & URXD_OVRRUN) flg = TTY_OVERRUN; #ifdef SUPPORT_SYSRQ sport->port.sysrq = 0; #endif goto error_return; }
static void transmit_chars_no_dma(struct uart_cris_port *up) { int max_count; struct circ_buf *xmit = &up->port.state->xmit; void __iomem *regi_ser = up->regi_ser; reg_ser_r_stat_din rstat; reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes }; if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { /* No more to send, so disable the interrupt. */ reg_ser_rw_intr_mask intr_mask; intr_mask = REG_RD(ser, regi_ser, rw_intr_mask); intr_mask.tr_rdy = 0; intr_mask.tr_empty = 0; REG_WR(ser, regi_ser, rw_intr_mask, intr_mask); up->write_ongoing = 0; return; } /* If the serport is fast, we send up to max_count bytes before exiting the loop. */ max_count = 64; do { reg_ser_rw_dout dout = { .data = xmit->buf[xmit->tail] }; REG_WR(ser, regi_ser, rw_dout, dout); REG_WR(ser, regi_ser, rw_ack_intr, ack_intr); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); up->port.icount.tx++; if (xmit->head == xmit->tail) break; rstat = REG_RD(ser, regi_ser, r_stat_din); } while ((--max_count > 0) && rstat.tr_rdy); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&up->port); } static void receive_chars_no_dma(struct uart_cris_port *up) { reg_ser_rs_stat_din stat_din; reg_ser_r_stat_din rstat; struct tty_port *port; struct uart_icount *icount; int max_count = 16; char flag; reg_ser_rw_ack_intr ack_intr = { 0 }; rstat = REG_RD(ser, up->regi_ser, r_stat_din); icount = &up->port.icount; port = &up->port.state->port; do { stat_din = REG_RD(ser, up->regi_ser, rs_stat_din); flag = TTY_NORMAL; ack_intr.dav = 1; REG_WR(ser, up->regi_ser, rw_ack_intr, ack_intr); icount->rx++; if (stat_din.framing_err | stat_din.par_err | stat_din.orun) { if (stat_din.data == 0x00 && stat_din.framing_err) { /* Most likely a break. */ flag = TTY_BREAK; icount->brk++; } else if (stat_din.par_err) { flag = TTY_PARITY; icount->parity++; } else if (stat_din.orun) { flag = TTY_OVERRUN; icount->overrun++; } else if (stat_din.framing_err) { flag = TTY_FRAME; icount->frame++; } } /* * If this becomes important, we probably *could* handle this * gracefully by keeping track of the unhandled character. */ if (!tty_insert_flip_char(port, stat_din.data, flag)) panic("%s: No tty buffer space", __func__); rstat = REG_RD(ser, up->regi_ser, r_stat_din); } while (rstat.dav && (max_count-- > 0)); spin_unlock(&up->port.lock); tty_flip_buffer_push(port); spin_lock(&up->port.lock); }
static void acm_rx_tasklet(unsigned long _acm) { struct acm *acm = (void *)_acm; struct acm_rb *buf; struct tty_struct *tty = acm->tty; struct acm_ru *rcv; //unsigned long flags; int i = 0; dbg("Entering acm_rx_tasklet"); if (!ACM_READY(acm) || acm->throttle) return; next_buffer: spin_lock(&acm->read_lock); if (list_empty(&acm->filled_read_bufs)) { spin_unlock(&acm->read_lock); goto urbs; } buf = list_entry(acm->filled_read_bufs.next, struct acm_rb, list); list_del(&buf->list); spin_unlock(&acm->read_lock); dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d\n", buf, buf->size); for (i = 0; i < buf->size && !acm->throttle; i++) { /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ if (tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); } tty_insert_flip_char(tty, buf->base[i], 0); } tty_flip_buffer_push(tty); spin_lock(&acm->throttle_lock); if (acm->throttle) { dbg("Throtteling noticed"); memmove(buf->base, buf->base + i, buf->size - i); buf->size -= i; spin_unlock(&acm->throttle_lock); spin_lock(&acm->read_lock); list_add(&buf->list, &acm->filled_read_bufs); spin_unlock(&acm->read_lock); return; } spin_unlock(&acm->throttle_lock); spin_lock(&acm->read_lock); list_add(&buf->list, &acm->spare_read_bufs); spin_unlock(&acm->read_lock); goto next_buffer; urbs: while (!list_empty(&acm->spare_read_bufs)) { spin_lock(&acm->read_lock); if (list_empty(&acm->spare_read_urbs)) { spin_unlock(&acm->read_lock); return; } rcv = list_entry(acm->spare_read_urbs.next, struct acm_ru, list); list_del(&rcv->list); spin_unlock(&acm->read_lock); buf = list_entry(acm->spare_read_bufs.next, struct acm_rb, list); list_del(&buf->list); rcv->buffer = buf; usb_fill_bulk_urb(rcv->urb, acm->dev, acm->rx_endpoint, buf->base, acm->readsize, acm_read_bulk, rcv); rcv->urb->transfer_dma = buf->dma; rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p\n", rcv->urb, rcv, buf); /* This shouldn't kill the driver as unsuccessful URBs are returned to the free-urbs-pool and resubmited ASAP */ if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { list_add(&buf->list, &acm->spare_read_bufs); spin_lock(&acm->read_lock); list_add(&rcv->list, &acm->spare_read_urbs); spin_unlock(&acm->read_lock); return; } } }
/* * Interrupt routine, called from common io layer */ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) { struct raw3215_info *raw; struct raw3215_req *req; struct tty_struct *tty; int cstat, dstat; int count, slen; raw = cdev->dev.driver_data; req = (struct raw3215_req *) intparm; cstat = irb->scsw.cstat; dstat = irb->scsw.dstat; if (cstat != 0) { raw->message = KERN_WARNING "Got nonzero channel status in raw3215_irq " "(dev sts 0x%2x, sch sts 0x%2x)"; raw->msg_dstat = dstat; raw->msg_cstat = cstat; tasklet_schedule(&raw->tasklet); } if (dstat & 0x01) { /* we got a unit exception */ dstat &= ~0x01; /* we can ignore it */ } switch (dstat) { case 0x80: if (cstat != 0) break; /* Attention interrupt, someone hit the enter key */ raw3215_mk_read_req(raw); if (MACHINE_IS_P390) memset(raw->inbuf, 0, RAW3215_INBUF_SIZE); tasklet_schedule(&raw->tasklet); break; case 0x08: case 0x0C: /* Channel end interrupt. */ if ((raw = req->info) == NULL) return; /* That shouldn't happen ... */ if (req->type == RAW3215_READ) { /* store residual count, then wait for device end */ req->residual = irb->scsw.count; } if (dstat == 0x08) break; case 0x04: /* Device end interrupt. */ if ((raw = req->info) == NULL) return; /* That shouldn't happen ... */ if (req->type == RAW3215_READ && raw->tty != NULL) { unsigned int cchar; tty = raw->tty; count = 160 - req->residual; if (MACHINE_IS_P390) { slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE); if (count > slen) count = slen; } else EBCASC(raw->inbuf, count); cchar = ctrlchar_handle(raw->inbuf, count, tty); switch (cchar & CTRLCHAR_MASK) { case CTRLCHAR_SYSRQ: break; case CTRLCHAR_CTRL: tty_insert_flip_char(tty, cchar, TTY_NORMAL); tty_flip_buffer_push(raw->tty); break; case CTRLCHAR_NONE: if (count < 2 || (strncmp(raw->inbuf+count-2, "\252n", 2) && strncmp(raw->inbuf+count-2, "^n", 2)) ) { /* add the auto \n */ raw->inbuf[count] = '\n'; count++; } else count -= 2; tty_insert_flip_string(tty, raw->inbuf, count); tty_flip_buffer_push(raw->tty); break; } } else if (req->type == RAW3215_WRITE) { raw->count -= req->len; raw->written -= req->len; } raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); /* check for empty wait */ if (waitqueue_active(&raw->empty_wait) && raw->queued_write == NULL && raw->queued_read == NULL) { wake_up_interruptible(&raw->empty_wait); } tasklet_schedule(&raw->tasklet); break; default: /* Strange interrupt, I'll do my best to clean up */ if (req != NULL && req->type != RAW3215_FREE) { if (req->type == RAW3215_WRITE) { raw->count -= req->len; raw->written -= req->len; } raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); } raw->message = KERN_WARNING "Spurious interrupt in in raw3215_irq " "(dev sts 0x%2x, sch sts 0x%2x)"; raw->msg_dstat = dstat; raw->msg_cstat = cstat; tasklet_schedule(&raw->tasklet); } return; }
static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs) { struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; struct tty_struct *tty = port->info->tty; unsigned int ufcon, ch, flag, ufstat, uerstat; int max_count = 64; while (max_count-- > 0) { ufcon = rd_regl(port, S3C2410_UFCON); ufstat = rd_regl(port, S3C2410_UFSTAT); if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) break; if (tty->flip.count >= TTY_FLIPBUF_SIZE) { if (tty->low_latency) tty_flip_buffer_push(tty); /* * If this failed then we will throw away the * bytes but must do so to clear interrupts */ } uerstat = rd_regl(port, S3C2410_UERSTAT); ch = rd_regb(port, S3C2410_URXH); if (port->flags & UPF_CONS_FLOW) { int txe = s3c24xx_serial_txempty_nofifo(port); if (rx_enabled(port)) { if (!txe) { rx_enabled(port) = 0; continue; } } else { if (txe) { ufcon |= S3C2410_UFCON_RESETRX; wr_regl(port, S3C2410_UFCON, ufcon); rx_enabled(port) = 1; goto out; } continue; } } /* insert the character into the buffer */ flag = TTY_NORMAL; port->icount.rx++; if (uerstat & S3C2410_UERSTAT_ANY) { dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n", ch, uerstat); /* check for break */ if (uerstat & S3C2410_UERSTAT_BREAK) { dbg("break!\n"); port->icount.brk++; if (uart_handle_break(port)) goto ignore_char; } if (uerstat & S3C2410_UERSTAT_FRAME) port->icount.frame++; if (uerstat & S3C2410_UERSTAT_OVERRUN) port->icount.overrun++; uerstat &= port->read_status_mask; if (uerstat & S3C2410_UERSTAT_BREAK) flag = TTY_BREAK; else if (uerstat & S3C2410_UERSTAT_PARITY) flag = TTY_PARITY; else if (uerstat & ( S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN)) flag = TTY_FRAME; } if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; if ((uerstat & port->ignore_status_mask) == 0) { tty_insert_flip_char(tty, ch, flag); } if ((uerstat & S3C2410_UERSTAT_OVERRUN) && tty->flip.count < TTY_FLIPBUF_SIZE) { /* * Overrun is special, since it's reported * immediately, and doesn't affect the current * character. */ tty_insert_flip_char(tty, 0, TTY_OVERRUN); } ignore_char: continue; } tty_flip_buffer_push(tty); out: return IRQ_HANDLED; }
static void empeg_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int i; int result; if (port_paranoia_check (port, __FUNCTION__)) return; dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); tty = port->tty; if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { /* gb - 2000/11/13 * If we insert too many characters we'll overflow the buffer. * This means we'll lose bytes - Decidedly bad. */ if(tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); } tty_insert_flip_char(tty, data[i], 0); } /* gb - 2000/11/13 * Goes straight through instead of scheduling - if tty->low_latency is set. */ tty_flip_buffer_push(tty); bytes_in += urb->actual_length; } /* Continue trying to always read */ FILL_BULK_URB( port->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, empeg_read_bulk_callback, port); port->read_urb->transfer_flags |= USB_QUEUE_BULK; result = usb_submit_urb(port->read_urb); if (result) err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); return; }
static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct mct_u232_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int status; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); switch (urb->status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); return; default: dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); goto exit; } if (!serial) { dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); /* * Work-a-round: handle the 'usual' bulk-in pipe here */ if (urb->transfer_buffer_length > 2) { int i; tty = port->tty; if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { tty_insert_flip_char(tty, data[i], 0); } tty_flip_buffer_push(tty); } goto exit; } /* * The interrupt-in pipe signals exceptional conditions (modem line * signal changes and errors). data[0] holds MSR, data[1] holds LSR. */ spin_lock_irqsave(&priv->lock, flags); priv->last_msr = data[MCT_U232_MSR_INDEX]; /* Record Control Line states */ mct_u232_msr_to_state(&priv->control_state, priv->last_msr); #if 0 /* Not yet handled. See belin_sa.c for further information */ /* Now to report any errors */ priv->last_lsr = data[MCT_U232_LSR_INDEX]; /* * fill in the flip buffer here, but I do not know the relation * to the current/next receive buffer or characters. I need * to look in to this before committing any code. */ if (priv->last_lsr & MCT_U232_LSR_ERR) { tty = port->tty; /* Overrun Error */ if (priv->last_lsr & MCT_U232_LSR_OE) { } /* Parity Error */ if (priv->last_lsr & MCT_U232_LSR_PE) { } /* Framing Error */ if (priv->last_lsr & MCT_U232_LSR_FE) { } /* Break Indicator */ if (priv->last_lsr & MCT_U232_LSR_BI) { } } #endif spin_unlock_irqrestore(&priv->lock, flags); exit: status = usb_submit_urb (urb, GFP_ATOMIC); if (status) err ("%s - usb_submit_urb failed with result %d", __FUNCTION__, status); } /* mct_u232_read_int_callback */
static void handle_rx(struct uart_port *port, unsigned int misr) { struct tty_struct *tty = port->state->port.tty; unsigned int vid; unsigned int sr; int count = 0; struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); vid = msm_hsl_port->ver_id; if ((msm_hsl_read(port, regmap[vid][UARTDM_SR]) & UARTDM_SR_OVERRUN_BMSK)) { port->icount.overrun++; tty_insert_flip_char(tty, 0, TTY_OVERRUN); msm_hsl_write(port, RESET_ERROR_STATUS, regmap[vid][UARTDM_CR]); } if (misr & UARTDM_ISR_RXSTALE_BMSK) { count = msm_hsl_read(port, regmap[vid][UARTDM_RX_TOTAL_SNAP]) - msm_hsl_port->old_snap_state; msm_hsl_port->old_snap_state = 0; } else { count = 4 * (msm_hsl_read(port, regmap[vid][UARTDM_RFWR])); msm_hsl_port->old_snap_state += count; } while (count > 0) { unsigned int c; char flag = TTY_NORMAL; sr = msm_hsl_read(port, regmap[vid][UARTDM_SR]); if ((sr & UARTDM_SR_RXRDY_BMSK) == 0) { msm_hsl_port->old_snap_state -= count; break; } c = msm_hsl_read(port, regmap[vid][UARTDM_RF]); if (sr & UARTDM_SR_RX_BREAK_BMSK) { port->icount.brk++; if (uart_handle_break(port)) continue; } else if (sr & UARTDM_SR_PAR_FRAME_BMSK) { port->icount.frame++; } else { port->icount.rx++; } sr &= port->read_status_mask; if (sr & UARTDM_SR_RX_BREAK_BMSK) flag = TTY_BREAK; else if (sr & UARTDM_SR_PAR_FRAME_BMSK) flag = TTY_FRAME; tty_insert_flip_string(tty, (char *) &c, (count > 4) ? 4 : count); count -= 4; } tty_flip_buffer_push(tty); }
static irqreturn_t imx_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned int rx,flg,ignored = 0; struct tty_struct *tty = sport->port.state->port.tty; unsigned long flags, temp; spin_lock_irqsave(&sport->port.lock,flags); while (readl(sport->port.membase + USR2) & USR2_RDR) { flg = TTY_NORMAL; sport->port.icount.rx++; rx = readl(sport->port.membase + URXD0); temp = readl(sport->port.membase + USR2); if (temp & USR2_BRCD) { writel(temp | USR2_BRCD, sport->port.membase + USR2); if (uart_handle_break(&sport->port)) continue; } if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) continue; if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { if (rx & URXD_PRERR) sport->port.icount.parity++; else if (rx & URXD_FRMERR) sport->port.icount.frame++; if (rx & URXD_OVRRUN) sport->port.icount.overrun++; if (rx & sport->port.ignore_status_mask) { if (++ignored > 100) goto out; continue; } rx &= sport->port.read_status_mask; if (rx & URXD_PRERR) flg = TTY_PARITY; else if (rx & URXD_FRMERR) flg = TTY_FRAME; if (rx & URXD_OVRRUN) flg = TTY_OVERRUN; #ifdef SUPPORT_SYSRQ sport->port.sysrq = 0; #endif } tty_insert_flip_char(tty, rx, flg); } out: spin_unlock_irqrestore(&sport->port.lock,flags); tty_flip_buffer_push(tty); return IRQ_HANDLED; }
/* * ------------------------------------------------------------ * receive_char () * * This routine deals with inputs from any lines. * ------------------------------------------------------------ */ static inline void dz_receive_chars(struct dz_port *dport) { struct tty_struct *tty = NULL; struct uart_icount *icount; int ignore = 0; unsigned short status, tmp; unsigned char ch, flag; /* this code is going to be a problem... the call to tty_flip_buffer is going to need to be rethought... */ do { status = dz_in(dport, DZ_RBUF); /* punt so we don't get duplicate characters */ if (!(status & DZ_DVAL)) goto ignore_char; ch = UCHAR(status); /* grab the char */ flag = TTY_NORMAL; #if 0 if (info->is_console) { if (ch == 0) return; /* it's a break ... */ } #endif tty = dport->port.info->tty;/* now tty points to the proper dev */ icount = &dport->port.icount; if (!tty) break; if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; icount->rx++; /* keep track of the statistics */ if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) { if (status & DZ_PERR) /* parity error */ icount->parity++; else if (status & DZ_FERR) /* frame error */ icount->frame++; if (status & DZ_OERR) /* overrun error */ icount->overrun++; /* check to see if we should ignore the character and mask off conditions that should be ignored */ if (status & dport->port.ignore_status_mask) { if (++ignore > 100) break; goto ignore_char; } /* mask off the error conditions we want to ignore */ tmp = status & dport->port.read_status_mask; if (tmp & DZ_PERR) { flag = TTY_PARITY; #ifdef DEBUG_DZ debug_console("PERR\n", 5); #endif } else if (tmp & DZ_FERR) { flag = TTY_FRAME; #ifdef DEBUG_DZ debug_console("FERR\n", 5); #endif } if (tmp & DZ_OERR) { #ifdef DEBUG_DZ debug_console("OERR\n", 5); #endif tty_insert_flip_char(tty, ch, flag); ch = 0; flag = TTY_OVERRUN; } } tty_insert_flip_char(tty, ch, flag); ignore_char: } while (status & DZ_DVAL); if (tty) tty_flip_buffer_push(tty); } /* * ------------------------------------------------------------ * transmit_char () * * This routine deals with outputs to any lines. * ------------------------------------------------------------ */ static inline void dz_transmit_chars(struct dz_port *dport) { struct circ_buf *xmit = &dport->port.info->xmit; unsigned char tmp; if (dport->port.x_char) { /* XON/XOFF chars */ dz_out(dport, DZ_TDR, dport->port.x_char); dport->port.icount.tx++; dport->port.x_char = 0; return; } /* if nothing to do or stopped or hardware stopped */ if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) { dz_stop_tx(&dport->port, 0); return; } /* * if something to do ... (rember the dz has no output fifo so we go * one char at a time :-< */ tmp = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1); dz_out(dport, DZ_TDR, tmp); dport->port.icount.tx++; if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS) uart_write_wakeup(&dport->port); /* Are we done */ if (uart_circ_empty(xmit)) dz_stop_tx(&dport->port, 0); } /* * ------------------------------------------------------------ * check_modem_status () * * Only valid for the MODEM line duh ! * ------------------------------------------------------------ */ static inline void check_modem_status(struct dz_port *dport) { unsigned short status; /* if not ne modem line just return */ if (dport->port.line != DZ_MODEM) return; status = dz_in(dport, DZ_MSR); /* it's easy, since DSR2 is the only bit in the register */ if (status) dport->port.icount.dsr++; }
static void receive_chars(struct serial_state *info) { int status; int serdatr; unsigned char ch, flag; struct async_icount *icount; int oe = 0; icount = &info->icount; status = UART_LSR_DR; /* We obviously have a character! */ serdatr = custom.serdatr; mb(); custom.intreq = IF_RBF; mb(); if((serdatr & 0x1ff) == 0) status |= UART_LSR_BI; if(serdatr & SDR_OVRUN) status |= UART_LSR_OE; ch = serdatr & 0xff; icount->rx++; #ifdef SERIAL_DEBUG_INTR printk("DR%02x:%02x...", ch, status); #endif flag = TTY_NORMAL; /* * We don't handle parity or frame errors - but I have left * the code in, since I'm not sure that the errors can't be * detected. */ if (status & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE)) { /* * For statistics only */ if (status & UART_LSR_BI) { status &= ~(UART_LSR_FE | UART_LSR_PE); icount->brk++; } else if (status & UART_LSR_PE) icount->parity++; else if (status & UART_LSR_FE) icount->frame++; if (status & UART_LSR_OE) icount->overrun++; /* * Now check to see if character should be * ignored, and mask off conditions which * should be ignored. */ if (status & info->ignore_status_mask) goto out; status &= info->read_status_mask; if (status & (UART_LSR_BI)) { #ifdef SERIAL_DEBUG_INTR printk("handling break...."); #endif flag = TTY_BREAK; if (info->tport.flags & ASYNC_SAK) do_SAK(info->tport.tty); } else if (status & UART_LSR_PE) flag = TTY_PARITY; else if (status & UART_LSR_FE) flag = TTY_FRAME; if (status & UART_LSR_OE) { /* * Overrun is special, since it's * reported immediately, and doesn't * affect the current character */ oe = 1; } } tty_insert_flip_char(&info->tport, ch, flag); if (oe == 1) tty_insert_flip_char(&info->tport, 0, TTY_OVERRUN); tty_flip_buffer_push(&info->tport); out: return; }
/** * cdns_uart_handle_rx - Handle the received bytes along with Rx errors. * @dev_id: Id of the UART port * @isrstatus: The interrupt status register value as read * Return: None */ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus) { struct uart_port *port = (struct uart_port *)dev_id; struct cdns_uart *cdns_uart = port->private_data; unsigned int data; unsigned int framerrprocessed = 0; char status = TTY_NORMAL; bool is_brk_support; is_brk_support = cdns_uart->quirks & CDNS_UART_BRK_DET; while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { data = cdns_uart_readl(CDNS_UART_FIFO_OFFSET); port->icount.rx++; /* * There is no hardware break detection in Zynq, so we interpret * framing error with all-zeros data as a break sequence. * Most of the time, there's another non-zero byte at the * end of the sequence. */ if (!is_brk_support && (isrstatus & CDNS_UART_IXR_FRAMING)) { if (!data) { port->read_status_mask |= CDNS_UART_IXR_BRK; framerrprocessed = 1; continue; } } if (is_brk_support && (isrstatus & CDNS_UART_IXR_BRK)) { port->icount.brk++; status = TTY_BREAK; if (uart_handle_break(port)) continue; } isrstatus &= port->read_status_mask; isrstatus &= ~port->ignore_status_mask; if ((isrstatus & CDNS_UART_IXR_TOUT) || (isrstatus & CDNS_UART_IXR_RXTRIG)) { if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) { port->read_status_mask &= ~CDNS_UART_IXR_BRK; port->icount.brk++; if (uart_handle_break(port)) continue; } #ifdef SUPPORT_SYSRQ /* * uart_handle_sysrq_char() doesn't work if * spinlocked, for some reason */ if (port->sysrq) { spin_unlock(&port->lock); if (uart_handle_sysrq_char(port, (unsigned char)data)) { spin_lock(&port->lock); continue; } spin_lock(&port->lock); } #endif if (isrstatus & CDNS_UART_IXR_PARITY) { port->icount.parity++; status = TTY_PARITY; } if ((isrstatus & CDNS_UART_IXR_FRAMING) && !framerrprocessed) { port->icount.frame++; status = TTY_FRAME; } if (isrstatus & CDNS_UART_IXR_OVERRUN) { port->icount.overrun++; tty_insert_flip_char(&port->state->port, 0, TTY_OVERRUN); } tty_insert_flip_char(&port->state->port, data, status); } } spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); spin_lock(&port->lock); }
/* bulk read call back function. check the status of the urb. if transfer * failed return. then update the status and the tty send data to tty subsys. * submit urb again. */ static void spcp8x5_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct spcp8x5_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; int result = urb->status; u8 status; char tty_flag; dev_dbg(&port->dev, "start, result = %d, urb->actual_length = %d\n,", result, urb->actual_length); /* check the urb status */ if (result) { if (result == -EPROTO) { /* spcp8x5 mysteriously fails with -EPROTO */ /* reschedule the read */ urb->dev = port->serial->dev; result = usb_submit_urb(urb , GFP_ATOMIC); if (result) dev_dbg(&port->dev, "failed submitting read urb %d\n", result); return; } dev_dbg(&port->dev, "unable to handle the error, exiting.\n"); return; } /* get tty_flag from status */ tty_flag = TTY_NORMAL; spin_lock_irqsave(&priv->lock, flags); status = priv->line_status; priv->line_status &= ~UART_STATE_TRANSIENT_MASK; spin_unlock_irqrestore(&priv->lock, flags); /* wake up the wait for termios */ wake_up_interruptible(&priv->delta_msr_wait); /* break takes precedence over parity, which takes precedence over * framing errors */ if (status & UART_BREAK_ERROR) tty_flag = TTY_BREAK; else if (status & UART_PARITY_ERROR) tty_flag = TTY_PARITY; else if (status & UART_FRAME_ERROR) tty_flag = TTY_FRAME; dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); tty = tty_port_tty_get(&port->port); if (tty && urb->actual_length) { /* overrun is special, not associated with a char */ if (status & UART_OVERRUN_ERROR) tty_insert_flip_char(tty, 0, TTY_OVERRUN); tty_insert_flip_string_fixed_flag(tty, data, tty_flag, urb->actual_length); tty_flip_buffer_push(tty); } if (status & UART_DCD) usb_serial_handle_dcd_change(port, tty, priv->line_status & MSR_STATUS_LINE_DCD); tty_kref_put(tty); /* Schedule the next read */ urb->dev = port->serial->dev; result = usb_submit_urb(urb , GFP_ATOMIC); if (result) dev_dbg(&port->dev, "failed submitting read urb %d\n", result); }
static void process_rx_char(struct usb_serial_port *port, unsigned char data) { struct urb *urb = port->read_urb; if (urb->actual_length) tty_insert_flip_char(&port->port, data, TTY_NORMAL); }