X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fipack%2Fdevices%2Fipoctal.c;h=8666d2d05eef9ab30bfe8f62d5f28ac35e7cfe9e;hb=b0d17fbdacb32f9f4b9ee1ad2b8f42f6a480d842;hp=576d53d926776cd270ce4572e6a3e0a1d48857f0;hpb=a13eea6bd9ee62ceacfc5243d54c84396bc86cb4;p=karo-tx-linux.git diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c index 576d53d92677..8666d2d05eef 100644 --- a/drivers/ipack/devices/ipoctal.c +++ b/drivers/ipack/devices/ipoctal.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include "ipoctal.h" @@ -38,21 +37,19 @@ struct ipoctal_channel { spinlock_t lock; unsigned int pointer_read; unsigned int pointer_write; - atomic_t open; struct tty_port tty_port; union scc2698_channel __iomem *regs; union scc2698_block __iomem *block_regs; unsigned int board_id; - unsigned char *board_write; u8 isr_rx_rdy_mask; u8 isr_tx_rdy_mask; + unsigned int rx_enable; }; struct ipoctal { struct ipack_device *dev; unsigned int board_id; struct ipoctal_channel channel[NR_CHANNELS]; - unsigned char write; struct tty_driver *tty_drv; u8 __iomem *mem8_space; u8 __iomem *int_space; @@ -64,28 +61,23 @@ static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty) channel = dev_get_drvdata(tty->dev); + /* + * Enable RX. TX will be enabled when + * there is something to send + */ iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); + channel->rx_enable = 1; return 0; } static int ipoctal_open(struct tty_struct *tty, struct file *file) { - int res; struct ipoctal_channel *channel; channel = dev_get_drvdata(tty->dev); - - if (atomic_read(&channel->open)) - return -EBUSY; - tty->driver_data = channel; - res = tty_port_open(&channel->tty_port, tty, file); - if (res) - return res; - - atomic_inc(&channel->open); - return 0; + return tty_port_open(&channel->tty_port, tty, file); } static void ipoctal_reset_stats(struct ipoctal_stats *stats) @@ -111,9 +103,7 @@ static void ipoctal_close(struct tty_struct *tty, struct file *filp) struct ipoctal_channel *channel = tty->driver_data; tty_port_close(&channel->tty_port, tty, filp); - - if (atomic_dec_and_test(&channel->open)) - ipoctal_free_channel(channel); + ipoctal_free_channel(channel); } static int ipoctal_get_icount(struct tty_struct *tty, @@ -137,11 +127,12 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel, struct tty_struct *tty, u8 sr) { unsigned char value; - unsigned char flag = TTY_NORMAL; + unsigned char flag; u8 isr; do { 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); @@ -183,10 +174,8 @@ static void ipoctal_irq_tx(struct ipoctal_channel *channel) unsigned char value; unsigned int *pointer_write = &channel->pointer_write; - if (channel->nb_bytes <= 0) { - channel->nb_bytes = 0; + if (channel->nb_bytes == 0) return; - } value = channel->tty_port.xmit_buf[*pointer_write]; iowrite8(value, &channel->regs->w.thr); @@ -194,15 +183,6 @@ static void ipoctal_irq_tx(struct ipoctal_channel *channel) (*pointer_write)++; *pointer_write = *pointer_write % PAGE_SIZE; channel->nb_bytes--; - - if ((channel->nb_bytes == 0) && - (waitqueue_active(&channel->queue))) { - - if (channel->board_id != IPACK1_DEVICE_ID_SBS_OCTAL_485) { - *channel->board_write = 1; - wake_up_interruptible(&channel->queue); - } - } } static void ipoctal_irq_channel(struct ipoctal_channel *channel) @@ -210,27 +190,24 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel) u8 isr, sr; struct tty_struct *tty; - /* If there is no client, skip the check */ - if (!atomic_read(&channel->open)) - return; - tty = tty_port_tty_get(&channel->tty_port); if (!tty) return; + + spin_lock(&channel->lock); /* 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)) { + if ((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); + /* 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) { + iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr); + iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); + } } /* RX data */ @@ -241,8 +218,8 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel) if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY)) ipoctal_irq_tx(channel); - tty_flip_buffer_push(tty); tty_kref_put(tty); + spin_unlock(&channel->lock); } static irqreturn_t ipoctal_irq_handler(void *arg) @@ -250,14 +227,14 @@ static irqreturn_t 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]); - /* Clear the IPack device interrupt */ readw(ipoctal->int_space + ACK_INT_REQ0); readw(ipoctal->int_space + ACK_INT_REQ1); + /* Check all channels */ + for (i = 0; i < NR_CHANNELS; i++) + ipoctal_irq_channel(&ipoctal->channel[i]); + return IRQ_HANDLED; } @@ -324,7 +301,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, struct ipoctal_channel *channel = &ipoctal->channel[i]; channel->regs = chan_regs + i; channel->block_regs = block_regs + (i >> 1); - channel->board_write = &ipoctal->write; channel->board_id = ipoctal->board_id; if (i & 1) { channel->isr_tx_rdy_mask = ISR_TxRDY_B; @@ -335,6 +311,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, } iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); + channel->rx_enable = 0; iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr); iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr); iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY, @@ -407,8 +384,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, ipoctal_reset_stats(&channel->stats); channel->nb_bytes = 0; - init_waitqueue_head(&channel->queue); - spin_lock_init(&channel->lock); channel->pointer_read = 0; channel->pointer_write = 0; @@ -419,12 +394,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, continue; } dev_set_drvdata(tty_dev, channel); - - /* - * Enable again the RX. TX will be enabled when - * there is something to send - */ - iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); } return 0; @@ -464,6 +433,7 @@ static int ipoctal_write_tty(struct tty_struct *tty, /* As the IP-OCTAL 485 only supports half duplex, do it manually */ if (channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) { iowrite8(CR_DISABLE_RX, &channel->regs->w.cr); + channel->rx_enable = 0; iowrite8(CR_CMD_ASSERT_RTSN, &channel->regs->w.cr); } @@ -472,10 +442,6 @@ static int ipoctal_write_tty(struct tty_struct *tty, * operations */ iowrite8(CR_ENABLE_TX, &channel->regs->w.cr); - wait_event_interruptible(channel->queue, *channel->board_write); - iowrite8(CR_DISABLE_TX, &channel->regs->w.cr); - - *channel->board_write = 0; return char_copied; } @@ -627,8 +593,9 @@ static void ipoctal_set_termios(struct tty_struct *tty, iowrite8(mr2, &channel->regs->w.mr); iowrite8(csr, &channel->regs->w.csr); - /* Enable again the RX */ - iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); + /* Enable again the RX, if it was before */ + if (channel->rx_enable) + iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); } static void ipoctal_hangup(struct tty_struct *tty) @@ -648,6 +615,7 @@ static void ipoctal_hangup(struct tty_struct *tty) tty_port_hangup(&channel->tty_port); iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); + channel->rx_enable = 0; iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr); iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr); iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);