Пример #1
0
static irqreturn_t isicom_interrupt(int irq, void *dev_id)
{
	struct isi_board *card = dev_id;
	struct isi_port *port;
	struct tty_struct *tty;
	unsigned long base;
	u16 header, word_count, count, channel;
	short byte_count;
	unsigned char *rp;

	if (!card || !(card->status & FIRMWARE_LOADED))
		return IRQ_NONE;

	base = card->base;

	/* did the card interrupt us? */
	if (!(inw(base + 0x0e) & 0x02))
		return IRQ_NONE;

	spin_lock(&card->card_lock);

	/*
	 * disable any interrupts from the PCI card and lower the
	 * interrupt line
	 */
	outw(0x8000, base+0x04);
	ClearInterrupt(base);

	inw(base);		/* get the dummy word out */
	header = inw(base);
	channel = (header & 0x7800) >> card->shift_count;
	byte_count = header & 0xff;

	if (channel + 1 > card->port_count) {
		pr_warn("%s(0x%lx): %d(channel) > port_count\n",
			__func__, base, channel + 1);
		outw(0x0000, base+0x04); /* enable interrupts */
		spin_unlock(&card->card_lock);
		return IRQ_HANDLED;
	}
	port = card->ports + channel;
	if (!tty_port_initialized(&port->port)) {
		outw(0x0000, base+0x04); /* enable interrupts */
		spin_unlock(&card->card_lock);
		return IRQ_HANDLED;
	}

	tty = tty_port_tty_get(&port->port);
	if (tty == NULL) {
		word_count = byte_count >> 1;
		while (byte_count > 1) {
			inw(base);
			byte_count -= 2;
		}
		if (byte_count & 0x01)
			inw(base);
		outw(0x0000, base+0x04); /* enable interrupts */
		spin_unlock(&card->card_lock);
		return IRQ_HANDLED;
	}
Пример #2
0
static int sierra_resume(struct usb_serial *serial)
{
	struct usb_serial_port *port;
	struct sierra_intf_private *intfdata = usb_get_serial_data(serial);
	int ec = 0;
	int i, err;

	spin_lock_irq(&intfdata->susp_lock);
	for (i = 0; i < serial->num_ports; i++) {
		port = serial->port[i];

		if (!tty_port_initialized(&port->port))
			continue;

		err = sierra_submit_delayed_urbs(port);
		if (err)
			ec++;

		err = sierra_submit_rx_urbs(port, GFP_ATOMIC);
		if (err)
			ec++;
	}
	intfdata->suspended = 0;
	spin_unlock_irq(&intfdata->susp_lock);

	return ec ? -EIO : 0;
}
Пример #3
0
/*
 * Fire up a 3215 device.
 */
static int raw3215_startup(struct raw3215_info *raw)
{
	unsigned long flags;

	if (tty_port_initialized(&raw->port))
		return 0;
	raw->line_pos = 0;
	tty_port_set_initialized(&raw->port, 1);
	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
	raw3215_try_io(raw);
	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);

	return 0;
}
Пример #4
0
/*
 * This routine will shutdown a serial port; interrupts are disabled, and
 * DTR is dropped if the hangup on close termio flag is on.
 */
static void shutdown(struct tty_struct *tty, struct serial_state *info)
{
	unsigned long	flags;
	struct serial_state *state;

	if (!tty_port_initialized(&info->tport))
		return;

	state = info;

#ifdef SERIAL_DEBUG_OPEN
	printk("Shutting down serial port %d ....\n", info->line);
#endif

	local_irq_save(flags); /* Disable interrupts */

	/*
	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
	 * here so the queue might never be waken up
	 */
	wake_up_interruptible(&info->tport.delta_msr_wait);

	/*
	 * Free the IRQ, if necessary
	 */
	free_irq(IRQ_AMIGA_VERTB, info);

	if (info->xmit.buf) {
		free_page((unsigned long) info->xmit.buf);
		info->xmit.buf = NULL;
	}

	info->IER = 0;
	custom.intena = IF_RBF | IF_TBE;
	mb();

	/* disable break condition */
	custom.adkcon = AC_UARTBRK;
	mb();

	if (C_HUPCL(tty))
		info->MCR &= ~(SER_DTR|SER_RTS);
	rtsdtr_ctrl(info->MCR);

	set_bit(TTY_IO_ERROR, &tty->flags);

	tty_port_set_initialized(&info->tport, 0);
	local_irq_restore(flags);
}
Пример #5
0
static inline void line_info(struct seq_file *m, int line,
		struct serial_state *state)
{
	char	stat_buf[30], control, status;
	unsigned long flags;

	seq_printf(m, "%d: uart:amiga_builtin", line);

	local_irq_save(flags);
	status = ciab.pra;
	control = tty_port_initialized(&state->tport) ? state->MCR : status;
	local_irq_restore(flags);

	stat_buf[0] = 0;
	stat_buf[1] = 0;
	if(!(control & SER_RTS))
		strcat(stat_buf, "|RTS");
	if(!(status & SER_CTS))
		strcat(stat_buf, "|CTS");
	if(!(control & SER_DTR))
		strcat(stat_buf, "|DTR");
	if(!(status & SER_DSR))
		strcat(stat_buf, "|DSR");
	if(!(status & SER_DCD))
		strcat(stat_buf, "|CD");

	if (state->quot)
		seq_printf(m, " baud:%d", state->baud_base / state->quot);

	seq_printf(m, " tx:%d rx:%d", state->icount.tx, state->icount.rx);

	if (state->icount.frame)
		seq_printf(m, " fe:%d", state->icount.frame);

	if (state->icount.parity)
		seq_printf(m, " pe:%d", state->icount.parity);

	if (state->icount.brk)
		seq_printf(m, " brk:%d", state->icount.brk);

	if (state->icount.overrun)
		seq_printf(m, " oe:%d", state->icount.overrun);

	/*
	 * Last thing is the RS-232 status lines
	 */
	seq_printf(m, " %s\n", stat_buf+1);
}
Пример #6
0
/*
 * ------------------------------------------------------------
 * rs_close()
 * 
 * This routine is called when the serial port gets closed.  First, we
 * wait for the last remaining data to be sent.  Then, we unlink its
 * async structure from the interrupt chain if necessary, and we free
 * that IRQ if nothing is left in the chain.
 * ------------------------------------------------------------
 */
static void rs_close(struct tty_struct *tty, struct file * filp)
{
	struct serial_state *state = tty->driver_data;
	struct tty_port *port = &state->tport;

	if (serial_paranoia_check(state, tty->name, "rs_close"))
		return;

	if (tty_port_close_start(port, tty, filp) == 0)
		return;

	/*
	 * At this point we stop accepting input.  To do this, we
	 * disable the receive line status interrupts, and tell the
	 * interrupt driver to stop checking the data ready bit in the
	 * line status register.
	 */
	state->read_status_mask &= ~UART_LSR_DR;
	if (tty_port_initialized(port)) {
	        /* disable receive interrupts */
	        custom.intena = IF_RBF;
		mb();
		/* clear any pending receive interrupt */
		custom.intreq = IF_RBF;
		mb();

		/*
		 * Before we drop DTR, make sure the UART transmitter
		 * has completely drained; this is especially
		 * important if there is a transmit FIFO!
		 */
		rs_wait_until_sent(tty, state->timeout);
	}
	shutdown(tty, state);
	rs_flush_buffer(tty);
		
	tty_ldisc_flush(tty);
	port->tty = NULL;

	tty_port_close_end(port, tty);
}
Пример #7
0
static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
{
	mutex_lock(&port->mutex);
	if (port->console)
		goto out;

	if (tty_port_initialized(port)) {
		tty_port_set_initialized(port, 0);
		/*
		 * Drop DTR/RTS if HUPCL is set. This causes any attached
		 * modem to hang up the line.
		 */
		if (tty && C_HUPCL(tty))
			tty_port_lower_dtr_rts(port);

		if (port->ops->shutdown)
			port->ops->shutdown(port);
	}
out:
	mutex_unlock(&port->mutex);
}
Пример #8
0
/*
 * Function to conditionally start an IO. A read is started immediately,
 * a write is only started immediately if the flush flag is on or the
 * amount of data is bigger than RAW3215_MIN_WRITE. If a write is not
 * done immediately a timer is started with a delay of RAW3215_TIMEOUT.
 */
