--- zzzz-none-000/linux-3.10.107/drivers/ipack/devices/ipoctal.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/ipack/devices/ipoctal.c 2021-02-04 17:41:59.000000000 +0000 @@ -55,6 +55,22 @@ u8 __iomem *int_space; }; +static inline struct ipoctal *chan_to_ipoctal(struct ipoctal_channel *chan, + unsigned int index) +{ + return container_of(chan, struct ipoctal, channel[index]); +} + +static void ipoctal_reset_channel(struct ipoctal_channel *channel) +{ + 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); + iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr); +} + static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty) { struct ipoctal_channel *channel; @@ -72,12 +88,20 @@ static int ipoctal_open(struct tty_struct *tty, struct file *file) { - struct ipoctal_channel *channel; + struct ipoctal_channel *channel = dev_get_drvdata(tty->dev); + struct ipoctal *ipoctal = chan_to_ipoctal(channel, tty->index); + int err; - channel = dev_get_drvdata(tty->dev); tty->driver_data = channel; - return tty_port_open(&channel->tty_port, tty, file); + if (!ipack_get_carrier(ipoctal->dev)) + return -EBUSY; + + err = tty_port_open(&channel->tty_port, tty, file); + if (err) + ipack_put_carrier(ipoctal->dev); + + return err; } static void ipoctal_reset_stats(struct ipoctal_stats *stats) @@ -151,7 +175,6 @@ flag = TTY_FRAME; } if (sr & SR_RECEIVED_BREAK) { - iowrite8(CR_CMD_RESET_BREAK_CHANGE, &channel->regs->w.cr); channel->stats.rcv_break++; flag = TTY_BREAK; } @@ -177,24 +200,28 @@ if (channel->nb_bytes == 0) return; + spin_lock(&channel->lock); value = channel->tty_port.xmit_buf[*pointer_write]; iowrite8(value, &channel->regs->w.thr); channel->stats.tx++; (*pointer_write)++; *pointer_write = *pointer_write % PAGE_SIZE; channel->nb_bytes--; + spin_unlock(&channel->lock); } static void ipoctal_irq_channel(struct ipoctal_channel *channel) { u8 isr, sr; - 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); + if (isr & (IMR_DELTA_BREAK_A | IMR_DELTA_BREAK_B)) + iowrite8(CR_CMD_RESET_BREAK_CHANGE, &channel->regs->w.cr); + if ((sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) { iowrite8(CR_DISABLE_TX, &channel->regs->w.cr); /* In case of RS-485, change from TX to RX when finishing TX. @@ -213,8 +240,6 @@ /* TX of each character */ if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY)) ipoctal_irq_tx(channel); - - spin_unlock(&channel->lock); } static irqreturn_t ipoctal_irq_handler(void *arg) @@ -305,10 +330,7 @@ channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_A; } - 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); + ipoctal_reset_channel(channel); iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY, &channel->regs->w.mr); /* mr1 */ iowrite8(0, &channel->regs->w.mr); /* mr2 */ @@ -324,13 +346,6 @@ &block_regs[i].w.imr); } - /* - * IP-OCTAL has different addresses to copy its IRQ vector. - * Depending of the carrier these addresses are accesible or not. - * More info in the datasheet. - */ - ipoctal->dev->bus->ops->request_irq(ipoctal->dev, - ipoctal_irq_handler, ipoctal); /* Dummy write */ iowrite8(1, ipoctal->mem8_space + 1); @@ -391,6 +406,14 @@ dev_set_drvdata(tty_dev, channel); } + /* + * IP-OCTAL has different addresses to copy its IRQ vector. + * Depending of the carrier these addresses are accesible or not. + * More info in the datasheet. + */ + ipoctal->dev->bus->ops->request_irq(ipoctal->dev, + ipoctal_irq_handler, ipoctal); + return 0; } @@ -467,11 +490,7 @@ cflag = tty->termios.c_cflag; /* Disable and reset everything before change the setup */ - iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); - 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); - iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr); + ipoctal_reset_channel(channel); /* Set Bits per chars */ switch (cflag & CSIZE) { @@ -609,12 +628,7 @@ 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); - iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr); + ipoctal_reset_channel(channel); clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags); wake_up_interruptible(&channel->tty_port.open_wait); @@ -627,15 +641,19 @@ if (channel == NULL) return; - 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); - iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr); + ipoctal_reset_channel(channel); clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags); } +static void ipoctal_cleanup(struct tty_struct *tty) +{ + struct ipoctal_channel *channel = tty->driver_data; + struct ipoctal *ipoctal = chan_to_ipoctal(channel, tty->index); + + /* release the carrier driver */ + ipack_put_carrier(ipoctal->dev); +} + static const struct tty_operations ipoctal_fops = { .ioctl = NULL, .open = ipoctal_open, @@ -647,6 +665,7 @@ .get_icount = ipoctal_get_icount, .hangup = ipoctal_hangup, .shutdown = ipoctal_shutdown, + .cleanup = ipoctal_cleanup, }; static int ipoctal_probe(struct ipack_device *dev)