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:
commit
d2fde28ce7
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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 = {
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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); /* */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
/*****************************************************************************/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
#ifndef _LINUX_SERIAL_H
|
||||
#define _LINUX_SERIAL_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <asm/page.h>
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue