Merge branch 'tty-updates' from Alan

* tty-updates: (75 commits)
  serial_8250: support for Sealevel Systems Model 7803 COMM+8
  hso maintainers update patch
  hso modem detect fix patch against Alan Cox'es tty tree
  tty: Fix an ircomm warning and note another bug
  drivers/char/cyclades.c: cy_pci_probe: fix error path
  Serial: UART driver changes for Cavium OCTEON.
  Serial: Allow port type to be specified when calling serial8250_register_port.
  8250: Serial driver changes to support future Cavium OCTEON serial patches.
  8250: Don't clobber spinlocks.
  fix for tty-serial-move-port
  tty: We want the port object to be persistent
  __FUNCTION__ is gcc-specific, use __func__
  serial: RS485 ioctl structure uses __u32 include linux/types.h
  tty: Drop the lock_kernel in the private ioctl hook
  synclink_cs: Convert to tty_port
  tty: use port methods for the rocket driver
  tty: kref the rocket driver
  tty: make rocketport use standard port->flags
  tty: Redo the rocket driver locking
  tty: Make epca use the port helpers
  ...
This commit is contained in:
Linus Torvalds 2009-01-02 10:25:51 -08:00
commit d2fde28ce7
64 changed files with 3559 additions and 2625 deletions

View File

@ -0,0 +1,132 @@
To support containers, we now allow multiple instances of devpts filesystem,
such that indices of ptys allocated in one instance are independent of indices
allocated in other instances of devpts.
To preserve backward compatibility, this support for multiple instances is
enabled only if:
- CONFIG_DEVPTS_MULTIPLE_INSTANCES=y, and
- '-o newinstance' mount option is specified while mounting devpts
IOW, devpts now supports both single-instance and multi-instance semantics.
If CONFIG_DEVPTS_MULTIPLE_INSTANCES=n, there is no change in behavior and
this referred to as the "legacy" mode. In this mode, the new mount options
(-o newinstance and -o ptmxmode) will be ignored with a 'bogus option' message
on console.
If CONFIG_DEVPTS_MULTIPLE_INSTANCES=y and devpts is mounted without the
'newinstance' option (as in current start-up scripts) the new mount binds
to the initial kernel mount of devpts. This mode is referred to as the
'single-instance' mode and the current, single-instance semantics are
preserved, i.e PTYs are common across the system.
The only difference between this single-instance mode and the legacy mode
is the presence of new, '/dev/pts/ptmx' node with permissions 0000, which
can safely be ignored.
If CONFIG_DEVPTS_MULTIPLE_INSTANCES=y and 'newinstance' option is specified,
the mount is considered to be in the multi-instance mode and a new instance
of the devpts fs is created. Any ptys created in this instance are independent
of ptys in other instances of devpts. Like in the single-instance mode, the
/dev/pts/ptmx node is present. To effectively use the multi-instance mode,
open of /dev/ptmx must be a redirected to '/dev/pts/ptmx' using a symlink or
bind-mount.
Eg: A container startup script could do the following:
$ chmod 0666 /dev/pts/ptmx
$ rm /dev/ptmx
$ ln -s pts/ptmx /dev/ptmx
$ ns_exec -cm /bin/bash
# We are now in new container
$ umount /dev/pts
$ mount -t devpts -o newinstance lxcpts /dev/pts
$ sshd -p 1234
where 'ns_exec -cm /bin/bash' calls clone() with CLONE_NEWNS flag and execs
/bin/bash in the child process. A pty created by the sshd is not visible in
the original mount of /dev/pts.
User-space changes
------------------
In multi-instance mode (i.e '-o newinstance' mount option is specified at least
once), following user-space issues should be noted.
1. If -o newinstance mount option is never used, /dev/pts/ptmx can be ignored
and no change is needed to system-startup scripts.
2. To effectively use multi-instance mode (i.e -o newinstance is specified)
administrators or startup scripts should "redirect" open of /dev/ptmx to
/dev/pts/ptmx using either a bind mount or symlink.
$ mount -t devpts -o newinstance devpts /dev/pts
followed by either
$ rm /dev/ptmx
$ ln -s pts/ptmx /dev/ptmx
$ chmod 666 /dev/pts/ptmx
or
$ mount -o bind /dev/pts/ptmx /dev/ptmx
3. The '/dev/ptmx -> pts/ptmx' symlink is the preferred method since it
enables better error-reporting and treats both single-instance and
multi-instance mounts similarly.
But this method requires that system-startup scripts set the mode of
/dev/pts/ptmx correctly (default mode is 0000). The scripts can set the
mode by, either
- adding ptmxmode mount option to devpts entry in /etc/fstab, or
- using 'chmod 0666 /dev/pts/ptmx'
4. If multi-instance mode mount is needed for containers, but the system
startup scripts have not yet been updated, container-startup scripts
should bind mount /dev/ptmx to /dev/pts/ptmx to avoid breaking single-
instance mounts.
Or, in general, container-startup scripts should use:
mount -t devpts -o newinstance -o ptmxmode=0666 devpts /dev/pts
if [ ! -L /dev/ptmx ]; then
mount -o bind /dev/pts/ptmx /dev/ptmx
fi
When all devpts mounts are multi-instance, /dev/ptmx can permanently be
a symlink to pts/ptmx and the bind mount can be ignored.
5. A multi-instance mount that is not accompanied by the /dev/ptmx to
/dev/pts/ptmx redirection would result in an unusable/unreachable pty.
mount -t devpts -o newinstance lxcpts /dev/pts
immediately followed by:
open("/dev/ptmx")
would create a pty, say /dev/pts/7, in the initial kernel mount.
But /dev/pts/7 would be invisible in the new mount.
6. The permissions for /dev/pts/ptmx node should be specified when mounting
/dev/pts, using the '-o ptmxmode=%o' mount option (default is 0000).
mount -t devpts -o newinstance -o ptmxmode=0644 devpts /dev/pts
The permissions can be later be changed as usual with 'chmod'.
chmod 666 /dev/pts/ptmx
7. A mount of devpts without the 'newinstance' option results in binding to
initial kernel mount. This behavior while preserving legacy semantics,
does not provide strict isolation in a container environment. i.e by
mounting devpts without the 'newinstance' option, a container could
get visibility into the 'host' or root container's devpts.
To workaround this and have strict isolation, all mounts of devpts,
including the mount in the root container, should use the newinstance
option.

View File

@ -2049,6 +2049,12 @@ M: mikulas@artax.karlin.mff.cuni.cz
W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
S: Maintained
HSO 3G Modem Driver (hso.c)
P: Denis Joseph Barrow
M: d.barow@option.com
W: http://www.pharscape.org
S: Maintained
HTCPEN TOUCHSCREEN DRIVER
P: Pau Oliva Fora
M: pof@eslack.org

View File

@ -190,7 +190,7 @@ config DIGIEPCA
config ESPSERIAL
tristate "Hayes ESP serial port support"
depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API
depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API && BROKEN
help
This is a driver which supports Hayes ESP serial ports. Both single
port cards and multiport cards are supported. Make sure to read
@ -443,6 +443,17 @@ config UNIX98_PTYS
All modern Linux systems use the Unix98 ptys. Say Y unless
you're on an embedded system and want to conserve memory.
config DEVPTS_MULTIPLE_INSTANCES
bool "Support multiple instances of devpts"
depends on UNIX98_PTYS
default n
---help---
Enable support for multiple instances of devpts filesystem.
If you want to have isolated PTY namespaces (eg: in containers),
say Y here. Otherwise, say N. If enabled, each mount of devpts
filesystem with the '-o newinstance' option will create an
independent PTY namespace.
config LEGACY_PTYS
bool "Legacy (BSD) PTY support"
default y

View File

@ -170,7 +170,7 @@ static __inline__ void rtsdtr_ctrl(int bits)
*/
static void rs_stop(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
struct async_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_stop"))
@ -190,7 +190,7 @@ static void rs_stop(struct tty_struct *tty)
static void rs_start(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
struct async_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_start"))
@ -861,7 +861,7 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
static void rs_flush_chars(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
struct async_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
@ -934,7 +934,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
static int rs_write_room(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
struct async_struct *info = tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_write_room"))
return 0;
@ -943,7 +943,7 @@ static int rs_write_room(struct tty_struct *tty)
static int rs_chars_in_buffer(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
struct async_struct *info = tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
return 0;
@ -952,7 +952,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
static void rs_flush_buffer(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
struct async_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
@ -969,7 +969,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
*/
static void rs_send_xchar(struct tty_struct *tty, char ch)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
struct async_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_send_char"))
@ -1004,7 +1004,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
*/
static void rs_throttle(struct tty_struct * tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
struct async_struct *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
@ -1029,7 +1029,7 @@ static void rs_throttle(struct tty_struct * tty)
static void rs_unthrottle(struct tty_struct * tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
struct async_struct *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
@ -1194,7 +1194,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int __user *value)
static int rs_tiocmget(struct tty_struct *tty, struct file *file)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
struct async_struct * info = tty->driver_data;
unsigned char control, status;
unsigned long flags;
@ -1217,7 +1217,7 @@ static int rs_tiocmget(struct tty_struct *tty, struct file *file)
static int rs_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
struct async_struct * info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
@ -1244,7 +1244,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file,
*/
static int rs_break(struct tty_struct *tty, int break_state)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
struct async_struct * info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_break"))
@ -1264,7 +1264,7 @@ static int rs_break(struct tty_struct *tty, int break_state)
static int rs_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
struct async_struct * info = tty->driver_data;
struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct icount;
void __user *argp = (void __user *)arg;
@ -1368,7 +1368,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
struct async_struct *info = tty->driver_data;
unsigned long flags;
unsigned int cflag = tty->termios->c_cflag;
@ -1428,7 +1428,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
*/
static void rs_close(struct tty_struct *tty, struct file * filp)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
struct async_struct * info = tty->driver_data;
struct serial_state *state;
unsigned long flags;
@ -1523,7 +1523,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
*/
static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
struct async_struct * info = tty->driver_data;
unsigned long orig_jiffies, char_time;
int lsr;
@ -1587,7 +1587,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
*/
static void rs_hangup(struct tty_struct *tty)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
struct async_struct * info = tty->driver_data;
struct serial_state *state = info->state;
if (serial_paranoia_check(info, tty->name, "rs_hangup"))

View File

@ -5010,7 +5010,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
if (nchan == 0) {
dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
"Serial-Modules\n");
return -EIO;
goto err_unmap;
}
} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
struct RUNTIME_9060 __iomem *ctl_addr;

View File

@ -69,7 +69,9 @@ static int invalid_lilo_config;
/*
* The ISA boards do window flipping into the same spaces so its only sane with
* a single lock. It's still pretty efficient.
* a single lock. It's still pretty efficient. This lock guards the hardware
* and the tty_port lock guards the kernel side stuff like use counts. Take
* this lock inside the port lock if you must take both.
*/
static DEFINE_SPINLOCK(epca_lock);
@ -156,14 +158,12 @@ static struct channel *verifyChannel(struct tty_struct *);
static void pc_sched_event(struct channel *, int);
static void epca_error(int, char *);
static void pc_close(struct tty_struct *, struct file *);
static void shutdown(struct channel *);
static void shutdown(struct channel *, struct tty_struct *tty);
static void pc_hangup(struct tty_struct *);
static int pc_write_room(struct tty_struct *);
static int pc_chars_in_buffer(struct tty_struct *);
static void pc_flush_buffer(struct tty_struct *);
static void pc_flush_chars(struct tty_struct *);
static int block_til_ready(struct tty_struct *, struct file *,
struct channel *);
static int pc_open(struct tty_struct *, struct file *);
static void post_fep_init(unsigned int crd);
static void epcapoll(unsigned long);
@ -173,7 +173,7 @@ static unsigned termios2digi_h(struct channel *ch, unsigned);
static unsigned termios2digi_i(struct channel *ch, unsigned);
static unsigned termios2digi_c(struct channel *ch, unsigned);
static void epcaparam(struct tty_struct *, struct channel *);
static void receive_data(struct channel *);
static void receive_data(struct channel *, struct tty_struct *tty);
static int pc_ioctl(struct tty_struct *, struct file *,
unsigned int, unsigned long);
static int info_ioctl(struct tty_struct *, struct file *,
@ -392,7 +392,7 @@ static struct channel *verifyChannel(struct tty_struct *tty)
* through tty->driver_data this should catch it.
*/
if (tty) {
struct channel *ch = (struct channel *)tty->driver_data;
struct channel *ch = tty->driver_data;
if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) {
if (ch->magic == EPCA_MAGIC)
return ch;
@ -419,76 +419,34 @@ static void epca_error(int line, char *msg)
static void pc_close(struct tty_struct *tty, struct file *filp)
{
struct channel *ch;
unsigned long flags;
struct tty_port *port;
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
ch = verifyChannel(tty);
if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&epca_lock, flags);
if (ch == NULL)
return;
}
if (ch->port.count-- > 1) {
/* Begin channel is open more than once */
/*
* Return without doing anything. Someone might still
* be using the channel.
*/
spin_unlock_irqrestore(&epca_lock, flags);
port = &ch->port;
if (tty_port_close_start(port, tty, filp) == 0)
return;
}
/* Port open only once go ahead with shutdown & reset */
BUG_ON(ch->port.count < 0);
/*
* Let the rest of the driver know the channel is being closed.
* This becomes important if an open is attempted before close
* is finished.
*/
ch->port.flags |= ASYNC_CLOSING;
tty->closing = 1;
spin_unlock_irqrestore(&epca_lock, flags);
if (ch->port.flags & ASYNC_INITIALIZED) {
/* Setup an event to indicate when the
transmit buffer empties */
setup_empty_event(tty, ch);
/* 30 seconds timeout */
tty_wait_until_sent(tty, 3000);
}
pc_flush_buffer(tty);
shutdown(ch, tty);
tty_ldisc_flush(tty);
shutdown(ch);
spin_lock_irqsave(&epca_lock, flags);
tty->closing = 0;
ch->event = 0;
ch->port.tty = NULL;
spin_unlock_irqrestore(&epca_lock, flags);
if (ch->port.blocked_open) {
if (ch->close_delay)
msleep_interruptible(jiffies_to_msecs(ch->close_delay));
wake_up_interruptible(&ch->port.open_wait);
}
ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
ASYNC_CLOSING);
wake_up_interruptible(&ch->port.close_wait);
}
tty_port_close_end(port, tty);
ch->event = 0; /* FIXME: review ch->event locking */
tty_port_tty_set(port, NULL);
}
static void shutdown(struct channel *ch)
static void shutdown(struct channel *ch, struct tty_struct *tty)
{
unsigned long flags;
struct tty_struct *tty;
struct board_chan __iomem *bc;
struct tty_port *port = &ch->port;
if (!(ch->port.flags & ASYNC_INITIALIZED))
if (!(port->flags & ASYNC_INITIALIZED))
return;
spin_lock_irqsave(&epca_lock, flags);
@ -503,7 +461,6 @@ static void shutdown(struct channel *ch)
*/
if (bc)
writeb(0, &bc->idata);
tty = ch->port.tty;
/* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
if (tty->termios->c_cflag & HUPCL) {
@ -517,32 +474,26 @@ static void shutdown(struct channel *ch)
* will have to reinitialized. Set a flag to indicate this.
*/
/* Prevent future Digi programmed interrupts from coming active */
ch->port.flags &= ~ASYNC_INITIALIZED;
port->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&epca_lock, flags);
}
static void pc_hangup(struct tty_struct *tty)
{
struct channel *ch;
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
ch = verifyChannel(tty);
if (ch != NULL) {
unsigned long flags;
pc_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
shutdown(ch, tty);
spin_lock_irqsave(&epca_lock, flags);
ch->port.tty = NULL;
ch->event = 0;
ch->port.count = 0;
ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
spin_unlock_irqrestore(&epca_lock, flags);
wake_up_interruptible(&ch->port.open_wait);
ch->event = 0; /* FIXME: review locking of ch->event */
tty_port_hangup(&ch->port);
}
}
@ -786,100 +737,22 @@ static void pc_flush_chars(struct tty_struct *tty)
}
}
static int block_til_ready(struct tty_struct *tty,
struct file *filp, struct channel *ch)
static int epca_carrier_raised(struct tty_port *port)
{
DECLARE_WAITQUEUE(wait, current);
int retval, do_clocal = 0;
unsigned long flags;
if (tty_hung_up_p(filp)) {
if (ch->port.flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
return retval;
}
/*
* If the device is in the middle of being closed, then block until
* it's done, and then try again.
*/
if (ch->port.flags & ASYNC_CLOSING) {
interruptible_sleep_on(&ch->port.close_wait);
if (ch->port.flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
else
return -ERESTARTSYS;
}
if (filp->f_flags & O_NONBLOCK) {
/*
* If non-blocking mode is set, then make the check up front
* and then exit.
*/
ch->port.flags |= ASYNC_NORMAL_ACTIVE;
struct channel *ch = container_of(port, struct channel, port);
if (ch->imodem & ch->dcd)
return 1;
return 0;
}
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
/* Block waiting for the carrier detect and the line to become free */
retval = 0;
add_wait_queue(&ch->port.open_wait, &wait);
spin_lock_irqsave(&epca_lock, flags);
/* We dec count so that pc_close will know when to free things */
if (!tty_hung_up_p(filp))
ch->port.count--;
ch->port.blocked_open++;
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(ch->port.flags & ASYNC_INITIALIZED)) {
if (ch->port.flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
break;
}
if (!(ch->port.flags & ASYNC_CLOSING) &&
(do_clocal || (ch->imodem & ch->dcd)))
break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
spin_unlock_irqrestore(&epca_lock, flags);
/*
* Allow someone else to be scheduled. We will occasionally go
* through this loop until one of the above conditions change.
* The below schedule call will allow other processes to enter
* and prevent this loop from hogging the cpu.
*/
schedule();
spin_lock_irqsave(&epca_lock, flags);
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&ch->port.open_wait, &wait);
if (!tty_hung_up_p(filp))
ch->port.count++;
ch->port.blocked_open--;
spin_unlock_irqrestore(&epca_lock, flags);
if (retval)
return retval;
ch->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
static void epca_raise_dtr_rts(struct tty_port *port)
{
}
static int pc_open(struct tty_struct *tty, struct file *filp)
{
struct channel *ch;
struct tty_port *port;
unsigned long flags;
int line, retval, boardnum;
struct board_chan __iomem *bc;
@ -890,6 +763,7 @@ static int pc_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
ch = &digi_channels[line];
port = &ch->port;
boardnum = ch->boardnum;
/* Check status of board configured in system. */
@ -926,22 +800,24 @@ static int pc_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
}
spin_lock_irqsave(&epca_lock, flags);
spin_lock_irqsave(&port->lock, flags);
/*
* Every time a channel is opened, increment a counter. This is
* necessary because we do not wish to flush and shutdown the channel
* until the last app holding the channel open, closes it.
*/
ch->port.count++;
port->count++;
/*
* Set a kernel structures pointer to our local channel structure. This
* way we can get to it when passed only a tty struct.
*/
tty->driver_data = ch;
port->tty = tty;
/*
* If this is the first time the channel has been opened, initialize
* the tty->termios struct otherwise let pc_close handle it.
*/
spin_lock(&epca_lock);
globalwinon(ch);
ch->statusflags = 0;
@ -956,31 +832,33 @@ static int pc_open(struct tty_struct *tty, struct file *filp)
writew(head, &bc->rout);
/* Set the channels associated tty structure */
ch->port.tty = tty;
/*
* The below routine generally sets up parity, baud, flow control
* issues, etc.... It effect both control flags and input flags.
*/
epcaparam(tty, ch);
ch->port.flags |= ASYNC_INITIALIZED;
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
spin_unlock(&epca_lock);
port->flags |= ASYNC_INITIALIZED;
spin_unlock_irqrestore(&port->lock, flags);
retval = block_til_ready(tty, filp, ch);
retval = tty_port_block_til_ready(port, tty, filp);
if (retval)
return retval;
/*
* Set this again in case a hangup set it to zero while this open() was
* waiting for the line...
*/
spin_lock_irqsave(&epca_lock, flags);
ch->port.tty = tty;
spin_lock_irqsave(&port->lock, flags);
port->tty = tty;
spin_lock(&epca_lock);
globalwinon(ch);
/* Enable Digi Data events */
writeb(1, &bc->idata);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
spin_unlock(&epca_lock);
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
@ -1016,8 +894,11 @@ static void __exit epca_module_exit(void)
}
ch = card_ptr[crd];
for (count = 0; count < bd->numports; count++, ch++) {
if (ch && ch->port.tty)
tty_hangup(ch->port.tty);
struct tty_struct *tty = tty_port_tty_get(&ch->port);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
}
}
pci_unregister_driver(&epca_driver);
@ -1042,6 +923,11 @@ static const struct tty_operations pc_ops = {
.break_ctl = pc_send_break
};
static const struct tty_port_operations epca_port_ops = {
.carrier_raised = epca_carrier_raised,
.raise_dtr_rts = epca_raise_dtr_rts,
};
static int info_open(struct tty_struct *tty, struct file *filp)
{
return 0;
@ -1377,6 +1263,7 @@ static void post_fep_init(unsigned int crd)
u16 tseg, rseg;
tty_port_init(&ch->port);
ch->port.ops = &epca_port_ops;
ch->brdchan = bc;
ch->mailbox = gd;
INIT_WORK(&ch->tqueue, do_softint);
@ -1428,7 +1315,7 @@ static void post_fep_init(unsigned int crd)
ch->boardnum = crd;
ch->channelnum = i;
ch->magic = EPCA_MAGIC;
ch->port.tty = NULL;
tty_port_tty_set(&ch->port, NULL);
if (shrinkmem) {
fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
@ -1510,7 +1397,7 @@ static void post_fep_init(unsigned int crd)
ch->fepstartca = 0;
ch->fepstopca = 0;
ch->close_delay = 50;
ch->port.close_delay = 50;
spin_unlock_irqrestore(&epca_lock, flags);
}
@ -1622,15 +1509,16 @@ static void doevent(int crd)
if (bc == NULL)
goto next;
tty = tty_port_tty_get(&ch->port);
if (event & DATA_IND) { /* Begin DATA_IND */
receive_data(ch);
receive_data(ch, tty);
assertgwinon(ch);
} /* End DATA_IND */
/* else *//* Fix for DCD transition missed bug */
if (event & MODEMCHG_IND) {
/* A modem signal change has been indicated */
ch->imodem = mstat;
if (ch->port.flags & ASYNC_CHECK_CD) {
if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) {
/* We are now receiving dcd */
if (mstat & ch->dcd)
wake_up_interruptible(&ch->port.open_wait);
@ -1638,7 +1526,6 @@ static void doevent(int crd)
pc_sched_event(ch, EPCA_EVENT_HANGUP);
}
}
tty = ch->port.tty;
if (tty) {
if (event & BREAK_IND) {
/* A break has been indicated */
@ -1658,6 +1545,7 @@ static void doevent(int crd)
tty_wakeup(tty);
}
}
tty_kref_put(tty);
}
next:
globalwinon(ch);
@ -1877,9 +1765,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
* that the driver will wait on carrier detect.
*/
if (ts->c_cflag & CLOCAL)
ch->port.flags &= ~ASYNC_CHECK_CD;
clear_bit(ASYNC_CHECK_CD, &ch->port.flags);
else
ch->port.flags |= ASYNC_CHECK_CD;
set_bit(ASYNC_CHECK_CD, &ch->port.flags);
mval = ch->m_dtr | ch->m_rts;
} /* End CBAUD not detected */
iflag = termios2digi_i(ch, ts->c_iflag);
@ -1952,11 +1840,10 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
}
/* Caller holds lock */
static void receive_data(struct channel *ch)
static void receive_data(struct channel *ch, struct tty_struct *tty)
{
unchar *rptr;
struct ktermios *ts = NULL;
struct tty_struct *tty;
struct board_chan __iomem *bc;
int dataToRead, wrapgap, bytesAvailable;
unsigned int tail, head;
@ -1969,7 +1856,6 @@ static void receive_data(struct channel *ch)
globalwinon(ch);
if (ch->statusflags & RXSTOPPED)
return;
tty = ch->port.tty;
if (tty)
ts = tty->termios;
bc = ch->brdchan;
@ -2029,7 +1915,7 @@ static void receive_data(struct channel *ch)
globalwinon(ch);
writew(tail, &bc->rout);
/* Must be called with global data */
tty_schedule_flip(ch->port.tty);
tty_schedule_flip(tty);
}
static int info_ioctl(struct tty_struct *tty, struct file *file,
@ -2097,7 +1983,7 @@ static int info_ioctl(struct tty_struct *tty, struct file *file,
static int pc_tiocmget(struct tty_struct *tty, struct file *file)
{
struct channel *ch = (struct channel *) tty->driver_data;
struct channel *ch = tty->driver_data;
struct board_chan __iomem *bc;
unsigned int mstat, mflag = 0;
unsigned long flags;
@ -2131,7 +2017,7 @@ static int pc_tiocmget(struct tty_struct *tty, struct file *file)
static int pc_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct channel *ch = (struct channel *) tty->driver_data;
struct channel *ch = tty->driver_data;
unsigned long flags;
if (!ch)
@ -2178,7 +2064,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
unsigned int mflag, mstat;
unsigned char startc, stopc;
struct board_chan __iomem *bc;
struct channel *ch = (struct channel *) tty->driver_data;
struct channel *ch = tty->driver_data;
void __user *argp = (void __user *)arg;
if (ch)
@ -2352,15 +2238,16 @@ static void do_softint(struct work_struct *work)
struct channel *ch = container_of(work, struct channel, tqueue);
/* Called in response to a modem change event */
if (ch && ch->magic == EPCA_MAGIC) {
struct tty_struct *tty = ch->port.tty;
struct tty_struct *tty = tty_port_tty_get(&ch->port);;
if (tty && tty->driver_data) {
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
tty_hangup(tty);
wake_up_interruptible(&ch->port.open_wait);
ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags);
}
}
tty_kref_put(tty);
}
}
@ -2473,7 +2360,7 @@ static void pc_unthrottle(struct tty_struct *tty)
static int pc_send_break(struct tty_struct *tty, int msec)
{
struct channel *ch = (struct channel *) tty->driver_data;
struct channel *ch = tty->driver_data;
unsigned long flags;
if (msec == -1)

View File

@ -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;

View File

@ -377,6 +377,7 @@ static void gs_shutdown_port (struct gs_port *port)
void gs_hangup(struct tty_struct *tty)
{
struct gs_port *port;
unsigned long flags;
func_enter ();
@ -386,9 +387,11 @@ void gs_hangup(struct tty_struct *tty)
return;
gs_shutdown_port (port);
spin_lock_irqsave(&port->port.lock, flags);
port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE);
port->port.tty = NULL;
port->port.count = 0;
spin_unlock_irqrestore(&port->port.lock, flags);
wake_up_interruptible(&port->port.open_wait);
func_exit ();
@ -397,7 +400,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 +413,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 +436,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 +448,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(&port->lock, flags);
if (!tty_hung_up_p(filp)) {
port->port.count--;
port->count--;
}
spin_unlock_irqrestore(&port->driver_lock, flags);
port->port.blocked_open++;
port->blocked_open++;
spin_unlock_irqrestore(&port->lock, flags);
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,19 +487,20 @@ 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);
if (!tty_hung_up_p(filp)) {
port->port.count++;
}
port->port.blocked_open--;
if (retval)
return retval;
remove_wait_queue(&port->open_wait, &wait);
port->port.flags |= ASYNC_NORMAL_ACTIVE;
spin_lock_irqsave(&port->lock, flags);
if (!tty_hung_up_p(filp)) {
port->count++;
}
port->blocked_open--;
if (retval == 0)
port->flags |= ASYNC_NORMAL_ACTIVE;
spin_unlock_irqrestore(&port->lock, flags);
func_exit ();
return 0;
return retval;
}
@ -506,7 +511,7 @@ void gs_close(struct tty_struct * tty, struct file * filp)
func_enter ();
port = (struct gs_port *) tty->driver_data;
port = tty->driver_data;
if (!port) return;
@ -516,10 +521,10 @@ void gs_close(struct tty_struct * tty, struct file * filp)
port->port.tty = tty;
}
spin_lock_irqsave(&port->driver_lock, flags);
spin_lock_irqsave(&port->port.lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&port->driver_lock, flags);
spin_unlock_irqrestore(&port->port.lock, flags);
if (port->rd->hungup)
port->rd->hungup (port);
func_exit ();
@ -538,7 +543,7 @@ void gs_close(struct tty_struct * tty, struct file * filp)
if (port->port.count) {
gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->port.count);
spin_unlock_irqrestore(&port->driver_lock, flags);
spin_unlock_irqrestore(&port->port.lock, flags);
func_exit ();
return;
}
@ -559,8 +564,10 @@ void gs_close(struct tty_struct * tty, struct file * filp)
* line status register.
*/
spin_lock_irqsave(&port->driver_lock, flags);
port->rd->disable_rx_interrupts (port);
spin_unlock_irqrestore(&port->driver_lock, flags);
spin_unlock_irqrestore(&port->port.lock, flags);
/* close has no way of returning "EINTR", so discard return value */
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
@ -573,20 +580,25 @@ void gs_close(struct tty_struct * tty, struct file * filp)
tty_ldisc_flush(tty);
tty->closing = 0;
spin_lock_irqsave(&port->driver_lock, flags);
port->event = 0;
port->rd->close (port);
port->rd->shutdown_port (port);
spin_unlock_irqrestore(&port->driver_lock, flags);
spin_lock_irqsave(&port->port.lock, flags);
port->port.tty = NULL;
if (port->port.blocked_open) {
if (port->close_delay) {
spin_unlock_irqrestore(&port->driver_lock, flags);
spin_unlock_irqrestore(&port->port.lock, flags);
msleep_interruptible(jiffies_to_msecs(port->close_delay));
spin_lock_irqsave(&port->driver_lock, flags);
spin_lock_irqsave(&port->port.lock, flags);
}
wake_up_interruptible(&port->port.open_wait);
}
port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED);
spin_unlock_irqrestore(&port->port.lock, flags);
wake_up_interruptible(&port->port.close_wait);
func_exit ();

View File

@ -529,7 +529,7 @@ static void hvc_set_winsz(struct work_struct *work)
tty = tty_kref_get(hp->tty);
spin_unlock_irqrestore(&hp->lock, hvc_flags);
tty_do_resize(tty, tty, &ws);
tty_do_resize(tty, &ws);
tty_kref_put(tty);
}

View File

