diff options
author | Jens Taprogge <jens.taprogge@taprogge.org> | 2012-09-12 14:55:30 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-09-12 18:54:16 +0200 |
commit | 87cfb955007ece1ba2a78a419c033942ee300972 (patch) | |
tree | 8a5bdeb02650329a89512b3c10c6e7895db4e85f /drivers | |
parent | Staging: ipack/devices/ipoctal: Store isr masks in ipoctal_channel (diff) | |
download | linux-87cfb955007ece1ba2a78a419c033942ee300972.tar.xz linux-87cfb955007ece1ba2a78a419c033942ee300972.zip |
Staging: ipack/devices/ipoctal: Split interrupt service routine.
Split the IRQ service routing in TX part and RX part.
Signed-off-by: Jens Taprogge <jens.taprogge@taprogge.org>
Signed-off-by: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/ipack/devices/ipoctal.c | 188 |
1 files changed, 97 insertions, 91 deletions
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c index 56e810b78ee3..e0be6604c1ec 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; } |