Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31f35939 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds
Browse files

tty_port: Add a port level carrier detect operation



This is the first step to generalising the various pieces of waiting logic
duplicated in all sorts of serial drivers.

Signed-off-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent c9b3976e
Loading
Loading
Loading
Loading
+37 −24
Original line number Diff line number Diff line
@@ -2054,6 +2054,15 @@ static void esp_hangup(struct tty_struct *tty)
	wake_up_interruptible(&info->port.open_wait);
}

static int esp_carrier_raised(struct tty_port *port)
{
	struct esp_struct *info = container_of(port, struct esp_struct, port);
	serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
	if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD)
		return 1;
	return 0;
}

/*
 * ------------------------------------------------------------
 * esp_open() and friends
@@ -2066,17 +2075,19 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
	int		retval;
	int		do_clocal = 0;
	unsigned long	flags;
	int		cd;
	struct tty_port *port = &info->port;

	/*
	 * If the device is in the middle of being closed, then block
	 * until it's done, and then try again.
	 */
	if (tty_hung_up_p(filp) ||
	    (info->port.flags & ASYNC_CLOSING)) {
		if (info->port.flags & ASYNC_CLOSING)
			interruptible_sleep_on(&info->port.close_wait);
	    (port->flags & ASYNC_CLOSING)) {
		if (port->flags & ASYNC_CLOSING)
			interruptible_sleep_on(&port->close_wait);
#ifdef SERIAL_DO_RESTART
		if (info->port.flags & ASYNC_HUP_NOTIFY)
		if (port->flags & ASYNC_HUP_NOTIFY)
			return -EAGAIN;
		else
			return -ERESTARTSYS;
@@ -2091,7 +2102,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
	 */
	if ((filp->f_flags & O_NONBLOCK) ||
	    (tty->flags & (1 << TTY_IO_ERROR))) {
		info->port.flags |= ASYNC_NORMAL_ACTIVE;
		port->flags |= ASYNC_NORMAL_ACTIVE;
		return 0;
	}

@@ -2101,20 +2112,20 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
	/*
	 * Block waiting for the carrier detect and the line to become
	 * free (i.e., not in use by the callout).  While we are in
	 * this loop, info->port.count is dropped by one, so that
	 * this loop, port->count is dropped by one, so that
	 * rs_close() knows when to free things.  We restore it upon
	 * exit, either normal or abnormal.
	 */
	retval = 0;
	add_wait_queue(&info->port.open_wait, &wait);
	add_wait_queue(&port->open_wait, &wait);
#ifdef SERIAL_DEBUG_OPEN
	printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n",
	       info->line, info->port.count);
	       info->line, port->count);
#endif
	spin_lock_irqsave(&info->lock, flags);
	if (!tty_hung_up_p(filp))
		info->port.count--;
	info->port.blocked_open++;
		port->count--;
	port->blocked_open++;
	while (1) {
		if ((tty->termios->c_cflag & CBAUD)) {
			unsigned int scratch;
@@ -2129,9 +2140,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
		}
		set_current_state(TASK_INTERRUPTIBLE);
		if (tty_hung_up_p(filp) ||
		    !(info->port.flags & ASYNC_INITIALIZED)) {
		    !(port->flags & ASYNC_INITIALIZED)) {
#ifdef SERIAL_DO_RESTART
			if (info->port.flags & ASYNC_HUP_NOTIFY)
			if (port->flags & ASYNC_HUP_NOTIFY)
				retval = -EAGAIN;
			else
				retval = -ERESTARTSYS;
@@ -2141,11 +2152,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
			break;
		}

		serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
		if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD)
			do_clocal = 1;
		cd = tty_port_carrier_raised(port);

		if (!(info->port.flags & ASYNC_CLOSING) &&
		if (!(port->flags & ASYNC_CLOSING) &&
		    (do_clocal))
			break;
		if (signal_pending(current)) {
@@ -2154,25 +2163,25 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
		}
#ifdef SERIAL_DEBUG_OPEN
		printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n",
		       info->line, info->port.count);
		       info->line, port->count);