@ -997,14 +997,14 @@ out:
static int hvsi_write_room(struct tty_struct *tty)
{
struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
struct hvsi_struct *hp = tty->driver_data;
return N_OUTBUF - hp->n_outbuf;
}
static int hvsi_chars_in_buffer(struct tty_struct *tty)
{
struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
struct hvsi_struct *hp = tty->driver_data;
return hp->n_outbuf;
}
@ -1070,7 +1070,7 @@ out:
*/
static void hvsi_throttle(struct tty_struct *tty)
{
struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
struct hvsi_struct *hp = tty->driver_data;
pr_debug("%s\n", __func__);
@ -1079,7 +1079,7 @@ static void hvsi_throttle(struct tty_struct *tty)
static void hvsi_unthrottle(struct tty_struct *tty)
{
struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;
int shouldflip = 0;
@ -1100,7 +1100,7 @@ static void hvsi_unthrottle(struct tty_struct *tty)
static int hvsi_tiocmget(struct tty_struct *tty, struct file *file)
{
struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
struct hvsi_struct *hp = tty->driver_data;
hvsi_get_mctrl(hp);
return hp->mctrl;
@ -1109,7 +1109,7 @@ static int hvsi_tiocmget(struct tty_struct *tty, struct file *file)
static int hvsi_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;
uint16_t new_mctrl;

View File

@ -328,11 +328,13 @@ static inline void drop_rts(struct isi_port *port)
}
/* card->lock MUST NOT be held */
static inline void raise_dtr_rts(struct isi_port *port)
static void isicom_raise_dtr_rts(struct tty_port *port)
{
struct isi_board *card = port->card;
struct isi_port *ip = container_of(port, struct isi_port, port);
struct isi_board *card = ip->card;
unsigned long base = card->base;
u16 channel = port->channel;
u16 channel = ip->channel;
if (!lock_card(card))
return;
@ -340,7 +342,7 @@ static inline void raise_dtr_rts(struct isi_port *port)
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0f04, base);
InterruptTheCard(base);
port->status |= (ISI_DTR | ISI_RTS);
ip->status |= (ISI_DTR | ISI_RTS);
unlock_card(card);
}
@ -830,80 +832,10 @@ static int isicom_setup_port(struct tty_struct *tty)
return 0;
}
static int block_til_ready(struct tty_struct *tty, struct file *filp,
struct isi_port *port)
static int isicom_carrier_raised(struct tty_port *port)
{
struct isi_board *card = port->card;
int do_clocal = 0, retval;
unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
/* block if port is in the process of being closed */
if (tty_hung_up_p(filp) || port->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)
return -EAGAIN;
else
return -ERESTARTSYS;
}
/* if non-blocking mode is set ... */
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;
return 0;
}
if (C_CLOCAL(tty))
do_clocal = 1;
/* block waiting for DCD to be asserted, and while
callout dev is busy */
retval = 0;
add_wait_queue(&port->port.open_wait, &wait);
spin_lock_irqsave(&card->card_lock, flags);
if (!tty_hung_up_p(filp))
port->port.count--;
port->port.blocked_open++;
spin_unlock_irqrestore(&card->card_lock, flags);
while (1) {
raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {
if (port->port.flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
break;
}
if (!(port->port.flags & ASYNC_CLOSING) &&
(do_clocal || (port->status & ISI_DCD))) {
break;
}
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->port.open_wait, &wait);
spin_lock_irqsave(&card->card_lock, flags);
if (!tty_hung_up_p(filp))
port->port.count++;
port->port.blocked_open--;
spin_unlock_irqrestore(&card->card_lock, flags);
if (retval)
return retval;
port->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
struct isi_port *ip = container_of(port, struct isi_port, port);
return (ip->status & ISI_DCD)?1 : 0;
}
static int isicom_open(struct tty_struct *tty, struct file *filp)
@ -932,12 +864,13 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
isicom_setup_board(card);
/* FIXME: locking on port.count etc */
port->port.count++;
tty->driver_data = port;
tty_port_tty_set(&port->port, tty);
error = isicom_setup_port(tty);
if (error == 0)
error = block_til_ready(tty, filp, port);
error = tty_port_block_til_ready(&port->port, tty, filp);
return error;
}
@ -1012,76 +945,30 @@ static void isicom_flush_buffer(struct tty_struct *tty)
static void isicom_close(struct tty_struct *tty, struct file *filp)
{
struct isi_port *port = tty->driver_data;
struct isi_port *ip = tty->driver_data;
struct tty_port *port = &ip->port;
struct isi_board *card;
unsigned long flags;
if (!port)
return;
card = port->card;
if (isicom_paranoia_check(port, tty->name, "isicom_close"))
BUG_ON(!ip);
card = ip->card;
if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
return;
pr_dbg("Close start!!!.\n");
spin_lock_irqsave(&card->card_lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&card->card_lock, flags);
return;
}
if (tty->count == 1 && port->port.count != 1) {
printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port "
"count tty->count = 1 port count = %d.\n",
card->base, port->port.count);
port->port.count = 1;
}
if (--port->port.count < 0) {
printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port "
"count for channel%d = %d", card->base, port->channel,
port->port.count);
port->port.count = 0;
}
if (port->port.count) {
spin_unlock_irqrestore(&card->card_lock, flags);
return;
}
port->port.flags |= ASYNC_CLOSING;
tty->closing = 1;
spin_unlock_irqrestore(&card->card_lock, flags);
if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->port.closing_wait);
/* indicate to the card that no more data can be received
on this port */
spin_lock_irqsave(&card->card_lock, flags);
if (port->port.flags & ASYNC_INITIALIZED) {
card->port_status &= ~(1 << port->channel);
if (port->flags & ASYNC_INITIALIZED) {
card->port_status &= ~(1 << ip->channel);
outw(card->port_status, card->base + 0x02);
}
isicom_shutdown_port(port);
isicom_shutdown_port(ip);
spin_unlock_irqrestore(&card->card_lock, flags);
isicom_flush_buffer(tty);
tty_ldisc_flush(tty);
spin_lock_irqsave(&card->card_lock, flags);
tty->closing = 0;
if (port->port.blocked_open) {
spin_unlock_irqrestore(&card->card_lock, flags);
if (port->port.close_delay) {
pr_dbg("scheduling until time out.\n");
msleep_interruptible(
jiffies_to_msecs(port->port.close_delay));
}
spin_lock_irqsave(&card->card_lock, flags);
wake_up_interruptible(&port->port.open_wait);
}
port->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
wake_up_interruptible(&port->port.close_wait);
spin_unlock_irqrestore(&card->card_lock, flags);
tty_port_close_end(port, tty);
}
/* write et all */
@ -1420,10 +1307,7 @@ static void isicom_hangup(struct tty_struct *tty)
isicom_shutdown_port(port);
spin_unlock_irqrestore(&port->card->card_lock, flags);
port->port.count = 0;
port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
tty_port_tty_set(&port->port, NULL);
wake_up_interruptible(&port->port.open_wait);
tty_port_hangup(&port->port);
}
@ -1452,6 +1336,11 @@ 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,
.raise_dtr_rts = isicom_raise_dtr_rts,
};
static int __devinit reset_card(struct pci_dev *pdev,
const unsigned int card, unsigned int *signature)
{
@ -1794,6 +1683,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;

View File

@ -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
@ -626,8 +626,6 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
static int stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp);
static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
struct stliport *portp, struct file *filp);
static int stli_setport(struct tty_struct *tty);
static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
@ -769,7 +767,7 @@ static int stli_parsebrd(struct stlconf *confp, char **argp)
break;
}
if (i == ARRAY_SIZE(stli_brdstr)) {
printk("STALLION: unknown board name, %s?\n", argp[0]);
printk(KERN_WARNING "istallion: unknown board name, %s?\n", argp[0]);
return 0;
}
@ -787,6 +785,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
{
struct stlibrd *brdp;
struct stliport *portp;
struct tty_port *port;
unsigned int minordev, brdnr, portnr;
int rc;
@ -808,30 +807,19 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
if (portp->devnr < 1)
return -ENODEV;
/*
* Check if this port is in the middle of closing. If so then wait
* until it is closed then return error status based on flag settings.
* The sleep here does not need interrupt protection since the wakeup
* for it is done with the same context.
*/
if (portp->port.flags & ASYNC_CLOSING) {
interruptible_sleep_on(&portp->port.close_wait);
if (portp->port.flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
return -ERESTARTSYS;
}
port = &portp->port;
/*
* On the first open of the device setup the port hardware, and
* initialize the per port data structure. Since initializing the port
* requires several commands to the board we will need to wait for any
* other open that is already initializing the port.
*
* Review - locking
*/
tty_port_tty_set(&portp->port, tty);
tty_port_tty_set(port, tty);
tty->driver_data = portp;
portp->port.count++;
port->count++;
wait_event_interruptible(portp->raw_wait,
!test_bit(ST_INITIALIZING, &portp->state));
@ -841,7 +829,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
set_bit(ST_INITIALIZING, &portp->state);
if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
portp->port.flags |= ASYNC_INITIALIZED;
/* Locking */
port->flags |= ASYNC_INITIALIZED;
clear_bit(TTY_IO_ERROR, &tty->flags);
}
clear_bit(ST_INITIALIZING, &portp->state);
@ -849,31 +838,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
if (rc < 0)
return rc;
}
/*
* Check if this port is in the middle of closing. If so then wait
* until it is closed then return error status, based on flag settings.
* The sleep here does not need interrupt protection since the wakeup
* for it is done with the same context.
*/
if (portp->port.flags & ASYNC_CLOSING) {
interruptible_sleep_on(&portp->port.close_wait);
if (portp->port.flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
return -ERESTARTSYS;
}
/*
* Based on type of open being done check if it can overlap with any
* previous opens still in effect. If we are a normal serial device
* then also we might have to wait for carrier.
*/
if (!(filp->f_flags & O_NONBLOCK)) {
if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0)
return rc;
}
portp->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
return tty_port_block_til_ready(&portp->port, tty, filp);
}
/*****************************************************************************/
@ -882,25 +847,16 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
{
struct stlibrd *brdp;
struct stliport *portp;
struct tty_port *port;
unsigned long flags;
portp = tty->driver_data;
if (portp == NULL)
return;
port = &portp->port;
spin_lock_irqsave(&stli_lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&stli_lock, flags);
if (tty_port_close_start(port, tty, filp) == 0)
return;
}
if ((tty->count == 1) && (portp->port.count != 1))
portp->port.count = 1;
if (portp->port.count-- > 1) {
spin_unlock_irqrestore(&stli_lock, flags);
return;
}
portp->port.flags |= ASYNC_CLOSING;
/*
* May want to wait for data to drain before closing. The BUSY flag
@ -908,15 +864,19 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
* updated by messages from the slave - indicating when all chars
* really have drained.
*/
spin_lock_irqsave(&stli_lock, flags);
if (tty == stli_txcooktty)
stli_flushchars(tty);
tty->closing = 1;
spin_unlock_irqrestore(&stli_lock, flags);
/* We end up doing this twice for the moment. This needs looking at
eventually. Note we still use portp->closing_wait as a result */
if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, portp->closing_wait);
portp->port.flags &= ~ASYNC_INITIALIZED;
/* FIXME: port locking here needs attending to */
port->flags &= ~ASYNC_INITIALIZED;
brdp = stli_brds[portp->brdnr];
stli_rawclose(brdp, portp, 0, 0);
if (tty->termios->c_cflag & HUPCL) {
@ -934,17 +894,8 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
set_bit(ST_DOFLUSHRX, &portp->state);
stli_flushbuffer(tty);
tty->closing = 0;
tty_port_tty_set(&portp->port, NULL);
if (portp->openwaitcnt) {
if (portp->close_delay)
msleep_interruptible(jiffies_to_msecs(portp->close_delay));
wake_up_interruptible(&portp->port.open_wait);
}
portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&portp->port.close_wait);
tty_port_close_end(port, tty);
tty_port_tty_set(port, NULL);
}
/*****************************************************************************/
@ -1183,61 +1134,22 @@ static int stli_setport(struct tty_struct *tty)
/*****************************************************************************/
/*
* 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...
*/
static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
struct stliport *portp, struct file *filp)
static int stli_carrier_raised(struct tty_port *port)
{
unsigned long flags;
int rc, doclocal;
struct stliport *portp = container_of(port, struct stliport, port);
return (portp->sigs & TIOCM_CD) ? 1 : 0;
}
rc = 0;
doclocal = 0;
if (tty->termios->c_cflag & CLOCAL)
doclocal++;
spin_lock_irqsave(&stli_lock, flags);
portp->openwaitcnt++;
if (! tty_hung_up_p(filp))
portp->port.count--;
spin_unlock_irqrestore(&stli_lock, flags);
for (;;) {
static void stli_raise_dtr_rts(struct tty_port *port)
{
struct stliport *portp = container_of(port, struct stliport, port);
struct stlibrd *brdp = stli_brds[portp->brdnr];
stli_mkasysigs(&portp->asig, 1, 1);
if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
&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)
rc = -EBUSY;
else
rc = -ERESTARTSYS;
break;
}
if (((portp->port.flags & ASYNC_CLOSING) == 0) &&
(doclocal || (portp->sigs & TIOCM_CD))) {
break;
}
if (signal_pending(current)) {
rc = -ERESTARTSYS;
break;
}
interruptible_sleep_on(&portp->port.open_wait);
if (stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
sizeof(asysigs_t), 0) < 0)
printk(KERN_WARNING "istallion: dtr raise failed.\n");
}
spin_lock_irqsave(&stli_lock, flags);
if (! tty_hung_up_p(filp))
portp->port.count++;
portp->openwaitcnt--;
spin_unlock_irqrestore(&stli_lock, flags);
return rc;
}
/*****************************************************************************/
@ -1550,7 +1462,7 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s
sio.irq = 0;
sio.flags = portp->port.flags;
sio.baud_base = portp->baud_base;
sio.close_delay = portp->close_delay;
sio.close_delay = portp->port.close_delay;
sio.closing_wait = portp->closing_wait;
sio.custom_divisor = portp->custom_divisor;
sio.xmit_fifo_size = 0;
@ -1582,7 +1494,7 @@ static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *s
return -EFAULT;
if (!capable(CAP_SYS_ADMIN)) {
if ((sio.baud_base != portp->baud_base) ||
(sio.close_delay != portp->close_delay) ||
(sio.close_delay != portp->port.close_delay) ||
((sio.flags & ~ASYNC_USR_MASK) !=
(portp->port.flags & ~ASYNC_USR_MASK)))
return -EPERM;
@ -1591,7 +1503,7 @@ static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *s
portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) |
(sio.flags & ASYNC_USR_MASK);
portp->baud_base = sio.baud_base;
portp->close_delay = sio.close_delay;
portp->port.close_delay = sio.close_delay;
portp->closing_wait = sio.closing_wait;
portp->custom_divisor = sio.custom_divisor;
@ -1821,6 +1733,7 @@ static void stli_hangup(struct tty_struct *tty)
{
struct stliport *portp;
struct stlibrd *brdp;
struct tty_port *port;
unsigned long flags;
portp = tty->driver_data;
@ -1831,8 +1744,11 @@ static void stli_hangup(struct tty_struct *tty)
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
return;
port = &portp->port;
portp->port.flags &= ~ASYNC_INITIALIZED;
spin_lock_irqsave(&port->lock, flags);
port->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&port->lock, flags);
if (!test_bit(ST_CLOSING, &portp->state))
stli_rawclose(brdp, portp, 0, 0);
@ -1853,12 +1769,9 @@ static void stli_hangup(struct tty_struct *tty)
clear_bit(ST_TXBUSY, &portp->state);
clear_bit(ST_RXSTOP, &portp->state);
set_bit(TTY_IO_ERROR, &tty->flags);
tty_port_tty_set(&portp->port, NULL);
portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
portp->port.count = 0;
spin_unlock_irqrestore(&stli_lock, flags);
wake_up_interruptible(&portp->port.open_wait);
tty_port_hangup(port);
}
/*****************************************************************************/
@ -2132,7 +2045,7 @@ static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigne
unsigned char __iomem *bits;
if (test_bit(ST_CMDING, &portp->state)) {
printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n",
printk(KERN_ERR "istallion: command already busy, cmd=%x!\n",
(int) cmd);
return;
}
@ -2692,16 +2605,17 @@ static int stli_initports(struct stlibrd *brdp)
for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) {
portp = kzalloc(sizeof(struct stliport), GFP_KERNEL);
if (!portp) {
printk("STALLION: failed to allocate port structure\n");
printk(KERN_WARNING "istallion: failed to allocate port structure\n");
continue;
}
tty_port_init(&portp->port);
portp->port.ops = &stli_port_ops;
portp->magic = STLI_PORTMAGIC;
portp->portnr = i;
portp->brdnr = brdp->brdnr;
portp->panelnr = panelnr;
portp->baud_base = STL_BAUDBASE;
portp->close_delay = STL_CLOSEDELAY;
portp->port.close_delay = STL_CLOSEDELAY;
portp->closing_wait = 30 * HZ;
init_waitqueue_head(&portp->port.open_wait);
init_waitqueue_head(&portp->port.close_wait);
@ -2758,7 +2672,7 @@ static void __iomem *stli_ecpgetmemptr(struct stlibrd *brdp, unsigned long offse
unsigned char val;
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
printk(KERN_ERR "istallion: shared memory pointer=%x out of "
"range at line=%d(%d), brd=%d\n",
(int) offset, line, __LINE__, brdp->brdnr);
ptr = NULL;
@ -2832,7 +2746,7 @@ static void __iomem *stli_ecpeigetmemptr(struct stlibrd *brdp, unsigned long off
unsigned char val;
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
printk(KERN_ERR "istallion: shared memory pointer=%x out of "
"range at line=%d(%d), brd=%d\n",
(int) offset, line, __LINE__, brdp->brdnr);
ptr = NULL;
@ -2884,7 +2798,7 @@ static void __iomem *stli_ecpmcgetmemptr(struct stlibrd *brdp, unsigned long off
unsigned char val;
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
printk(KERN_ERR "istallion: shared memory pointer=%x out of "
"range at line=%d(%d), brd=%d\n",
(int) offset, line, __LINE__, brdp->brdnr);
ptr = NULL;
@ -2929,7 +2843,7 @@ static void __iomem *stli_ecppcigetmemptr(struct stlibrd *brdp, unsigned long of
unsigned char val;
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
printk(KERN_ERR "istallion: shared memory pointer=%x out of "
"range at line=%d(%d), board=%d\n",
(int) offset, line, __LINE__, brdp->brdnr);
ptr = NULL;
@ -2994,7 +2908,7 @@ static void __iomem *stli_onbgetmemptr(struct stlibrd *brdp, unsigned long offse
void __iomem *ptr;
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
printk(KERN_ERR "istallion: shared memory pointer=%x out of "
"range at line=%d(%d), brd=%d\n",
(int) offset, line, __LINE__, brdp->brdnr);
ptr = NULL;
@ -3060,7 +2974,7 @@ static void __iomem *stli_onbegetmemptr(struct stlibrd *brdp, unsigned long offs
unsigned char val;
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
printk(KERN_ERR "istallion: shared memory pointer=%x out of "
"range at line=%d(%d), brd=%d\n",
(int) offset, line, __LINE__, brdp->brdnr);
ptr = NULL;
@ -3499,7 +3413,7 @@ static int stli_startbrd(struct stlibrd *brdp)
#endif
if (nrdevs < (brdp->nrports + 1)) {
printk(KERN_ERR "STALLION: slave failed to allocate memory for "
printk(KERN_ERR "istallion: slave failed to allocate memory for "
"all devices, devices=%d\n", nrdevs);
brdp->nrports = nrdevs - 1;
}
@ -3509,13 +3423,13 @@ static int stli_startbrd(struct stlibrd *brdp)
brdp->bitsize = (nrdevs + 7) / 8;
memoff = readl(&hdrp->memp);
if (memoff > brdp->memsize) {
printk(KERN_ERR "STALLION: corrupted shared memory region?\n");
printk(KERN_ERR "istallion: corrupted shared memory region?\n");
rc = -EIO;
goto stli_donestartup;
}
memp = (cdkmem_t __iomem *) EBRDGETMEMPTR(brdp, memoff);
if (readw(&memp->dtype) != TYP_ASYNCTRL) {
printk(KERN_ERR "STALLION: no slave control device found\n");
printk(KERN_ERR "istallion: no slave control device found\n");
goto stli_donestartup;
}
memp++;
@ -3600,7 +3514,7 @@ static int __devinit stli_brdinit(struct stlibrd *brdp)
retval = stli_initonb(brdp);
break;
default:
printk(KERN_ERR "STALLION: board=%d is unknown board "
printk(KERN_ERR "istallion: board=%d is unknown board "
"type=%d\n", brdp->brdnr, brdp->brdtype);
retval = -ENODEV;
}
@ -3609,7 +3523,7 @@ static int __devinit stli_brdinit(struct stlibrd *brdp)
return retval;
stli_initports(brdp);
printk(KERN_INFO "STALLION: %s found, board=%d io=%x mem=%x "
printk(KERN_INFO "istallion: %s found, board=%d io=%x mem=%x "
"nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype],
brdp->brdnr, brdp->iobase, (int) brdp->memaddr,
brdp->nrpanels, brdp->nrports);
@ -3703,7 +3617,7 @@ static int stli_eisamemprobe(struct stlibrd *brdp)
if (! foundit) {
brdp->memaddr = 0;
brdp->membase = NULL;
printk(KERN_ERR "STALLION: failed to probe shared memory "
printk(KERN_ERR "istallion: failed to probe shared memory "
"region for %s in EISA slot=%d\n",
stli_brdnames[brdp->brdtype], (brdp->iobase >> 12));
return -ENODEV;
@ -3848,7 +3762,7 @@ static int __devinit stli_pciprobe(struct pci_dev *pdev,
mutex_lock(&stli_brdslock);
brdnr = stli_getbrdnr();
if (brdnr < 0) {
printk(KERN_INFO "STALLION: too many boards found, "
printk(KERN_INFO "istallion: too many boards found, "
"maximum supported %d\n", STL_MAXBRDS);
mutex_unlock(&stli_brdslock);
retval = -EIO;
@ -3920,7 +3834,7 @@ static struct stlibrd *stli_allocbrd(void)
brdp = kzalloc(sizeof(struct stlibrd), GFP_KERNEL);
if (!brdp) {
printk(KERN_ERR "STALLION: failed to allocate memory "
printk(KERN_ERR "istallion: failed to allocate memory "
"(size=%Zd)\n", sizeof(struct stlibrd));
return NULL;
}
@ -4518,6 +4432,11 @@ static const struct tty_operations stli_ops = {
.tiocmset = stli_tiocmset,
};
static const struct tty_port_operations stli_port_ops = {
.carrier_raised = stli_carrier_raised,
.raise_dtr_rts = stli_raise_dtr_rts,
};
/*****************************************************************************/
/*
* Loadable module initialization stuff.
@ -4554,7 +4473,7 @@ static int __init istallion_module_init(void)
stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
if (!stli_txcookbuf) {
printk(KERN_ERR "STALLION: failed to allocate memory "
printk(KERN_ERR "istallion: failed to allocate memory "
"(size=%d)\n", STLI_TXBUFSIZE);
retval = -ENOMEM;
goto err;
@ -4579,7 +4498,7 @@ static int __init istallion_module_init(void)
retval = tty_register_driver(stli_serial);
if (retval) {
printk(KERN_ERR "STALLION: failed to register serial driver\n");
printk(KERN_ERR "istallion: failed to register serial driver\n");
goto err_ttyput;
}
@ -4593,7 +4512,7 @@ static int __init istallion_module_init(void)
*/
retval = register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem);
if (retval) {
printk(KERN_ERR "STALLION: failed to register serial memory "
printk(KERN_ERR "istallion: failed to register serial memory "
"device\n");
goto err_deinit;
}

View File

@ -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;
}

View File

@ -541,74 +541,21 @@ static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
return status;
}
static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
struct mxser_port *port)
static int mxser_carrier_raised(struct tty_port *port)
{
DECLARE_WAITQUEUE(wait, current);
int retval;
int do_clocal = 0;
struct mxser_port *mp = container_of(port, struct mxser_port, port);
return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
}
static void mxser_raise_dtr_rts(struct tty_port *port)
{
struct mxser_port *mp = container_of(port, struct mxser_port, port);
unsigned long flags;
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
*/
if ((filp->f_flags & O_NONBLOCK) ||
test_bit(TTY_IO_ERROR, &tty->flags)) {
port->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
/*
* 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
* mxser_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);
spin_lock_irqsave(&port->slock, flags);
if (!tty_hung_up_p(filp))
port->port.count--;
spin_unlock_irqrestore(&port->slock, flags);
port->port.blocked_open++;
while (1) {
spin_lock_irqsave(&port->slock, flags);
outb(inb(port->ioaddr + UART_MCR) |
UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
spin_unlock_irqrestore(&port->slock, flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {
if (port->port.flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
break;
}
if (!(port->port.flags & ASYNC_CLOSING) &&
(do_clocal ||
(inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->port.open_wait, &wait);
if (!tty_hung_up_p(filp))
port->port.count++;
port->port.blocked_open--;
if (retval)
return retval;
port->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
spin_lock_irqsave(&mp->slock, flags);
outb(inb(mp->ioaddr + UART_MCR) |
UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
spin_unlock_irqrestore(&mp->slock, flags);
}
static int mxser_set_baud(struct tty_struct *tty, long newspd)
@ -1087,14 +1034,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
/*
* Start up serial port
*/
spin_lock_irqsave(&info->slock, flags);
spin_lock_irqsave(&info->port.lock, flags);
info->port.count++;
spin_unlock_irqrestore(&info->slock, flags);
spin_unlock_irqrestore(&info->port.lock, flags);
retval = mxser_startup(tty);
if (retval)
return retval;
retval = mxser_block_til_ready(tty, filp, info);
retval = tty_port_block_til_ready(&info->port, tty, filp);
if (retval)
return retval;
@ -1133,57 +1080,26 @@ static void mxser_flush_buffer(struct tty_struct *tty)
static void mxser_close(struct tty_struct *tty, struct file *filp)
{
struct mxser_port *info = tty->driver_data;
struct tty_port *port = &info->port;
unsigned long timeout;
unsigned long flags;
if (tty->index == MXSER_PORTS)
return;
if (!info)
return;
spin_lock_irqsave(&info->slock, flags);
if (tty_port_close_start(port, tty, filp) == 0)
return;
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&info->slock, flags);
return;
}
if ((tty->count == 1) && (info->port.count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. Info->port.count should always
* be one in these conditions. If it's greater than
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
printk(KERN_ERR "mxser_close: bad serial port count; "
"tty->count is 1, info->port.count is %d\n", info->port.count);
info->port.count = 1;
}
if (--info->port.count < 0) {
printk(KERN_ERR "mxser_close: bad serial port count for "
"ttys%d: %d\n", tty->index, info->port.count);
info->port.count = 0;
}
if (info->port.count) {
spin_unlock_irqrestore(&info->slock, flags);
return;
}
info->port.flags |= ASYNC_CLOSING;
spin_unlock_irqrestore(&info->slock, flags);
/*
* Save the termios structure, since this port may have
* separate termios for callout and dialin.
*
* FIXME: Can this go ?
*/
if (info->port.flags & ASYNC_NORMAL_ACTIVE)
info->normal_termios = *tty->termios;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, info->port.closing_wait);
/*
* At this point we stop accepting input. To do this, we
* disable the receive line status interrupts, and tell the
@ -1209,19 +1125,12 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
}
}
mxser_shutdown(tty);
mxser_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
tty_port_tty_set(&info->port, NULL);
if (info->port.blocked_open) {
if (info->port.close_delay)
schedule_timeout_interruptible(info->port.close_delay);
wake_up_interruptible(&info->port.open_wait);
}
info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
/* Right now the tty_port set is done outside of the close_end helper
as we don't yet have everyone using refcounts */
tty_port_close_end(port, tty);
tty_port_tty_set(port, NULL);
}
static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
@ -2146,10 +2055,7 @@ static void mxser_hangup(struct tty_struct *tty)
mxser_flush_buffer(tty);
mxser_shutdown(tty);
info->port.count = 0;
info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
tty_port_tty_set(&info->port, NULL);
wake_up_interruptible(&info->port.open_wait);
tty_port_hangup(&info->port);
}
/*
@ -2449,6 +2355,11 @@ static const struct tty_operations mxser_ops = {
.tiocmset = mxser_tiocmset,
};
struct tty_port_operations mxser_port_ops = {
.carrier_raised = mxser_carrier_raised,
.raise_dtr_rts = mxser_raise_dtr_rts,
};
/*
* The MOXA Smartio/Industio serial driver boot-time initialization code!
*/
@ -2482,6 +2393,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
for (i = 0; i < brd->info->nports; i++) {
info = &brd->ports[i];
tty_port_init(&info->port);
info->port.ops = &mxser_port_ops;
info->board = brd;
info->stop_rx = 0;
info->ldisc_stop_rx = 0;

View File

@ -1003,7 +1003,7 @@ static int r3964_open(struct tty_struct *tty)
static void r3964_close(struct tty_struct *tty)
{
struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
struct r3964_info *pInfo = tty->disc_data;
struct r3964_client_info *pClient, *pNext;
struct r3964_message *pMsg;
struct r3964_block_header *pHeader, *pNextHeader;
@ -1058,7 +1058,7 @@ static void r3964_close(struct tty_struct *tty)
static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
unsigned char __user * buf, size_t nr)
{
struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
struct r3964_info *pInfo = tty->disc_data;
struct r3964_client_info *pClient;
struct r3964_message *pMsg;
struct r3964_client_message theMsg;
@ -1113,7 +1113,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
const unsigned char *data, size_t count)
{
struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
struct r3964_info *pInfo = tty->disc_data;
struct r3964_block_header *pHeader;
struct r3964_client_info *pClient;
unsigned char *new_data;
@ -1182,7 +1182,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
static int r3964_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
struct r3964_info *pInfo = tty->disc_data;
if (pInfo == NULL)
return -EINVAL;
switch (cmd) {
@ -1216,7 +1216,7 @@ static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
struct poll_table_struct *wait)
{
struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
struct r3964_info *pInfo = tty->disc_data;
struct r3964_client_info *pClient;
struct r3964_message *pMsg = NULL;
unsigned long flags;
@ -1241,7 +1241,7 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
struct r3964_info *pInfo = tty->disc_data;
const unsigned char *p;
char *f, flags = 0;
int i;

File diff suppressed because it is too large Load Diff

View File

@ -353,6 +353,7 @@ struct ctrl_ul {
/* This holds all information that is needed regarding a port */
struct port {
struct tty_port port;
u8 update_flow_control;
struct ctrl_ul ctrl_ul;
struct ctrl_dl ctrl_dl;
@ -365,8 +366,6 @@ struct port {
u8 toggle_ul;
u16 token_dl;
struct tty_struct *tty;
int tty_open_count;
/* mutex to ensure one access patch to this port */
struct mutex tty_sem;
wait_queue_head_t tty_wait;
@ -788,14 +787,14 @@ static void disable_transmit_dl(enum port_type port, struct nozomi *dc)
* Return 1 - send buffer to card and ack.
* Return 0 - don't ack, don't send buffer to card.
*/
static int send_data(enum port_type index, const struct nozomi *dc)
static int send_data(enum port_type index, struct nozomi *dc)
{
u32 size = 0;
const struct port *port = &dc->port[index];
struct port *port = &dc->port[index];
const u8 toggle = port->toggle_ul;
void __iomem *addr = port->ul_addr[toggle];
const u32 ul_size = port->ul_size[toggle];
struct tty_struct *tty = port->tty;
struct tty_struct *tty = tty_port_tty_get(&port->port);
/* Get data from tty and place in buf for now */
size = __kfifo_get(port->fifo_ul, dc->send_buf,
@ -803,6 +802,7 @@ static int send_data(enum port_type index, const struct nozomi *dc)
if (size == 0) {
DBG4("No more data to send, disable link:");
tty_kref_put(tty);
return 0;
}
@ -815,6 +815,7 @@ static int send_data(enum port_type index, const struct nozomi *dc)
if (tty)
tty_wakeup(tty);
tty_kref_put(tty);
return 1;
}
@ -826,7 +827,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
u32 offset = 4;
struct port *port = &dc->port[index];
void __iomem *addr = port->dl_addr[port->toggle_dl];
struct tty_struct *tty = port->tty;
struct tty_struct *tty = tty_port_tty_get(&port->port);
int i;
if (unlikely(!tty)) {
@ -870,7 +871,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
}
set_bit(index, &dc->flip);
tty_kref_put(tty);
return 1;
}
@ -1276,9 +1277,15 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id)
exit_handler:
spin_unlock(&dc->spin_mutex);
for (a = 0; a < NOZOMI_MAX_PORTS; a++)
if (test_and_clear_bit(a, &dc->flip))
tty_flip_buffer_push(dc->port[a].tty);
for (a = 0; a < NOZOMI_MAX_PORTS; a++) {
struct tty_struct *tty;
if (test_and_clear_bit(a, &dc->flip)) {
tty = tty_port_tty_get(&dc->port[a].port);
if (tty)
tty_flip_buffer_push(tty);
tty_kref_put(tty);
}
}
return IRQ_HANDLED;
none:
spin_unlock(&dc->spin_mutex);
@ -1453,12 +1460,10 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
for (i = 0; i < MAX_PORT; i++) {
mutex_init(&dc->port[i].tty_sem);
dc->port[i].tty_open_count = 0;
dc->port[i].tty = NULL;
tty_port_init(&dc->port[i].port);
tty_register_device(ntty_driver, dc->index_start + i,
&pdev->dev);
}
return 0;
err_free_sbuf:
@ -1482,14 +1487,16 @@ static void __devexit tty_exit(struct nozomi *dc)
flush_scheduled_work();
for (i = 0; i < MAX_PORT; ++i)
if (dc->port[i].tty && \
list_empty(&dc->port[i].tty->hangup_work.entry))
tty_hangup(dc->port[i].tty);
for (i = 0; i < MAX_PORT; ++i) {
struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port);
if (tty && list_empty(&tty->hangup_work.entry))
tty_hangup(tty);
tty_kref_put(tty);
}
/* Racy below - surely should wait for scheduled work to be done or
complete off a hangup method ? */
while (dc->open_ttys)
msleep(1);
for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i)
tty_unregister_device(ntty_driver, i);
}
@ -1579,23 +1586,22 @@ static int ntty_open(struct tty_struct *tty, struct file *file)
if (mutex_lock_interruptible(&port->tty_sem))
return -ERESTARTSYS;
port->tty_open_count++;
port->port.count++;
dc->open_ttys++;
/* Enable interrupt downlink for channel */
if (port->tty_open_count == 1) {
if (port->port.count == 1) {
/* FIXME: is this needed now ? */
tty->low_latency = 1;
tty->driver_data = port;
port->tty = tty;
tty_port_tty_set(&port->port, tty);
DBG1("open: %d", port->token_dl);
spin_lock_irqsave(&dc->spin_mutex, flags);
dc->last_ier = dc->last_ier | port->token_dl;
writew(dc->last_ier, dc->reg_ier);
spin_unlock_irqrestore(&dc->spin_mutex, flags);
}
mutex_unlock(&port->tty_sem);
return 0;
}
@ -1606,31 +1612,30 @@ static int ntty_open(struct tty_struct *tty, struct file *file)
static void ntty_close(struct tty_struct *tty, struct file *file)
{
struct nozomi *dc = get_dc_by_tty(tty);
struct port *port = tty->driver_data;
struct port *nport = tty->driver_data;
struct tty_port *port = &nport->port;
unsigned long flags;
if (!dc || !port)
if (!dc || !nport)
return;
if (mutex_lock_interruptible(&port->tty_sem))
return;
/* Users cannot interrupt a close */
mutex_lock(&nport->tty_sem);
if (!port->tty_open_count)
goto exit;
WARN_ON(!port->count);
dc->open_ttys--;
port->tty_open_count--;
port->count--;
tty_port_tty_set(port, NULL);
if (port->tty_open_count == 0) {
DBG1("close: %d", port->token_dl);
if (port->count == 0) {
DBG1("close: %d", nport->token_dl);
spin_lock_irqsave(&dc->spin_mutex, flags);
dc->last_ier &= ~(port->token_dl);
dc->last_ier &= ~(nport->token_dl);
writew(dc->last_ier, dc->reg_ier);
spin_unlock_irqrestore(&dc->spin_mutex, flags);
}
exit:
mutex_unlock(&port->tty_sem);
mutex_unlock(&nport->tty_sem);
}
/*
@ -1660,7 +1665,7 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
return -EAGAIN;
}
if (unlikely(!port->tty_open_count)) {
if (unlikely(!port->port.count)) {
DBG1(" ");
goto exit;
}
@ -1710,7 +1715,7 @@ static int ntty_write_room(struct tty_struct *tty)
if (!mutex_trylock(&port->tty_sem))
return 0;
if (!port->tty_open_count)
if (!port->port.count)
goto exit;
room = port->fifo_ul->size - __kfifo_len(port->fifo_ul);
@ -1866,7 +1871,7 @@ static s32 ntty_chars_in_buffer(struct tty_struct *tty)
goto exit_in_buffer;
}
if (unlikely(!port->tty_open_count)) {
if (unlikely(!port->port.count)) {
dev_err(&dc->pdev->dev, "No tty open?\n");
rval = -ENODEV;
goto exit_in_buffer;

File diff suppressed because it is too large Load Diff

View File

@ -5,8 +5,6 @@
*
* Added support for a Unix98-style ptmx device.
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
* Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to
* waiting writers -- Sapan Bhatia <sapan@corewars.org>
*
* When reading this code see also fs/devpts. In particular note that the
* driver_data field is used by the devpts side as a binding to the devpts
@ -217,7 +215,6 @@ static int pty_open(struct tty_struct *tty, struct file *filp)
clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
set_bit(TTY_THROTTLED, &tty->flags);
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
retval = 0;
out:
return retval;
@ -230,6 +227,55 @@ static void pty_set_termios(struct tty_struct *tty,
tty->termios->c_cflag |= (CS8 | CREAD);
}
/**
* pty_do_resize - resize event
* @tty: tty being resized
* @real_tty: real tty (not the same as tty if using a pty/tty pair)
* @rows: rows (character)
* @cols: cols (character)
*
* Update the termios variables and send the neccessary signals to
* peform a terminal resize correctly
*/
int pty_resize(struct tty_struct *tty, struct winsize *ws)
{
struct pid *pgrp, *rpgrp;
unsigned long flags;
struct tty_struct *pty = tty->link;
/* For a PTY we need to lock the tty side */
mutex_lock(&tty->termios_mutex);
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
goto done;
/* Get the PID values and reference them so we can
avoid holding the tty ctrl lock while sending signals.
We need to lock these individually however. */
spin_lock_irqsave(&tty->ctrl_lock, flags);
pgrp = get_pid(tty->pgrp);
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
spin_lock_irqsave(&pty->ctrl_lock, flags);
rpgrp = get_pid(pty->pgrp);
spin_unlock_irqrestore(&pty->ctrl_lock, flags);
if (pgrp)
kill_pgrp(pgrp, SIGWINCH, 1);
if (rpgrp != pgrp && rpgrp)
kill_pgrp(rpgrp, SIGWINCH, 1);
put_pid(pgrp);
put_pid(rpgrp);
tty->winsize = *ws;
pty->winsize = *ws; /* Never used so will go away soon */
done:
mutex_unlock(&tty->termios_mutex);
return 0;
}
static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct tty_struct *o_tty;
@ -290,6 +336,7 @@ static const struct tty_operations pty_ops = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.resize = pty_resize
};
/* Traditional BSD devices */
@ -319,6 +366,7 @@ static const struct tty_operations pty_ops_bsd = {
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.ioctl = pty_bsd_ioctl,
.resize = pty_resize
};
static void __init legacy_pty_init(void)
@ -561,7 +609,8 @@ static const struct tty_operations ptm_unix98_ops = {
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.ioctl = pty_unix98_ioctl,
.shutdown = pty_unix98_shutdown
.shutdown = pty_unix98_shutdown,
.resize = pty_resize
};
static const struct tty_operations pty_unix98_ops = {

View File

@ -173,7 +173,7 @@ static void rio_disable_tx_interrupts(void *ptr);
static void rio_enable_tx_interrupts(void *ptr);
static void rio_disable_rx_interrupts(void *ptr);
static void rio_enable_rx_interrupts(void *ptr);
static int rio_get_CD(void *ptr);
static int rio_carrier_raised(struct tty_port *port);
static void rio_shutdown_port(void *ptr);
static int rio_set_real_termios(void *ptr);
static void rio_hungup(void *ptr);
@ -224,7 +224,6 @@ static struct real_driver rio_real_driver = {
rio_enable_tx_interrupts,
rio_disable_rx_interrupts,
rio_enable_rx_interrupts,
rio_get_CD,
rio_shutdown_port,
rio_set_real_termios,
rio_chars_in_buffer,
@ -476,9 +475,9 @@ static void rio_enable_rx_interrupts(void *ptr)
/* Jeez. Isn't this simple? */
static int rio_get_CD(void *ptr)
static int rio_carrier_raised(struct tty_port *port)
{
struct Port *PortP = ptr;
struct Port *PortP = container_of(port, struct Port, gs.port);
int rv;
func_enter();
@ -797,16 +796,9 @@ static int rio_init_drivers(void)
return 1;
}
static void *ckmalloc(int size)
{
void *p;
p = kzalloc(size, GFP_KERNEL);
return p;
}
static const struct tty_port_operations rio_port_ops = {
.carrier_raised = rio_carrier_raised,
};
static int rio_init_datastructures(void)
{
@ -826,33 +818,30 @@ static int rio_init_datastructures(void)
#define TMIO_SZ sizeof(struct termios *)
rio_dprintk(RIO_DEBUG_INIT, "getting : %Zd %Zd %Zd %Zd %Zd bytes\n", RI_SZ, RIO_HOSTS * HOST_SZ, RIO_PORTS * PORT_SZ, RIO_PORTS * TMIO_SZ, RIO_PORTS * TMIO_SZ);
if (!(p = ckmalloc(RI_SZ)))
if (!(p = kzalloc(RI_SZ, GFP_KERNEL)))
goto free0;
if (!(p->RIOHosts = ckmalloc(RIO_HOSTS * HOST_SZ)))
if (!(p->RIOHosts = kzalloc(RIO_HOSTS * HOST_SZ, GFP_KERNEL)))
goto free1;
if (!(p->RIOPortp = ckmalloc(RIO_PORTS * PORT_SZ)))
if (!(p->RIOPortp = kzalloc(RIO_PORTS * PORT_SZ, GFP_KERNEL)))
goto free2;
p->RIOConf = RIOConf;
rio_dprintk(RIO_DEBUG_INIT, "Got : %p %p %p\n", p, p->RIOHosts, p->RIOPortp);
#if 1
for (i = 0; i < RIO_PORTS; i++) {
port = p->RIOPortp[i] = ckmalloc(sizeof(struct Port));
port = p->RIOPortp[i] = kzalloc(sizeof(struct Port), GFP_KERNEL);
if (!port) {
goto free6;
}
rio_dprintk(RIO_DEBUG_INIT, "initing port %d (%d)\n", i, port->Mapped);
tty_port_init(&port->gs.port);
port->gs.port.ops = &rio_port_ops;
port->PortNum = i;
port->gs.magic = RIO_MAGIC;
port->gs.close_delay = HZ / 2;
port->gs.closing_wait = 30 * HZ;
port->gs.rd = &rio_real_driver;
spin_lock_init(&port->portSem);
/*
* Initializing wait queue
*/
init_waitqueue_head(&port->gs.port.open_wait);
init_waitqueue_head(&port->gs.port.close_wait);
}
#else
/* We could postpone initializing them to when they are configured. */

View File

@ -857,98 +857,21 @@ static void rc_shutdown_port(struct tty_struct *tty,
rc_shutdown_board(bp);
}
static int block_til_ready(struct tty_struct *tty, struct file *filp,
struct riscom_port *port)
static int carrier_raised(struct tty_port *port)
{
DECLARE_WAITQUEUE(wait, current);
struct riscom_board *bp = port_Board(port);
int retval;
int do_clocal = 0;
int CD;
struct riscom_port *p = container_of(port, struct riscom_port, port);
struct riscom_board *bp = port_Board(p);
unsigned long flags;
/*
* 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)
return -EAGAIN;
else
return -ERESTARTSYS;
}
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
*/
if ((filp->f_flags & O_NONBLOCK) ||
(tty->flags & (1 << TTY_IO_ERROR))) {
port->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
if (C_CLOCAL(tty))
do_clocal = 1;
/*
* 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->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);
int CD;
spin_lock_irqsave(&riscom_lock, flags);
if (!tty_hung_up_p(filp))
port->port.count--;
spin_unlock_irqrestore(&riscom_lock, flags);
port->port.blocked_open++;
while (1) {
spin_lock_irqsave(&riscom_lock, flags);
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_CAR, port_No(p));
CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
rc_out(bp, CD180_MSVR, MSVR_RTS);
bp->DTR &= ~(1u << port_No(port));
bp->DTR &= ~(1u << port_No(p));
rc_out(bp, RC_DTR, bp->DTR);
spin_unlock_irqrestore(&riscom_lock, flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(port->port.flags & ASYNC_INITIALIZED)) {
if (port->port.flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
break;
}
if (!(port->port.flags & ASYNC_CLOSING) &&
(do_clocal || CD))
break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
schedule();
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&port->port.open_wait, &wait);
if (!tty_hung_up_p(filp))
port->port.count++;
port->port.blocked_open--;
if (retval)
return retval;
port->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
return CD;
}
static int rc_open(struct tty_struct *tty, struct file *filp)
@ -977,13 +900,13 @@ static int rc_open(struct tty_struct *tty, struct file *filp)
error = rc_setup_port(bp, port);
if (error == 0)
error = block_til_ready(tty, filp, port);
error = tty_port_block_til_ready(&port->port, tty, filp);
return error;
}
static void rc_flush_buffer(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
unsigned long flags;
if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
@ -998,7 +921,7 @@ static void rc_flush_buffer(struct tty_struct *tty)
static void rc_close(struct tty_struct *tty, struct file *filp)
{
struct riscom_port *port = (struct riscom_port *) tty->driver_data;
struct riscom_port *port = tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
unsigned long timeout;
@ -1006,40 +929,19 @@ static void rc_close(struct tty_struct *tty, struct file *filp)
if (!port || rc_paranoia_check(port, tty->name, "close"))
return;
spin_lock_irqsave(&riscom_lock, flags);
if (tty_hung_up_p(filp))
goto out;
bp = port_Board(port);
if ((tty->count == 1) && (port->port.count != 1)) {
printk(KERN_INFO "rc%d: rc_close: bad port count;"
" tty->count is 1, port count is %d\n",
board_No(bp), port->port.count);
port->port.count = 1;
}
if (--port->port.count < 0) {
printk(KERN_INFO "rc%d: rc_close: bad port count "
"for tty%d: %d\n",
board_No(bp), port_No(port), port->port.count);
port->port.count = 0;
}
if (port->port.count)
goto out;
port->port.flags |= ASYNC_CLOSING;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->port.closing_wait);
if (tty_port_close_start(&port->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.
*/
spin_lock_irqsave(&riscom_lock, flags);
port->IER &= ~IER_RXD;
if (port->port.flags & ASYNC_INITIALIZED) {
port->IER &= ~IER_TXRDY;
@ -1053,33 +955,24 @@ static void rc_close(struct tty_struct *tty, struct file *filp)
*/
timeout = jiffies + HZ;
while (port->IER & IER_TXEMPTY) {
spin_unlock_irqrestore(&riscom_lock, flags);
msleep_interruptible(jiffies_to_msecs(port->timeout));
spin_lock_irqsave(&riscom_lock, flags);
if (time_after(jiffies, timeout))
break;
}
}
rc_shutdown_port(tty, bp, port);
rc_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
port->port.tty = NULL;
if (port->port.blocked_open) {
if (port->port.close_delay)
msleep_interruptible(jiffies_to_msecs(port->port.close_delay));
wake_up_interruptible(&port->port.open_wait);
}
port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&port->port.close_wait);
out:
spin_unlock_irqrestore(&riscom_lock, flags);
tty_port_close_end(&port->port, tty);
}
static int rc_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
struct riscom_board *bp;
int c, total = 0;
unsigned long flags;
@ -1122,7 +1015,7 @@ static int rc_write(struct tty_struct *tty,
static int rc_put_char(struct tty_struct *tty, unsigned char ch)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
unsigned long flags;
int ret = 0;
@ -1146,7 +1039,7 @@ out:
static void rc_flush_chars(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
unsigned long flags;
if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
@ -1166,7 +1059,7 @@ static void rc_flush_chars(struct tty_struct *tty)
static int rc_write_room(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
int ret;
if (rc_paranoia_check(port, tty->name, "rc_write_room"))
@ -1180,7 +1073,7 @@ static int rc_write_room(struct tty_struct *tty)
static int rc_chars_in_buffer(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
return 0;
@ -1190,7 +1083,7 @@ static int rc_chars_in_buffer(struct tty_struct *tty)
static int rc_tiocmget(struct tty_struct *tty, struct file *file)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
struct riscom_board *bp;
unsigned char status;
unsigned int result;
@ -1220,7 +1113,7 @@ static int rc_tiocmget(struct tty_struct *tty, struct file *file)
static int rc_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
unsigned long flags;
struct riscom_board *bp;
@ -1252,7 +1145,7 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
static int rc_send_break(struct tty_struct *tty, int length)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
struct riscom_board *bp = port_Board(port);
unsigned long flags;
@ -1345,7 +1238,7 @@ static int rc_get_serial_info(struct riscom_port *port,
static int rc_ioctl(struct tty_struct *tty, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
void __user *argp = (void __user *)arg;
int retval;
@ -1371,7 +1264,7 @@ static int rc_ioctl(struct tty_struct *tty, struct file *filp,
static void rc_throttle(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
@ -1393,7 +1286,7 @@ static void rc_throttle(struct tty_struct *tty)
static void rc_unthrottle(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
@ -1415,7 +1308,7 @@ static void rc_unthrottle(struct tty_struct *tty)
static void rc_stop(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
@ -1433,7 +1326,7 @@ static void rc_stop(struct tty_struct *tty)
static void rc_start(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
@ -1454,8 +1347,9 @@ static void rc_start(struct tty_struct *tty)
static void rc_hangup(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
if (rc_paranoia_check(port, tty->name, "rc_hangup"))
return;
@ -1463,16 +1357,18 @@ static void rc_hangup(struct tty_struct *tty)
bp = port_Board(port);
rc_shutdown_port(tty, bp, port);
spin_lock_irqsave(&port->port.lock, flags);
port->port.count = 0;
port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
port->port.tty = NULL;
wake_up_interruptible(&port->port.open_wait);
spin_unlock_irqrestore(&port->port.lock, flags);
}
static void rc_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_port *port = tty->driver_data;
unsigned long flags;
if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
@ -1510,6 +1406,11 @@ static const struct tty_operations riscom_ops = {
.break_ctl = rc_send_break,
};
static const struct tty_port_operations riscom_port_ops = {
.carrier_raised = carrier_raised,
};
static int __init rc_init_drivers(void)
{
int error;
@ -1541,6 +1442,7 @@ static int __init rc_init_drivers(void)
memset(rc_port, 0, sizeof(rc_port));
for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
tty_port_init(&rc_port[i].port);
rc_port[i].port.ops = &riscom_port_ops;
rc_port[i].magic = RISCOM8_MAGIC;
}
return 0;

View File

@ -135,6 +135,7 @@ static int rcktpt_type[NUM_BOARDS];
static int is_PCI[NUM_BOARDS];
static rocketModel_t rocketModel[NUM_BOARDS];
static int max_board;
static const struct tty_port_operations rocket_port_ops;
/*
* The following arrays define the interrupt bits corresponding to each AIOP.
@ -435,15 +436,15 @@ static void rp_do_transmit(struct r_port *info)
#endif
if (!info)
return;
if (!info->port.tty) {
printk(KERN_WARNING "rp: WARNING %s called with "
"info->port.tty==NULL\n", __func__);
tty = tty_port_tty_get(&info->port);
if (tty == NULL) {
printk(KERN_WARNING "rp: WARNING %s called with tty==NULL\n", __func__);
clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
return;
}
spin_lock_irqsave(&info->slock, flags);
tty = info->port.tty;
info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
/* Loop sending data to FIFO until done or FIFO full */
@ -477,6 +478,7 @@ static void rp_do_transmit(struct r_port *info)
}
spin_unlock_irqrestore(&info->slock, flags);
tty_kref_put(tty);
#ifdef ROCKET_DEBUG_INTR
printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head,
@ -498,18 +500,18 @@ static void rp_handle_port(struct r_port *info)
if (!info)
return;
if ((info->flags & ROCKET_INITIALIZED) == 0) {
if ((info->port.flags & ASYNC_INITIALIZED) == 0) {
printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
"info->flags & NOT_INIT\n");
return;
}
if (!info->port.tty) {
tty = tty_port_tty_get(&info->port);
if (!tty) {
printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
"info->port.tty==NULL\n");
"tty==NULL\n");
return;
}
cp = &info->channel;
tty = info->port.tty;
IntMask = sGetChanIntID(cp) & info->intmask;
#ifdef ROCKET_DEBUG_INTR
@ -541,6 +543,7 @@ static void rp_handle_port(struct r_port *info)
printk(KERN_INFO "DSR change...\n");
}
#endif
tty_kref_put(tty);
}
/*
@ -649,9 +652,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
info->board = board;
info->aiop = aiop;
info->chan = chan;
info->port.closing_wait = 3000;
info->port.close_delay = 50;
init_waitqueue_head(&info->port.open_wait);
tty_port_init(&info->port);
info->port.ops = &rocket_port_ops;
init_completion(&info->close_wait);
info->flags &= ~ROCKET_MODE_MASK;
switch (pc104[board][line]) {
@ -710,7 +712,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
* Configures a rocketport port according to its termio settings. Called from
* user mode into the driver (exception handler). *info CD manipulation is spinlock protected.
*/
static void configure_r_port(struct r_port *info,
static void configure_r_port(struct tty_struct *tty, struct r_port *info,
struct ktermios *old_termios)
{
unsigned cflag;
@ -718,7 +720,7 @@ static void configure_r_port(struct r_port *info,
unsigned rocketMode;
int bits, baud, divisor;
CHANNEL_t *cp;
struct ktermios *t = info->port.tty->termios;
struct ktermios *t = tty->termios;
cp = &info->channel;
cflag = t->c_cflag;
@ -751,7 +753,7 @@ static void configure_r_port(struct r_port *info,
}
/* baud rate */
baud = tty_get_baud_rate(info->port.tty);
baud = tty_get_baud_rate(tty);
if (!baud)
baud = 9600;
divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;
@ -769,7 +771,7 @@ static void configure_r_port(struct r_port *info,
sSetBaud(cp, divisor);
/* FIXME: Should really back compute a baud rate from the divisor */
tty_encode_baud_rate(info->port.tty, baud, baud);
tty_encode_baud_rate(tty, baud, baud);
if (cflag & CRTSCTS) {
info->intmask |= DELTA_CTS;
@ -794,15 +796,15 @@ static void configure_r_port(struct r_port *info,
* Handle software flow control in the board
*/
#ifdef ROCKET_SOFT_FLOW
if (I_IXON(info->port.tty)) {
if (I_IXON(tty)) {
sEnTxSoftFlowCtl(cp);
if (I_IXANY(info->port.tty)) {
if (I_IXANY(tty)) {
sEnIXANY(cp);
} else {
sDisIXANY(cp);
}
sSetTxXONChar(cp, START_CHAR(info->port.tty));
sSetTxXOFFChar(cp, STOP_CHAR(info->port.tty));
sSetTxXONChar(cp, START_CHAR(tty));
sSetTxXOFFChar(cp, STOP_CHAR(tty));
} else {
sDisTxSoftFlowCtl(cp);
sDisIXANY(cp);
@ -814,24 +816,24 @@ static void configure_r_port(struct r_port *info,
* Set up ignore/read mask words
*/
info->read_status_mask = STMRCVROVRH | 0xFF;
if (I_INPCK(info->port.tty))
if (I_INPCK(tty))
info->read_status_mask |= STMFRAMEH | STMPARITYH;
if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
if (I_BRKINT(tty) || I_PARMRK(tty))
info->read_status_mask |= STMBREAKH;
/*
* Characters to ignore
*/
info->ignore_status_mask = 0;
if (I_IGNPAR(info->port.tty))
if (I_IGNPAR(tty))
info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
if (I_IGNBRK(info->port.tty)) {
if (I_IGNBRK(tty)) {
info->ignore_status_mask |= STMBREAKH;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too. (For real raw support).
*/
if (I_IGNPAR(info->port.tty))
if (I_IGNPAR(tty))
info->ignore_status_mask |= STMRCVROVRH;
}
@ -864,107 +866,18 @@ static void configure_r_port(struct r_port *info,
}
}
/* info->port.count is considered critical, protected by spinlocks. */
static int block_til_ready(struct tty_struct *tty, struct file *filp,
struct r_port *info)
static int carrier_raised(struct tty_port *port)
{
DECLARE_WAITQUEUE(wait, current);
int retval;
int do_clocal = 0, extra_count = 0;
unsigned long flags;
/*
* 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))
return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
if (info->flags & ROCKET_CLOSING) {
if (wait_for_completion_interruptible(&info->close_wait))
return -ERESTARTSYS;
return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
struct r_port *info = container_of(port, struct r_port, port);
return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
}
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
*/
if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
info->flags |= ROCKET_NORMAL_ACTIVE;
return 0;
}
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
/*
* Block waiting for the carrier detect and the line to become free. While we are in
* this loop, info->port.count is dropped by one, so that rp_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);
#ifdef ROCKET_DEBUG_OPEN
printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->port.count);
#endif
spin_lock_irqsave(&info->slock, flags);
#ifdef ROCKET_DISABLE_SIMUSAGE
info->flags |= ROCKET_NORMAL_ACTIVE;
#else
if (!tty_hung_up_p(filp)) {
extra_count = 1;
info->port.count--;
}
#endif
info->port.blocked_open++;
spin_unlock_irqrestore(&info->slock, flags);
while (1) {
if (tty->termios->c_cflag & CBAUD) {
static void raise_dtr_rts(struct tty_port *port)
{
struct r_port *info = container_of(port, struct r_port, port);
sSetDTR(&info->channel);
sSetRTS(&info->channel);
}
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(info->flags & ROCKET_INITIALIZED)) {
if (info->flags & ROCKET_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
break;
}
if (!(info->flags & ROCKET_CLOSING) && (do_clocal || (sGetChanStatusLo(&info->channel) & CD_ACT)))
break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
#ifdef ROCKET_DEBUG_OPEN
printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n",
info->line, info->port.count, info->flags);
#endif
schedule(); /* Don't hold spinlock here, will hang PC */
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&info->port.open_wait, &wait);
spin_lock_irqsave(&info->slock, flags);
if (extra_count)
info->port.count++;
info->port.blocked_open--;
spin_unlock_irqrestore(&info->slock, flags);
#ifdef ROCKET_DEBUG_OPEN
printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n",
info->line, info->port.count);
#endif
if (retval)
return retval;
info->flags |= ROCKET_NORMAL_ACTIVE;
return 0;
}
/*
* Exception handler that opens a serial port. Creates xmit_buf storage, fills in
@ -973,24 +886,26 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
static int rp_open(struct tty_struct *tty, struct file *filp)
{
struct r_port *info;
struct tty_port *port;
int line = 0, retval;
CHANNEL_t *cp;
unsigned long page;
line = tty->index;
if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL))
if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL))
return -ENXIO;
port = &info->port;
page = __get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
if (info->flags & ROCKET_CLOSING) {
if (port->flags & ASYNC_CLOSING) {
retval = wait_for_completion_interruptible(&info->close_wait);
free_page(page);
if (retval)
return retval;
return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
}
/*
@ -1002,9 +917,9 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
info->xmit_buf = (unsigned char *) page;
tty->driver_data = info;
info->port.tty = tty;
tty_port_tty_set(port, tty);
if (info->port.count++ == 0) {
if (port->count++ == 0) {
atomic_inc(&rp_num_ports_open);
#ifdef ROCKET_DEBUG_OPEN
@ -1019,7 +934,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
/*
* Info->count is now 1; so it's safe to sleep now.
*/
if ((info->flags & ROCKET_INITIALIZED) == 0) {
if (!test_bit(ASYNC_INITIALIZED, &port->flags)) {
cp = &info->channel;
sSetRxTrigger(cp, TRIG_1);
if (sGetChanStatus(cp) & CD_ACT)
@ -1043,21 +958,21 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
sEnRxFIFO(cp);
sEnTransmit(cp);
info->flags |= ROCKET_INITIALIZED;
set_bit(ASYNC_INITIALIZED, &info->port.flags);
/*
* Set up the tty->alt_speed kludge
*/
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
info->port.tty->alt_speed = 57600;
tty->alt_speed = 57600;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
info->port.tty->alt_speed = 115200;
tty->alt_speed = 115200;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
info->port.tty->alt_speed = 230400;
tty->alt_speed = 230400;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
info->port.tty->alt_speed = 460800;
tty->alt_speed = 460800;
configure_r_port(info, NULL);
configure_r_port(tty, info, NULL);
if (tty->termios->c_cflag & CBAUD) {
sSetDTR(cp);
sSetRTS(cp);
@ -1066,7 +981,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
/* Starts (or resets) the maint polling loop */
mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
retval = block_til_ready(tty, filp, info);
retval = tty_port_block_til_ready(port, tty, filp);
if (retval) {
#ifdef ROCKET_DEBUG_OPEN
printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);
@ -1081,8 +996,8 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
*/
static void rp_close(struct tty_struct *tty, struct file *filp)
{
struct r_port *info = (struct r_port *) tty->driver_data;
unsigned long flags;
struct r_port *info = tty->driver_data;
struct tty_port *port = &info->port;
int timeout;
CHANNEL_t *cp;
@ -1093,53 +1008,10 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count);
#endif
if (tty_hung_up_p(filp))
if (tty_port_close_start(port, tty, filp) == 0)
return;
spin_lock_irqsave(&info->slock, flags);
if ((tty->count == 1) && (info->port.count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. Info->count should always
* be one in these conditions. If it's greater than
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
printk(KERN_WARNING "rp_close: bad serial port count; "
"tty->count is 1, info->port.count is %d\n", info->port.count);
info->port.count = 1;
}
if (--info->port.count < 0) {
printk(KERN_WARNING "rp_close: bad serial port count for "
"ttyR%d: %d\n", info->line, info->port.count);
info->port.count = 0;
}
if (info->port.count) {
spin_unlock_irqrestore(&info->slock, flags);
return;
}
info->flags |= ROCKET_CLOSING;
spin_unlock_irqrestore(&info->slock, flags);
cp = &info->channel;
/*
* Notify the line discpline to only process XON/XOFF characters
*/
tty->closing = 1;
/*
* If transmission was throttled by the application request,
* just flush the xmit buffer.
*/
if (tty->flow_stopped)
rp_flush_buffer(tty);
/*
* Wait for the transmit buffer to clear
*/
if (info->port.closing_wait != ROCKET_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, info->port.closing_wait);
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
@ -1168,19 +1040,24 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
if (info->port.blocked_open) {
if (info->port.close_delay) {
msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
/* We can't yet use tty_port_close_end as the buffer handling in this
driver is a bit different to the usual */
if (port->blocked_open) {
if (port->close_delay) {
msleep_interruptible(jiffies_to_msecs(port->close_delay));
}
wake_up_interruptible(&info->port.open_wait);
wake_up_interruptible(&port->open_wait);
} else {
if (info->xmit_buf) {
free_page((unsigned long) info->xmit_buf);
info->xmit_buf = NULL;
}
}
info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE);
info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE);
tty->closing = 0;
tty_port_tty_set(port, NULL);
wake_up_interruptible(&port->close_wait);
complete_all(&info->close_wait);
atomic_dec(&rp_num_ports_open);
@ -1195,7 +1072,7 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
static void rp_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
CHANNEL_t *cp;
unsigned cflag;
@ -1213,7 +1090,7 @@ static void rp_set_termios(struct tty_struct *tty,
/* Or CMSPAR */
tty->termios->c_cflag &= ~CMSPAR;
configure_r_port(info, old_termios);
configure_r_port(tty, info, old_termios);
cp = &info->channel;
@ -1238,7 +1115,7 @@ static void rp_set_termios(struct tty_struct *tty,
static int rp_break(struct tty_struct *tty, int break_state)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
unsigned long flags;
if (rocket_paranoia_check(info, "rp_break"))
@ -1284,7 +1161,7 @@ static int sGetChanRI(CHANNEL_T * ChP)
*/
static int rp_tiocmget(struct tty_struct *tty, struct file *file)
{
struct r_port *info = (struct r_port *)tty->driver_data;
struct r_port *info = tty->driver_data;
unsigned int control, result, ChanStatus;
ChanStatus = sGetChanStatusLo(&info->channel);
@ -1305,7 +1182,7 @@ static int rp_tiocmget(struct tty_struct *tty, struct file *file)
static int rp_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct r_port *info = (struct r_port *)tty->driver_data;
struct r_port *info = tty->driver_data;
if (set & TIOCM_RTS)
info->channel.TxControl[3] |= SET_RTS;
@ -1338,7 +1215,8 @@ static int get_config(struct r_port *info, struct rocket_config __user *retinfo)
return 0;
}
static int set_config(struct r_port *info, struct rocket_config __user *new_info)
static int set_config(struct tty_struct *tty, struct r_port *info,
struct rocket_config __user *new_info)
{
struct rocket_config new_serial;
@ -1350,7 +1228,7 @@ static int set_config(struct r_port *info, struct rocket_config __user *new_info
if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK))
return -EPERM;
info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
configure_r_port(info, NULL);
configure_r_port(tty, info, NULL);
return 0;
}
@ -1359,15 +1237,15 @@ static int set_config(struct r_port *info, struct rocket_config __user *new_info
info->port.closing_wait = new_serial.closing_wait;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
info->port.tty->alt_speed = 57600;
tty->alt_speed = 57600;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
info->port.tty->alt_speed = 115200;
tty->alt_speed = 115200;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
info->port.tty->alt_speed = 230400;
tty->alt_speed = 230400;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
info->port.tty->alt_speed = 460800;
tty->alt_speed = 460800;
configure_r_port(info, NULL);
configure_r_port(tty, info, NULL);
return 0;
}
@ -1434,7 +1312,7 @@ static int get_version(struct r_port *info, struct rocket_version __user *retver
static int rp_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
void __user *argp = (void __user *)arg;
int ret = 0;
@ -1452,7 +1330,7 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file,
ret = get_config(info, argp);
break;
case RCKP_SET_CONFIG:
ret = set_config(info, argp);
ret = set_config(tty, info, argp);
break;
case RCKP_GET_PORTS:
ret = get_ports(info, argp);
@ -1472,7 +1350,7 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file,
static void rp_send_xchar(struct tty_struct *tty, char ch)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
CHANNEL_t *cp;
if (rocket_paranoia_check(info, "rp_send_xchar"))
@ -1487,7 +1365,7 @@ static void rp_send_xchar(struct tty_struct *tty, char ch)
static void rp_throttle(struct tty_struct *tty)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
CHANNEL_t *cp;
#ifdef ROCKET_DEBUG_THROTTLE
@ -1507,7 +1385,7 @@ static void rp_throttle(struct tty_struct *tty)
static void rp_unthrottle(struct tty_struct *tty)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
CHANNEL_t *cp;
#ifdef ROCKET_DEBUG_THROTTLE
printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
@ -1534,7 +1412,7 @@ static void rp_unthrottle(struct tty_struct *tty)
*/
static void rp_stop(struct tty_struct *tty)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
#ifdef ROCKET_DEBUG_FLOW
printk(KERN_INFO "stop %s: %d %d....\n", tty->name,
@ -1550,7 +1428,7 @@ static void rp_stop(struct tty_struct *tty)
static void rp_start(struct tty_struct *tty)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
#ifdef ROCKET_DEBUG_FLOW
printk(KERN_INFO "start %s: %d %d....\n", tty->name,
@ -1570,7 +1448,7 @@ static void rp_start(struct tty_struct *tty)
*/
static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
CHANNEL_t *cp;
unsigned long orig_jiffies;
int check_time, exit_time;
@ -1627,7 +1505,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
static void rp_hangup(struct tty_struct *tty)
{
CHANNEL_t *cp;
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
if (rocket_paranoia_check(info, "rp_hangup"))
return;
@ -1636,15 +1514,13 @@ static void rp_hangup(struct tty_struct *tty)
printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
#endif
rp_flush_buffer(tty);
if (info->flags & ROCKET_CLOSING)
if (info->port.flags & ASYNC_CLOSING)
return;
if (info->port.count)
atomic_dec(&rp_num_ports_open);
clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
info->port.count = 0;
info->flags &= ~ROCKET_NORMAL_ACTIVE;
info->port.tty = NULL;
tty_port_hangup(&info->port);
cp = &info->channel;
sDisRxFIFO(cp);
@ -1653,7 +1529,7 @@ static void rp_hangup(struct tty_struct *tty)
sDisCTSFlowCtl(cp);
sDisTxSoftFlowCtl(cp);
sClrTxXOFF(cp);
info->flags &= ~ROCKET_INITIALIZED;
info->port.flags &= ~ASYNC_INITIALIZED;
wake_up_interruptible(&info->port.open_wait);
}
@ -1667,7 +1543,7 @@ static void rp_hangup(struct tty_struct *tty)
*/
static int rp_put_char(struct tty_struct *tty, unsigned char ch)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
CHANNEL_t *cp;
unsigned long flags;
@ -1714,7 +1590,7 @@ static int rp_put_char(struct tty_struct *tty, unsigned char ch)
static int rp_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
CHANNEL_t *cp;
const unsigned char *b;
int c, retval = 0;
@ -1764,7 +1640,8 @@ static int rp_write(struct tty_struct *tty,
/* Write remaining data into the port's xmit_buf */
while (1) {
if (!info->port.tty) /* Seemingly obligatory check... */
/* Hung up ? */
if (!test_bit(ASYNC_NORMAL_ACTIVE, &info->port.flags))
goto end;
c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
c = min(c, XMIT_BUF_SIZE - info->xmit_head);
@ -1806,7 +1683,7 @@ end:
*/
static int rp_write_room(struct tty_struct *tty)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
int ret;
if (rocket_paranoia_check(info, "rp_write_room"))
@ -1827,7 +1704,7 @@ static int rp_write_room(struct tty_struct *tty)
*/
static int rp_chars_in_buffer(struct tty_struct *tty)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
CHANNEL_t *cp;
if (rocket_paranoia_check(info, "rp_chars_in_buffer"))
@ -1848,7 +1725,7 @@ static int rp_chars_in_buffer(struct tty_struct *tty)
*/
static void rp_flush_buffer(struct tty_struct *tty)
{
struct r_port *info = (struct r_port *) tty->driver_data;
struct r_port *info = tty->driver_data;
CHANNEL_t *cp;
unsigned long flags;
@ -2371,6 +2248,11 @@ static const struct tty_operations rocket_ops = {
.tiocmset = rp_tiocmset,
};
static const struct tty_port_operations rocket_port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts,
};
/*
* The module "startup" routine; it's run when the module is loaded.
*/

View File

@ -39,7 +39,7 @@ struct rocket_version {
/*
* Rocketport flags
*/
#define ROCKET_CALLOUT_NOHUP 0x00000001
/*#define ROCKET_CALLOUT_NOHUP 0x00000001 */
#define ROCKET_FORCE_CD 0x00000002
#define ROCKET_HUP_NOTIFY 0x00000004
#define ROCKET_SPLIT_TERMIOS 0x00000008

View File

@ -1162,11 +1162,6 @@ struct r_port {
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
/* Internal flags used only by the rocketport driver */
#define ROCKET_INITIALIZED 0x80000000 /* Port is active */
#define ROCKET_CLOSING 0x40000000 /* Serial port is closing */
#define ROCKET_NORMAL_ACTIVE 0x20000000 /* Normal port is active */
/*
* Assigned major numbers for the Comtrol Rocketport
*/

View File

@ -306,7 +306,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
*/
int paste_selection(struct tty_struct *tty)
{
struct vc_data *vc = (struct vc_data *)tty->driver_data;
struct vc_data *vc = tty->driver_data;
int pasted = 0;
unsigned int count;
struct tty_ldisc *ld;

View File

@ -122,7 +122,7 @@ static void a2232_disable_tx_interrupts(void *ptr);
static void a2232_enable_tx_interrupts(void *ptr);
static void a2232_disable_rx_interrupts(void *ptr);
static void a2232_enable_rx_interrupts(void *ptr);
static int a2232_get_CD(void *ptr);
static int a2232_carrier_raised(struct tty_port *port);
static void a2232_shutdown_port(void *ptr);
static int a2232_set_real_termios(void *ptr);
static int a2232_chars_in_buffer(void *ptr);
@ -148,7 +148,6 @@ static struct real_driver a2232_real_driver = {
a2232_enable_tx_interrupts,
a2232_disable_rx_interrupts,
a2232_enable_rx_interrupts,
a2232_get_CD,
a2232_shutdown_port,
a2232_set_real_termios,
a2232_chars_in_buffer,
@ -260,9 +259,10 @@ static void a2232_enable_rx_interrupts(void *ptr)
port->disable_rx = 0;
}
static int a2232_get_CD(void *ptr)
static int a2232_carrier_raised(struct tty_port *port)
{
return ((struct a2232_port *) ptr)->cd_status;
struct a2232_port *ap = container_of(port, struct a2232_port, gs.port);
return ap->cd_status;
}
static void a2232_shutdown_port(void *ptr)
@ -460,14 +460,14 @@ static void a2232_throttle(struct tty_struct *tty)
if switched on. So the only thing we can do at this
layer here is not taking any characters out of the
A2232 buffer any more. */
struct a2232_port *port = (struct a2232_port *) tty->driver_data;
struct a2232_port *port = tty->driver_data;
port->throttle_input = -1;
}
static void a2232_unthrottle(struct tty_struct *tty)
{
/* Unthrottle: dual to "throttle()" above. */
struct a2232_port *port = (struct a2232_port *) tty->driver_data;
struct a2232_port *port = tty->driver_data;
port->throttle_input = 0;
}
@ -638,6 +638,10 @@ int ch, err, n, p;
return IRQ_HANDLED;
}
static const struct tty_port_operations a2232_port_ops = {
.carrier_raised = a2232_carrier_raised,
};
static void a2232_init_portstructs(void)
{
struct a2232_port *port;
@ -645,6 +649,8 @@ static void a2232_init_portstructs(void)
for (i = 0; i < MAX_A2232_BOARDS*NUMLINES; i++) {
port = a2232_ports + i;
tty_port_init(&port->gs.port);
port->gs.port.ops = &a2232_port_ops;
port->which_a2232 = i/NUMLINES;
port->which_port_on_a2232 = i%NUMLINES;
port->disable_rx = port->throttle_input = port->cd_status = 0;
@ -652,11 +658,6 @@ static void a2232_init_portstructs(void)
port->gs.close_delay = HZ/2;
port->gs.closing_wait = 30 * HZ;
port->gs.rd = &a2232_real_driver;
#ifdef NEW_WRITE_LOCKING
mutex_init(&(port->gs.port_write_mutex));
#endif
init_waitqueue_head(&port->gs.port.open_wait);
init_waitqueue_head(&port->gs.port.close_wait);
}
}

View File

@ -315,7 +315,7 @@ u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd)
static void cy_stop(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
int channel;
unsigned long flags;
@ -337,7 +337,7 @@ static void cy_stop(struct tty_struct *tty)
static void cy_start(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
int channel;
unsigned long flags;
@ -1062,7 +1062,7 @@ static void config_setup(struct cyclades_port *info)
static int cy_put_char(struct tty_struct *tty, unsigned char ch)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_IO
@ -1090,7 +1090,7 @@ static int cy_put_char(struct tty_struct *tty, unsigned char ch)
static void cy_flush_chars(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
unsigned long flags;
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
int channel;
@ -1122,7 +1122,7 @@ static void cy_flush_chars(struct tty_struct *tty)
*/
static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
unsigned long flags;
int c, total = 0;
@ -1166,7 +1166,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
static int cy_write_room(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
int ret;
#ifdef SERIAL_DEBUG_IO
@ -1183,7 +1183,7 @@ static int cy_write_room(struct tty_struct *tty)
static int cy_chars_in_buffer(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
#ifdef SERIAL_DEBUG_IO
printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
@ -1197,7 +1197,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
static void cy_flush_buffer(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_IO
@ -1218,7 +1218,7 @@ static void cy_flush_buffer(struct tty_struct *tty)
*/
static void cy_throttle(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
unsigned long flags;
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
int channel;
@ -1250,7 +1250,7 @@ static void cy_throttle(struct tty_struct *tty)
static void cy_unthrottle(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
unsigned long flags;
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
int channel;
@ -1345,7 +1345,7 @@ check_and_exit:
static int cy_tiocmget(struct tty_struct *tty, struct file *file)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
int channel;
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
unsigned long flags;
@ -1369,7 +1369,7 @@ static int
cy_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
int channel;
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
unsigned long flags;
@ -1532,7 +1532,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
unsigned long val;
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
int ret_val = 0;
void __user *argp = (void __user *)arg;
@ -1607,7 +1607,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
#ifdef SERIAL_DEBUG_OTHER
printk("cy_set_termios %s\n", tty->name);
@ -1631,7 +1631,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
static void cy_close(struct tty_struct *tty, struct file *filp)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
/* CP('C'); */
#ifdef SERIAL_DEBUG_OTHER
@ -1698,7 +1698,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
*/
void cy_hangup(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
struct cyclades_port *info = tty->driver_data;
#ifdef SERIAL_DEBUG_OTHER
printk("cy_hangup %s\n", tty->name); /* */

View File

@ -1450,7 +1450,7 @@ static int sx_open(struct tty_struct *tty, struct file *filp)
static void sx_flush_buffer(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
unsigned long flags;
struct specialix_board *bp;
@ -1472,7 +1472,7 @@ static void sx_flush_buffer(struct tty_struct *tty)
static void sx_close(struct tty_struct *tty, struct file *filp)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
unsigned long timeout;
@ -1585,7 +1585,7 @@ static void sx_close(struct tty_struct *tty, struct file *filp)
static int sx_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
struct specialix_board *bp;
int c, total = 0;
unsigned long flags;
@ -1637,7 +1637,7 @@ static int sx_write(struct tty_struct *tty,
static int sx_put_char(struct tty_struct *tty, unsigned char ch)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
unsigned long flags;
struct specialix_board *bp;
@ -1676,7 +1676,7 @@ static int sx_put_char(struct tty_struct *tty, unsigned char ch)
static void sx_flush_chars(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
unsigned long flags;
struct specialix_board *bp = port_Board(port);
@ -1703,7 +1703,7 @@ static void sx_flush_chars(struct tty_struct *tty)
static int sx_write_room(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
int ret;
func_enter();
@ -1724,7 +1724,7 @@ static int sx_write_room(struct tty_struct *tty)
static int sx_chars_in_buffer(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
func_enter();
@ -1738,7 +1738,7 @@ static int sx_chars_in_buffer(struct tty_struct *tty)
static int sx_tiocmget(struct tty_struct *tty, struct file *file)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
struct specialix_board *bp;
unsigned char status;
unsigned int result;
@ -1780,7 +1780,7 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file)
static int sx_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
unsigned long flags;
struct specialix_board *bp;
@ -1820,7 +1820,7 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
static int sx_send_break(struct tty_struct *tty, int length)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
struct specialix_board *bp = port_Board(port);
unsigned long flags;
@ -1931,7 +1931,7 @@ static int sx_get_serial_info(struct specialix_port *port,
static int sx_ioctl(struct tty_struct *tty, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
void __user *argp = (void __user *)arg;
func_enter();
@ -1959,7 +1959,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp,
static void sx_throttle(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
@ -2004,7 +2004,7 @@ static void sx_throttle(struct tty_struct *tty)
static void sx_unthrottle(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
@ -2045,7 +2045,7 @@ static void sx_unthrottle(struct tty_struct *tty)
static void sx_stop(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
@ -2072,7 +2072,7 @@ static void sx_stop(struct tty_struct *tty)
static void sx_start(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
@ -2100,7 +2100,7 @@ static void sx_start(struct tty_struct *tty)
static void sx_hangup(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
@ -2135,7 +2135,7 @@ static void sx_hangup(struct tty_struct *tty)
static void sx_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_port *port = tty->driver_data;
unsigned long flags;
struct specialix_board *bp;

View File

@ -130,6 +130,8 @@ static char stl_unwanted[SC26198_RXFIFOSIZE];
static DEFINE_MUTEX(stl_brdslock);
static struct stlbrd *stl_brds[STL_MAXBRDS];
static const struct tty_port_operations stl_port_ops;
/*
* Per board state flags. Used with the state field of the board struct.
* Not really much here!
@ -407,7 +409,6 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
static int stl_brdinit(struct stlbrd *brdp);
static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp);
static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp);
/*
* CD1400 uart specific handling functions.
@ -703,8 +704,9 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
{
struct stlport *portp;
struct stlbrd *brdp;
struct tty_port *port;
unsigned int minordev, brdnr, panelnr;
int portnr, rc;
int portnr;
pr_debug("stl_open(tty=%p,filp=%p): device=%s\n", tty, filp, tty->name);
@ -715,6 +717,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
brdp = stl_brds[brdnr];
if (brdp == NULL)
return -ENODEV;
minordev = MINOR2PORT(minordev);
for (portnr = -1, panelnr = 0; panelnr < STL_MAXPANELS; panelnr++) {
if (brdp->panels[panelnr] == NULL)
@ -731,16 +734,17 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
portp = brdp->panels[panelnr]->ports[portnr];
if (portp == NULL)
return -ENODEV;
port = &portp->port;
/*
* On the first open of the device setup the port hardware, and
* initialize the per port data structure.
*/
tty_port_tty_set(&portp->port, tty);
tty_port_tty_set(port, tty);
tty->driver_data = portp;
portp->port.count++;
port->count++;
if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
if ((port->flags & ASYNC_INITIALIZED) == 0) {
if (!portp->tx.buf) {
portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
if (!portp->tx.buf)
@ -754,91 +758,24 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
stl_enablerxtx(portp, 1, 1);
stl_startrxtx(portp, 1, 0);
clear_bit(TTY_IO_ERROR, &tty->flags);
portp->port.flags |= ASYNC_INITIALIZED;
port->flags |= ASYNC_INITIALIZED;
}
/*
* Check if this port is in the middle of closing. If so then wait
* until it is closed then return error status, based on flag settings.
* The sleep here does not need interrupt protection since the wakeup
* for it is done with the same context.
*/
if (portp->port.flags & ASYNC_CLOSING) {
interruptible_sleep_on(&portp->port.close_wait);
if (portp->port.flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
return -ERESTARTSYS;
}
/*
* Based on type of open being done check if it can overlap with any
* previous opens still in effect. If we are a normal serial device
* then also we might have to wait for carrier.
*/
if (!(filp->f_flags & O_NONBLOCK))
if ((rc = stl_waitcarrier(tty, portp, filp)) != 0)
return rc;
portp->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
return tty_port_block_til_ready(port, tty, filp);
}
/*****************************************************************************/
/*
* 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...
*/
static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp,
struct file *filp)
static int stl_carrier_raised(struct tty_port *port)
{
unsigned long flags;
int rc, doclocal;
struct stlport *portp = container_of(port, struct stlport, port);
return (portp->sigs & TIOCM_CD) ? 1 : 0;
}
pr_debug("stl_waitcarrier(portp=%p,filp=%p)\n", portp, filp);
rc = 0;
doclocal = 0;
spin_lock_irqsave(&stallion_lock, flags);
if (tty->termios->c_cflag & CLOCAL)
doclocal++;
portp->openwaitcnt++;
if (! tty_hung_up_p(filp))
portp->port.count--;
for (;;) {
static void stl_raise_dtr_rts(struct tty_port *port)
{
struct stlport *portp = container_of(port, struct stlport, port);
/* Takes brd_lock internally */
stl_setsignals(portp, 1, 1);
if (tty_hung_up_p(filp) ||
((portp->port.flags & ASYNC_INITIALIZED) == 0)) {
if (portp->port.flags & ASYNC_HUP_NOTIFY)
rc = -EBUSY;
else
rc = -ERESTARTSYS;
break;
}
if (((portp->port.flags & ASYNC_CLOSING) == 0) &&
(doclocal || (portp->sigs & TIOCM_CD)))
break;
if (signal_pending(current)) {
rc = -ERESTARTSYS;
break;
}
/* FIXME */
interruptible_sleep_on(&portp->port.open_wait);
}
if (! tty_hung_up_p(filp))
portp->port.count++;
portp->openwaitcnt--;
spin_unlock_irqrestore(&stallion_lock, flags);
return rc;
}
/*****************************************************************************/
@ -890,47 +827,29 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
static void stl_close(struct tty_struct *tty, struct file *filp)
{
struct stlport *portp;
struct tty_port *port;
unsigned long flags;
pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp);
portp = tty->driver_data;
if (portp == NULL)
return;
BUG_ON(portp == NULL);
spin_lock_irqsave(&stallion_lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&stallion_lock, flags);
return;
}
if ((tty->count == 1) && (portp->port.count != 1))
portp->port.count = 1;
if (portp->port.count-- > 1) {
spin_unlock_irqrestore(&stallion_lock, flags);
return;
}
portp->port.count = 0;
portp->port.flags |= ASYNC_CLOSING;
port = &portp->port;
if (tty_port_close_start(port, tty, filp) == 0)
return;
/*
* May want to wait for any data to drain before closing. The BUSY
* flag keeps track of whether we are still sending or not - it is
* very accurate for the cd1400, not quite so for the sc26198.
* (The sc26198 has no "end-of-data" interrupt only empty FIFO)
*/
tty->closing = 1;
spin_unlock_irqrestore(&stallion_lock, flags);
if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, portp->closing_wait);
stl_waituntilsent(tty, (HZ / 2));
spin_lock_irqsave(&stallion_lock, flags);
spin_lock_irqsave(&port->lock, flags);
portp->port.flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&stallion_lock, flags);
spin_unlock_irqrestore(&port->lock, flags);
stl_disableintrs(portp);
if (tty->termios->c_cflag & HUPCL)
@ -944,20 +863,9 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
portp->tx.head = NULL;
portp->tx.tail = NULL;
}
set_bit(TTY_IO_ERROR, &tty->flags);
tty_ldisc_flush(tty);
tty->closing = 0;
tty_port_tty_set(&portp->port, NULL);
if (portp->openwaitcnt) {
if (portp->close_delay)
msleep_interruptible(jiffies_to_msecs(portp->close_delay));
wake_up_interruptible(&portp->port.open_wait);
}
portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&portp->port.close_wait);
tty_port_close_end(port, tty);
tty_port_tty_set(port, NULL);
}
/*****************************************************************************/
@ -1405,14 +1313,20 @@ static void stl_stop(struct tty_struct *tty)
static void stl_hangup(struct tty_struct *tty)
{
struct stlport *portp;
struct tty_port *port;
unsigned long flags;
pr_debug("stl_hangup(tty=%p)\n", tty);
portp = tty->driver_data;
if (portp == NULL)
return;
port = &portp->port;
spin_lock_irqsave(&port->lock, flags);
port->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&port->lock, flags);
portp->port.flags &= ~ASYNC_INITIALIZED;
stl_disableintrs(portp);
if (tty->termios->c_cflag & HUPCL)
stl_setsignals(portp, 0, 0);
@ -1426,10 +1340,7 @@ static void stl_hangup(struct tty_struct *tty)
portp->tx.head = NULL;
portp->tx.tail = NULL;
}
tty_port_tty_set(&portp->port, NULL);
portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
portp->port.count = 0;
wake_up_interruptible(&portp->port.open_wait);
tty_port_hangup(port);
}
/*****************************************************************************/
@ -1776,6 +1687,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
break;
}
tty_port_init(&portp->port);
portp->port.ops = &stl_port_ops;
portp->magic = STL_PORTMAGIC;
portp->portnr = i;
portp->brdnr = panelp->brdnr;
@ -2659,6 +2571,11 @@ static const struct tty_operations stl_ops = {
.tiocmset = stl_tiocmset,
};
static const struct tty_port_operations stl_port_ops = {
.carrier_raised = stl_carrier_raised,
.raise_dtr_rts = stl_raise_dtr_rts,
};
/*****************************************************************************/
/* CD1400 HARDWARE FUNCTIONS */
/*****************************************************************************/

View File

@ -279,7 +279,7 @@ static void sx_disable_tx_interrupts(void *ptr);
static void sx_enable_tx_interrupts(void *ptr);
static void sx_disable_rx_interrupts(void *ptr);
static void sx_enable_rx_interrupts(void *ptr);
static int sx_get_CD(void *ptr);
static int sx_carrier_raised(struct tty_port *port);
static void sx_shutdown_port(void *ptr);
static int sx_set_real_termios(void *ptr);
static void sx_close(void *ptr);
@ -360,7 +360,6 @@ static struct real_driver sx_real_driver = {
sx_enable_tx_interrupts,
sx_disable_rx_interrupts,
sx_enable_rx_interrupts,
sx_get_CD,
sx_shutdown_port,
sx_set_real_termios,
sx_chars_in_buffer,
@ -791,7 +790,7 @@ static int sx_getsignals(struct sx_port *port)
sx_dprintk(SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) "
"%02x/%02x\n",
(o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0,
port->c_dcd, sx_get_CD(port),
port->c_dcd, tty_port_carrier_raised(&port->gs.port),
sx_read_channel_byte(port, hi_ip),
sx_read_channel_byte(port, hi_state));
@ -1190,7 +1189,7 @@ static inline void sx_check_modem_signals(struct sx_port *port)
hi_state = sx_read_channel_byte(port, hi_state);
sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",
port->c_dcd, sx_get_CD(port));
port->c_dcd, tty_port_carrier_raised(&port->gs.port));
if (hi_state & ST_BREAK) {
hi_state &= ~ST_BREAK;
@ -1202,11 +1201,11 @@ static inline void sx_check_modem_signals(struct sx_port *port)
hi_state &= ~ST_DCD;
sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");
sx_write_channel_byte(port, hi_state, hi_state);
c_dcd = sx_get_CD(port);
c_dcd = tty_port_carrier_raised(&port->gs.port);
sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);
if (c_dcd != port->c_dcd) {
port->c_dcd = c_dcd;
if (sx_get_CD(port)) {
if (tty_port_carrier_raised(&port->gs.port)) {
/* DCD went UP */
if ((sx_read_channel_byte(port, hi_hstat) !=
HS_IDLE_CLOSED) &&
@ -1415,13 +1414,10 @@ static void sx_enable_rx_interrupts(void *ptr)
}
/* Jeez. Isn't this simple? */
static int sx_get_CD(void *ptr)
static int sx_carrier_raised(struct tty_port *port)
{
struct sx_port *port = ptr;
func_enter2();
func_exit();
return ((sx_read_channel_byte(port, hi_ip) & IP_DCD) != 0);
struct sx_port *sp = container_of(port, struct sx_port, gs.port);
return ((sx_read_channel_byte(sp, hi_ip) & IP_DCD) != 0);
}
/* Jeez. Isn't this simple? */
@ -1536,7 +1532,7 @@ static int sx_open(struct tty_struct *tty, struct file *filp)
}
/* tty->low_latency = 1; */
port->c_dcd = sx_get_CD(port);
port->c_dcd = sx_carrier_raised(&port->gs.port);
sx_dprintk(SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
func_exit();
@ -1945,7 +1941,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp,
static void sx_throttle(struct tty_struct *tty)
{
struct sx_port *port = (struct sx_port *)tty->driver_data;
struct sx_port *port = tty->driver_data;
func_enter2();
/* If the port is using any type of input flow
@ -1959,7 +1955,7 @@ static void sx_throttle(struct tty_struct *tty)
static void sx_unthrottle(struct tty_struct *tty)
{
struct sx_port *port = (struct sx_port *)tty->driver_data;
struct sx_port *port = tty->driver_data;
func_enter2();
/* Always unthrottle even if flow control is not enabled on
@ -2354,6 +2350,10 @@ static const struct tty_operations sx_ops = {
.tiocmset = sx_tiocmset,
};
static const struct tty_port_operations sx_port_ops = {
.carrier_raised = sx_carrier_raised,
};
static int sx_init_drivers(void)
{
int error;
@ -2410,6 +2410,7 @@ static int sx_init_portstructs(int nboards, int nports)
for (j = 0; j < boards[i].nports; j++) {
sx_dprintk(SX_DEBUG_INIT, "initing port %d\n", j);
tty_port_init(&port->gs.port);
port->gs.port.ops = &sx_port_ops;
port->gs.magic = SX_MAGIC;
port->gs.close_delay = HZ / 2;
port->gs.closing_wait = 30 * HZ;

View File

@ -977,7 +977,7 @@ static void ldisc_receive_buf(struct tty_struct *tty,
*/
static void mgsl_stop(struct tty_struct *tty)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
if (mgsl_paranoia_check(info, tty->name, "mgsl_stop"))
@ -1000,7 +1000,7 @@ static void mgsl_stop(struct tty_struct *tty)
*/
static void mgsl_start(struct tty_struct *tty)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
if (mgsl_paranoia_check(info, tty->name, "mgsl_start"))
@ -2057,7 +2057,7 @@ static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
*/
static void mgsl_flush_chars(struct tty_struct *tty)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
if ( debug_level >= DEBUG_LEVEL_INFO )
@ -2109,7 +2109,7 @@ static int mgsl_write(struct tty_struct * tty,
const unsigned char *buf, int count)
{
int c, ret = 0;
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
if ( debug_level >= DEBUG_LEVEL_INFO )
@ -2232,7 +2232,7 @@ cleanup:
*/
static int mgsl_write_room(struct tty_struct *tty)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
int ret;
if (mgsl_paranoia_check(info, tty->name, "mgsl_write_room"))
@ -2267,7 +2267,7 @@ static int mgsl_write_room(struct tty_struct *tty)
*/
static int mgsl_chars_in_buffer(struct tty_struct *tty)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_chars_in_buffer(%s)\n",
@ -2301,7 +2301,7 @@ static int mgsl_chars_in_buffer(struct tty_struct *tty)
*/
static void mgsl_flush_buffer(struct tty_struct *tty)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -2329,7 +2329,7 @@ static void mgsl_flush_buffer(struct tty_struct *tty)
*/
static void mgsl_send_xchar(struct tty_struct *tty, char ch)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -2358,7 +2358,7 @@ static void mgsl_send_xchar(struct tty_struct *tty, char ch)
*/
static void mgsl_throttle(struct tty_struct * tty)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -2388,7 +2388,7 @@ static void mgsl_throttle(struct tty_struct * tty)
*/
static void mgsl_unthrottle(struct tty_struct * tty)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -2841,7 +2841,7 @@ static int modem_input_wait(struct mgsl_struct *info,int arg)
*/
static int tiocmget(struct tty_struct *tty, struct file *file)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned int result;
unsigned long flags;
@ -2867,7 +2867,7 @@ static int tiocmget(struct tty_struct *tty, struct file *file)
static int tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -2898,7 +2898,7 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
*/
static int mgsl_break(struct tty_struct *tty, int break_state)
{
struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct * info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -2932,7 +2932,7 @@ static int mgsl_break(struct tty_struct *tty, int break_state)
static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct * info = tty->driver_data;
int ret;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -3042,7 +3042,7 @@ static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigne
*/
static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -3096,7 +3096,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
*/
static void mgsl_close(struct tty_struct *tty, struct file * filp)
{
struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct * info = tty->driver_data;
if (mgsl_paranoia_check(info, tty->name, "mgsl_close"))
return;
@ -3105,69 +3105,17 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp)
printk("%s(%d):mgsl_close(%s) entry, count=%d\n",
__FILE__,__LINE__, info->device_name, info->port.count);
if (!info->port.count)
return;
if (tty_hung_up_p(filp))
if (tty_port_close_start(&info->port, tty, filp) == 0)
goto cleanup;
if ((tty->count == 1) && (info->port.count != 1)) {
/*
* tty->count is 1 and the tty structure will be freed.
* info->port.count should be one in this case.
* if it's not, correct it so that the port is shutdown.
*/
printk("mgsl_close: bad refcount; tty->count is 1, "
"info->port.count is %d\n", info->port.count);
info->port.count = 1;
}
info->port.count--;
/* if at least one open remaining, leave hardware active */
if (info->port.count)
goto cleanup;
info->port.flags |= ASYNC_CLOSING;
/* set tty->closing to notify line discipline to
* only process XON/XOFF characters. Only the N_TTY
* discipline appears to use this (ppp does not).
*/
tty->closing = 1;
/* wait for transmit data to clear all layers */
if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_close(%s) calling tty_wait_until_sent\n",
__FILE__,__LINE__, info->device_name );
tty_wait_until_sent(tty, info->port.closing_wait);
}
if (info->port.flags & ASYNC_INITIALIZED)
mgsl_wait_until_sent(tty, info->timeout);
mgsl_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(info);
tty->closing = 0;
tty_port_close_end(&info->port, tty);
info->port.tty = NULL;
if (info->port.blocked_open) {
if (info->port.close_delay) {
msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
}
wake_up_interruptible(&info->port.open_wait);
}
info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&info->port.close_wait);
cleanup:
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_close(%s) exit, count=%d\n", __FILE__,__LINE__,
@ -3188,7 +3136,7 @@ cleanup:
*/
static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct * info = tty->driver_data;
unsigned long orig_jiffies, char_time;
if (!info )
@ -3261,7 +3209,7 @@ exit:
*/
static void mgsl_hangup(struct tty_struct *tty)
{
struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
struct mgsl_struct * info = tty->driver_data;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_hangup(%s)\n",
@ -3281,6 +3229,35 @@ static void mgsl_hangup(struct tty_struct *tty)
} /* end of mgsl_hangup() */
/*
* carrier_raised()
*
* Return true if carrier is raised
*/
static int carrier_raised(struct tty_port *port)
{
unsigned long flags;
struct mgsl_struct *info = container_of(port, struct mgsl_struct, port);
spin_lock_irqsave(&info->irq_spinlock, flags);
usc_get_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock, flags);
return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
}
static void raise_dtr_rts(struct tty_port *port)
{
struct mgsl_struct *info = container_of(port, struct mgsl_struct, port);
unsigned long flags;
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
usc_set_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
/* block_til_ready()
*
* Block the current process until the specified port
@ -3302,6 +3279,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
bool do_clocal = false;
bool extra_count = false;
unsigned long flags;
int dcd;
struct tty_port *port = &info->port;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready on %s\n",
@ -3309,7 +3288,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)){
/* nonblock mode is set or port is not enabled */
info->port.flags |= ASYNC_NORMAL_ACTIVE;
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@ -3318,50 +3297,42 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
/* Wait for 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
* mgsl_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);
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready before block on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->port.count );
__FILE__,__LINE__, tty->driver->name, port->count );
spin_lock_irqsave(&info->irq_spinlock, flags);
if (!tty_hung_up_p(filp)) {
extra_count = true;
info->port.count--;
port->count--;
}
spin_unlock_irqrestore(&info->irq_spinlock, flags);
info->port.blocked_open++;
port->blocked_open++;
while (1) {
if (tty->termios->c_cflag & CBAUD) {
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
usc_set_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
if (tty->termios->c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){
retval = (info->port.flags & ASYNC_HUP_NOTIFY) ?
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
retval = (port->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS;
break;
}
spin_lock_irqsave(&info->irq_spinlock,flags);
usc_get_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
dcd = tty_port_carrier_raised(&info->port);
if (!(info->port.flags & ASYNC_CLOSING) &&
(do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
if (!(port->flags & ASYNC_CLOSING) && (do_clocal || dcd))
break;
}
if (signal_pending(current)) {
retval = -ERESTARTSYS;
@ -3370,24 +3341,25 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready blocking on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->port.count );
__FILE__,__LINE__, tty->driver->name, port->count );
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->port.open_wait, &wait);
remove_wait_queue(&port->open_wait, &wait);
/* FIXME: Racy on hangup during close wait */
if (extra_count)
info->port.count++;
info->port.blocked_open--;
port->count++;
port->blocked_open--;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready after blocking on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->port.count );
__FILE__,__LINE__, tty->driver->name, port->count );
if (!retval)
info->port.flags |= ASYNC_NORMAL_ACTIVE;
port->flags |= ASYNC_NORMAL_ACTIVE;
return retval;
@ -4304,6 +4276,12 @@ static void mgsl_add_device( struct mgsl_struct *info )
} /* end of mgsl_add_device() */
static const struct tty_port_operations mgsl_port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts,
};
/* mgsl_allocate_device()
*
* Allocate and initialize a device instance structure
@ -4322,6 +4300,7 @@ static struct mgsl_struct* mgsl_allocate_device(void)
printk("Error can't allocate device instance data\n");
} else {
tty_port_init(&info->port);
info->port.ops = &mgsl_port_ops;
info->magic = MGSL_MAGIC;
INIT_WORK(&info->task, mgsl_bh_handler);
info->max_frame_size = 4096;

View File

@ -720,44 +720,9 @@ static void close(struct tty_struct *tty, struct file *filp)
return;
DBGINFO(("%s close entry, count=%d\n", info->device_name, info->port.count));
if (!info->port.count)
return;
if (tty_hung_up_p(filp))
if (tty_port_close_start(&info->port, tty, filp) == 0)
goto cleanup;
if ((tty->count == 1) && (info->port.count != 1)) {
/*
* tty->count is 1 and the tty structure will be freed.
* info->port.count should be one in this case.
* if it's not, correct it so that the port is shutdown.
*/
DBGERR(("%s close: bad refcount; tty->count=1, "
"info->port.count=%d\n", info->device_name, info->port.count));
info->port.count = 1;
}
info->port.count--;
/* if at least one open remaining, leave hardware active */
if (info->port.count)
goto cleanup;
info->port.flags |= ASYNC_CLOSING;
/* set tty->closing to notify line discipline to
* only process XON/XOFF characters. Only the N_TTY
* discipline appears to use this (ppp does not).
*/
tty->closing = 1;
/* wait for transmit data to clear all layers */
if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
DBGINFO(("%s call tty_wait_until_sent\n", info->device_name));
tty_wait_until_sent(tty, info->port.closing_wait);
}
if (info->port.flags & ASYNC_INITIALIZED)
wait_until_sent(tty, info->timeout);
flush_buffer(tty);
@ -765,20 +730,8 @@ static void close(struct tty_struct *tty, struct file *filp)
shutdown(info);
tty->closing = 0;
tty_port_close_end(&info->port, tty);
info->port.tty = NULL;
if (info->port.blocked_open) {
if (info->port.close_delay) {
msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
}
wake_up_interruptible(&info->port.open_wait);
}
info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&info->port.close_wait);
cleanup:
DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->port.count));
}
@ -3132,6 +3085,29 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
return 0;
}
static int carrier_raised(struct tty_port *port)
{
unsigned long flags;
struct slgt_info *info = container_of(port, struct slgt_info, port);
spin_lock_irqsave(&info->lock,flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
return (info->signals & SerialSignal_DCD) ? 1 : 0;
}
static void raise_dtr_rts(struct tty_port *port)
{
unsigned long flags;
struct slgt_info *info = container_of(port, struct slgt_info, port);
spin_lock_irqsave(&info->lock,flags);
info->signals |= SerialSignal_RTS + SerialSignal_DTR;
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
/*
* block current process until the device is ready to open
*/
@ -3143,12 +3119,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
bool do_clocal = false;
bool extra_count = false;
unsigned long flags;
int cd;
struct tty_port *port = &info->port;
DBGINFO(("%s block_til_ready\n", tty->driver->name));
if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
/* nonblock mode is set or port is not enabled */
info->port.flags |= ASYNC_NORMAL_ACTIVE;
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@ -3157,46 +3135,38 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
/* Wait for 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
* 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);
spin_lock_irqsave(&info->lock, flags);
if (!tty_hung_up_p(filp)) {
extra_count = true;
info->port.count--;
port->count--;
}
spin_unlock_irqrestore(&info->lock, flags);
info->port.blocked_open++;
port->blocked_open++;
while (1) {
if ((tty->termios->c_cflag & CBAUD)) {
spin_lock_irqsave(&info->lock,flags);
info->signals |= SerialSignal_RTS + SerialSignal_DTR;
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
if ((tty->termios->c_cflag & CBAUD))
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){
retval = (info->port.flags & ASYNC_HUP_NOTIFY) ?
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
retval = (port->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS;
break;
}
spin_lock_irqsave(&info->lock,flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
cd = tty_port_carrier_raised(port);
if (!(info->port.flags & ASYNC_CLOSING) &&
(do_clocal || (info->signals & SerialSignal_DCD)) ) {
if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd ))
break;
}
if (signal_pending(current)) {
retval = -ERESTARTSYS;
@ -3208,14 +3178,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->port.open_wait, &wait);
remove_wait_queue(&port->open_wait, &wait);
if (extra_count)
info->port.count++;
info->port.blocked_open--;
port->count++;
port->blocked_open--;
if (!retval)
info->port.flags |= ASYNC_NORMAL_ACTIVE;
port->flags |= ASYNC_NORMAL_ACTIVE;
DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
return retval;
@ -3444,6 +3414,11 @@ static void add_device(struct slgt_info *info)
#endif
}
static const struct tty_port_operations slgt_port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts,
};
/*
* allocate device instance structure, return NULL on failure
*/
@ -3458,6 +3433,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
driver_name, adapter_num, port_num));
} else {
tty_port_init(&info->port);
info->port.ops = &slgt_port_ops;
info->magic = MGSL_MAGIC;
INIT_WORK(&info->task, bh_handler);
info->max_frame_size = 4096;

View File

@ -558,6 +558,7 @@ static void release_resources(SLMP_INFO *info);
static int startup(SLMP_INFO *info);
static int block_til_ready(struct tty_struct *tty, struct file * filp,SLMP_INFO *info);
static int carrier_raised(struct tty_port *port);
static void shutdown(SLMP_INFO *info);
static void program_hw(SLMP_INFO *info);
static void change_params(SLMP_INFO *info);
@ -800,7 +801,7 @@ cleanup:
*/
static void close(struct tty_struct *tty, struct file *filp)
{
SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO * info = tty->driver_data;
if (sanity_check(info, tty->name, "close"))
return;
@ -809,70 +810,18 @@ static void close(struct tty_struct *tty, struct file *filp)
printk("%s(%d):%s close() entry, count=%d\n",
__FILE__,__LINE__, info->device_name, info->port.count);
if (!info->port.count)
return;
if (tty_hung_up_p(filp))
if (tty_port_close_start(&info->port, tty, filp) == 0)
goto cleanup;
if ((tty->count == 1) && (info->port.count != 1)) {
/*
* tty->count is 1 and the tty structure will be freed.
* info->port.count should be one in this case.
* if it's not, correct it so that the port is shutdown.
*/
printk("%s(%d):%s close: bad refcount; tty->count is 1, "
"info->port.count is %d\n",
__FILE__,__LINE__, info->device_name, info->port.count);
info->port.count = 1;
}
info->port.count--;
/* if at least one open remaining, leave hardware active */
if (info->port.count)
goto cleanup;
info->port.flags |= ASYNC_CLOSING;
/* set tty->closing to notify line discipline to
* only process XON/XOFF characters. Only the N_TTY
* discipline appears to use this (ppp does not).
*/
tty->closing = 1;
/* wait for transmit data to clear all layers */
if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s close() calling tty_wait_until_sent\n",
__FILE__,__LINE__, info->device_name );
tty_wait_until_sent(tty, info->port.closing_wait);
}
if (info->port.flags & ASYNC_INITIALIZED)
wait_until_sent(tty, info->timeout);
flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(info);
tty->closing = 0;
tty_port_close_end(&info->port, tty);
info->port.tty = NULL;
if (info->port.blocked_open) {
if (info->port.close_delay) {
msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
}
wake_up_interruptible(&info->port.open_wait);
}
info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&info->port.close_wait);
cleanup:
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__,
@ -884,7 +833,7 @@ cleanup:
*/
static void hangup(struct tty_struct *tty)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s hangup()\n",
@ -907,7 +856,7 @@ static void hangup(struct tty_struct *tty)
*/
static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -960,7 +909,7 @@ static int write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
int c, ret = 0;
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -1038,7 +987,7 @@ cleanup:
*/
static int put_char(struct tty_struct *tty, unsigned char ch)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
int ret = 0;
@ -1075,7 +1024,7 @@ static int put_char(struct tty_struct *tty, unsigned char ch)
*/
static void send_xchar(struct tty_struct *tty, char ch)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -1099,7 +1048,7 @@ static void send_xchar(struct tty_struct *tty, char ch)
*/
static void wait_until_sent(struct tty_struct *tty, int timeout)
{
SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO * info = tty->driver_data;
unsigned long orig_jiffies, char_time;
if (!info )
@ -1166,7 +1115,7 @@ exit:
*/
static int write_room(struct tty_struct *tty)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
int ret;
if (sanity_check(info, tty->name, "write_room"))
@ -1193,7 +1142,7 @@ static int write_room(struct tty_struct *tty)
*/
static void flush_chars(struct tty_struct *tty)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
if ( debug_level >= DEBUG_LEVEL_INFO )
@ -1232,7 +1181,7 @@ static void flush_chars(struct tty_struct *tty)
*/
static void flush_buffer(struct tty_struct *tty)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -1254,7 +1203,7 @@ static void flush_buffer(struct tty_struct *tty)
*/
static void tx_hold(struct tty_struct *tty)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
if (sanity_check(info, tty->name, "tx_hold"))
@ -1274,7 +1223,7 @@ static void tx_hold(struct tty_struct *tty)
*/
static void tx_release(struct tty_struct *tty)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
if (sanity_check(info, tty->name, "tx_release"))
@ -1304,7 +1253,7 @@ static void tx_release(struct tty_struct *tty)
static int do_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
int error;
struct mgsl_icount cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser; /* user space */
@ -1515,7 +1464,7 @@ done:
*/
static int chars_in_buffer(struct tty_struct *tty)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
if (sanity_check(info, tty->name, "chars_in_buffer"))
return 0;
@ -1531,7 +1480,7 @@ static int chars_in_buffer(struct tty_struct *tty)
*/
static void throttle(struct tty_struct * tty)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -1556,7 +1505,7 @@ static void throttle(struct tty_struct * tty)
*/
static void unthrottle(struct tty_struct * tty)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -1587,7 +1536,7 @@ static void unthrottle(struct tty_struct * tty)
static int set_break(struct tty_struct *tty, int break_state)
{
unsigned char RegValue;
SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO * info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -3269,7 +3218,7 @@ static int modem_input_wait(SLMP_INFO *info,int arg)
*/
static int tiocmget(struct tty_struct *tty, struct file *file)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned int result;
unsigned long flags;
@ -3295,7 +3244,7 @@ static int tiocmget(struct tty_struct *tty, struct file *file)
static int tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
SLMP_INFO *info = tty->driver_data;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@ -3318,7 +3267,28 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
return 0;
}
static int carrier_raised(struct tty_port *port)
{
SLMP_INFO *info = container_of(port, SLMP_INFO, port);
unsigned long flags;
spin_lock_irqsave(&info->lock,flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
}
static void raise_dtr_rts(struct tty_port *port)
{
SLMP_INFO *info = container_of(port, SLMP_INFO, port);
unsigned long flags;
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
/* Block the current process until the specified port is ready to open.
*/
@ -3330,6 +3300,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
bool do_clocal = false;
bool extra_count = false;
unsigned long flags;
int cd;
struct tty_port *port = &info->port;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s block_til_ready()\n",
@ -3338,7 +3310,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)){
/* nonblock mode is set or port is not enabled */
/* just verify that callout device is not active */
info->port.flags |= ASYNC_NORMAL_ACTIVE;
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@ -3347,50 +3319,42 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
/* Wait for 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
* 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);
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s block_til_ready() before block, count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->port.count );
__FILE__,__LINE__, tty->driver->name, port->count );
spin_lock_irqsave(&info->lock, flags);
if (!tty_hung_up_p(filp)) {
extra_count = true;
info->port.count--;
port->count--;
}
spin_unlock_irqrestore(&info->lock, flags);
info->port.blocked_open++;
port->blocked_open++;
while (1) {
if ((tty->termios->c_cflag & CBAUD)) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
if (tty->termios->c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){
retval = (info->port.flags & ASYNC_HUP_NOTIFY) ?
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
retval = (port->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS;
break;
}
spin_lock_irqsave(&info->lock,flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
cd = tty_port_carrier_raised(port);
if (!(info->port.flags & ASYNC_CLOSING) &&
(do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd))
break;
}
if (signal_pending(current)) {
retval = -ERESTARTSYS;
@ -3399,24 +3363,24 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s block_til_ready() count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->port.count );
__FILE__,__LINE__, tty->driver->name, port->count );
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->port.open_wait, &wait);
remove_wait_queue(&port->open_wait, &wait);
if (extra_count)
info->port.count++;
info->port.blocked_open--;
port->count++;
port->blocked_open--;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s block_til_ready() after, count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->port.count );
__FILE__,__LINE__, tty->driver->name, port->count );
if (!retval)
info->port.flags |= ASYNC_NORMAL_ACTIVE;
port->flags |= ASYNC_NORMAL_ACTIVE;
return retval;
}
@ -3782,6 +3746,11 @@ static void add_device(SLMP_INFO *info)
#endif
}
static const struct tty_port_operations port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts,
};
/* Allocate and initialize a device instance structure
*
* Return Value: pointer to SLMP_INFO if success, otherwise NULL
@ -3798,6 +3767,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
__FILE__,__LINE__, adapter_num, port_num);
} else {
tty_port_init(&info->port);
info->port.ops = &port_ops;
info->magic = MGSL_MAGIC;
INIT_WORK(&info->task, bh_handler);
info->max_frame_size = 4096;
@ -3940,6 +3910,7 @@ static const struct tty_operations ops = {
.tiocmset = tiocmset,
};
static void synclinkmp_cleanup(void)
{
int rc;

View File

@ -1111,9 +1111,7 @@ void tty_write_message(struct tty_struct *tty, char *msg)
* Locks the line discipline as required
* Writes to the tty driver are serialized by the atomic_write_lock
* and are then processed in chunks to the device. The line discipline
* write method will not be involked in parallel for each device
* The line discipline write method is called under the big
* kernel lock for historical reasons. New code should not rely on this.
* write method will not be invoked in parallel for each device.
*/
static ssize_t tty_write(struct file *file, const char __user *buf,
@ -1213,7 +1211,7 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
* be held until the 'fast-open' is also done. Will change once we
* have refcounting in the driver and per driver locking
*/
struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
struct inode *inode, int idx)
{
struct tty_struct *tty;
@ -2050,7 +2048,6 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
/**
* tty_do_resize - resize event
* @tty: tty being resized
* @real_tty: real tty (not the same as tty if using a pty/tty pair)
* @rows: rows (character)
* @cols: cols (character)
*
@ -2058,41 +2055,34 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
* peform a terminal resize correctly
*/
int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize *ws)
int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
{
struct pid *pgrp, *rpgrp;
struct pid *pgrp;
unsigned long flags;
/* For a PTY we need to lock the tty side */
mutex_lock(&real_tty->termios_mutex);
if (!memcmp(ws, &real_tty->winsize, sizeof(*ws)))
/* Lock the tty */
mutex_lock(&tty->termios_mutex);
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
goto done;
/* Get the PID values and reference them so we can
avoid holding the tty ctrl lock while sending signals */
spin_lock_irqsave(&tty->ctrl_lock, flags);
pgrp = get_pid(tty->pgrp);
rpgrp = get_pid(real_tty->pgrp);
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
if (pgrp)
kill_pgrp(pgrp, SIGWINCH, 1);
if (rpgrp != pgrp && rpgrp)
kill_pgrp(rpgrp, SIGWINCH, 1);
put_pid(pgrp);
put_pid(rpgrp);
tty->winsize = *ws;
real_tty->winsize = *ws;
done:
mutex_unlock(&real_tty->termios_mutex);
mutex_unlock(&tty->termios_mutex);
return 0;
}
/**
* tiocswinsz - implement window size set ioctl
* @tty; tty
* @tty; tty side of tty
* @arg: user buffer for result
*
* Copies the user idea of the window size to the kernel. Traditionally
@ -2105,17 +2095,16 @@ done:
* then calls into the default method.
*/
static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize __user *arg)
static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
{
struct winsize tmp_ws;
if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
return -EFAULT;
if (tty->ops->resize)
return tty->ops->resize(tty, real_tty, &tmp_ws);
return tty->ops->resize(tty, &tmp_ws);
else
return tty_do_resize(tty, real_tty, &tmp_ws);
return tty_do_resize(tty, &tmp_ws);
}
/**
@ -2540,7 +2529,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCGWINSZ:
return tiocgwinsz(real_tty, p);
case TIOCSWINSZ:
return tiocswinsz(tty, real_tty, p);
return tiocswinsz(real_tty, p);
case TIOCCONS:
return real_tty != tty ? -EINVAL : tioccons(file);
case FIONBIO:
@ -2785,6 +2774,8 @@ void initialize_tty_struct(struct tty_struct *tty,
INIT_WORK(&tty->hangup_work, do_tty_hangup);
mutex_init(&tty->atomic_read_lock);
mutex_init(&tty->atomic_write_lock);
mutex_init(&tty->output_lock);
mutex_init(&tty->echo_lock);
spin_lock_init(&tty->read_lock);
spin_lock_init(&tty->ctrl_lock);
INIT_LIST_HEAD(&tty->tty_files);

View File

@ -316,8 +316,7 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
{
/* wait_event is a macro */
wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
if (tty->ldisc.refcount == 0)
printk(KERN_ERR "tty_ldisc_ref_wait\n");
WARN_ON(tty->ldisc.refcount == 0);
return &tty->ldisc;
}
@ -376,15 +375,17 @@ EXPORT_SYMBOL_GPL(tty_ldisc_deref);
* @tty: terminal to activate ldisc on
*
* Set the TTY_LDISC flag when the line discipline can be called
* again. Do necessary wakeups for existing sleepers.
* again. Do necessary wakeups for existing sleepers. Clear the LDISC
* changing flag to indicate any ldisc change is now over.
*
* Note: nobody should set this bit except via this function. Clearing
* directly is allowed.
* Note: nobody should set the TTY_LDISC bit except via this function.
* Clearing directly is allowed.
*/
void tty_ldisc_enable(struct tty_struct *tty)
{
set_bit(TTY_LDISC, &tty->flags);
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
wake_up(&tty_ldisc_wait);
}
@ -496,7 +497,14 @@ restart:
* reference to the line discipline. The TTY_LDISC bit
* prevents anyone taking a reference once it is clear.
* We need the lock to avoid racing reference takers.
*
* We must clear the TTY_LDISC bit here to avoid a livelock
* with a userspace app continually trying to use the tty in
* parallel to the change and re-referencing the tty.
*/
clear_bit(TTY_LDISC, &tty->flags);
if (o_tty)
clear_bit(TTY_LDISC, &o_tty->flags);
spin_lock_irqsave(&tty_ldisc_lock, flags);
if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
@ -528,7 +536,7 @@ restart:
* If the TTY_LDISC bit is set, then we are racing against
* another ldisc change
*/
if (!test_bit(TTY_LDISC, &tty->flags)) {
if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
struct tty_ldisc *ld;
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
tty_ldisc_put(new_ldisc.ops);
@ -536,10 +544,14 @@ restart:
tty_ldisc_deref(ld);
goto restart;
}
clear_bit(TTY_LDISC, &tty->flags);
/*
* This flag is used to avoid two parallel ldisc changes. Once
* open and close are fine grained locked this may work better
* as a mutex shared with the open/close/hup paths
*/
set_bit(TTY_LDISC_CHANGING, &tty->flags);
if (o_tty)
clear_bit(TTY_LDISC, &o_tty->flags);
set_bit(TTY_LDISC_CHANGING, &o_tty->flags);
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
/*

View File

@ -7,6 +7,7 @@
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/slab.h>
@ -94,3 +95,227 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_tty_set);
/**
* tty_port_hangup - hangup helper
* @port: tty port
*
* Perform port level tty hangup flag and count changes. Drop the tty
* reference.
*/
void tty_port_hangup(struct tty_port *port)
{
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
if (port->tty)
tty_kref_put(port->tty);
port->tty = NULL;
spin_unlock_irqrestore(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
}
EXPORT_SYMBOL(tty_port_hangup);
/**
* tty_port_carrier_raised - carrier raised check
* @port: tty port
*
* Wrapper for the carrier detect logic. For the moment this is used
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
int tty_port_carrier_raised(struct tty_port *port)
{
if (port->ops->carrier_raised == NULL)
return 1;
return port->ops->carrier_raised(port);
}
EXPORT_SYMBOL(tty_port_carrier_raised);
/**
* tty_port_raise_dtr_rts - Riase DTR/RTS
* @port: tty port
*
* Wrapper for the DTR/RTS raise logic. For the moment this is used
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
void tty_port_raise_dtr_rts(struct tty_port *port)
{
if (port->ops->raise_dtr_rts)
port->ops->raise_dtr_rts(port);
}
EXPORT_SYMBOL(tty_port_raise_dtr_rts);
/**
* tty_port_block_til_ready - Waiting logic for tty open
* @port: the tty port being opened
* @tty: the tty device being bound
* @filp: the file pointer of the opener
*
* Implement the core POSIX/SuS tty behaviour when opening a tty device.
* Handles:
* - hangup (both before and during)
* - non blocking open
* - rts/dtr/dcd
* - signals
* - port flags and counts
*
* The passed tty_port must implement the carrier_raised method if it can
* do carrier detect and the raise_dtr_rts method if it supports software
* management of these lines. Note that the dtr/rts raise is done each
* iteration as a hangup may have previously dropped them while we wait.
*/
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;
DECLARE_WAITQUEUE(wait, current);
int cd;
/* block if port is in the process of being closed */
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;
}
/* 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 ((filp->f_flags & O_NONBLOCK) ||
(tty->flags & (1 << TTY_IO_ERROR))) {
port->flags |= ASYNC_NORMAL_ACTIVE;
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;
add_wait_queue(&port->open_wait, &wait);
/* The port lock protects the port counts */
spin_lock_irqsave(&port->lock, flags);
if (!tty_hung_up_p(filp))
port->count--;
port->blocked_open++;
spin_unlock_irqrestore(&port->lock, flags);
while (1) {
/* Indicate we are open */
if (tty->termios->c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
/* Check for a hangup or uninitialised port. Return accordingly */
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
break;
}
/* Probe the carrier. For devices with no carrier detect this
will always return true */
cd = tty_port_carrier_raised(port);
if (!(port->flags & ASYNC_CLOSING) &&
(do_clocal || cd))
break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&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--;
if (retval == 0)
port->flags |= ASYNC_NORMAL_ACTIVE;
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
EXPORT_SYMBOL(tty_port_block_til_ready);
int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
{
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
if( tty->count == 1 && port->count != 1) {
printk(KERN_WARNING
"tty_port_close_start: tty->count = 1 port count = %d.\n",
port->count);
port->count = 1;
}
if (--port->count < 0) {
printk(KERN_WARNING "tty_port_close_start: count = %d\n",
port->count);
port->count = 0;
}
if (port->count) {
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
port->flags |= ASYNC_CLOSING;
tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags);
/* Don't block on a stalled port, just pull the chain */
if (tty->flow_stopped)
tty_driver_flush_buffer(tty);
if (port->flags & ASYNC_INITIALIZED &&
port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->closing_wait);
return 1;
}
EXPORT_SYMBOL(tty_port_close_start);
void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
{
unsigned long flags;
tty_ldisc_flush(tty);
spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
if (port->blocked_open) {
spin_unlock_irqrestore(&port->lock, flags);
if (port->close_delay) {
msleep_interruptible(
jiffies_to_msecs(port->close_delay));
}
spin_lock_irqsave(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
}
port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
wake_up_interruptible(&port->close_wait);
spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_close_end);

View File

@ -69,7 +69,7 @@ static void scc_disable_tx_interrupts(void * ptr);
static void scc_enable_tx_interrupts(void * ptr);
static void scc_disable_rx_interrupts(void * ptr);
static void scc_enable_rx_interrupts(void * ptr);
static int scc_get_CD(void * ptr);
static int scc_carrier_raised(struct tty_port *port);
static void scc_shutdown_port(void * ptr);
static int scc_set_real_termios(void *ptr);
static void scc_hungup(void *ptr);
@ -100,7 +100,6 @@ static struct real_driver scc_real_driver = {
scc_enable_tx_interrupts,
scc_disable_rx_interrupts,
scc_enable_rx_interrupts,
scc_get_CD,
scc_shutdown_port,
scc_set_real_termios,
scc_chars_in_buffer,
@ -129,6 +128,10 @@ static const struct tty_operations scc_ops = {
.break_ctl = scc_break_ctl,
};
static const struct tty_port_operations scc_port_ops = {
.carrier_raised = scc_carrier_raised,
};
/*----------------------------------------------------------------------------
* vme_scc_init() and support functions
*---------------------------------------------------------------------------*/
@ -176,6 +179,8 @@ static void scc_init_portstructs(void)
for (i = 0; i < 2; i++) {
port = scc_ports + i;
tty_port_init(&port->gs.port);
port->gs.port.ops = &scc_port_ops;
port->gs.magic = SCC_MAGIC;
port->gs.close_delay = HZ/2;
port->gs.closing_wait = 30 * HZ;
@ -624,10 +629,10 @@ static void scc_enable_rx_interrupts(void *ptr)
}
static int scc_get_CD(void *ptr)
static int scc_carrier_raised(struct tty_port *port)
{
struct scc_port *port = ptr;
unsigned channel = port->channel;
struct scc_port *sc = container_of(port, struct scc_port, gs.port);
unsigned channel = sc->channel;
return !!(scc_last_status_reg[channel] & SR_DCD);
}
@ -638,7 +643,7 @@ static void scc_shutdown_port(void *ptr)
struct scc_port *port = ptr;
port->gs.port.flags &= ~ GS_ACTIVE;
if (port->gs.port.tty && port->gs.port.tty->termios->c_cflag & HUPCL) {
if (port->gs.port.tty && (port->gs.port.tty->termios->c_cflag & HUPCL)) {
scc_setsignals (port, 0, 0);
}
}
@ -779,7 +784,7 @@ static void scc_setsignals(struct scc_port *port, int dtr, int rts)
static void scc_send_xchar(struct tty_struct *tty, char ch)
{
struct scc_port *port = (struct scc_port *)tty->driver_data;
struct scc_port *port = tty->driver_data;
port->x_char = ch;
if (ch)
@ -896,7 +901,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp)
return retval;
}
port->c_dcd = scc_get_CD (port);
port->c_dcd = tty_port_carrier_raised(&port->gs.port);
scc_enable_rx_interrupts(port);
@ -906,7 +911,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp)
static void scc_throttle (struct tty_struct * tty)
{
struct scc_port *port = (struct scc_port *)tty->driver_data;
struct scc_port *port = tty->driver_data;
unsigned long flags;
SCC_ACCESS_INIT(port);
@ -922,7 +927,7 @@ static void scc_throttle (struct tty_struct * tty)
static void scc_unthrottle (struct tty_struct * tty)
{
struct scc_port *port = (struct scc_port *)tty->driver_data;
struct scc_port *port = tty->driver_data;
unsigned long flags;
SCC_ACCESS_INIT(port);
@ -945,7 +950,7 @@ static int scc_ioctl(struct tty_struct *tty, struct file *file,
static int scc_break_ctl(struct tty_struct *tty, int break_state)
{
struct scc_port *port = (struct scc_port *)tty->driver_data;
struct scc_port *port = tty->driver_data;
unsigned long flags;
SCC_ACCESS_INIT(port);

View File

@ -819,8 +819,8 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
* ctrl_lock of the tty IFF a tty is passed.
*/
static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
struct vc_data *vc, unsigned int cols, unsigned int lines)
static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
unsigned int cols, unsigned int lines)
{
unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
unsigned int old_cols, old_rows, old_row_size, old_screen_size;
@ -932,7 +932,7 @@ static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
ws.ws_row = vc->vc_rows;
ws.ws_col = vc->vc_cols;
ws.ws_ypixel = vc->vc_scan_lines;
tty_do_resize(tty, real_tty, &ws);
tty_do_resize(tty, &ws);
}
if (CON_IS_VISIBLE(vc))
@ -954,13 +954,12 @@ static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
{
return vc_do_resize(vc->vc_tty, vc->vc_tty, vc, cols, rows);
return vc_do_resize(vc->vc_tty, vc, cols, rows);
}
/**
* vt_resize - resize a VT
* @tty: tty to resize
* @real_tty: tty if a pty/tty pair
* @ws: winsize attributes
*
* Resize a virtual terminal. This is called by the tty layer as we
@ -971,14 +970,13 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
* termios_mutex and the tty ctrl_lock in that order.
*/
int vt_resize(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize *ws)
int vt_resize(struct tty_struct *tty, struct winsize *ws)
{
struct vc_data *vc = tty->driver_data;
int ret;
acquire_console_sem();
ret = vc_do_resize(tty, real_tty, vc, ws->ws_col, ws->ws_row);
ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
release_console_sem();
return ret;
}
@ -2679,7 +2677,7 @@ static int con_write_room(struct tty_struct *tty)
{
if (tty->stopped)
return 0;
return 4096; /* No limit, really; we're not buffering */
return 32768; /* No limit, really; we're not buffering */
}
static int con_chars_in_buffer(struct tty_struct *tty)

View File

@ -366,7 +366,7 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct vc_data *vc = (struct vc_data *)tty->driver_data;
struct vc_data *vc = tty->driver_data;
struct console_font_op op; /* used in multiple places here */
struct kbd_struct * kbd;
unsigned int console;

View File

@ -3,6 +3,8 @@
* Driver for Option High Speed Mobile Devices.
*
* Copyright (C) 2008 Option International
* Filip Aben <f.aben@option.com>
* Denis Joseph Barrow <d.barow@option.com>
* Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd)
* <ajb@spheresystems.co.uk>
* Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
@ -39,8 +41,11 @@
* port is opened, as this have a huge impact on the network port
* throughput.
*
* Interface 2: Standard modem interface - circuit switched interface, should
* not be used.
* Interface 2: Standard modem interface - circuit switched interface, this
* can be used to make a standard ppp connection however it
* should not be used in conjunction with the IP network interface
* enabled for USB performance reasons i.e. if using this set
* ideally disable_net=1.
*
*****************************************************************************/
@ -63,6 +68,8 @@
#include <linux/usb/cdc.h>
#include <net/arp.h>
#include <asm/byteorder.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#define DRIVER_VERSION "1.2"
@ -182,6 +189,41 @@ enum rx_ctrl_state{
RX_PENDING
};
#define BM_REQUEST_TYPE (0xa1)
#define B_NOTIFICATION (0x20)
#define W_VALUE (0x0)
#define W_INDEX (0x2)
#define W_LENGTH (0x2)
#define B_OVERRUN (0x1<<6)
#define B_PARITY (0x1<<5)
#define B_FRAMING (0x1<<4)
#define B_RING_SIGNAL (0x1<<3)
#define B_BREAK (0x1<<2)
#define B_TX_CARRIER (0x1<<1)
#define B_RX_CARRIER (0x1<<0)
struct hso_serial_state_notification {
u8 bmRequestType;
u8 bNotification;
u16 wValue;
u16 wIndex;
u16 wLength;
u16 UART_state_bitmap;
} __attribute__((packed));
struct hso_tiocmget {
struct mutex mutex;
wait_queue_head_t waitq;
int intr_completed;
struct usb_endpoint_descriptor *endp;
struct urb *urb;
struct hso_serial_state_notification serial_state_notification;
u16 prev_UART_state_bitmap;
struct uart_icount icount;
};
struct hso_serial {
struct hso_device *parent;
int magic;
@ -219,6 +261,7 @@ struct hso_serial {
spinlock_t serial_lock;
int (*write_data) (struct hso_serial *serial);
struct hso_tiocmget *tiocmget;
/* Hacks required to get flow control
* working on the serial receive buffers
* so as not to drop characters on the floor.
@ -305,7 +348,7 @@ static void async_get_intf(struct work_struct *data);
static void async_put_intf(struct work_struct *data);
static int hso_put_activity(struct hso_device *hso_dev);
static int hso_get_activity(struct hso_device *hso_dev);
static void tiocmget_intr_callback(struct urb *urb);
/*****************************************************************************/
/* Helping functions */
/*****************************************************************************/
@ -362,8 +405,6 @@ static struct tty_driver *tty_drv;
static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS];
static struct hso_device *network_table[HSO_MAX_NET_DEVICES];
static spinlock_t serial_table_lock;
static struct ktermios *hso_serial_termios[HSO_SERIAL_TTY_MINORS];
static struct ktermios *hso_serial_termios_locked[HSO_SERIAL_TTY_MINORS];
static const s32 default_port_spec[] = {
HSO_INTF_MUX | HSO_PORT_NETWORK,
@ -1009,23 +1050,11 @@ static void read_bulk_callback(struct urb *urb)
/* Serial driver functions */
static void _hso_serial_set_termios(struct tty_struct *tty,
struct ktermios *old)
static void hso_init_termios(struct ktermios *termios)
{
struct hso_serial *serial = get_serial_by_tty(tty);
struct ktermios *termios;
if ((!tty) || (!tty->termios) || (!serial)) {
printk(KERN_ERR "%s: no tty structures", __func__);
return;
}
D4("port %d", serial->minor);
/*
* The default requirements for this device are:
*/
termios = tty->termios;
termios->c_iflag &=
~(IGNBRK /* disable ignore break */
| BRKINT /* disable break causes interrupt */
@ -1057,15 +1086,38 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
termios->c_cflag |= CS8; /* character size 8 bits */
/* baud rate 115200 */
tty_encode_baud_rate(serial->tty, 115200, 115200);
tty_termios_encode_baud_rate(termios, 115200, 115200);
}
static void _hso_serial_set_termios(struct tty_struct *tty,
struct ktermios *old)
{
struct hso_serial *serial = get_serial_by_tty(tty);
struct ktermios *termios;
if (!serial) {
printk(KERN_ERR "%s: no tty structures", __func__);
return;
}
D4("port %d", serial->minor);
/*
* Force low_latency on; otherwise the pushes are scheduled;
* this is bad as it opens up the possibility of dropping bytes
* on the floor. We don't want to drop bytes on the floor. :)
* Fix up unsupported bits
*/
serial->tty->low_latency = 1;
return;
termios = tty->termios;
termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
termios->c_cflag &=
~(CSIZE /* no size */
| PARENB /* disable parity bit */
| CBAUD /* clear current baud rate */
| CBAUDEX); /* clear current buad rate */
termios->c_cflag |= CS8; /* character size 8 bits */
/* baud rate 115200 */
tty_encode_baud_rate(tty, 115200, 115200);
}
static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb)
@ -1228,6 +1280,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
/* sanity check */
if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) {
WARN_ON(1);
tty->driver_data = NULL;
D1("Failed to open port");
return -ENODEV;
@ -1242,8 +1295,10 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
kref_get(&serial->parent->ref);
/* setup */
spin_lock_irq(&serial->serial_lock);
tty->driver_data = serial;
serial->tty = tty;
serial->tty = tty_kref_get(tty);
spin_unlock_irq(&serial->serial_lock);
/* check for port already opened, if not set the termios */
serial->open_count++;
@ -1285,6 +1340,10 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
D1("Closing serial port");
/* Open failed, no close cleanup required */
if (serial == NULL)
return;
mutex_lock(&serial->parent->mutex);
usb_gone = serial->parent->usb_gone;
@ -1297,10 +1356,13 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
kref_put(&serial->parent->ref, hso_serial_ref_free);
if (serial->open_count <= 0) {
serial->open_count = 0;
if (serial->tty) {
spin_lock_irq(&serial->serial_lock);
if (serial->tty == tty) {
serial->tty->driver_data = NULL;
serial->tty = NULL;
tty_kref_put(tty);
}
spin_unlock_irq(&serial->serial_lock);
if (!usb_gone)
hso_stop_serial_device(serial->parent);
tasklet_kill(&serial->unthrottle_tasklet);
@ -1400,25 +1462,217 @@ static int hso_serial_chars_in_buffer(struct tty_struct *tty)
return chars;
}
int tiocmget_submit_urb(struct hso_serial *serial,
struct hso_tiocmget *tiocmget,
struct usb_device *usb)
{
int result;
if (serial->parent->usb_gone)
return -ENODEV;
usb_fill_int_urb(tiocmget->urb, usb,
usb_rcvintpipe(usb,
tiocmget->endp->
bEndpointAddress & 0x7F),
&tiocmget->serial_state_notification,
sizeof(struct hso_serial_state_notification),
tiocmget_intr_callback, serial,
tiocmget->endp->bInterval);
result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC);
if (result) {
dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__,
result);
}
return result;
}
static void tiocmget_intr_callback(struct urb *urb)
{
struct hso_serial *serial = urb->context;
struct hso_tiocmget *tiocmget;
int status = urb->status;
u16 UART_state_bitmap, prev_UART_state_bitmap;
struct uart_icount *icount;
struct hso_serial_state_notification *serial_state_notification;
struct usb_device *usb;
/* Sanity checks */
if (!serial)
return;
if (status) {
log_usb_status(status, __func__);
return;
}
tiocmget = serial->tiocmget;
if (!tiocmget)
return;
usb = serial->parent->usb;
serial_state_notification = &tiocmget->serial_state_notification;
if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE ||
serial_state_notification->bNotification != B_NOTIFICATION ||
le16_to_cpu(serial_state_notification->wValue) != W_VALUE ||
le16_to_cpu(serial_state_notification->wIndex) != W_INDEX ||
le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) {
dev_warn(&usb->dev,
"hso received invalid serial state notification\n");
DUMP(serial_state_notification,
sizeof(hso_serial_state_notifation))
} else {
UART_state_bitmap = le16_to_cpu(serial_state_notification->
UART_state_bitmap);
prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap;
icount = &tiocmget->icount;
spin_lock(&serial->serial_lock);
if ((UART_state_bitmap & B_OVERRUN) !=
(prev_UART_state_bitmap & B_OVERRUN))
icount->parity++;
if ((UART_state_bitmap & B_PARITY) !=
(prev_UART_state_bitmap & B_PARITY))
icount->parity++;
if ((UART_state_bitmap & B_FRAMING) !=
(prev_UART_state_bitmap & B_FRAMING))
icount->frame++;
if ((UART_state_bitmap & B_RING_SIGNAL) &&
!(prev_UART_state_bitmap & B_RING_SIGNAL))
icount->rng++;
if ((UART_state_bitmap & B_BREAK) !=
(prev_UART_state_bitmap & B_BREAK))
icount->brk++;
if ((UART_state_bitmap & B_TX_CARRIER) !=
(prev_UART_state_bitmap & B_TX_CARRIER))
icount->dsr++;
if ((UART_state_bitmap & B_RX_CARRIER) !=
(prev_UART_state_bitmap & B_RX_CARRIER))
icount->dcd++;
tiocmget->prev_UART_state_bitmap = UART_state_bitmap;
spin_unlock(&serial->serial_lock);
tiocmget->intr_completed = 1;
wake_up_interruptible(&tiocmget->waitq);
}
memset(serial_state_notification, 0,
sizeof(struct hso_serial_state_notification));
tiocmget_submit_urb(serial,
tiocmget,
serial->parent->usb);
}
/*
* next few functions largely stolen from drivers/serial/serial_core.c
*/
/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was
*/
static int
hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
{
DECLARE_WAITQUEUE(wait, current);
struct uart_icount cprev, cnow;
struct hso_tiocmget *tiocmget;
int ret;
tiocmget = serial->tiocmget;
if (!tiocmget)
return -ENOENT;
/*
* note the counters on entry
*/
spin_lock_irq(&serial->serial_lock);
memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount));
spin_unlock_irq(&serial->serial_lock);
add_wait_queue(&tiocmget->waitq, &wait);
for (;;) {
spin_lock_irq(&serial->serial_lock);
memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
spin_unlock_irq(&serial->serial_lock);
set_current_state(TASK_INTERRUPTIBLE);
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) {
ret = 0;
break;
}
schedule();
/* see if a signal did it */
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
cprev = cnow;
}
current->state = TASK_RUNNING;
remove_wait_queue(&tiocmget->waitq, &wait);
return ret;
}
/*
* Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
* Return: write counters to the user passed counter struct
* NB: both 1->0 and 0->1 transitions are counted except for
* RI where only 0->1 is counted.
*/
static int hso_get_count(struct hso_serial *serial,
struct serial_icounter_struct __user *icnt)
{
struct serial_icounter_struct icount;
struct uart_icount cnow;
struct hso_tiocmget *tiocmget = serial->tiocmget;
if (!tiocmget)
return -ENOENT;
spin_lock_irq(&serial->serial_lock);
memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
spin_unlock_irq(&serial->serial_lock);
icount.cts = cnow.cts;
icount.dsr = cnow.dsr;
icount.rng = cnow.rng;
icount.dcd = cnow.dcd;
icount.rx = cnow.rx;
icount.tx = cnow.tx;
icount.frame = cnow.frame;
icount.overrun = cnow.overrun;
icount.parity = cnow.parity;
icount.brk = cnow.brk;
icount.buf_overrun = cnow.buf_overrun;
return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
}
static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file)
{
unsigned int value;
int retval;
struct hso_serial *serial = get_serial_by_tty(tty);
unsigned long flags;
struct hso_tiocmget *tiocmget;
u16 UART_state_bitmap;
/* sanity check */
if (!serial) {
D1("no tty structures");
return -EINVAL;
}
spin_lock_irqsave(&serial->serial_lock, flags);
value = ((serial->rts_state) ? TIOCM_RTS : 0) |
spin_lock_irq(&serial->serial_lock);
retval = ((serial->rts_state) ? TIOCM_RTS : 0) |
((serial->dtr_state) ? TIOCM_DTR : 0);
spin_unlock_irqrestore(&serial->serial_lock, flags);
tiocmget = serial->tiocmget;
if (tiocmget) {
return value;
UART_state_bitmap = le16_to_cpu(
tiocmget->prev_UART_state_bitmap);
if (UART_state_bitmap & B_RING_SIGNAL)
retval |= TIOCM_RNG;
if (UART_state_bitmap & B_RX_CARRIER)
retval |= TIOCM_CD;
if (UART_state_bitmap & B_TX_CARRIER)
retval |= TIOCM_DSR;
}
spin_unlock_irq(&serial->serial_lock);
return retval;
}
static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
@ -1460,6 +1714,32 @@ static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
USB_CTRL_SET_TIMEOUT);
}
static int hso_serial_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct hso_serial *serial = get_serial_by_tty(tty);
void __user *uarg = (void __user *)arg;
int ret = 0;
D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
if (!serial)
return -ENODEV;
switch (cmd) {
case TIOCMIWAIT:
ret = hso_wait_modem_status(serial, arg);
break;
case TIOCGICOUNT:
ret = hso_get_count(serial, uarg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
/* starts a transmit */
static void hso_kick_transmit(struct hso_serial *serial)
{
@ -1653,6 +1933,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
{
struct hso_serial *serial = urb->context;
int status = urb->status;
struct tty_struct *tty;
/* sanity check */
if (!serial) {
@ -1662,14 +1943,18 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
spin_lock(&serial->serial_lock);
serial->tx_urb_used = 0;
tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock);
if (status) {
log_usb_status(status, __func__);
tty_kref_put(tty);
return;
}
hso_put_activity(serial->parent);
if (serial->tty)
tty_wakeup(serial->tty);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
hso_kick_transmit(serial);
D1(" ");
@ -1706,6 +1991,7 @@ static void ctrl_callback(struct urb *urb)
struct hso_serial *serial = urb->context;
struct usb_ctrlrequest *req;
int status = urb->status;
struct tty_struct *tty;
/* sanity check */
if (!serial)
@ -1713,9 +1999,11 @@ static void ctrl_callback(struct urb *urb)
spin_lock(&serial->serial_lock);
serial->tx_urb_used = 0;
tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock);
if (status) {
log_usb_status(status, __func__);
tty_kref_put(tty);
return;
}
@ -1734,25 +2022,31 @@ static void ctrl_callback(struct urb *urb)
spin_unlock(&serial->serial_lock);
} else {
hso_put_activity(serial->parent);
if (serial->tty)
tty_wakeup(serial->tty);
if (tty)
tty_wakeup(tty);
/* response to a write command */
hso_kick_transmit(serial);
}
tty_kref_put(tty);
}
/* handle RX data for serial port */
static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
{
struct tty_struct *tty = serial->tty;
struct tty_struct *tty;
int write_length_remaining = 0;
int curr_write_len;
/* Sanity check */
if (urb == NULL || serial == NULL) {
D1("serial = NULL");
return -2;
}
spin_lock(&serial->serial_lock);
tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock);
/* Push data to tty */
if (tty) {
write_length_remaining = urb->actual_length -
@ -1774,6 +2068,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
serial->curr_rx_urb_offset = 0;
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
}
tty_kref_put(tty);
return write_length_remaining;
}
@ -1922,7 +2217,10 @@ static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags)
serial->shared_int->use_count++;
mutex_unlock(&serial->shared_int->shared_int_lock);
}
if (serial->tiocmget)
tiocmget_submit_urb(serial,
serial->tiocmget,
serial->parent->usb);
return result;
}
@ -1930,6 +2228,7 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
{
int i;
struct hso_serial *serial = dev2ser(hso_dev);
struct hso_tiocmget *tiocmget;
if (!serial)
return -ENODEV;
@ -1958,6 +2257,11 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
}
mutex_unlock(&serial->shared_int->shared_int_lock);
}
tiocmget = serial->tiocmget;
if (tiocmget) {
wake_up_interruptible(&tiocmget->waitq);
usb_kill_urb(tiocmget->urb);
}
return 0;
}
@ -2304,6 +2608,20 @@ exit:
return NULL;
}
static void hso_free_tiomget(struct hso_serial *serial)
{
struct hso_tiocmget *tiocmget = serial->tiocmget;
if (tiocmget) {
kfree(tiocmget);
if (tiocmget->urb) {
usb_free_urb(tiocmget->urb);
tiocmget->urb = NULL;
}
serial->tiocmget = NULL;
}
}
/* Frees an AT channel ( goes for both mux and non-mux ) */
static void hso_free_serial_device(struct hso_device *hso_dev)
{
@ -2322,6 +2640,7 @@ static void hso_free_serial_device(struct hso_device *hso_dev)
else
mutex_unlock(&serial->shared_int->shared_int_lock);
}
hso_free_tiomget(serial);
kfree(serial);
hso_free_device(hso_dev);
}
@ -2333,6 +2652,7 @@ static struct hso_device *hso_create_bulk_serial_device(
struct hso_device *hso_dev;
struct hso_serial *serial;
int num_urbs;
struct hso_tiocmget *tiocmget;
hso_dev = hso_create_device(interface, port);
if (!hso_dev)
@ -2345,8 +2665,27 @@ static struct hso_device *hso_create_bulk_serial_device(
serial->parent = hso_dev;
hso_dev->port_data.dev_serial = serial;
if (port & HSO_PORT_MODEM)
if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) {
num_urbs = 2;
serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget),
GFP_KERNEL);
/* it isn't going to break our heart if serial->tiocmget
* allocation fails don't bother checking this.
*/
if (serial->tiocmget) {
tiocmget = serial->tiocmget;
tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
if (tiocmget->urb) {
mutex_init(&tiocmget->mutex);
init_waitqueue_head(&tiocmget->waitq);
tiocmget->endp = hso_get_ep(
interface,
USB_ENDPOINT_XFER_INT,
USB_DIR_IN);
} else
hso_free_tiomget(serial);
}
}
else
num_urbs = 1;
@ -2382,6 +2721,7 @@ static struct hso_device *hso_create_bulk_serial_device(
exit2:
hso_serial_common_free(serial);
exit:
hso_free_tiomget(serial);
kfree(serial);
hso_free_device(hso_dev);
return NULL;
@ -2786,15 +3126,20 @@ static void hso_serial_ref_free(struct kref *ref)
static void hso_free_interface(struct usb_interface *interface)
{
struct hso_serial *hso_dev;
struct tty_struct *tty;
int i;
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
if (serial_table[i]
&& (serial_table[i]->interface == interface)) {
hso_dev = dev2ser(serial_table[i]);
if (hso_dev->tty)
tty_hangup(hso_dev->tty);
spin_lock_irq(&hso_dev->serial_lock);
tty = tty_kref_get(hso_dev->tty);
spin_unlock_irq(&hso_dev->serial_lock);
if (tty)
tty_hangup(tty);
mutex_lock(&hso_dev->parent->mutex);
tty_kref_put(tty);
hso_dev->parent->usb_gone = 1;
mutex_unlock(&hso_dev->parent->mutex);
kref_put(&serial_table[i]->ref, hso_serial_ref_free);
@ -2887,6 +3232,7 @@ static const struct tty_operations hso_serial_ops = {
.close = hso_serial_close,
.write = hso_serial_write,
.write_room = hso_serial_write_room,
.ioctl = hso_serial_ioctl,
.set_termios = hso_serial_set_termios,
.chars_in_buffer = hso_serial_chars_in_buffer,
.tiocmget = hso_serial_tiocmget,
@ -2939,9 +3285,7 @@ static int __init hso_init(void)
tty_drv->subtype = SERIAL_TYPE_NORMAL;
tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_drv->init_termios = tty_std_termios;
tty_drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_drv->termios = hso_serial_termios;
tty_drv->termios_locked = hso_serial_termios_locked;
hso_init_termios(&tty_drv->init_termios);
tty_set_operations(tty_drv, &hso_serial_ops);
/* register the tty driver */

View File

@ -279,6 +279,13 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO,
},
[PORT_OCTEON] = {
.name = "OCTEON",
.fifo_size = 64,
.tx_loadsz = 64,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO,
},
};
#if defined (CONFIG_SERIAL_8250_AU1X00)
@ -303,16 +310,16 @@ static const u8 au_io_out_map[] = {
};
/* sane hardware needs no mapping */
static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
static inline int map_8250_in_reg(struct uart_port *p, int offset)
{
if (up->port.iotype != UPIO_AU)
if (p->iotype != UPIO_AU)
return offset;
return au_io_in_map[offset];
}
static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
static inline int map_8250_out_reg(struct uart_port *p, int offset)
{
if (up->port.iotype != UPIO_AU)
if (p->iotype != UPIO_AU)
return offset;
return au_io_out_map[offset];
}
@ -341,16 +348,16 @@ static const u8
[UART_SCR] = 0x2c
};
static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
static inline int map_8250_in_reg(struct uart_port *p, int offset)
{
if (up->port.iotype != UPIO_RM9000)
if (p->iotype != UPIO_RM9000)
return offset;
return regmap_in[offset];
}
static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
static inline int map_8250_out_reg(struct uart_port *p, int offset)
{
if (up->port.iotype != UPIO_RM9000)
if (p->iotype != UPIO_RM9000)
return offset;
return regmap_out[offset];
}
@ -363,108 +370,170 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
#endif
static unsigned int serial_in(struct uart_8250_port *up, int offset)
static unsigned int hub6_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
outb(p->hub6 - 1 + offset, p->iobase);
return inb(p->iobase + 1);
}
static void hub6_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
outb(p->hub6 - 1 + offset, p->iobase);
outb(value, p->iobase + 1);
}
static unsigned int mem_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
return readb(p->membase + offset);
}
static void mem_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
writeb(value, p->membase + offset);
}
static void mem32_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
writel(value, p->membase + offset);
}
static unsigned int mem32_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
return readl(p->membase + offset);
}
#ifdef CONFIG_SERIAL_8250_AU1X00
static unsigned int au_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
return __raw_readl(p->membase + offset);
}
static void au_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
__raw_writel(value, p->membase + offset);
}
#endif
static unsigned int tsi_serial_in(struct uart_port *p, int offset)
{
unsigned int tmp;
offset = map_8250_in_reg(up, offset) << up->port.regshift;
switch (up->port.iotype) {
case UPIO_HUB6:
outb(up->port.hub6 - 1 + offset, up->port.iobase);
return inb(up->port.iobase + 1);
case UPIO_MEM:
case UPIO_DWAPB:
return readb(up->port.membase + offset);
case UPIO_RM9000:
case UPIO_MEM32:
return readl(up->port.membase + offset);
#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
return __raw_readl(up->port.membase + offset);
#endif
case UPIO_TSI:
offset = map_8250_in_reg(p, offset) << p->regshift;
if (offset == UART_IIR) {
tmp = readl(up->port.membase + (UART_IIR & ~3));
tmp = readl(p->membase + (UART_IIR & ~3));
return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
} else
return readb(up->port.membase + offset);
default:
return inb(up->port.iobase + offset);
}
return readb(p->membase + offset);
}
static void
serial_out(struct uart_8250_port *up, int offset, int value)
static void tsi_serial_out(struct uart_port *p, int offset, int value)
{
/* Save the offset before it's remapped */
int save_offset = offset;
offset = map_8250_out_reg(up, offset) << up->port.regshift;
switch (up->port.iotype) {
case UPIO_HUB6:
outb(up->port.hub6 - 1 + offset, up->port.iobase);
outb(value, up->port.iobase + 1);
break;
case UPIO_MEM:
writeb(value, up->port.membase + offset);
break;
case UPIO_RM9000:
case UPIO_MEM32:
writel(value, up->port.membase + offset);
break;
#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
__raw_writel(value, up->port.membase + offset);
break;
#endif
case UPIO_TSI:
offset = map_8250_out_reg(p, offset) << p->regshift;
if (!((offset == UART_IER) && (value & UART_IER_UUE)))
writeb(value, up->port.membase + offset);
break;
writeb(value, p->membase + offset);
}
case UPIO_DWAPB:
static void dwapb_serial_out(struct uart_port *p, int offset, int value)
{
int save_offset = offset;
offset = map_8250_out_reg(p, offset) << p->regshift;
/* Save the LCR value so it can be re-written when a
* Busy Detect interrupt occurs. */
if (save_offset == UART_LCR)
if (save_offset == UART_LCR) {
struct uart_8250_port *up = (struct uart_8250_port *)p;
up->lcr = value;
writeb(value, up->port.membase + offset);
}
writeb(value, p->membase + offset);
/* Read the IER to ensure any interrupt is cleared before
* returning from ISR. */
if (save_offset == UART_TX || save_offset == UART_IER)
value = serial_in(up, UART_IER);
value = p->serial_in(p, UART_IER);
}
static unsigned int io_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
return inb(p->iobase + offset);
}
static void io_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
outb(value, p->iobase + offset);
}
static void set_io_from_upio(struct uart_port *p)
{
switch (p->iotype) {
case UPIO_HUB6:
p->serial_in = hub6_serial_in;
p->serial_out = hub6_serial_out;
break;
case UPIO_MEM:
p->serial_in = mem_serial_in;
p->serial_out = mem_serial_out;
break;
case UPIO_RM9000:
case UPIO_MEM32:
p->serial_in = mem32_serial_in;
p->serial_out = mem32_serial_out;
break;
#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
p->serial_in = au_serial_in;
p->serial_out = au_serial_out;
break;
#endif
case UPIO_TSI:
p->serial_in = tsi_serial_in;
p->serial_out = tsi_serial_out;
break;
case UPIO_DWAPB:
p->serial_in = mem_serial_in;
p->serial_out = dwapb_serial_out;
break;
default:
outb(value, up->port.iobase + offset);
p->serial_in = io_serial_in;
p->serial_out = io_serial_out;
break;
}
}
static void
serial_out_sync(struct uart_8250_port *up, int offset, int value)
{
switch (up->port.iotype) {
struct uart_port *p = &up->port;
switch (p->iotype) {
case UPIO_MEM:
case UPIO_MEM32:
#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
#endif
case UPIO_DWAPB:
serial_out(up, offset, value);
serial_in(up, UART_LCR); /* safe, no side-effects */
p->serial_out(p, offset, value);
p->serial_in(p, UART_LCR); /* safe, no side-effects */
break;
default:
serial_out(up, offset, value);
p->serial_out(p, offset, value);
}
}
#define serial_in(up, offset) \
(up->port.serial_in(&(up)->port, (offset)))
#define serial_out(up, offset, value) \
(up->port.serial_out(&(up)->port, (offset), (value)))
/*
* We used to support using pause I/O for certain machines. We
* haven't supported this for a while, but just in case it's badly
@ -2576,6 +2645,7 @@ static void __init serial8250_isa_init_ports(void)
up->port.membase = old_serial_port[i].iomem_base;
up->port.iotype = old_serial_port[i].io_type;
up->port.regshift = old_serial_port[i].iomem_reg_shift;
set_io_from_upio(&up->port);
if (share_irqs)
up->port.flags |= UPF_SHARE_IRQ;
}
@ -2752,12 +2822,30 @@ static struct uart_driver serial8250_reg = {
*/
int __init early_serial_setup(struct uart_port *port)
{
struct uart_port *p;
if (port->line >= ARRAY_SIZE(serial8250_ports))
return -ENODEV;
serial8250_isa_init_ports();
serial8250_ports[port->line].port = *port;
serial8250_ports[port->line].port.ops = &serial8250_pops;
p = &serial8250_ports[port->line].port;
p->iobase = port->iobase;
p->membase = port->membase;
p->irq = port->irq;
p->uartclk = port->uartclk;
p->fifosize = port->fifosize;
p->regshift = port->regshift;
p->iotype = port->iotype;
p->flags = port->flags;
p->mapbase = port->mapbase;
p->private_data = port->private_data;
set_io_from_upio(p);
if (port->serial_in)
p->serial_in = port->serial_in;
if (port->serial_out)
p->serial_out = port->serial_out;
return 0;
}
@ -2822,6 +2910,9 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.mapbase = p->mapbase;
port.hub6 = p->hub6;
port.private_data = p->private_data;
port.type = p->type;
port.serial_in = p->serial_in;
port.serial_out = p->serial_out;
port.dev = &dev->dev;
if (share_irqs)
port.flags |= UPF_SHARE_IRQ;
@ -2976,6 +3067,20 @@ int serial8250_register_port(struct uart_port *port)
if (port->dev)
uart->port.dev = port->dev;
if (port->flags & UPF_FIXED_TYPE) {
uart->port.type = port->type;
uart->port.fifosize = uart_config[port->type].fifo_size;
uart->capabilities = uart_config[port->type].flags;
uart->tx_loadsz = uart_config[port->type].tx_loadsz;
}
set_io_from_upio(&uart->port);
/* Possibly override default I/O functions. */
if (port->serial_in)
uart->port.serial_in = port->serial_in;
if (port->serial_out)
uart->port.serial_out = port->serial_out;
ret = uart_add_one_port(&serial8250_reg, &uart->port);
if (ret == 0)
ret = uart->port.line;

View File

@ -42,7 +42,8 @@ struct pci_serial_quirk {
u32 subvendor;
u32 subdevice;
int (*init)(struct pci_dev *dev);
int (*setup)(struct serial_private *, struct pciserial_board *,
int (*setup)(struct serial_private *,
const struct pciserial_board *,
struct uart_port *, int);
void (*exit)(struct pci_dev *dev);
};
@ -107,7 +108,7 @@ setup_port(struct serial_private *priv, struct uart_port *port,
* ADDI-DATA GmbH communication cards <info@addi-data.com>
*/
static int addidata_apci7800_setup(struct serial_private *priv,
struct pciserial_board *board,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar = 0, offset = board->first_offset;
@ -134,7 +135,7 @@ static int addidata_apci7800_setup(struct serial_private *priv,
* Not that ugly ;) -- HW
*/
static int
afavlab_setup(struct serial_private *priv, struct pciserial_board *board,
afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@ -188,7 +189,8 @@ static int pci_hp_diva_init(struct pci_dev *dev)
* some serial ports are supposed to be hidden on certain models.
*/
static int
pci_hp_diva_setup(struct serial_private *priv, struct pciserial_board *board,
pci_hp_diva_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int offset = board->first_offset;
@ -306,7 +308,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
static int
sbs_setup(struct serial_private *priv, struct pciserial_board *board,
sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@ -463,7 +465,7 @@ static int pci_siig_init(struct pci_dev *dev)
}
static int pci_siig_setup(struct serial_private *priv,
struct pciserial_board *board,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
@ -534,7 +536,8 @@ static int pci_timedia_init(struct pci_dev *dev)
* Ugh, this is ugly as all hell --- TYT
*/
static int
pci_timedia_setup(struct serial_private *priv, struct pciserial_board *board,
pci_timedia_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar = 0, offset = board->first_offset;
@ -568,7 +571,7 @@ pci_timedia_setup(struct serial_private *priv, struct pciserial_board *board,
*/
static int
titan_400l_800l_setup(struct serial_private *priv,
struct pciserial_board *board,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@ -737,8 +740,41 @@ static void __devexit pci_ite887x_exit(struct pci_dev *dev)
release_region(ioport, ITE_887x_IOSIZE);
}
/*
* Oxford Semiconductor Inc.
* Check that device is part of the Tornado range of devices, then determine
* the number of ports available on the device.
*/
static int pci_oxsemi_tornado_init(struct pci_dev *dev)
{
u8 __iomem *p;
unsigned long deviceID;
unsigned int number_uarts = 0;
/* OxSemi Tornado devices are all 0xCxxx */
if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
(dev->device & 0xF000) != 0xC000)
return 0;
p = pci_iomap(dev, 0, 5);
if (p == NULL)
return -ENOMEM;
deviceID = ioread32(p);
/* Tornado device */
if (deviceID == 0x07000200) {
number_uarts = ioread8(p + 4);
printk(KERN_DEBUG
"%d ports detected on Oxford PCI Express device\n",
number_uarts);
}
pci_iounmap(dev, p);
return number_uarts;
}
static int
pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
pci_default_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar, offset = board->first_offset, maxnr;
@ -1017,6 +1053,25 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.init = pci_netmos_init,
.setup = pci_default_setup,
},
/*
* For Oxford Semiconductor and Mainpine
*/
{
.vendor = PCI_VENDOR_ID_OXSEMI,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.init = pci_oxsemi_tornado_init,
.setup = pci_default_setup,
},
{
.vendor = PCI_VENDOR_ID_MAINPINE,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.init = pci_oxsemi_tornado_init,
.setup = pci_default_setup,
},
/*
* Default "match everything" terminator entry
*/
@ -1048,7 +1103,7 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
}
static inline int get_pci_irq(struct pci_dev *dev,
struct pciserial_board *board)
const struct pciserial_board *board)
{
if (board->flags & FL_NOIRQ)
return 0;
@ -1843,8 +1898,8 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
}
static inline int
serial_pci_matches(struct pciserial_board *board,
struct pciserial_board *guessed)
serial_pci_matches(const struct pciserial_board *board,
const struct pciserial_board *guessed)
{
return
board->num_ports == guessed->num_ports &&
@ -1854,54 +1909,14 @@ serial_pci_matches(struct pciserial_board *board,
board->first_offset == guessed->first_offset;
}
/*
* Oxford Semiconductor Inc.
* Check that device is part of the Tornado range of devices, then determine
* the number of ports available on the device.
*/
static int pci_oxsemi_tornado_init(struct pci_dev *dev, struct pciserial_board *board)
{
u8 __iomem *p;
unsigned long deviceID;
unsigned int number_uarts;
/* OxSemi Tornado devices are all 0xCxxx */
if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
(dev->device & 0xF000) != 0xC000)
return 0;
p = pci_iomap(dev, 0, 5);
if (p == NULL)
return -ENOMEM;
deviceID = ioread32(p);
/* Tornado device */
if (deviceID == 0x07000200) {
number_uarts = ioread8(p + 4);
board->num_ports = number_uarts;
printk(KERN_DEBUG
"%d ports detected on Oxford PCI Express device\n",
number_uarts);
}
pci_iounmap(dev, p);
return 0;
}
struct serial_private *
pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board)
pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
{
struct uart_port serial_port;
struct serial_private *priv;
struct pci_serial_quirk *quirk;
int rc, nr_ports, i;
/*
* Find number of ports on board
*/
if (dev->vendor == PCI_VENDOR_ID_OXSEMI ||
dev->vendor == PCI_VENDOR_ID_MAINPINE)
pci_oxsemi_tornado_init(dev, board);
nr_ports = board->num_ports;
/*
@ -2028,7 +2043,8 @@ static int __devinit
pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
{
struct serial_private *priv;
struct pciserial_board *board, tmp;
const struct pciserial_board *board;
struct pciserial_board tmp;
int rc;
if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
@ -2055,7 +2071,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
* We matched one of our class entries. Try to
* determine the parameters of this board.
*/
rc = serial_pci_guess_board(dev, board);
rc = serial_pci_guess_board(dev, &tmp);
if (rc)
goto disable;
} else {
@ -2271,6 +2287,9 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_8_115200 },
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_8_460800 },
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_8_115200 },
@ -2371,6 +2390,9 @@ static struct pci_device_id serial_pci_tbl[] = {
* www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html).
* For now just used the hex ID 0x950a.
*/
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
pbn_b0_2_115200 },
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_2_1130000 },

View File

@ -22,7 +22,8 @@
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#ifdef CONFIG_KGDB_UART
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
#include <linux/kgdb.h>
#include <asm/irq_regs.h>
#endif
@ -45,6 +46,16 @@
static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
# ifndef CONFIG_SERIAL_BFIN_PIO
# error KGDB only support UART in PIO mode.
# endif
static int kgdboc_port_line;
static int kgdboc_break_enabled;
#endif
/*
* Setup for console. Argument comes from the menuconfig
*/
@ -62,13 +73,17 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
static void bfin_serial_reset_irda(struct uart_port *port);
/*
* interrupts are disabled on entry
*/
static void bfin_serial_stop_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
#ifdef CONFIG_SERIAL_BFIN_DMA
struct circ_buf *xmit = &uart->port.info->xmit;
#endif
while (!(UART_GET_LSR(uart) & TEMT))
cpu_relax();
@ -94,6 +109,14 @@ static void bfin_serial_stop_tx(struct uart_port *port)
static void bfin_serial_start_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
struct tty_struct *tty = uart->port.info->port.tty;
/*
* To avoid losting RX interrupt, we reset IR function
* before sending data.
*/
if (tty->termios->c_line == N_IRDA)
bfin_serial_reset_irda(port);
#ifdef CONFIG_SERIAL_BFIN_DMA
if (uart->tx_done)
@ -110,9 +133,7 @@ static void bfin_serial_start_tx(struct uart_port *port)
static void bfin_serial_stop_rx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
#ifdef CONFIG_KGDB_UART
if (uart->port.line != CONFIG_KGDB_UART_PORT)
#endif
UART_CLEAR_IER(uart, ERBFI);
}
@ -123,49 +144,6 @@ static void bfin_serial_enable_ms(struct uart_port *port)
{
}
#ifdef CONFIG_KGDB_UART
static int kgdb_entry_state;
void kgdb_put_debug_char(int chr)
{
struct bfin_serial_port *uart;
if (CONFIG_KGDB_UART_PORT < 0
|| CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
uart = &bfin_serial_ports[0];
else
uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
while (!(UART_GET_LSR(uart) & THRE)) {
SSYNC();
}
UART_CLEAR_DLAB(uart);
UART_PUT_CHAR(uart, (unsigned char)chr);
SSYNC();
}
int kgdb_get_debug_char(void)
{
struct bfin_serial_port *uart;
unsigned char chr;
if (CONFIG_KGDB_UART_PORT < 0
|| CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
uart = &bfin_serial_ports[0];
else
uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
while(!(UART_GET_LSR(uart) & DR)) {
SSYNC();
}
UART_CLEAR_DLAB(uart);
chr = UART_GET_CHAR(uart);
SSYNC();
return chr;
}
#endif
#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO)
# define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold)
@ -178,7 +156,7 @@ int kgdb_get_debug_char(void)
#ifdef CONFIG_SERIAL_BFIN_PIO
static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
struct tty_struct *tty = uart->port.info->port.tty;
struct tty_struct *tty = NULL;
unsigned int status, ch, flg;
static struct timeval anomaly_start = { .tv_sec = 0 };
@ -188,27 +166,18 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
ch = UART_GET_CHAR(uart);
uart->port.icount.rx++;
#ifdef CONFIG_KGDB_UART
if (uart->port.line == CONFIG_KGDB_UART_PORT) {
struct pt_regs *regs = get_irq_regs();
if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */
kgdb_breakkey_pressed(regs);
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
if (kgdb_connected && kgdboc_port_line == uart->port.line)
if (ch == 0x3) {/* Ctrl + C */
kgdb_breakpoint();
return;
} else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */
kgdb_entry_state = 1;
} else if (kgdb_entry_state == 1 && ch == 'q') {
kgdb_entry_state = 0;
kgdb_breakkey_pressed(regs);
return;
} else if (ch == 0x3) {/* Ctrl + C */
kgdb_entry_state = 0;
kgdb_breakkey_pressed(regs);
return;
} else {
kgdb_entry_state = 0;
}
}
if (!uart->port.info || !uart->port.info->tty)
return;
#endif
tty = uart->port.info->tty;
if (ANOMALY_05000363) {
/* The BF533 (and BF561) family of processors have a nice anomaly
@ -250,6 +219,7 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
return;
known_good_char:
status &= ~BI;
anomaly_start.tv_sec = 0;
}
}
@ -445,7 +415,9 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
{
int x_pos, pos;
int x_pos, pos, flags;
spin_lock_irqsave(&uart->port.lock, flags);
uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
@ -463,6 +435,8 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
}
spin_unlock_irqrestore(&uart->port.lock, flags);
mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
}
@ -497,10 +471,9 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
spin_lock(&uart->port.lock);
irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
clear_dma_irqstat(uart->rx_dma_channel);
bfin_serial_dma_rx_chars(uart);
spin_unlock(&uart->port.lock);
mod_timer(&(uart->rx_dma_timer), jiffies);
return IRQ_HANDLED;
}
#endif
@ -630,16 +603,16 @@ static int bfin_serial_startup(struct uart_port *port)
uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
add_timer(&(uart->rx_dma_timer));
#else
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled)
kgdboc_break_enabled = 0;
else {
# endif
if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
"BFIN_UART_RX", uart)) {
# ifdef CONFIG_KGDB_UART
if (uart->port.line != CONFIG_KGDB_UART_PORT) {
# endif
printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
return -EBUSY;
# ifdef CONFIG_KGDB_UART
}
# endif
}
if (request_irq
@ -685,6 +658,10 @@ static int bfin_serial_startup(struct uart_port *port)
}
}
# endif
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
}
# endif
#endif
UART_SET_IER(uart, ERBFI);
return 0;
@ -715,9 +692,6 @@ static void bfin_serial_shutdown(struct uart_port *port)
default:
break;
};
#endif
#ifdef CONFIG_KGDB_UART
if (uart->port.line != CONFIG_KGDB_UART_PORT)
#endif
free_irq(uart->port.irq, uart);
free_irq(uart->port.irq+1, uart);
@ -887,6 +861,65 @@ static void bfin_serial_set_ldisc(struct uart_port *port)
}
}
#ifdef CONFIG_CONSOLE_POLL
static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
while (!(UART_GET_LSR(uart) & THRE))
cpu_relax();
UART_CLEAR_DLAB(uart);
UART_PUT_CHAR(uart, (unsigned char)chr);
}
static int bfin_serial_poll_get_char(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
unsigned char chr;
while (!(UART_GET_LSR(uart) & DR))
cpu_relax();
UART_CLEAR_DLAB(uart);
chr = UART_GET_CHAR(uart);
return chr;
}
#endif
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
static void bfin_kgdboc_port_shutdown(struct uart_port *port)
{
if (kgdboc_break_enabled) {
kgdboc_break_enabled = 0;
bfin_serial_shutdown(port);
}
}
static int bfin_kgdboc_port_startup(struct uart_port *port)
{
kgdboc_port_line = port->line;
kgdboc_break_enabled = !bfin_serial_startup(port);
return 0;
}
#endif
static void bfin_serial_reset_irda(struct uart_port *port)
{
int line = port->line;
unsigned short val;
val = UART_GET_GCTL(&bfin_serial_ports[line]);
val &= ~(IREN | RPOLC);
UART_PUT_GCTL(&bfin_serial_ports[line], val);
SSYNC();
val |= (IREN | RPOLC);
UART_PUT_GCTL(&bfin_serial_ports[line], val);
SSYNC();
}
static struct uart_ops bfin_serial_pops = {
.tx_empty = bfin_serial_tx_empty,
.set_mctrl = bfin_serial_set_mctrl,
@ -905,6 +938,15 @@ static struct uart_ops bfin_serial_pops = {
.request_port = bfin_serial_request_port,
.config_port = bfin_serial_config_port,
.verify_port = bfin_serial_verify_port,
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
.kgdboc_port_startup = bfin_kgdboc_port_startup,
.kgdboc_port_shutdown = bfin_kgdboc_port_shutdown,
#endif
#ifdef CONFIG_CONSOLE_POLL
.poll_put_char = bfin_serial_poll_put_char,
.poll_get_char = bfin_serial_poll_get_char,
#endif
};
static void __init bfin_serial_init_ports(void)
@ -950,7 +992,7 @@ static void __init bfin_serial_init_ports(void)
}
#ifdef CONFIG_SERIAL_BFIN_CONSOLE
#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
/*
* If the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
@ -994,16 +1036,13 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
}
pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
}
#endif
#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
static struct uart_driver bfin_serial_reg;
static int __init
bfin_serial_console_setup(struct console *co, char *options)
{
struct bfin_serial_port *uart;
# ifdef CONFIG_SERIAL_BFIN_CONSOLE
int baud = 57600;
int bits = 8;
int parity = 'n';
@ -1011,7 +1050,6 @@ bfin_serial_console_setup(struct console *co, char *options)
int flow = 'r';
# else
int flow = 'n';
# endif
# endif
/*
@ -1023,16 +1061,12 @@ bfin_serial_console_setup(struct console *co, char *options)
co->index = 0;
uart = &bfin_serial_ports[co->index];
# ifdef CONFIG_SERIAL_BFIN_CONSOLE
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
bfin_serial_console_get_options(uart, &baud, &parity, &bits);
return uart_set_options(&uart->port, co, baud, parity, bits, flow);
# else
return 0;
# endif
}
#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
defined (CONFIG_EARLY_PRINTK) */
@ -1076,10 +1110,7 @@ static int __init bfin_serial_rs_console_init(void)
{
bfin_serial_init_ports();
register_console(&bfin_serial_console);
#ifdef CONFIG_KGDB_UART
kgdb_entry_state = 0;
init_kgdb_uart();
#endif
return 0;
}
console_initcall(bfin_serial_rs_console_init);
@ -1144,7 +1175,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port,
return &bfin_early_serial_console;
}
#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
#endif /* CONFIG_EARLY_PRINTK */
static struct uart_driver bfin_serial_reg = {
.owner = THIS_MODULE,
@ -1235,10 +1266,6 @@ static struct platform_driver bfin_serial_driver = {
static int __init bfin_serial_init(void)
{
int ret;
#ifdef CONFIG_KGDB_UART
struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
struct ktermios t;
#endif
pr_info("Serial: Blackfin serial driver\n");
@ -1252,21 +1279,6 @@ static int __init bfin_serial_init(void)
uart_unregister_driver(&bfin_serial_reg);
}
}
#ifdef CONFIG_KGDB_UART
if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {
request_irq(uart->port.irq, bfin_serial_rx_int,
IRQF_DISABLED, "BFIN_UART_RX", uart);
pr_info("Request irq for kgdb uart port\n");
UART_SET_IER(uart, ERBFI);
SSYNC();
t.c_cflag = CS8|B57600;
t.c_iflag = 0;
t.c_oflag = 0;
t.c_lflag = ICANON;
t.c_line = CONFIG_KGDB_UART_PORT;
bfin_serial_set_termios(&uart->port, &t, &t);
}
#endif
return ret;
}
@ -1276,6 +1288,7 @@ static void __exit bfin_serial_exit(void)
uart_unregister_driver(&bfin_serial_reg);
}
module_init(bfin_serial_init);
module_exit(bfin_serial_exit);

View File

@ -99,7 +99,7 @@ static void sport_stop_tx(struct uart_port *port);
static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
{
pr_debug("%s value:%x\n", __FUNCTION__, value);
pr_debug("%s value:%x\n", __func__, value);
/* Place a Start and Stop bit */
__asm__ volatile (
"R2 = b#01111111100;\n\t"
@ -110,7 +110,7 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
:"=r"(value)
:"0"(value)
:"R2", "R3");
pr_debug("%s value:%x\n", __FUNCTION__, value);
pr_debug("%s value:%x\n", __func__, value);
SPORT_PUT_TX(up, value);
}
@ -120,7 +120,7 @@ static inline unsigned int rx_one_byte(struct sport_uart_port *up)
unsigned int value, extract;
value = SPORT_GET_RX32(up);
pr_debug("%s value:%x\n", __FUNCTION__, value);
pr_debug("%s value:%x\n", __func__, value);
/* Extract 8 bits data */
__asm__ volatile (
@ -151,12 +151,12 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
/* Set TCR1 and TCR2 */
SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK));
SPORT_PUT_TCR2(up, 10);
pr_debug("%s TCR1:%x, TCR2:%x\n", __FUNCTION__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
/* Set RCR1 and RCR2 */
SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
SPORT_PUT_RCR2(up, 28);
pr_debug("%s RCR1:%x, RCR2:%x\n", __FUNCTION__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
tclkdiv = sclk/(2 * baud_rate) - 1;
tfsdiv = 12;
@ -166,7 +166,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
SPORT_PUT_RCLKDIV(up, rclkdiv);
SSYNC();
pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, tfsdiv:%d, rclkdiv:%d\n",
__FUNCTION__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv);
__func__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv);
return 0;
}
@ -231,7 +231,7 @@ static int sport_startup(struct uart_port *port)
char buffer[20];
int retval;
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
memset(buffer, 20, '\0');
snprintf(buffer, 20, "%s rx", up->name);
retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
@ -320,7 +320,7 @@ static unsigned int sport_tx_empty(struct uart_port *port)
unsigned int stat;
stat = SPORT_GET_STAT(up);
pr_debug("%s stat:%04x\n", __FUNCTION__, stat);
pr_debug("%s stat:%04x\n", __func__, stat);
if (stat & TXHRE) {
return TIOCSER_TEMT;
} else
@ -329,13 +329,13 @@ static unsigned int sport_tx_empty(struct uart_port *port)
static unsigned int sport_get_mctrl(struct uart_port *port)
{
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
return (TIOCM_CTS | TIOCM_CD | TIOCM_DSR);
}
static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
}
static void sport_stop_tx(struct uart_port *port)
@ -343,7 +343,7 @@ static void sport_stop_tx(struct uart_port *port)
struct sport_uart_port *up = (struct sport_uart_port *)port;
unsigned int stat;
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
stat = SPORT_GET_STAT(up);
while(!(stat & TXHRE)) {
@ -366,21 +366,21 @@ static void sport_start_tx(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
/* Write data into SPORT FIFO before enable SPROT to transmit */
sport_uart_tx_chars(up);
/* Enable transmit, then an interrupt will generated */
SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
SSYNC();
pr_debug("%s exit\n", __FUNCTION__);
pr_debug("%s exit\n", __func__);
}
static void sport_stop_rx(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
/* Disable sport to stop rx */
SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
SSYNC();
@ -388,19 +388,19 @@ static void sport_stop_rx(struct uart_port *port)
static void sport_enable_ms(struct uart_port *port)
{
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
}
static void sport_break_ctl(struct uart_port *port, int break_state)
{
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
}
static void sport_shutdown(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
/* Disable sport */
SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
@ -421,7 +421,7 @@ static void sport_shutdown(struct uart_port *port)
static void sport_set_termios(struct uart_port *port,
struct termios *termios, struct termios *old)
{
pr_debug("%s enter, c_cflag:%08x\n", __FUNCTION__, termios->c_cflag);
pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
uart_update_timeout(port, CS8 ,port->uartclk);
}
@ -429,18 +429,18 @@ static const char *sport_type(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
return up->name;
}
static void sport_release_port(struct uart_port *port)
{
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
}
static int sport_request_port(struct uart_port *port)
{
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
return 0;
}
@ -448,13 +448,13 @@ static void sport_config_port(struct uart_port *port, int flags)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
up->port.type = PORT_BFIN_SPORT;
}
static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
{
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
return 0;
}
@ -527,7 +527,7 @@ static int sport_uart_suspend(struct platform_device *dev, pm_message_t state)
{
struct sport_uart_port *sport = platform_get_drvdata(dev);
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
if (sport)
uart_suspend_port(&sport_uart_reg, &sport->port);
@ -538,7 +538,7 @@ static int sport_uart_resume(struct platform_device *dev)
{
struct sport_uart_port *sport = platform_get_drvdata(dev);
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
if (sport)
uart_resume_port(&sport_uart_reg, &sport->port);
@ -547,7 +547,7 @@ static int sport_uart_resume(struct platform_device *dev)
static int sport_uart_probe(struct platform_device *dev)
{
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
sport_uart_ports[dev->id].port.dev = &dev->dev;
uart_add_one_port(&sport_uart_reg, &sport_uart_ports[dev->id].port);
platform_set_drvdata(dev, &sport_uart_ports[dev->id]);
@ -559,7 +559,7 @@ static int sport_uart_remove(struct platform_device *dev)
{
struct sport_uart_port *sport = platform_get_drvdata(dev);
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
platform_set_drvdata(dev, NULL);
if (sport)
@ -582,7 +582,7 @@ static int __init sport_uart_init(void)
{
int ret;
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
ret = uart_register_driver(&sport_uart_reg);
if (ret != 0) {
printk(KERN_ERR "Failed to register %s:%d\n",
@ -597,13 +597,13 @@ static int __init sport_uart_init(void)
}
pr_debug("%s exit\n", __FUNCTION__);
pr_debug("%s exit\n", __func__);
return ret;
}
static void __exit sport_uart_exit(void)
{
pr_debug("%s enter\n", __FUNCTION__);
pr_debug("%s enter\n", __func__);
platform_driver_unregister(&sport_uart_driver);
uart_unregister_driver(&sport_uart_reg);
}

View File

@ -272,7 +272,7 @@ static void jsm_tty_close(struct uart_port *port)
jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
bd = channel->ch_bd;
ts = channel->uart_port.info->port.tty->termios;
ts = port->info->port.tty->termios;
channel->ch_flags &= ~(CH_STOPI);

View File

@ -50,7 +50,7 @@ static struct lock_class_key port_lock_key;
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->port.blocked_open : 0))
#define uart_users(state) ((state)->count + (state)->info.port.blocked_open)
#ifdef CONFIG_SERIAL_CORE_CONSOLE
#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
@ -94,7 +94,7 @@ static void __uart_start(struct tty_struct *tty)
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->port;
if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
if (!uart_circ_empty(&state->info.xmit) && state->info.xmit.buf &&
!tty->stopped && !tty->hw_stopped)
port->ops->start_tx(port);
}
@ -113,7 +113,7 @@ static void uart_start(struct tty_struct *tty)
static void uart_tasklet_action(unsigned long data)
{
struct uart_state *state = (struct uart_state *)data;
tty_wakeup(state->info->port.tty);
tty_wakeup(state->info.port.tty);
}
static inline void
@ -139,7 +139,7 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
*/
static int uart_startup(struct uart_state *state, int init_hw)
{
struct uart_info *info = state->info;
struct uart_info *info = &state->info;
struct uart_port *port = state->port;
unsigned long page;
int retval = 0;
@ -212,14 +212,15 @@ static int uart_startup(struct uart_state *state, int init_hw)
*/
static void uart_shutdown(struct uart_state *state)
{
struct uart_info *info = state->info;
struct uart_info *info = &state->info;
struct uart_port *port = state->port;
struct tty_struct *tty = info->port.tty;
/*
* Set the TTY IO error marker
*/
if (info->port.tty)
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
if (info->flags & UIF_INITIALIZED) {
info->flags &= ~UIF_INITIALIZED;
@ -227,7 +228,7 @@ static void uart_shutdown(struct uart_state *state)
/*
* Turn off DTR and RTS early.
*/
if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
if (!tty || (tty->termios->c_cflag & HUPCL))
uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
/*
@ -427,7 +428,7 @@ EXPORT_SYMBOL(uart_get_divisor);
static void
uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
{
struct tty_struct *tty = state->info->port.tty;
struct tty_struct *tty = state->info.port.tty;
struct uart_port *port = state->port;
struct ktermios *termios;
@ -444,14 +445,14 @@ uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
* Set flags based on termios cflag
*/
if (termios->c_cflag & CRTSCTS)
state->info->flags |= UIF_CTS_FLOW;
state->info.flags |= UIF_CTS_FLOW;
else
state->info->flags &= ~UIF_CTS_FLOW;
state->info.flags &= ~UIF_CTS_FLOW;
if (termios->c_cflag & CLOCAL)
state->info->flags &= ~UIF_CHECK_CD;
state->info.flags &= ~UIF_CHECK_CD;
else
state->info->flags |= UIF_CHECK_CD;
state->info.flags |= UIF_CHECK_CD;
port->ops->set_termios(port, termios, old_termios);
}
@ -479,7 +480,7 @@ static int uart_put_char(struct tty_struct *tty, unsigned char ch)
{
struct uart_state *state = tty->driver_data;
return __uart_put_char(state->port, &state->info->xmit, ch);
return __uart_put_char(state->port, &state->info.xmit, ch);
}
static void uart_flush_chars(struct tty_struct *tty)
@ -500,13 +501,13 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
* This means you called this function _after_ the port was
* closed. No cookie for you.
*/
if (!state || !state->info) {
if (!state) {
WARN_ON(1);
return -EL3HLT;
}
port = state->port;
circ = &state->info->xmit;
circ = &state->info.xmit;
if (!circ->buf)
return 0;
@ -537,7 +538,7 @@ static int uart_write_room(struct tty_struct *tty)
int ret;
spin_lock_irqsave(&state->port->lock, flags);
ret = uart_circ_chars_free(&state->info->xmit);
ret = uart_circ_chars_free(&state->info.xmit);
spin_unlock_irqrestore(&state->port->lock, flags);
return ret;
}
@ -549,7 +550,7 @@ static int uart_chars_in_buffer(struct tty_struct *tty)
int ret;
spin_lock_irqsave(&state->port->lock, flags);
ret = uart_circ_chars_pending(&state->info->xmit);
ret = uart_circ_chars_pending(&state->info.xmit);
spin_unlock_irqrestore(&state->port->lock, flags);
return ret;
}
@ -564,7 +565,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
* This means you called this function _after_ the port was
* closed. No cookie for you.
*/
if (!state || !state->info) {
if (!state) {
WARN_ON(1);
return;
}
@ -573,7 +574,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
pr_debug("uart_flush_buffer(%d) called\n", tty->index);
spin_lock_irqsave(&port->lock, flags);
uart_circ_clear(&state->info->xmit);
uart_circ_clear(&state->info.xmit);
if (port->ops->flush_buffer)
port->ops->flush_buffer(port);
spin_unlock_irqrestore(&port->lock, flags);
@ -837,15 +838,15 @@ static int uart_set_info(struct uart_state *state,
state->closing_wait = closing_wait;
if (new_serial.xmit_fifo_size)
port->fifosize = new_serial.xmit_fifo_size;
if (state->info->port.tty)
state->info->port.tty->low_latency =
if (state->info.port.tty)
state->info.port.tty->low_latency =
(port->flags & UPF_LOW_LATENCY) ? 1 : 0;
check_and_exit:
retval = 0;
if (port->type == PORT_UNKNOWN)
goto exit;
if (state->info->flags & UIF_INITIALIZED) {
if (state->info.flags & UIF_INITIALIZED) {
if (((old_flags ^ port->flags) & UPF_SPD_MASK) ||
old_custom_divisor != port->custom_divisor) {
/*
@ -858,7 +859,7 @@ static int uart_set_info(struct uart_state *state,
printk(KERN_NOTICE
"%s sets custom speed on %s. This "
"is deprecated.\n", current->comm,
tty_name(state->info->port.tty, buf));
tty_name(state->info.port.tty, buf));
}
uart_change_speed(state, NULL);
}
@ -889,8 +890,8 @@ static int uart_get_lsr_info(struct uart_state *state,
* interrupt happens).
*/
if (port->x_char ||
((uart_circ_chars_pending(&state->info->xmit) > 0) &&
!state->info->port.tty->stopped && !state->info->port.tty->hw_stopped))
((uart_circ_chars_pending(&state->info.xmit) > 0) &&
!state->info.port.tty->stopped && !state->info.port.tty->hw_stopped))
result &= ~TIOCSER_TEMT;
return put_user(result, value);
@ -1017,7 +1018,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
port->ops->enable_ms(port);
spin_unlock_irq(&port->lock);
add_wait_queue(&state->info->delta_msr_wait, &wait);
add_wait_queue(&state->info.delta_msr_wait, &wait);
for (;;) {
spin_lock_irq(&port->lock);
memcpy(&cnow, &port->icount, sizeof(struct uart_icount));
@ -1045,7 +1046,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
}
current->state = TASK_RUNNING;
remove_wait_queue(&state->info->delta_msr_wait, &wait);
remove_wait_queue(&state->info.delta_msr_wait, &wait);
return ret;
}
@ -1241,7 +1242,7 @@ static void uart_set_termios(struct tty_struct *tty,
*/
if (!(old_termios->c_cflag & CLOCAL) &&
(tty->termios->c_cflag & CLOCAL))
wake_up_interruptible(&state->info->port.open_wait);
wake_up_interruptible(&info->port.open_wait);
#endif
}
@ -1303,7 +1304,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
* At this point, we stop accepting input. To do this, we
* disable the receive line status interrupts.
*/
if (state->info->flags & UIF_INITIALIZED) {
if (state->info.flags & UIF_INITIALIZED) {
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
port->ops->stop_rx(port);
@ -1322,9 +1323,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
tty_ldisc_flush(tty);
tty->closing = 0;
state->info->port.tty = NULL;
state->info.port.tty = NULL;
if (state->info->port.blocked_open) {
if (state->info.port.blocked_open) {
if (state->close_delay)
msleep_interruptible(state->close_delay);
} else if (!uart_console(port)) {
@ -1334,8 +1335,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
/*
* Wake up anyone trying to open this port.
*/
state->info->flags &= ~UIF_NORMAL_ACTIVE;
wake_up_interruptible(&state->info->port.open_wait);
state->info.flags &= ~UIF_NORMAL_ACTIVE;
wake_up_interruptible(&state->info.port.open_wait);
done:
mutex_unlock(&state->mutex);
@ -1409,19 +1410,20 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
static void uart_hangup(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_info *info = &state->info;
BUG_ON(!kernel_locked());
pr_debug("uart_hangup(%d)\n", state->port->line);
mutex_lock(&state->mutex);
if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
if (info->flags & UIF_NORMAL_ACTIVE) {
uart_flush_buffer(tty);
uart_shutdown(state);
state->count = 0;
state->info->flags &= ~UIF_NORMAL_ACTIVE;
state->info->port.tty = NULL;
wake_up_interruptible(&state->info->port.open_wait);
wake_up_interruptible(&state->info->delta_msr_wait);
info->flags &= ~UIF_NORMAL_ACTIVE;
info->port.tty = NULL;
wake_up_interruptible(&info->port.open_wait);
wake_up_interruptible(&info->delta_msr_wait);
}
mutex_unlock(&state->mutex);
}
@ -1434,7 +1436,7 @@ static void uart_hangup(struct tty_struct *tty)
*/
static void uart_update_termios(struct uart_state *state)
{
struct tty_struct *tty = state->info->port.tty;
struct tty_struct *tty = state->info.port.tty;
struct uart_port *port = state->port;
if (uart_console(port) && port->cons->cflag) {
@ -1469,7 +1471,7 @@ static int
uart_block_til_ready(struct file *filp, struct uart_state *state)
{
DECLARE_WAITQUEUE(wait, current);
struct uart_info *info = state->info;
struct uart_info *info = &state->info;
struct uart_port *port = state->port;
unsigned int mctrl;
@ -1563,28 +1565,6 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
ret = -ENXIO;
goto err_unlock;
}
/* BKL: RACE HERE - LEAK */
/* We should move this into the uart_state structure and kill off
this whole complexity */
if (!state->info) {
state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);
if (state->info) {
init_waitqueue_head(&state->info->port.open_wait);
init_waitqueue_head(&state->info->delta_msr_wait);
/*
* Link the info into the other structures.
*/
state->port->info = state->info;
tasklet_init(&state->info->tlet, uart_tasklet_action,
(unsigned long)state);
} else {
ret = -ENOMEM;
goto err_unlock;
}
}
return state;
err_unlock:
@ -1641,9 +1621,10 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
* Any failures from here onwards should not touch the count.
*/
tty->driver_data = state;
state->port->info = &state->info;
tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
tty->alt_speed = 0;
state->info->port.tty = tty;
state->info.port.tty = tty;
/*
* If the port is in the middle of closing, bail out now.
@ -1676,8 +1657,8 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
/*
* If this is the first open to succeed, adjust things to suit.
*/
if (retval == 0 && !(state->info->flags & UIF_NORMAL_ACTIVE)) {
state->info->flags |= UIF_NORMAL_ACTIVE;
if (retval == 0 && !(state->info.flags & UIF_NORMAL_ACTIVE)) {
state->info.flags |= UIF_NORMAL_ACTIVE;
uart_update_termios(state);
}
@ -2028,11 +2009,11 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
}
port->suspended = 1;
if (state->info && state->info->flags & UIF_INITIALIZED) {
if (state->info.flags & UIF_INITIALIZED) {
const struct uart_ops *ops = port->ops;
int tries;
state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
state->info.flags = (state->info.flags & ~UIF_INITIALIZED)
| UIF_SUSPENDED;
spin_lock_irq(&port->lock);
@ -2107,15 +2088,15 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
/*
* If that's unset, use the tty termios setting.
*/
if (state->info && state->info->port.tty && termios.c_cflag == 0)
termios = *state->info->port.tty->termios;
if (state->info.port.tty && termios.c_cflag == 0)
termios = *state->info.port.tty->termios;
uart_change_pm(state, 0);
port->ops->set_termios(port, &termios, NULL);
console_start(port->cons);
}
if (state->info && state->info->flags & UIF_SUSPENDED) {
if (state->info.flags & UIF_SUSPENDED) {
const struct uart_ops *ops = port->ops;
int ret;
@ -2130,7 +2111,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
ops->set_mctrl(port, port->mctrl);
ops->start_tx(port);
spin_unlock_irq(&port->lock);
state->info->flags |= UIF_INITIALIZED;
state->info.flags |= UIF_INITIALIZED;
} else {
/*
* Failed to resume - maybe hardware went away?
@ -2140,7 +2121,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
uart_shutdown(state);
}
state->info->flags &= ~UIF_SUSPENDED;
state->info.flags &= ~UIF_SUSPENDED;
}
mutex_unlock(&state->mutex);
@ -2198,11 +2179,14 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
* Now do the auto configuration stuff. Note that config_port
* is expected to claim the resources and map the port for us.
*/
flags = UART_CONFIG_TYPE;
flags = 0;
if (port->flags & UPF_AUTO_IRQ)
flags |= UART_CONFIG_IRQ;
if (port->flags & UPF_BOOT_AUTOCONF) {
if (!(port->flags & UPF_FIXED_TYPE)) {
port->type = PORT_UNKNOWN;
flags |= UART_CONFIG_TYPE;
}
port->ops->config_port(port, flags);
}
@ -2383,8 +2367,12 @@ int uart_register_driver(struct uart_driver *drv)
state->close_delay = 500; /* .5 seconds */
state->closing_wait = 30000; /* 30 seconds */
mutex_init(&state->mutex);
tty_port_init(&state->info.port);
init_waitqueue_head(&state->info.delta_msr_wait);
tasklet_init(&state->info.tlet, uart_tasklet_action,
(unsigned long)state);
}
retval = tty_register_driver(normal);
@ -2455,7 +2443,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
state->pm_state = -1;
port->cons = drv->cons;
port->info = state->info;
port->info = &state->info;
/*
* If this port is a console, then the spinlock is already
@ -2527,17 +2515,10 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
*/
tty_unregister_device(drv->tty_driver, port->line);
info = state->info;
info = &state->info;
if (info && info->port.tty)
tty_vhangup(info->port.tty);
/*
* All users of this port should now be disconnected from
* this driver, and the port shut down. We should be the
* only thread fiddling with this port from now on.
*/
state->info = NULL;
/*
* Free the port IO and memory resources, if any.
*/
@ -2552,10 +2533,8 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
/*
* Kill the tasklet, and free resources.
*/
if (info) {
if (info)
tasklet_kill(&info->tlet);
kfree(info);
}
state->port = NULL;
mutex_unlock(&port_mutex);

View File

@ -241,12 +241,25 @@ static void usb_console_write(struct console *co,
}
}
static struct tty_driver *usb_console_device(struct console *co, int *index)
{
struct tty_driver **p = (struct tty_driver **)co->data;
if (!*p)
return NULL;
*index = co->index;
return *p;
}
static struct console usbcons = {
.name = "ttyUSB",
.write = usb_console_write,
.device = usb_console_device,
.setup = usb_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &usb_serial_tty_driver,
};
void usb_serial_console_disconnect(struct usb_serial *serial)

View File

@ -1054,6 +1054,8 @@ static int set_serial_info(struct tty_struct *tty,
if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
return -EFAULT;
lock_kernel();
old_priv = *priv;
/* Do error checking and permission checking */
@ -1069,8 +1071,10 @@ static int set_serial_info(struct tty_struct *tty,
}
if ((new_serial.baud_base != priv->baud_base) &&
(new_serial.baud_base < 9600))
(new_serial.baud_base < 9600)) {
unlock_kernel();
return -EINVAL;
}
/* Make the changes - these are privileged changes! */
@ -1098,8 +1102,11 @@ check_and_exit:
(priv->flags & ASYNC_SPD_MASK)) ||
(((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
(old_priv.custom_divisor != priv->custom_divisor))) {
unlock_kernel();
change_speed(tty, port);
}
else
unlock_kernel();
return 0;
} /* set_serial_info */

View File

@ -878,6 +878,7 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
dbg("%sstate=%d", __func__, break_state);
/* LOCKING */
if (break_state)
lcr |= MCT_U232_SET_BREAK;

View File

@ -721,10 +721,10 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
spin_lock_irqsave(&priv->lock, flags);
lcr = priv->last_lcr;
spin_unlock_irqrestore(&priv->lock, flags);
if (break_state)
lcr |= MCT_U232_SET_BREAK;
spin_unlock_irqrestore(&priv->lock, flags);
mct_u232_set_line_ctrl(serial, lcr);
} /* mct_u232_break_ctl */

View File

@ -1343,6 +1343,7 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
else
data = mos7840_port->shadowLCR & ~LCR_SET_BREAK;
/* FIXME: no locking on shadowLCR anywhere in driver */
mos7840_port->shadowLCR = data;
dbg("mcs7840_break mos7840_port->shadowLCR is %x\n",
mos7840_port->shadowLCR);
@ -2214,10 +2215,12 @@ static int mos7840_set_modem_info(struct moschip_port *mos7840_port,
break;
}
lock_kernel();
mos7840_port->shadowMCR = mcr;
Data = mos7840_port->shadowMCR;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
unlock_kernel();
if (status < 0) {
dbg("setting MODEM_CONTROL_REGISTER Failed\n");
return -1;

View File

@ -269,15 +269,19 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
return;
}
--port->port.count;
if (port->port.count == 0)
if (port->port.count == 1)
/* only call the device specific close if this
* port is being closed by the last owner */
* port is being closed by the last owner. Ensure we do
* this before we drop the port count. The call is protected
* by the port mutex
*/
port->serial->type->close(tty, port, filp);
if (port->port.count == (port->console? 1 : 0)) {
if (port->port.count == (port->console ? 2 : 1)) {
struct tty_struct *tty = tty_port_tty_get(&port->port);
if (tty) {
/* We must do this before we drop the port count to
zero. */
if (tty->driver_data)
tty->driver_data = NULL;
tty_port_tty_set(&port->port, NULL);
@ -285,13 +289,14 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
}
}
if (port->port.count == 0) {
if (port->port.count == 1) {
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected)
usb_autopm_put_interface(port->serial->interface);
mutex_unlock(&port->serial->disc_mutex);
module_put(port->serial->type->driver.owner);
}
--port->port.count;
mutex_unlock(&port->mutex);
usb_serial_put(port->serial);
@ -334,6 +339,10 @@ static int serial_chars_in_buffer(struct tty_struct *tty)
dbg("%s = port %d", __func__, port->number);
WARN_ON(!port->port.count);
/* if the device was unplugged then any remaining characters
fell out of the connector ;) */
if (port->serial->disconnected)
return 0;
/* pass on to the driver specific version of this function */
return port->serial->type->chars_in_buffer(tty);
}
@ -373,9 +382,7 @@ static int serial_ioctl(struct tty_struct *tty, struct file *file,
/* pass on to the driver specific version of this function
if it is available */
if (port->serial->type->ioctl) {
lock_kernel();
retval = port->serial->type->ioctl(tty, file, cmd, arg);
unlock_kernel();
} else
retval = -ENOIOCTLCMD;
return retval;
@ -404,11 +411,8 @@ static int serial_break(struct tty_struct *tty, int break_state)
WARN_ON(!port->port.count);
/* pass on to the driver specific version of this function
if it is available */
if (port->serial->type->break_ctl) {
lock_kernel();
if (port->serial->type->break_ctl)
port->serial->type->break_ctl(tty, break_state);
unlock_kernel();
}
return 0;
}

View File

@ -27,25 +27,32 @@
#define DEVPTS_SUPER_MAGIC 0x1cd1
#define DEVPTS_DEFAULT_MODE 0600
/*
* ptmx is a new node in /dev/pts and will be unused in legacy (single-
* instance) mode. To prevent surprises in user space, set permissions of
* ptmx to 0. Use 'chmod' or remount with '-o ptmxmode' to set meaningful
* permissions.
*/
#define DEVPTS_DEFAULT_PTMX_MODE 0000
#define PTMX_MINOR 2
extern int pty_limit; /* Config limit on Unix98 ptys */
static DEFINE_IDA(allocated_ptys);
static DEFINE_MUTEX(allocated_ptys_lock);
static struct vfsmount *devpts_mnt;
static struct dentry *devpts_root;
static struct {
struct pts_mount_opts {
int setuid;
int setgid;
uid_t uid;
gid_t gid;
umode_t mode;
} config = {.mode = DEVPTS_DEFAULT_MODE};
umode_t ptmxmode;
int newinstance;
};
enum {
Opt_uid, Opt_gid, Opt_mode,
Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance,
Opt_err
};
@ -53,18 +60,50 @@ static const match_table_t tokens = {
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
{Opt_mode, "mode=%o"},
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
{Opt_ptmxmode, "ptmxmode=%o"},
{Opt_newinstance, "newinstance"},
#endif
{Opt_err, NULL}
};
static int devpts_remount(struct super_block *sb, int *flags, char *data)
struct pts_fs_info {
struct ida allocated_ptys;
struct pts_mount_opts mount_opts;
struct dentry *ptmx_dentry;
};
static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
{
return sb->s_fs_info;
}
static inline struct super_block *pts_sb_from_inode(struct inode *inode)
{
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
return inode->i_sb;
#endif
return devpts_mnt->mnt_sb;
}
#define PARSE_MOUNT 0
#define PARSE_REMOUNT 1
static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
{
char *p;
config.setuid = 0;
config.setgid = 0;
config.uid = 0;
config.gid = 0;
config.mode = DEVPTS_DEFAULT_MODE;
opts->setuid = 0;
opts->setgid = 0;
opts->uid = 0;
opts->gid = 0;
opts->mode = DEVPTS_DEFAULT_MODE;
opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
/* newinstance makes sense only on initial mount */
if (op == PARSE_MOUNT)
opts->newinstance = 0;
while ((p = strsep(&data, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS];
@ -79,20 +118,32 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
case Opt_uid:
if (match_int(&args[0], &option))
return -EINVAL;
config.uid = option;
config.setuid = 1;
opts->uid = option;
opts->setuid = 1;
break;
case Opt_gid:
if (match_int(&args[0], &option))
return -EINVAL;
config.gid = option;
config.setgid = 1;
opts->gid = option;
opts->setgid = 1;
break;
case Opt_mode:
if (match_octal(&args[0], &option))
return -EINVAL;
config.mode = option & S_IALLUGO;
opts->mode = option & S_IALLUGO;
break;
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
case Opt_ptmxmode:
if (match_octal(&args[0], &option))
return -EINVAL;
opts->ptmxmode = option & S_IALLUGO;
break;
case Opt_newinstance:
/* newinstance makes sense only on initial mount */
if (op == PARSE_MOUNT)
opts->newinstance = 1;
break;
#endif
default:
printk(KERN_ERR "devpts: called with bogus options\n");
return -EINVAL;
@ -102,13 +153,108 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
return 0;
}
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
static int mknod_ptmx(struct super_block *sb)
{
int mode;
int rc = -ENOMEM;
struct dentry *dentry;
struct inode *inode;
struct dentry *root = sb->s_root;
struct pts_fs_info *fsi = DEVPTS_SB(sb);
struct pts_mount_opts *opts = &fsi->mount_opts;
mutex_lock(&root->d_inode->i_mutex);
/* If we have already created ptmx node, return */
if (fsi->ptmx_dentry) {
rc = 0;
goto out;
}
dentry = d_alloc_name(root, "ptmx");
if (!dentry) {
printk(KERN_NOTICE "Unable to alloc dentry for ptmx node\n");
goto out;
}
/*
* Create a new 'ptmx' node in this mount of devpts.
*/
inode = new_inode(sb);
if (!inode) {
printk(KERN_ERR "Unable to alloc inode for ptmx node\n");
dput(dentry);
goto out;
}
inode->i_ino = 2;
inode->i_uid = inode->i_gid = 0;
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
mode = S_IFCHR|opts->ptmxmode;
init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2));
d_add(dentry, inode);
fsi->ptmx_dentry = dentry;
rc = 0;
printk(KERN_DEBUG "Created ptmx node in devpts ino %lu\n",
inode->i_ino);
out:
mutex_unlock(&root->d_inode->i_mutex);
return rc;
}
static void update_ptmx_mode(struct pts_fs_info *fsi)
{
struct inode *inode;
if (fsi->ptmx_dentry) {
inode = fsi->ptmx_dentry->d_inode;
inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode;
}
}
#else
static inline void update_ptmx_mode(struct pts_fs_info *fsi)
{
return;
}
#endif
static int devpts_remount(struct super_block *sb, int *flags, char *data)
{
int err;
struct pts_fs_info *fsi = DEVPTS_SB(sb);
struct pts_mount_opts *opts = &fsi->mount_opts;
err = parse_mount_options(data, PARSE_REMOUNT, opts);
/*
* parse_mount_options() restores options to default values
* before parsing and may have changed ptmxmode. So, update the
* mode in the inode too. Bogus options don't fail the remount,
* so do this even on error return.
*/
update_ptmx_mode(fsi);
return err;
}
static int devpts_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
if (config.setuid)
seq_printf(seq, ",uid=%u", config.uid);
if (config.setgid)
seq_printf(seq, ",gid=%u", config.gid);
seq_printf(seq, ",mode=%03o", config.mode);
struct pts_fs_info *fsi = DEVPTS_SB(vfs->mnt_sb);
struct pts_mount_opts *opts = &fsi->mount_opts;
if (opts->setuid)
seq_printf(seq, ",uid=%u", opts->uid);
if (opts->setgid)
seq_printf(seq, ",gid=%u", opts->gid);
seq_printf(seq, ",mode=%03o", opts->mode);
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
#endif
return 0;
}
@ -119,6 +265,21 @@ static const struct super_operations devpts_sops = {
.show_options = devpts_show_options,
};
static void *new_pts_fs_info(void)
{
struct pts_fs_info *fsi;
fsi = kzalloc(sizeof(struct pts_fs_info), GFP_KERNEL);
if (!fsi)
return NULL;
ida_init(&fsi->allocated_ptys);
fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
return fsi;
}
static int
devpts_fill_super(struct super_block *s, void *data, int silent)
{
@ -130,9 +291,13 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
s->s_op = &devpts_sops;
s->s_time_gran = 1;
s->s_fs_info = new_pts_fs_info();
if (!s->s_fs_info)
goto fail;
inode = new_inode(s);
if (!inode)
goto fail;
goto free_fsi;
inode->i_ino = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
@ -142,27 +307,226 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
inode->i_fop = &simple_dir_operations;
inode->i_nlink = 2;
devpts_root = s->s_root = d_alloc_root(inode);
s->s_root = d_alloc_root(inode);
if (s->s_root)
return 0;
printk("devpts: get root dentry failed\n");
printk(KERN_ERR "devpts: get root dentry failed\n");
iput(inode);
free_fsi:
kfree(s->s_fs_info);
fail:
return -ENOMEM;
}
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
static int compare_init_pts_sb(struct super_block *s, void *p)
{
if (devpts_mnt)
return devpts_mnt->mnt_sb == s;
return 0;
}
/*
* Safely parse the mount options in @data and update @opts.
*
* devpts ends up parsing options two times during mount, due to the
* two modes of operation it supports. The first parse occurs in
* devpts_get_sb() when determining the mode (single-instance or
* multi-instance mode). The second parse happens in devpts_remount()
* or new_pts_mount() depending on the mode.
*
* Parsing of options modifies the @data making subsequent parsing
* incorrect. So make a local copy of @data and parse it.
*
* Return: 0 On success, -errno on error
*/
static int safe_parse_mount_options(void *data, struct pts_mount_opts *opts)
{
int rc;
void *datacp;
if (!data)
return 0;
/* Use kstrdup() ? */
datacp = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!datacp)
return -ENOMEM;
memcpy(datacp, data, PAGE_SIZE);
rc = parse_mount_options((char *)datacp, PARSE_MOUNT, opts);
kfree(datacp);
return rc;
}
/*
* Mount a new (private) instance of devpts. PTYs created in this
* instance are independent of the PTYs in other devpts instances.
*/
static int new_pts_mount(struct file_system_type *fs_type, int flags,
void *data, struct vfsmount *mnt)
{
int err;
struct pts_fs_info *fsi;
struct pts_mount_opts *opts;
printk(KERN_NOTICE "devpts: newinstance mount\n");
err = get_sb_nodev(fs_type, flags, data, devpts_fill_super, mnt);
if (err)
return err;
fsi = DEVPTS_SB(mnt->mnt_sb);
opts = &fsi->mount_opts;
err = parse_mount_options(data, PARSE_MOUNT, opts);
if (err)
goto fail;
err = mknod_ptmx(mnt->mnt_sb);
if (err)
goto fail;
return 0;
fail:
dput(mnt->mnt_sb->s_root);
deactivate_super(mnt->mnt_sb);
return err;
}
/*
* Check if 'newinstance' mount option was specified in @data.
*
* Return: -errno on error (eg: invalid mount options specified)
* : 1 if 'newinstance' mount option was specified
* : 0 if 'newinstance' mount option was NOT specified
*/
static int is_new_instance_mount(void *data)
{
int rc;
struct pts_mount_opts opts;
if (!data)
return 0;
rc = safe_parse_mount_options(data, &opts);
if (!rc)
rc = opts.newinstance;
return rc;
}
/*
* get_init_pts_sb()
*
* This interface is needed to support multiple namespace semantics in
* devpts while preserving backward compatibility of the current 'single-
* namespace' semantics. i.e all mounts of devpts without the 'newinstance'
* mount option should bind to the initial kernel mount, like
* get_sb_single().
*
* Mounts with 'newinstance' option create a new private namespace.
*
* But for single-mount semantics, devpts cannot use get_sb_single(),
* because get_sb_single()/sget() find and use the super-block from
* the most recent mount of devpts. But that recent mount may be a
* 'newinstance' mount and get_sb_single() would pick the newinstance
* super-block instead of the initial super-block.
*
* This interface is identical to get_sb_single() except that it
* consistently selects the 'single-namespace' superblock even in the
* presence of the private namespace (i.e 'newinstance') super-blocks.
*/
static int get_init_pts_sb(struct file_system_type *fs_type, int flags,
void *data, struct vfsmount *mnt)
{
struct super_block *s;
int error;
s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL);
if (IS_ERR(s))
return PTR_ERR(s);
if (!s->s_root) {
s->s_flags = flags;
error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
if (error) {
up_write(&s->s_umount);
deactivate_super(s);
return error;
}
s->s_flags |= MS_ACTIVE;
}
do_remount_sb(s, flags, data, 0);
return simple_set_mnt(mnt, s);
}
/*
* Mount or remount the initial kernel mount of devpts. This type of
* mount maintains the legacy, single-instance semantics, while the
* kernel still allows multiple-instances.
*/
static int init_pts_mount(struct file_system_type *fs_type, int flags,
void *data, struct vfsmount *mnt)
{
int err;
err = get_init_pts_sb(fs_type, flags, data, mnt);
if (err)
return err;
err = mknod_ptmx(mnt->mnt_sb);
if (err) {
dput(mnt->mnt_sb->s_root);
deactivate_super(mnt->mnt_sb);
}
return err;
}
static int devpts_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
int new;
new = is_new_instance_mount(data);
if (new < 0)
return new;
if (new)
return new_pts_mount(fs_type, flags, data, mnt);
return init_pts_mount(fs_type, flags, data, mnt);
}
#else
/*
* This supports only the legacy single-instance semantics (no
* multiple-instance semantics)
*/
static int devpts_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data, struct vfsmount *mnt)
{
return get_sb_single(fs_type, flags, data, devpts_fill_super, mnt);
}
#endif
static void devpts_kill_sb(struct super_block *sb)
{
struct pts_fs_info *fsi = DEVPTS_SB(sb);
kfree(fsi);
kill_litter_super(sb);
}
static struct file_system_type devpts_fs_type = {
.owner = THIS_MODULE,
.name = "devpts",
.get_sb = devpts_get_sb,
.kill_sb = kill_anon_super,
.kill_sb = devpts_kill_sb,
};
/*
@ -172,16 +536,17 @@ static struct file_system_type devpts_fs_type = {
int devpts_new_index(struct inode *ptmx_inode)
{
struct super_block *sb = pts_sb_from_inode(ptmx_inode);
struct pts_fs_info *fsi = DEVPTS_SB(sb);
int index;
int ida_ret;
retry:
if (!ida_pre_get(&allocated_ptys, GFP_KERNEL)) {
if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
return -ENOMEM;
}
mutex_lock(&allocated_ptys_lock);
ida_ret = ida_get_new(&allocated_ptys, &index);
ida_ret = ida_get_new(&fsi->allocated_ptys, &index);
if (ida_ret < 0) {
mutex_unlock(&allocated_ptys_lock);
if (ida_ret == -EAGAIN)
@ -190,7 +555,7 @@ retry:
}
if (index >= pty_limit) {
ida_remove(&allocated_ptys, index);
ida_remove(&fsi->allocated_ptys, index);
mutex_unlock(&allocated_ptys_lock);
return -EIO;
}
@ -200,18 +565,26 @@ retry:
void devpts_kill_index(struct inode *ptmx_inode, int idx)
{
struct super_block *sb = pts_sb_from_inode(ptmx_inode);
struct pts_fs_info *fsi = DEVPTS_SB(sb);
mutex_lock(&allocated_ptys_lock);
ida_remove(&allocated_ptys, idx);
ida_remove(&fsi->allocated_ptys, idx);
mutex_unlock(&allocated_ptys_lock);
}
int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
{
int number = tty->index; /* tty layer puts index from devpts_new_index() in here */
/* tty layer puts index from devpts_new_index() in here */
int number = tty->index;
struct tty_driver *driver = tty->driver;
dev_t device = MKDEV(driver->major, driver->minor_start+number);
struct dentry *dentry;
struct inode *inode = new_inode(devpts_mnt->mnt_sb);
struct super_block *sb = pts_sb_from_inode(ptmx_inode);
struct inode *inode = new_inode(sb);
struct dentry *root = sb->s_root;
struct pts_fs_info *fsi = DEVPTS_SB(sb);
struct pts_mount_opts *opts = &fsi->mount_opts;
char s[12];
/* We're supposed to be given the slave end of a pty */
@ -221,25 +594,25 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
if (!inode)
return -ENOMEM;
inode->i_ino = number+2;
inode->i_uid = config.setuid ? config.uid : current_fsuid();
inode->i_gid = config.setgid ? config.gid : current_fsgid();
inode->i_ino = number + 3;
inode->i_uid = opts->setuid ? opts->uid : current_fsuid();
inode->i_gid = opts->setgid ? opts->gid : current_fsgid();
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
init_special_inode(inode, S_IFCHR|config.mode, device);
init_special_inode(inode, S_IFCHR|opts->mode, device);
inode->i_private = tty;
tty->driver_data = inode;
sprintf(s, "%d", number);
mutex_lock(&devpts_root->d_inode->i_mutex);
mutex_lock(&root->d_inode->i_mutex);
dentry = d_alloc_name(devpts_root, s);
dentry = d_alloc_name(root, s);
if (!IS_ERR(dentry)) {
d_add(dentry, inode);
fsnotify_create(devpts_root->d_inode, dentry);
fsnotify_create(root->d_inode, dentry);
}
mutex_unlock(&devpts_root->d_inode->i_mutex);
mutex_unlock(&root->d_inode->i_mutex);
return 0;
}
@ -256,20 +629,27 @@ struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
void devpts_pty_kill(struct tty_struct *tty)
{
struct inode *inode = tty->driver_data;
struct super_block *sb = pts_sb_from_inode(inode);
struct dentry *root = sb->s_root;
struct dentry *dentry;
BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
mutex_lock(&devpts_root->d_inode->i_mutex);
mutex_lock(&root->d_inode->i_mutex);
dentry = d_find_alias(inode);
if (dentry && !IS_ERR(dentry)) {
if (IS_ERR(dentry))
goto out;
if (dentry) {
inode->i_nlink--;
d_delete(dentry);
dput(dentry);
dput(dentry); /* d_alloc_name() in devpts_pty_new() */
}
mutex_unlock(&devpts_root->d_inode->i_mutex);
dput(dentry); /* d_find_alias above */
out:
mutex_unlock(&root->d_inode->i_mutex);
}
static int __init init_devpts_fs(void)

View File

@ -31,7 +31,7 @@ struct pciserial_board {
struct serial_private;
struct serial_private *
pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board);
pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board);
void pciserial_remove_ports(struct serial_private *priv);
void pciserial_suspend_ports(struct serial_private *priv);
void pciserial_resume_ports(struct serial_private *priv);

View File

@ -21,7 +21,6 @@ struct real_driver {
void (*enable_tx_interrupts) (void *);
void (*disable_rx_interrupts) (void *);
void (*enable_rx_interrupts) (void *);
int (*get_CD) (void *);
void (*shutdown_port) (void*);
int (*set_real_termios) (void*);
int (*chars_in_buffer) (void*);

View File

@ -59,9 +59,7 @@ struct stliport {
unsigned int devnr;
int baud_base;
int custom_divisor;
int close_delay;
int closing_wait;
int openwaitcnt;
int rc;
int argsize;
void *argp;

View File

@ -1766,6 +1766,7 @@
#define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081
#define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082
#define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050
#define PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL 0x2530
#define PCI_VENDOR_ID_RADISYS 0x1331
@ -1795,6 +1796,7 @@
#define PCI_DEVICE_ID_SEALEVEL_UCOMM232 0x7202
#define PCI_DEVICE_ID_SEALEVEL_COMM4 0x7401
#define PCI_DEVICE_ID_SEALEVEL_COMM8 0x7801
#define PCI_DEVICE_ID_SEALEVEL_7803 0x7803
#define PCI_DEVICE_ID_SEALEVEL_UCOMM8 0x7804
#define PCI_VENDOR_ID_HYPERCOPE 0x1365

View File

@ -10,8 +10,9 @@
#ifndef _LINUX_SERIAL_H
#define _LINUX_SERIAL_H
#ifdef __KERNEL__
#include <linux/types.h>
#ifdef __KERNEL__
#include <asm/page.h>
/*

View File

@ -28,6 +28,9 @@ struct plat_serial8250_port {
unsigned char iotype; /* UPIO_* */
unsigned char hub6;
upf_t flags; /* UPF_* flags */
unsigned int type; /* If UPF_FIXED_TYPE */
unsigned int (*serial_in)(struct uart_port *, int);
void (*serial_out)(struct uart_port *, int, int);
};
/*

View File

@ -40,7 +40,8 @@
#define PORT_NS16550A 14
#define PORT_XSCALE 15
#define PORT_RM9000 16 /* PMC-Sierra RM9xxx internal UART */
#define PORT_MAX_8250 16 /* max port ID */
#define PORT_OCTEON 17 /* Cavium OCTEON internal UART */
#define PORT_MAX_8250 17 /* max port ID */
/*
* ARM specific type numbers. These are not currently guaranteed
@ -248,6 +249,8 @@ struct uart_port {
spinlock_t lock; /* port lock */
unsigned long iobase; /* in/out[bwl] */
unsigned char __iomem *membase; /* read/write[bwl] */
unsigned int (*serial_in)(struct uart_port *, int);
void (*serial_out)(struct uart_port *, int, int);
unsigned int irq; /* irq number */
unsigned int uartclk; /* base uart clock */
unsigned int fifosize; /* tx fifo size */
@ -293,6 +296,8 @@ struct uart_port {
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
#define UPF_SHARE_IRQ ((__force upf_t) (1 << 24))
/* The exact UART type is known and should not be probed. */
#define UPF_FIXED_TYPE ((__force upf_t) (1 << 27))
#define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28))
#define UPF_FIXED_PORT ((__force upf_t) (1 << 29))
#define UPF_DEAD ((__force upf_t) (1 << 30))
@ -315,36 +320,14 @@ struct uart_port {
void *private_data; /* generic platform data pointer */
};
/*
* This is the state information which is persistent across opens.
* The low level driver must not to touch any elements contained
* within.
*/
struct uart_state {
unsigned int close_delay; /* msec */
unsigned int closing_wait; /* msec */
#define USF_CLOSING_WAIT_INF (0)
#define USF_CLOSING_WAIT_NONE (~0U)
int count;
int pm_state;
struct uart_info *info;
struct uart_port *port;
struct mutex mutex;
};
#define UART_XMIT_SIZE PAGE_SIZE
typedef unsigned int __bitwise__ uif_t;
/*
* This is the state information which is only valid when the port
* is open; it may be freed by the core driver once the device has
* is open; it may be cleared the core driver once the device has
* been closed. Either the low level driver or the core can modify
* stuff here.
*/
typedef unsigned int __bitwise__ uif_t;
struct uart_info {
struct tty_port port;
struct circ_buf xmit;
@ -366,6 +349,29 @@ struct uart_info {
wait_queue_head_t delta_msr_wait;
};
/*
* This is the state information which is persistent across opens.
* The low level driver must not to touch any elements contained
* within.
*/
struct uart_state {
unsigned int close_delay; /* msec */
unsigned int closing_wait; /* msec */
#define USF_CLOSING_WAIT_INF (0)
#define USF_CLOSING_WAIT_NONE (~0U)
int count;
int pm_state;
struct uart_info info;
struct uart_port *port;
struct mutex mutex;
};
#define UART_XMIT_SIZE PAGE_SIZE
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
@ -439,8 +445,13 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port);
#define uart_circ_chars_free(circ) \
(CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
#define uart_tx_stopped(portp) \
((portp)->info->port.tty->stopped || (portp)->info->port.tty->hw_stopped)
static inline int uart_tx_stopped(struct uart_port *port)
{
struct tty_struct *tty = port->info->port.tty;
if(tty->stopped || tty->hw_stopped)
return 1;
return 0;
}
/*
* The following are helper functions for the low level drivers.
@ -451,7 +462,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
#ifdef SUPPORT_SYSRQ
if (port->sysrq) {
if (ch && time_before(jiffies, port->sysrq)) {
handle_sysrq(ch, port->info ? port->info->port.tty : NULL);
handle_sysrq(ch, port->info->port.tty);
port->sysrq = 0;
return 1;
}

View File

@ -180,8 +180,17 @@ struct signal_struct;
* until a hangup so don't use the wrong path.
*/
struct tty_port;
struct tty_port_operations {
/* Return 1 if the carrier is raised */
int (*carrier_raised)(struct tty_port *port);
void (*raise_dtr_rts)(struct tty_port *port);
};
struct tty_port {
struct tty_struct *tty; /* Back pointer */
const struct tty_port_operations *ops; /* Port operations */
spinlock_t lock; /* Lock protecting tty field */
int blocked_open; /* Waiting to open */
int count; /* Usage count */
@ -253,6 +262,7 @@ struct tty_struct {
unsigned int column;
unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
unsigned char closing:1;
unsigned char echo_overrun:1;
unsigned short minimum_to_wake;
unsigned long overrun_time;
int num_overrun;
@ -262,11 +272,16 @@ struct tty_struct {
int read_tail;
int read_cnt;
unsigned long read_flags[N_TTY_BUF_SIZE/(8*sizeof(unsigned long))];
unsigned char *echo_buf;
unsigned int echo_pos;
unsigned int echo_cnt;
int canon_data;
unsigned long canon_head;
unsigned int canon_column;
struct mutex atomic_read_lock;
struct mutex atomic_write_lock;
struct mutex output_lock;
struct mutex echo_lock;
unsigned char *write_buf;
int write_cnt;
spinlock_t read_lock;
@ -295,6 +310,7 @@ struct tty_struct {
#define TTY_PUSH 6 /* n_tty private */
#define TTY_CLOSING 7 /* ->close() in progress */
#define TTY_LDISC 9 /* Line discipline attached */
#define TTY_LDISC_CHANGING 10 /* Line discipline changing */
#define TTY_HW_COOK_OUT 14 /* Hardware can do output cooking */
#define TTY_HW_COOK_IN 15 /* Hardware can do input cooking */
#define TTY_PTY_LOCK 16 /* pty private */
@ -354,8 +370,7 @@ extern int tty_write_room(struct tty_struct *tty);
extern void tty_driver_flush_buffer(struct tty_struct *tty);
extern void tty_throttle(struct tty_struct *tty);
extern void tty_unthrottle(struct tty_struct *tty);
extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize *ws);
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
extern void tty_shutdown(struct tty_struct *tty);
extern void tty_free_termios(struct tty_struct *tty);
extern int is_current_pgrp_orphaned(void);
@ -421,6 +436,14 @@ extern int tty_port_alloc_xmit_buf(struct tty_port *port);
extern void tty_port_free_xmit_buf(struct tty_port *port);
extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
extern int tty_port_carrier_raised(struct tty_port *port);
extern void tty_port_raise_dtr_rts(struct tty_port *port);
extern void tty_port_hangup(struct tty_port *port);
extern int tty_port_block_til_ready(struct tty_port *port,
struct tty_struct *tty, struct file *filp);
extern int tty_port_close_start(struct tty_port *port,
struct tty_struct *tty, struct file *filp);
extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
extern int tty_unregister_ldisc(int disc);

View File

@ -196,8 +196,7 @@
* Optional: If not provided then the write method is called under
* the atomic write lock to keep it serialized with the ldisc.
*
* int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
* unsigned int rows, unsigned int cols);
* int (*resize)(struct tty_struct *tty, struct winsize *ws)
*
* Called when a termios request is issued which changes the
* requested terminal geometry.
@ -258,8 +257,7 @@ struct tty_operations {
int (*tiocmget)(struct tty_struct *tty, struct file *file);
int (*tiocmset)(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize *ws);
int (*resize)(struct tty_struct *tty, struct winsize *ws);
int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
#ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct tty_driver *driver, int line, char *options);

View File

@ -371,9 +371,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
IRDA_DEBUG(2, "%s()\n", __func__ );
line = tty->index;
if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) {
if (line >= IRCOMM_TTY_PORTS)
return -ENODEV;
}
/* Check if instance already exists */
self = hashbin_lock_find(ircomm_tty, line, NULL);
@ -405,6 +404,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
* Force TTY into raw mode by default which is usually what
* we want for IrCOMM and IrLPT. This way applications will
* not have to twiddle with printcap etc.
*
* Note this is completely usafe and doesn't work properly
*/
tty->termios->c_iflag = 0;
tty->termios->c_oflag = 0;