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);
}
示例#2
0
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);
}
示例#3
0
/*
 * 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;
}
示例#4
0
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;
}
示例#5
0
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;
}
示例#6
0
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;
}
示例#7
0
文件: con3215.c 项目: 513855417/linux
/*
 * 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);
}
示例#8
0
/*
 * 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);
}
示例#9
0
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;
}
示例#11
0
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);
}
示例#12
0
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;
}
示例#13
0
/*
 * 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);
}
示例#14
0
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;
}
示例#15
0
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;
}
示例#17
0
文件: imx.c 项目: ivucica/linux
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;
}
示例#18
0
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);
}
示例#19
0
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;
		}
	}
}
示例#20
0
/*
 * 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;
}
示例#21
0
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;
}
示例#22
0
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 */
示例#24
0
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);
}
示例#25
0
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;
}
示例#26
0
文件: dz.c 项目: OpenHMR/Open-HMR600
/*
 * ------------------------------------------------------------
 * 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++;
}
示例#27
0
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;
}
示例#28
0
/**
 * 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);
}
示例#29
0
/* 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);
}
示例#30
0
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);
}