#endif
		spin_unlock_irqrestore(&info->lock, flags);
		schedule();
		spin_lock_irqsave(&info->lock, flags);
	}
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&info->port.open_wait, &wait);
	remove_wait_queue(&port->open_wait, &wait);
	if (!tty_hung_up_p(filp))
		info->port.count++;
	info->port.blocked_open--;
		port->count++;
	port->blocked_open--;
	spin_unlock_irqrestore(&info->lock, flags);
#ifdef SERIAL_DEBUG_OPEN
	printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n",
	       info->line, info->port.count);
	       info->line, port->count);
#endif
	if (retval)
		return retval;
	info->port.flags |= ASYNC_NORMAL_ACTIVE;
	port->flags |= ASYNC_NORMAL_ACTIVE;
	return 0;
}

@@ -2329,6 +2338,10 @@ static const struct tty_operations esp_ops = {
	.tiocmset = esp_tiocmset,
};

static const struct tty_port_operations esp_port_ops = {
	.esp_carrier_raised,
};

/*
 * The serial driver boot-time initialization code!
 */
@@ -2415,6 +2428,8 @@ static int __init espserial_init(void)
	offset = 0;

	do {
		tty_port_init(&info->port);
		info->port.ops = &esp_port_ops;
		info->io_port = esp[i] + offset;
		info->irq = irq[i];
		info->line = (i * 8) + (offset / 8);
@@ -2437,8 +2452,6 @@ static int __init espserial_init(void)
		info->config.flow_off = flow_off;
		info->config.pio_threshold = pio_threshold;
		info->next_port = ports;
		init_waitqueue_head(&info->port.open_wait);
		init_waitqueue_head(&info->port.close_wait);
		init_waitqueue_head(&info->delta_msr_wait);
		init_waitqueue_head(&info->break_wait);
		ports = info;
+22 −21
Original line number Diff line number Diff line
@@ -397,7 +397,8 @@ void gs_hangup(struct tty_struct *tty)

int gs_block_til_ready(void *port_, struct file * filp)
{
	struct gs_port *port = port_;
	struct gs_port *gp = port_;
	struct tty_port *port = &gp->port;
	DECLARE_WAITQUEUE(wait, current);
	int    retval;
	int    do_clocal = 0;
@@ -409,16 +410,16 @@ int gs_block_til_ready(void *port_, struct file * filp)

	if (!port) return 0;

	tty = port->port.tty;
	tty = port->tty;

	gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); 
	/*
	 * If the device is in the middle of being closed, then block
	 * until it's done, and then try again.
	 */
	if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
		interruptible_sleep_on(&port->port.close_wait);
		if (port->port.flags & ASYNC_HUP_NOTIFY)
	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
		interruptible_sleep_on(&port->close_wait);
		if (port->flags & ASYNC_HUP_NOTIFY)
			return -EAGAIN;
		else
			return -ERESTARTSYS;
@@ -432,7 +433,7 @@ int gs_block_til_ready(void *port_, struct file * filp)
	 */
	if ((filp->f_flags & O_NONBLOCK) ||
	    (tty->flags & (1 << TTY_IO_ERROR))) {
		port->port.flags |= ASYNC_NORMAL_ACTIVE;
		port->flags |= ASYNC_NORMAL_ACTIVE;
		return 0;
	}

@@ -444,34 +445,34 @@ int gs_block_til_ready(void *port_, struct file * filp)
	/*
	 * Block waiting for the carrier detect and the line to become
	 * free (i.e., not in use by the callout).  While we are in
	 * this loop, port->port.count is dropped by one, so that
	 * this loop, port->count is dropped by one, so that
	 * rs_close() knows when to free things.  We restore it upon
	 * exit, either normal or abnormal.
	 */
	retval = 0;

	add_wait_queue(&port->port.open_wait, &wait);
	add_wait_queue(&port->open_wait, &wait);

	gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); 
	spin_lock_irqsave(&port->driver_lock, flags);
	spin_lock_irqsave(&gp->driver_lock, flags);
	if (!tty_hung_up_p(filp)) {
		port->port.count--;
		port->count--;
	}
	spin_unlock_irqrestore(&port->driver_lock, flags);
	port->port.blocked_open++;
	spin_unlock_irqrestore(&gp->driver_lock, flags);
	port->blocked_open++;
	while (1) {
		CD = port->rd->get_CD (port);
		CD = tty_port_carrier_raised(port);
		gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD);
		set_current_state (TASK_INTERRUPTIBLE);
		if (tty_hung_up_p(filp) ||
		    !(port->port.flags & ASYNC_INITIALIZED)) {
			if (port->port.flags & ASYNC_HUP_NOTIFY)
		    !(port->flags & ASYNC_INITIALIZED)) {
			if (port->flags & ASYNC_HUP_NOTIFY)
				retval = -EAGAIN;
			else
				retval = -ERESTARTSYS;
			break;
		}
		if (!(port->port.flags & ASYNC_CLOSING) &&
		if (!(port->flags & ASYNC_CLOSING) &&
		    (do_clocal || CD))
			break;
		gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", 
@@ -483,17 +484,17 @@ int gs_block_til_ready(void *port_, struct file * filp)
		schedule();
	}
	gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n",
		    port->port.blocked_open);
		    port->blocked_open);
	set_current_state (TASK_RUNNING);
	remove_wait_queue(&port->port.open_wait, &wait);
	remove_wait_queue(&port->open_wait, &wait);
	if (!tty_hung_up_p(filp)) {
		port->port.count++;
		port->count++;
	}
	port->port.blocked_open--;
	port->blocked_open--;
	if (retval)
		return retval;

	port->port.flags |= ASYNC_NORMAL_ACTIVE;
	port->flags |= ASYNC_NORMAL_ACTIVE;
	func_exit ();
	return 0;
}			 
+32 −19
Original line number Diff line number Diff line
@@ -830,20 +830,28 @@ static int isicom_setup_port(struct tty_struct *tty)
	return 0;
}

