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;
}