[PATCH 08/24] Staging: ipack/devices/ipoctal: Split interrupt service routine.

Samuel Iglesias Gonsalvez siglesias at igalia.com
Wed Sep 12 12:55:30 UTC 2012


From: Jens Taprogge <jens.taprogge at taprogge.org>

Split the IRQ service routing in TX part and RX part.

Signed-off-by: Jens Taprogge <jens.taprogge at taprogge.org>
Signed-off-by: Samuel Iglesias Gonsalvez <siglesias at igalia.com>
---
 drivers/staging/ipack/devices/ipoctal.c |  188 ++++++++++++++++---------------
 1 file changed, 97 insertions(+), 91 deletions(-)

diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c
index 56e810b..e0be660 100644
--- a/drivers/staging/ipack/devices/ipoctal.c
+++ b/drivers/staging/ipack/devices/ipoctal.c
@@ -163,109 +163,115 @@ static int ipoctal_get_icount(struct tty_struct *tty,
 	return 0;
 }
 
-static int ipoctal_irq_handler(void *arg)
+static void ipoctal_irq_rx(struct ipoctal_channel *channel,
+			   struct tty_struct *tty, u8 sr)
+{
+	unsigned char value = ioread8(&channel->regs->r.rhr);
+	unsigned char flag = TTY_NORMAL;
+
+	/* Error: count statistics */
+	if (sr & SR_ERROR) {
+		iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
+
+		if (sr & SR_OVERRUN_ERROR) {
+			channel->stats.overrun_err++;
+			/* Overrun doesn't affect the current character*/
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+		}
+		if (sr & SR_PARITY_ERROR) {
+			channel->stats.parity_err++;
+			flag = TTY_PARITY;
+		}
+		if (sr & SR_FRAMING_ERROR) {
+			channel->stats.framing_err++;
+			flag = TTY_FRAME;
+		}
+		if (sr & SR_RECEIVED_BREAK) {
+			channel->stats.rcv_break++;
+			flag = TTY_BREAK;
+		}
+	}
+
+	tty_insert_flip_char(tty, value, flag);
+}
+
+static void ipoctal_irq_tx(struct ipoctal_channel *channel)
 {
-	unsigned int ichannel;
-	unsigned char isr;
-	unsigned char sr;
 	unsigned char value;
-	unsigned char flag;
-	struct tty_struct *tty;
-	struct ipoctal *ipoctal = (struct ipoctal *) arg;
-	struct ipoctal_channel *channel;
+	unsigned int *pointer_write = &channel->pointer_write;
 
-	/* Check all channels */
-	for (ichannel = 0; ichannel < NR_CHANNELS; ichannel++) {
-		channel = &ipoctal->channel[ichannel];
-		/* If there is no client, skip the check */
-		if (!atomic_read(&channel->open))
-			continue;
+	if (channel->nb_bytes <= 0) {
+		channel->nb_bytes = 0;
+		return;
+	}
 
-		tty = tty_port_tty_get(&channel->tty_port);
-		if (!tty)
-			continue;
+	value = channel->tty_port.xmit_buf[*pointer_write];
+	iowrite8(value, &channel->regs->w.thr);
+	channel->stats.tx++;
+	channel->count_wr++;
+	(*pointer_write)++;
+	*pointer_write = *pointer_write % PAGE_SIZE;
+	channel->nb_bytes--;
 
-		/*
-		 * The HW is organized in pair of channels.
-		 * See which register we need to read from
-		 */
-		isr = ioread8(&channel->block_regs->r.isr);
-		sr = ioread8(&channel->regs->r.sr);
+	if ((channel->nb_bytes == 0) &&
+	    (waitqueue_active(&channel->queue))) {
 
-		/* In case of RS-485, change from TX to RX when finishing TX.
-		 * Half-duplex.
-		 */
-		if ((ipoctal->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) &&
-		    (sr & SR_TX_EMPTY) &&
-		    (channel->nb_bytes == 0)) {
-			iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
-			iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr);
-			iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
-			ipoctal->write = 1;
+		if (channel->board_id != IPACK1_DEVICE_ID_SBS_OCTAL_485) {
+			*channel->board_write = 1;
 			wake_up_interruptible(&channel->queue);
 		}
+	}
+}
 
-		/* RX data */
-		if ((isr && channel->isr_rx_rdy_mask) && (sr & SR_RX_READY)) {
-			value = ioread8(&channel->regs->r.rhr);
-			flag = TTY_NORMAL;
-
-			/* Error: count statistics */
-			if (sr & SR_ERROR) {
-				iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
-
-				if (sr & SR_OVERRUN_ERROR) {
-					channel->stats.overrun_err++;
-					/* Overrun doesn't affect the current character*/
-					tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-				}
-				if (sr & SR_PARITY_ERROR) {
-					channel->stats.parity_err++;
-					flag = TTY_PARITY;
-				}
-				if (sr & SR_FRAMING_ERROR) {
-					channel->stats.framing_err++;
-					flag = TTY_FRAME;
-				}
-				if (sr & SR_RECEIVED_BREAK) {
-					channel->stats.rcv_break++;
-					flag = TTY_BREAK;
-				}
-			}
-
-			tty_insert_flip_char(tty, value, flag);
-		}
+static void ipoctal_irq_channel(struct ipoctal_channel *channel)
+{
+	u8 isr, sr;
+	struct tty_struct *tty;
 
-		/* TX of each character */
-		if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY)) {
-			unsigned int *pointer_write = &channel->pointer_write;
-
-			if (channel->nb_bytes <= 0) {
-				channel->nb_bytes = 0;
-				continue;
-			}
-
-			value = channel->tty_port.xmit_buf[*pointer_write];
-			iowrite8(value, &channel->regs->w.thr);
-			channel->stats.tx++;
-			channel->count_wr++;
-			(*pointer_write)++;
-			*pointer_write = *pointer_write % PAGE_SIZE;
-			channel->nb_bytes--;
-
-			if ((channel->nb_bytes == 0) &&
-			    (waitqueue_active(&channel->queue))) {
-
-				if (ipoctal->board_id != IPACK1_DEVICE_ID_SBS_OCTAL_485) {
-					ipoctal->write = 1;
-					wake_up_interruptible(&channel->queue);
-				}
-			}
-		}
+	/* If there is no client, skip the check */
+	if (!atomic_read(&channel->open))
+		return;
 