static int isicom_carrier_raised(struct tty_port *port)
{
	struct isi_port *ip = container_of(port, struct isi_port, port);
	return (ip->status & ISI_DCD)?1 : 0;
}

static int block_til_ready(struct tty_struct *tty, struct file *filp,
	struct isi_port *port)
	struct isi_port *ip)
{
	struct isi_board *card = port->card;
	struct isi_board *card = ip->card;
	struct tty_port *port = &ip->port;
	int do_clocal = 0, retval;
	unsigned long flags;
	DECLARE_WAITQUEUE(wait, current);
	int cd;

	/* block if port is in the process of being closed */

	if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
		pr_dbg("block_til_ready: close in progress.\n");
		interruptible_sleep_on(&port->port.close_wait);
		if (port->port.flags & ASYNC_HUP_NOTIFY)
		interruptible_sleep_on(&port->close_wait);
		if (port->flags & ASYNC_HUP_NOTIFY)
			return -EAGAIN;
		else
			return -ERESTARTSYS;
@@ -854,7 +862,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
	if ((filp->f_flags & O_NONBLOCK) ||
			(tty->flags & (1 << TTY_IO_ERROR))) {
		pr_dbg("block_til_ready: non-block mode.\n");
		port->port.flags |= ASYNC_NORMAL_ACTIVE;
		port->flags |= ASYNC_NORMAL_ACTIVE;
		return 0;
	}

@@ -864,29 +872,29 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
	/* block waiting for DCD to be asserted, and while
						callout dev is busy */
	retval = 0;
	add_wait_queue(&port->port.open_wait, &wait);
	add_wait_queue(&port->open_wait, &wait);

