Beispiel #1
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 (port->flags & ASYNC_INITIALIZED) {
		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;

	/*
	 * Set up the tty->alt_speed kludge
	 */
	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
		tty->alt_speed = 57600;
	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
		tty->alt_speed = 115200;
	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
		tty->alt_speed = 230400;
	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
		tty->alt_speed = 460800;

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

	port->flags |= ASYNC_INITIALIZED;
	local_irq_restore(flags);
	return 0;

errout:
	local_irq_restore(flags);
	return retval;
}
Beispiel #2
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;
}
Beispiel #3
0
static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
			   struct serial_struct __user * new_info)
{
	struct tty_port *port = &state->tport;
	struct serial_struct new_serial;
	bool change_spd;
	int 			retval = 0;

	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
		return -EFAULT;

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

	if (new_serial.baud_base < 9600) {
		tty_unlock();
		return -EINVAL;
	}

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

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

check_and_exit:
	if (port->flags & ASYNC_INITIALIZED) {
		if (change_spd) {
			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
				tty->alt_speed = 57600;
			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
				tty->alt_speed = 115200;
			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
				tty->alt_speed = 230400;
			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
				tty->alt_speed = 460800;
			change_speed(tty, state, NULL);
		}
	} else
		retval = startup(tty, state);
	tty_unlock();
	return retval;
}
static int set_serial_info(struct async_struct * info,
			   struct serial_struct __user * new_info)
{
	struct serial_struct new_serial;
 	struct serial_state old_state, *state;
	unsigned int		change_irq,change_port;
	int 			retval = 0;

	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
		return -EFAULT;

	lock_kernel();
	state = info->state;
	old_state = *state;
  
	change_irq = new_serial.irq != state->irq;
	change_port = (new_serial.port != state->port);
	if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) {
	  unlock_kernel();
	  return -EINVAL;
	}
  
	if (!serial_isroot()) {
		if ((new_serial.baud_base != state->baud_base) ||
		    (new_serial.close_delay != state->close_delay) ||
		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
		     (state->flags & ~ASYNC_USR_MASK)))
			return -EPERM;
		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
			       (new_serial.flags & ASYNC_USR_MASK));
		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
			       (new_serial.flags & ASYNC_USR_MASK));
		state->custom_divisor = new_serial.custom_divisor;
		goto check_and_exit;
	}

	if (new_serial.baud_base < 9600) {
		unlock_kernel();
		return -EINVAL;
	}

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

	state->baud_base = new_serial.baud_base;
	state->flags = ((state->flags & ~ASYNC_FLAGS) |
			(new_serial.flags & ASYNC_FLAGS));
	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
		       (info->flags & ASYNC_INTERNAL_FLAGS));
	state->custom_divisor = new_serial.custom_divisor;
	state->close_delay = new_serial.close_delay * HZ/100;
	state->closing_wait = new_serial.closing_wait * HZ/100;
	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;

check_and_exit:
	if (info->flags & ASYNC_INITIALIZED) {
		if (((old_state.flags & ASYNC_SPD_MASK) !=
		     (state->flags & ASYNC_SPD_MASK)) ||
		    (old_state.custom_divisor != state->custom_divisor)) {
			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
				info->tty->alt_speed = 57600;
			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
				info->tty->alt_speed = 115200;
			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
				info->tty->alt_speed = 230400;
			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
				info->tty->alt_speed = 460800;
			change_speed(info, NULL);
		}
	} else
		retval = startup(info);
	unlock_kernel();
	return retval;
}