static inline void raw3215_try_io(struct raw3215_info *raw)
{
	if (!tty_port_initialized(&raw->port) || tty_port_suspended(&raw->port))
		return;
	if (raw->queued_read != NULL)
		raw3215_start_io(raw);
	else if (raw->queued_write != NULL) {
		if ((raw->queued_write->delayable == 0) ||
		    (raw->flags & RAW3215_FLUSHING)) {
			/* execute write requests bigger than minimum size */
			raw3215_start_io(raw);
		}
	}
	if ((raw->queued_read || raw->queued_write) &&
	    !(raw->flags & RAW3215_WORKING) &&
	    !(raw->flags & RAW3215_TIMER_RUNS)) {
		raw->timer.expires = RAW3215_TIMEOUT + jiffies;
		add_timer(&raw->timer);
		raw->flags |= RAW3215_TIMER_RUNS;
	}
}
Пример #9
0
/*
 * Shutdown a 3215 device.
 */
static void raw3215_shutdown(struct raw3215_info *raw)
{
	DECLARE_WAITQUEUE(wait, current);
	unsigned long flags;

	if (!tty_port_initialized(&raw->port) || (raw->flags & RAW3215_FIXED))
		return;
	/* Wait for outstanding requests, then free irq */
	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
	if ((raw->flags & RAW3215_WORKING) ||
	    raw->queued_write != NULL ||
	    raw->queued_read != NULL) {
		add_wait_queue(&raw->empty_wait, &wait);
		set_current_state(TASK_INTERRUPTIBLE);
		spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
		schedule();
		spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
		remove_wait_queue(&raw->empty_wait, &wait);
		set_current_state(TASK_RUNNING);
		tty_port_set_initialized(&raw->port, 1);
	}
	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}
Пример #10
0
int tty_port_block_til_ready(struct tty_port *port,
				struct tty_struct *tty, struct file *filp)
{
	int do_clocal = 0, retval;
	unsigned long flags;
	DEFINE_WAIT(wait);

	/* if non-blocking mode is set we can pass directly to open unless
	   the port has just hung up or is in another error state */
	if (tty_io_error(tty)) {
		tty_port_set_active(port, 1);
		return 0;
	}
	if (filp == NULL || (filp->f_flags & O_NONBLOCK)) {
		/* Indicate we are open */
		if (C_BAUD(tty))
			tty_port_raise_dtr_rts(port);
		tty_port_set_active(port, 1);
		return 0;
	}

	if (C_CLOCAL(tty))
		do_clocal = 1;

	/* Block waiting until we can proceed. We may need to wait for the
	   carrier, but we must also wait for any close that is in progress
	   before the next open may complete */

	retval = 0;

	/* The port lock protects the port counts */
	spin_lock_irqsave(&port->lock, flags);
	port->count--;
	port->blocked_open++;
	spin_unlock_irqrestore(&port->lock, flags);