	spin_lock_irqsave(&card->card_lock, flags);
	if (!tty_hung_up_p(filp))
		port->port.count--;
	port->port.blocked_open++;
		port->count--;
	port->blocked_open++;
	spin_unlock_irqrestore(&card->card_lock, flags);

	while (1) {
		raise_dtr_rts(port);
		raise_dtr_rts(ip);

		set_current_state(TASK_INTERRUPTIBLE);
		if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {
			if (port->port.flags & ASYNC_HUP_NOTIFY)
		if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
			if (port->flags & ASYNC_HUP_NOTIFY)
				retval = -EAGAIN;
			else
				retval = -ERESTARTSYS;
			break;
		}
		if (!(port->port.flags & ASYNC_CLOSING) &&
				(do_clocal || (port->status & ISI_DCD))) {
		cd = tty_port_carrier_raised(port);
		if (!(port->flags & ASYNC_CLOSING) &&
				(do_clocal || cd))
			break;
		}
		if (signal_pending(current)) {
			retval = -ERESTARTSYS;
			break;
@@ -894,15 +902,15 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
		schedule();
	}
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&port->port.open_wait, &wait);
	remove_wait_queue(&port->open_wait, &wait);
	spin_lock_irqsave(&card->card_lock, flags);
	if (!tty_hung_up_p(filp))
		port->port.count++;
	port->port.blocked_open--;
		port->count++;
	port->blocked_open--;
	spin_unlock_irqrestore(&card->card_lock, flags);
	if (retval)
		return retval;
	port->port.flags |= ASYNC_NORMAL_ACTIVE;
	port->flags |= ASYNC_NORMAL_ACTIVE;
	return 0;
}

@@ -1452,6 +1460,10 @@ static const struct tty_operations isicom_ops = {
	.break_ctl		= isicom_send_break,
};

static const struct tty_port_operations isicom_port_ops = {
	.carrier_raised		= isicom_carrier_raised,
};