-		tty_flip_buffer_push(tty);
-		tty_kref_put(tty);
+	tty = tty_port_tty_get(&channel->tty_port);
+	if (!tty)
+		return;
+	/* The HW is organized in pair of channels.  See which register we need
+	 * to read from */
+	isr = ioread8(&channel->block_regs->r.isr);
+	sr = ioread8(&channel->regs->r.sr);
+
+	/* In case of RS-485, change from TX to RX when finishing TX.
+	 * Half-duplex. */
+	if ((channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) &&
+	    (sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) {
+		iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
+		iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr);
+		iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
+		*channel->board_write = 1;
+		wake_up_interruptible(&channel->queue);
 	}
+
+	/* RX data */
+	if ((isr & channel->isr_rx_rdy_mask) && (sr & SR_RX_READY))
+		ipoctal_irq_rx(channel, tty, sr);
+
+	/* TX of each character */
+	if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY))
+		ipoctal_irq_tx(channel);
+
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+static int ipoctal_irq_handler(void *arg)
+{
+	unsigned int i;
+	struct ipoctal *ipoctal = (struct ipoctal *) arg;
+
+	/* Check all channels */
+	for (i = 0; i < NR_CHANNELS; i++)
+		ipoctal_irq_channel(&ipoctal->channel[i]);
+
 	return IRQ_HANDLED;
 }
 
-- 
1.7.10.4




More information about the devel mailing list