	while (1) {
		/* Indicate we are open */
		if (C_BAUD(tty) && tty_port_initialized(port))
			tty_port_raise_dtr_rts(port);

		prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
		/* Check for a hangup or uninitialised port.
							Return accordingly */
		if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
			if (port->flags & ASYNC_HUP_NOTIFY)
				retval = -EAGAIN;
			else
				retval = -ERESTARTSYS;
			break;
		}
		/*
		 * Probe the carrier. For devices with no carrier detect
		 * tty_port_carrier_raised will always return true.
		 * Never ask drivers if CLOCAL is set, this causes troubles
		 * on some hardware.
		 */
		if (do_clocal || tty_port_carrier_raised(port))
			break;
		if (signal_pending(current)) {
			retval = -ERESTARTSYS;
			break;
		}
		tty_unlock(tty);
		schedule();
		tty_lock(tty);
	}
	finish_wait(&port->open_wait, &wait);

	/* Update counts. A parallel hangup will have set count to zero and
	   we must not mess that up further */
	spin_lock_irqsave(&port->lock, flags);
	if (!tty_hung_up_p(filp))
		port->count++;
	port->blocked_open--;
	spin_unlock_irqrestore(&port->lock, flags);
	if (retval == 0)
		tty_port_set_active(port, 1);
	return retval;
}
Пример #11
0
static void isicom_tx(struct timer_list *unused)
{
	unsigned long flags, base;
	unsigned int retries;
	short count = (BOARD_COUNT-1), card;
	short txcount, wrd, residue, word_count, cnt;
	struct isi_port *port;
	struct tty_struct *tty;

	/*	find next active board	*/
	card = (prev_card + 1) & 0x0003;
	while (count-- > 0) {
		if (isi_card[card].status & BOARD_ACTIVE)
			break;
		card = (card + 1) & 0x0003;
	}
	if (!(isi_card[card].status & BOARD_ACTIVE))
		goto sched_again;

	prev_card = card;

	count = isi_card[card].port_count;
	port = isi_card[card].ports;
	base = isi_card[card].base;

	spin_lock_irqsave(&isi_card[card].card_lock, flags);
	for (retries = 0; retries < 100; retries++) {
		if (inw(base + 0xe) & 0x1)
			break;
		udelay(2);
	}
	if (retries >= 100)
		goto unlock;

	tty = tty_port_tty_get(&port->port);
	if (tty == NULL)
		goto put_unlock;

	for (; count > 0; count--, port++) {
		/* port not active or tx disabled to force flow control */
		if (!tty_port_initialized(&port->port) ||
			!(port->status & ISI_TXOK))
			continue;

		txcount = min_t(short, TX_SIZE, port->xmit_cnt);
		if (txcount <= 0 || tty->stopped || tty->hw_stopped)
			continue;

		if (!(inw(base + 0x02) & (1 << port->channel)))
			continue;

		pr_debug("txing %d bytes, port%d.\n",
			 txcount, port->channel + 1);
		outw((port->channel << isi_card[card].shift_count) | txcount,
			base);
		residue = NO;
		wrd = 0;
		while (1) {
			cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE
					- port->xmit_tail));
			if (residue == YES) {
				residue = NO;
				if (cnt > 0) {
					wrd |= (port->port.xmit_buf[port->xmit_tail]
									<< 8);
					port->xmit_tail = (port->xmit_tail + 1)
						& (SERIAL_XMIT_SIZE - 1);
					port->xmit_cnt--;
					txcount--;
					cnt--;
					outw(wrd, base);
				} else {
					outw(wrd, base);
					break;
				}
			}
			if (cnt <= 0)
				break;
			word_count = cnt >> 1;
			outsw(base, port->port.xmit_buf+port->xmit_tail, word_count);
			port->xmit_tail = (port->xmit_tail
				+ (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
			txcount -= (word_count << 1);
			port->xmit_cnt -= (word_count << 1);
			if (cnt & 0x0001) {
				residue = YES;
				wrd = port->port.xmit_buf[port->xmit_tail];
				port->xmit_tail = (port->xmit_tail + 1)
					& (SERIAL_XMIT_SIZE - 1);
				port->xmit_cnt--;
				txcount--;
			}
		}

		InterruptTheCard(base);
		if (port->xmit_cnt <= 0)
			port->status &= ~ISI_TXOK;
		if (port->xmit_cnt <= WAKEUP_CHARS)
			tty_wakeup(tty);
	}

put_unlock:
	tty_kref_put(tty);
unlock:
	spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
	/*	schedule another tx for hopefully in about 10ms	*/
sched_again:
	mod_timer(&tx, jiffies + msecs_to_jiffies(10));
}
Пример #12
0
static int startup(struct tty_struct *tty, struct serial_state *info)
{
	struct tty_port *port = &info->tport;
	unsigned long flags;
	int	retval=0;
	unsigned long page;

	page = get_zeroed_page(GFP_KERNEL);
	if (!page)
		return -ENOMEM;

	local_irq_save(flags);

	if (tty_port_initialized(port)) {
		free_page(page);
		goto errout;
	}

	if (info->xmit.buf)
		free_page(page);
	else
		info->xmit.buf = (unsigned char *) page;

#ifdef SERIAL_DEBUG_OPEN
	printk("starting up ttys%d ...", info->line);
#endif

	/* Clear anything in the input buffer */

	custom.intreq = IF_RBF;
	mb();

	retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info);
	if (retval) {
	  if (serial_isroot()) {
	      set_bit(TTY_IO_ERROR, &tty->flags);
	    retval = 0;
	  }
	  goto errout;
	}

	/* enable both Rx and Tx interrupts */
	custom.intena = IF_SETCLR | IF_RBF | IF_TBE;
	mb();
	info->IER = UART_IER_MSI;

	/* remember current state of the DCD and CTS bits */
	current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR);

	info->MCR = 0;
	if (C_BAUD(tty))
	  info->MCR = SER_DTR | SER_RTS;
	rtsdtr_ctrl(info->MCR);

	clear_bit(TTY_IO_ERROR, &tty->flags);
	info->xmit.head = info->xmit.tail = 0;

	/*
	 * and set the speed of the serial port
	 */
	change_speed(tty, info, NULL);

	tty_port_set_initialized(port, 1);
	local_irq_restore(flags);
	return 0;