static int __devinit reset_card(struct pci_dev *pdev,
	const unsigned int card, unsigned int *signature)
{
@@ -1794,6 +1806,7 @@ static int __init isicom_init(void)
		spin_lock_init(&isi_card[idx].card_lock);
		for (channel = 0; channel < 16; channel++, port++) {
			tty_port_init(&port->port);
			port->port.ops = &isicom_port_ops;
			port->magic = ISICOM_MAGIC;
			port->card = &isi_card[idx];
			port->channel = channel;
+20 −8
Original line number Diff line number Diff line
@@ -151,7 +151,7 @@ static char *stli_drvversion = "5.6.0";
static char	*stli_serialname = "ttyE";

static struct tty_driver	*stli_serial;

static const struct tty_port_operations stli_port_ops;

#define	STLI_TXBUFSIZE		4096

@@ -1183,6 +1183,12 @@ static int stli_setport(struct tty_struct *tty)

/*****************************************************************************/

static int stli_carrier_raised(struct tty_port *port)
{
	struct stliport *portp = container_of(port, struct stliport, port);
	return (portp->sigs & TIOCM_CD) ? 1 : 0;
}

/*
 *	Possibly need to wait for carrier (DCD signal) to come high. Say
 *	maybe because if we are clocal then we don't need to wait...
@@ -1193,6 +1199,7 @@ static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
{
	unsigned long flags;
	int rc, doclocal;
	struct tty_port *port = &portp->port;

	rc = 0;
	doclocal = 0;
@@ -1203,7 +1210,7 @@ static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
	spin_lock_irqsave(&stli_lock, flags);
	portp->openwaitcnt++;
	if (! tty_hung_up_p(filp))
		portp->port.count--;
		port->count--;
	spin_unlock_irqrestore(&stli_lock, flags);

	for (;;) {
@@ -1212,27 +1219,27 @@ static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
		    &portp->asig, sizeof(asysigs_t), 0)) < 0)
			break;
		if (tty_hung_up_p(filp) ||
		    ((portp->port.flags & ASYNC_INITIALIZED) == 0)) {
			if (portp->port.flags & ASYNC_HUP_NOTIFY)
		    ((port->flags & ASYNC_INITIALIZED) == 0)) {
			if (port->flags & ASYNC_HUP_NOTIFY)
				rc = -EBUSY;
			else
				rc = -ERESTARTSYS;
			break;
		}
		if (((portp->port.flags & ASYNC_CLOSING) == 0) &&
		    (doclocal || (portp->sigs & TIOCM_CD))) {
		if (((port->flags & ASYNC_CLOSING) == 0) &&
		    (doclocal || tty_port_carrier_raised(port))) {
			break;
		}
		if (signal_pending(current)) {
			rc = -ERESTARTSYS;
			break;
		}
		interruptible_sleep_on(&portp->port.open_wait);
		interruptible_sleep_on(&port->open_wait);
	}

	spin_lock_irqsave(&stli_lock, flags);
	if (! tty_hung_up_p(filp))
		portp->port.count++;
		port->count++;
	portp->openwaitcnt--;
	spin_unlock_irqrestore(&stli_lock, flags);

@@ -2696,6 +2703,7 @@ static int stli_initports(struct stlibrd *brdp)
			continue;
		}
		tty_port_init(&portp->port);
		portp->port.ops = &stli_port_ops;
		portp->magic = STLI_PORTMAGIC;
		portp->portnr = i;
		portp->brdnr = brdp->brdnr;
@@ -4518,6 +4526,10 @@ static const struct tty_operations stli_ops = {
	.tiocmset = stli_tiocmset,
};

static const struct tty_port_operations stli_port_ops = {
	.carrier_raised = stli_carrier_raised,
};

/*****************************************************************************/
/*
 *	Loadable module initialization stuff.
+21 −5
Original line number Diff line number Diff line
@@ -206,6 +206,7 @@ static void moxa_poll(unsigned long);
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
static void moxa_setup_empty_event(struct tty_struct *);
static void moxa_shut_down(struct tty_struct *);
static int moxa_carrier_raised(struct tty_port *);
/*
 * moxa board interface functions:
 */
@@ -405,6 +406,10 @@ static const struct tty_operations moxa_ops = {
	.tiocmset = moxa_tiocmset,
};

static const struct tty_port_operations moxa_port_ops = {
	.carrier_raised = moxa_carrier_raised,
};

static struct tty_driver *moxaDriver;
static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
static DEFINE_SPINLOCK(moxa_lock);
@@ -826,6 +831,7 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)

	for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
		tty_port_init(&p->port);
		p->port.ops = &moxa_port_ops;
		p->type = PORT_16550A;
		p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
	}
@@ -1115,15 +1121,27 @@ static void moxa_close_port(struct tty_struct *tty)
	tty_port_tty_set(&ch->port, NULL);
}

static int moxa_carrier_raised(struct tty_port *port)
{
	struct moxa_port *ch = container_of(port, struct moxa_port, port);
	int dcd;

	spin_lock_bh(&moxa_lock);
	dcd = ch->DCDState;
	spin_unlock_bh(&moxa_lock);
	return dcd;
}

static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
			    struct moxa_port *ch)
{
	struct tty_port *port = &ch->port;
	DEFINE_WAIT(wait);
	int retval = 0;
	u8 dcd;

	while (1) {
		prepare_to_wait(&ch->port.open_wait, &wait, TASK_INTERRUPTIBLE);
		prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
		if (tty_hung_up_p(filp)) {
#ifdef SERIAL_DO_RESTART
			retval = -ERESTARTSYS;
@@ -1132,9 +1150,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
#endif
			break;
		}
		spin_lock_bh(&moxa_lock);
		dcd = ch->DCDState;
		spin_unlock_bh(&moxa_lock);
		dcd = tty_port_carrier_raised(port);
		if (dcd)
			break;

@@ -1144,7 +1160,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
		}
		schedule();
	}
	finish_wait(&ch->port.open_wait, &wait);
	finish_wait(&port->open_wait, &wait);

	return retval;
}
Loading