errout:
	local_irq_restore(flags);
	return retval;
}
Пример #13
0
static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
	struct serial_state *state = tty->driver_data;
	struct tty_port *port = &state->tport;
	bool change_spd;
	int 			retval = 0;

	tty_lock(tty);
	change_spd = ((ss->flags ^ port->flags) & ASYNC_SPD_MASK) ||
		ss->custom_divisor != state->custom_divisor;
	if (ss->irq || ss->port != state->port ||
			ss->xmit_fifo_size != state->xmit_fifo_size) {
		tty_unlock(tty);
		return -EINVAL;
	}
  
	if (!serial_isroot()) {
		if ((ss->baud_base != state->baud_base) ||
		    (ss->close_delay != port->close_delay) ||
		    (ss->xmit_fifo_size != state->xmit_fifo_size) ||
		    ((ss->flags & ~ASYNC_USR_MASK) !=
		     (port->flags & ~ASYNC_USR_MASK))) {
			tty_unlock(tty);
			return -EPERM;
		}
		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
			       (ss->flags & ASYNC_USR_MASK));
		state->custom_divisor = ss->custom_divisor;
		goto check_and_exit;
	}

	if (ss->baud_base < 9600) {
		tty_unlock(tty);
		return -EINVAL;
	}

	/*
	 * OK, past this point, all the error checking has been done.
	 * At this point, we start making changes.....
	 */

	state->baud_base = ss->baud_base;
	port->flags = ((port->flags & ~ASYNC_FLAGS) |
			(ss->flags & ASYNC_FLAGS));
	state->custom_divisor = ss->custom_divisor;
	port->close_delay = ss->close_delay * HZ/100;
	port->closing_wait = ss->closing_wait * HZ/100;
	port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;

check_and_exit:
	if (tty_port_initialized(port)) {
		if (change_spd) {
			/* warn about deprecation unless clearing */
			if (ss->flags & ASYNC_SPD_MASK)
				dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
			change_speed(tty, state, NULL);
		}
	} else
		retval = startup(tty, state);
	tty_unlock(tty);
	return retval;
}