mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-04-01 11:54:10 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6: (58 commits) tty: split the lock up a bit further tty: Move the leader test in disassociate tty: Push the bkl down a bit in the hangup code tty: Push the lock down further into the ldisc code tty: push the BKL down into the handlers a bit tty: moxa: split open lock tty: moxa: Kill the use of lock_kernel tty: moxa: Fix modem op locking tty: moxa: Kill off the throttle method tty: moxa: Locking clean up tty: moxa: rework the locking a bit tty: moxa: Use more tty_port ops tty: isicom: fix deadlock on shutdown tty: mxser: Use the new locking rules to fix setserial properly tty: mxser: use the tty_port_open method tty: isicom: sort out the board init logic tty: isicom: switch to the new tty_port_open helper tty: tty_port: Add a kref object to the tty port tty: istallion: tty port open/close methods tty: stallion: Convert to the tty_port_open/close methods ...
This commit is contained in:
commit
0f4974c439
36 changed files with 929 additions and 3828 deletions
|
@ -1,154 +0,0 @@
|
||||||
HAYES ESP DRIVER VERSION 2.1
|
|
||||||
|
|
||||||
A big thanks to the people at Hayes, especially Alan Adamson. Their support
|
|
||||||
has enabled me to provide enhancements to the driver.
|
|
||||||
|
|
||||||
Please report your experiences with this driver to me (arobinso@nyx.net). I
|
|
||||||
am looking for both positive and negative feedback.
|
|
||||||
|
|
||||||
*** IMPORTANT CHANGES FOR 2.1 ***
|
|
||||||
Support for PIO mode. Five situations will cause PIO mode to be used:
|
|
||||||
1) A multiport card is detected. PIO mode will always be used. (8 port cards
|
|
||||||
do not support DMA).
|
|
||||||
2) The DMA channel is set to an invalid value (anything other than 1 or 3).
|
|
||||||
3) The DMA buffer/channel could not be allocated. The port will revert to PIO
|
|
||||||
mode until it is reopened.
|
|
||||||
4) Less than a specified number of bytes need to be transferred to/from the
|
|
||||||
FIFOs. PIO mode will be used for that transfer only.
|
|
||||||
5) A port needs to do a DMA transfer and another port is already using the
|
|
||||||
DMA channel. PIO mode will be used for that transfer only.
|
|
||||||
|
|
||||||
Since the Hayes ESP seems to conflict with other cards (notably sound cards)
|
|
||||||
when using DMA, DMA is turned off by default. To use DMA, it must be turned
|
|
||||||
on explicitly, either with the "dma=" option described below or with
|
|
||||||
setserial. A multiport card can be forced into DMA mode by using setserial;
|
|
||||||
however, most multiport cards don't support DMA.
|
|
||||||
|
|
||||||
The latest version of setserial allows the enhanced configuration of the ESP
|
|
||||||
card to be viewed and modified.
|
|
||||||
***
|
|
||||||
|
|
||||||
This package contains the files needed to compile a module to support the Hayes
|
|
||||||
ESP card. The drivers are basically a modified version of the serial drivers.
|
|
||||||
|
|
||||||
Features:
|
|
||||||
|
|
||||||
- Uses the enhanced mode of the ESP card, allowing a wider range of
|
|
||||||
interrupts and features than compatibility mode
|
|
||||||
- Uses DMA and 16 bit PIO mode to transfer data to and from the ESP's FIFOs,
|
|
||||||
reducing CPU load
|
|
||||||
- Supports primary and secondary ports
|
|
||||||
|
|
||||||
|
|
||||||
If the driver is compiled as a module, the IRQs to use can be specified by
|
|
||||||
using the irq= option. The format is:
|
|
||||||
|
|
||||||
irq=[0x100],[0x140],[0x180],[0x200],[0x240],[0x280],[0x300],[0x380]
|
|
||||||
|
|
||||||
The address in brackets is the base address of the card. The IRQ of
|
|
||||||
nonexistent cards can be set to 0. If an IRQ of a card that does exist is set
|
|
||||||
to 0, the driver will attempt to guess at the correct IRQ. For example, to set
|
|
||||||
the IRQ of the card at address 0x300 to 12, the insmod command would be:
|
|
||||||
|
|
||||||
insmod esp irq=0,0,0,0,0,0,12,0
|
|
||||||
|
|
||||||
The custom divisor can be set by using the divisor= option. The format is the
|
|
||||||
same as for the irq= option. Each divisor value is a series of hex digits,
|
|
||||||
with each digit representing the divisor to use for a corresponding port. The
|
|
||||||
divisor value is constructed RIGHT TO LEFT. Specifying a nonzero divisor value
|
|
||||||
will automatically set the spd_cust flag. To calculate the divisor to use for
|
|
||||||
a certain baud rate, divide the port's base baud (generally 921600) by the
|
|
||||||
desired rate. For example, to set the divisor of the primary port at 0x300 to
|
|
||||||
4 and the divisor of the secondary port at 0x308 to 8, the insmod command would
|
|
||||||
be:
|
|
||||||
|
|
||||||
insmod esp divisor=0,0,0,0,0,0,0x84,0
|
|
||||||
|
|
||||||
The dma= option can be used to set the DMA channel. The channel can be either
|
|
||||||
1 or 3. Specifying any other value will force the driver to use PIO mode.
|
|
||||||
For example, to set the DMA channel to 3, the insmod command would be:
|
|
||||||
|
|
||||||
insmod esp dma=3
|
|
||||||
|
|
||||||
The rx_trigger= and tx_trigger= options can be used to set the FIFO trigger
|
|
||||||
levels. They specify when the ESP card should send an interrupt. Larger
|
|
||||||
values will decrease the number of interrupts; however, a value too high may
|
|
||||||
result in data loss. Valid values are 1 through 1023, with 768 being the
|
|
||||||
default. For example, to set the receive trigger level to 512 bytes and the
|
|
||||||
transmit trigger level to 700 bytes, the insmod command would be:
|
|
||||||
|
|
||||||
insmod esp rx_trigger=512 tx_trigger=700
|
|
||||||
|
|
||||||
The flow_off= and flow_on= options can be used to set the hardware flow off/
|
|
||||||
flow on levels. The flow on level must be lower than the flow off level, and
|
|
||||||
the flow off level should be higher than rx_trigger. Valid values are 1
|
|
||||||
through 1023, with 1016 being the default flow off level and 944 being the
|
|
||||||
default flow on level. For example, to set the flow off level to 1000 bytes
|
|
||||||
and the flow on level to 935 bytes, the insmod command would be:
|
|
||||||
|
|
||||||
insmod esp flow_off=1000 flow_on=935
|
|
||||||
|
|
||||||
The rx_timeout= option can be used to set the receive timeout value. This
|
|
||||||
value indicates how long after receiving the last character that the ESP card
|
|
||||||
should wait before signalling an interrupt. Valid values are 0 though 255,
|
|
||||||
with 128 being the default. A value too high will increase latency, and a
|
|
||||||
value too low will cause unnecessary interrupts. For example, to set the
|
|
||||||
receive timeout to 255, the insmod command would be:
|
|
||||||
|
|
||||||
insmod esp rx_timeout=255
|
|
||||||
|
|
||||||
The pio_threshold= option sets the threshold (in number of characters) for
|
|
||||||
using PIO mode instead of DMA mode. For example, if this value is 32,
|
|
||||||
transfers of 32 bytes or less will always use PIO mode.
|
|
||||||
|
|
||||||
insmod esp pio_threshold=32
|
|
||||||
|
|
||||||
Multiple options can be listed on the insmod command line by separating each
|
|
||||||
option with a space. For example:
|
|
||||||
|
|
||||||
insmod esp dma=3 trigger=512
|
|
||||||
|
|
||||||
The esp module can be automatically loaded when needed. To cause this to
|
|
||||||
happen, add the following lines to /etc/modprobe.conf (replacing the last line
|
|
||||||
with options for your configuration):
|
|
||||||
|
|
||||||
alias char-major-57 esp
|
|
||||||
alias char-major-58 esp
|
|
||||||
options esp irq=0,0,0,0,0,0,3,0 divisor=0,0,0,0,0,0,0x4,0
|
|
||||||
|
|
||||||
You may also need to run 'depmod -a'.
|
|
||||||
|
|
||||||
Devices must be created manually. To create the devices, note the output from
|
|
||||||
the module after it is inserted. The output will appear in the location where
|
|
||||||
kernel messages usually appear (usually /var/adm/messages). Create two devices
|
|
||||||
for each 'tty' mentioned, one with major of 57 and the other with major of 58.
|
|
||||||
The minor number should be the same as the tty number reported. The commands
|
|
||||||
would be (replace ? with the tty number):
|
|
||||||
|
|
||||||
mknod /dev/ttyP? c 57 ?
|
|
||||||
mknod /dev/cup? c 58 ?
|
|
||||||
|
|
||||||
For example, if the following line appears:
|
|
||||||
|
|
||||||
Oct 24 18:17:23 techno kernel: ttyP8 at 0x0140 (irq = 3) is an ESP primary port
|
|
||||||
|
|
||||||
...two devices should be created:
|
|
||||||
|
|
||||||
mknod /dev/ttyP8 c 57 8
|
|
||||||
mknod /dev/cup8 c 58 8
|
|
||||||
|
|
||||||
You may need to set the permissions on the devices:
|
|
||||||
|
|
||||||
chmod 666 /dev/ttyP*
|
|
||||||
chmod 666 /dev/cup*
|
|
||||||
|
|
||||||
The ESP module and the serial module should not conflict (they can be used at
|
|
||||||
the same time). After the ESP module has been loaded the ports on the ESP card
|
|
||||||
will no longer be accessible by the serial driver.
|
|
||||||
|
|
||||||
If I/O errors are experienced when accessing the port, check for IRQ and DMA
|
|
||||||
conflicts ('cat /proc/interrupts' and 'cat /proc/dma' for a list of IRQs and
|
|
||||||
DMAs currently in use).
|
|
||||||
|
|
||||||
Enjoy!
|
|
||||||
Andrew J. Robinson <arobinso@nyx.net>
|
|
|
@ -42,7 +42,8 @@ TTY side interfaces:
|
||||||
open() - Called when the line discipline is attached to
|
open() - Called when the line discipline is attached to
|
||||||
the terminal. No other call into the line
|
the terminal. No other call into the line
|
||||||
discipline for this tty will occur until it
|
discipline for this tty will occur until it
|
||||||
completes successfully. Can sleep.
|
completes successfully. Returning an error will
|
||||||
|
prevent the ldisc from being attached. Can sleep.
|
||||||
|
|
||||||
close() - This is called on a terminal when the line
|
close() - This is called on a terminal when the line
|
||||||
discipline is being unplugged. At the point of
|
discipline is being unplugged. At the point of
|
||||||
|
@ -52,7 +53,7 @@ close() - This is called on a terminal when the line
|
||||||
hangup() - Called when the tty line is hung up.
|
hangup() - Called when the tty line is hung up.
|
||||||
The line discipline should cease I/O to the tty.
|
The line discipline should cease I/O to the tty.
|
||||||
No further calls into the ldisc code will occur.
|
No further calls into the ldisc code will occur.
|
||||||
Can sleep.
|
The return value is ignored. Can sleep.
|
||||||
|
|
||||||
write() - A process is writing data through the line
|
write() - A process is writing data through the line
|
||||||
discipline. Multiple write calls are serialized
|
discipline. Multiple write calls are serialized
|
||||||
|
@ -83,6 +84,10 @@ ioctl() - Called when an ioctl is handed to the tty layer
|
||||||
that might be for the ldisc. Multiple ioctl calls
|
that might be for the ldisc. Multiple ioctl calls
|
||||||
may occur in parallel. May sleep.
|
may occur in parallel. May sleep.
|
||||||
|
|
||||||
|
compat_ioctl() - Called when a 32 bit ioctl is handed to the tty layer
|
||||||
|
that might be for the ldisc. Multiple ioctl calls
|
||||||
|
may occur in parallel. May sleep.
|
||||||
|
|
||||||
Driver Side Interfaces:
|
Driver Side Interfaces:
|
||||||
|
|
||||||
receive_buf() - Hand buffers of bytes from the driver to the ldisc
|
receive_buf() - Hand buffers of bytes from the driver to the ldisc
|
||||||
|
|
|
@ -196,7 +196,7 @@ static const struct file_operations rs_proc_fops = {
|
||||||
.release = single_release,
|
.release = single_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct tty_operations serial_ops = {
|
static const struct tty_operations serial_ops = {
|
||||||
.open = rs_open,
|
.open = rs_open,
|
||||||
.close = rs_close,
|
.close = rs_close,
|
||||||
.write = rs_write,
|
.write = rs_write,
|
||||||
|
|
|
@ -201,19 +201,6 @@ config DIGIEPCA
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called epca.
|
module will be called epca.
|
||||||
|
|
||||||
config ESPSERIAL
|
|
||||||
tristate "Hayes ESP serial port support"
|
|
||||||
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
|
|
||||||
<file:Documentation/hayes-esp.txt>.
|
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
|
||||||
module will be called esp.
|
|
||||||
|
|
||||||
If unsure, say N.
|
|
||||||
|
|
||||||
config MOXA_INTELLIO
|
config MOXA_INTELLIO
|
||||||
tristate "Moxa Intellio support"
|
tristate "Moxa Intellio support"
|
||||||
depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
|
depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
|
||||||
|
|
|
@ -18,7 +18,6 @@ obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
|
||||||
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
|
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
|
||||||
obj-$(CONFIG_AUDIT) += tty_audit.o
|
obj-$(CONFIG_AUDIT) += tty_audit.o
|
||||||
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
|
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
|
||||||
obj-$(CONFIG_ESPSERIAL) += esp.o
|
|
||||||
obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o
|
obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o
|
||||||
obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o
|
obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o
|
||||||
obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
|
obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
|
||||||
|
|
|
@ -226,7 +226,7 @@ bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct tty_operations bfin_jc_ops = {
|
static const struct tty_operations bfin_jc_ops = {
|
||||||
.open = bfin_jc_open,
|
.open = bfin_jc_open,
|
||||||
.close = bfin_jc_close,
|
.close = bfin_jc_close,
|
||||||
.write = bfin_jc_write,
|
.write = bfin_jc_write,
|
||||||
|
|
|
@ -935,7 +935,7 @@ static int info_open(struct tty_struct *tty, struct file *filp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct tty_operations info_ops = {
|
static const struct tty_operations info_ops = {
|
||||||
.open = info_open,
|
.open = info_open,
|
||||||
.ioctl = info_ioctl,
|
.ioctl = info_ioctl,
|
||||||
};
|
};
|
||||||
|
|
2533
drivers/char/esp.c
2533
drivers/char/esp.c
File diff suppressed because it is too large
Load diff
|
@ -793,35 +793,30 @@ static inline void isicom_setup_board(struct isi_board *bp)
|
||||||
{
|
{
|
||||||
int channel;
|
int channel;
|
||||||
struct isi_port *port;
|
struct isi_port *port;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&bp->card_lock, flags);
|
bp->count++;
|
||||||
if (bp->status & BOARD_ACTIVE) {
|
if (!(bp->status & BOARD_INIT)) {
|
||||||
spin_unlock_irqrestore(&bp->card_lock, flags);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
port = bp->ports;
|
port = bp->ports;
|
||||||
bp->status |= BOARD_ACTIVE;
|
|
||||||
for (channel = 0; channel < bp->port_count; channel++, port++)
|
for (channel = 0; channel < bp->port_count; channel++, port++)
|
||||||
drop_dtr_rts(port);
|
drop_dtr_rts(port);
|
||||||
spin_unlock_irqrestore(&bp->card_lock, flags);
|
}
|
||||||
|
bp->status |= BOARD_ACTIVE | BOARD_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int isicom_setup_port(struct tty_struct *tty)
|
/* Activate and thus setup board are protected from races against shutdown
|
||||||
|
by the tty_port mutex */
|
||||||
|
|
||||||
|
static int isicom_activate(struct tty_port *tport, struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct isi_port *port = tty->driver_data;
|
struct isi_port *port = container_of(tport, struct isi_port, port);
|
||||||
struct isi_board *card = port->card;
|
struct isi_board *card = port->card;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (port->port.flags & ASYNC_INITIALIZED)
|
if (tty_port_alloc_xmit_buf(tport) < 0)
|
||||||
return 0;
|
|
||||||
if (tty_port_alloc_xmit_buf(&port->port) < 0)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_irqsave(&card->card_lock, flags);
|
spin_lock_irqsave(&card->card_lock, flags);
|
||||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
isicom_setup_board(card);
|
||||||
if (port->port.count == 1)
|
|
||||||
card->count++;
|
|
||||||
|
|
||||||
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
|
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
|
||||||
|
|
||||||
|
@ -832,9 +827,7 @@ static int isicom_setup_port(struct tty_struct *tty)
|
||||||
outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
|
outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
|
||||||
InterruptTheCard(card->base);
|
InterruptTheCard(card->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
isicom_config_port(tty);
|
isicom_config_port(tty);
|
||||||
port->port.flags |= ASYNC_INITIALIZED;
|
|
||||||
spin_unlock_irqrestore(&card->card_lock, flags);
|
spin_unlock_irqrestore(&card->card_lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -877,79 +870,31 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
|
||||||
struct isi_port *port;
|
struct isi_port *port;
|
||||||
struct isi_board *card;
|
struct isi_board *card;
|
||||||
struct tty_port *tport;
|
struct tty_port *tport;
|
||||||
int error = 0;
|
|
||||||
|
|
||||||
tport = isicom_find_port(tty);
|
tport = isicom_find_port(tty);
|
||||||
if (tport == NULL)
|
if (tport == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
port = container_of(tport, struct isi_port, port);
|
port = container_of(tport, struct isi_port, port);
|
||||||
card = &isi_card[BOARD(tty->index)];
|
card = &isi_card[BOARD(tty->index)];
|
||||||
isicom_setup_board(card);
|
|
||||||
|
|
||||||
/* FIXME: locking on port.count etc */
|
return tty_port_open(tport, tty, filp);
|
||||||
port->port.count++;
|
|
||||||
tty->driver_data = port;
|
|
||||||
tty_port_tty_set(&port->port, tty);
|
|
||||||
/* FIXME: Locking on Initialized flag */
|
|
||||||
if (!test_bit(ASYNCB_INITIALIZED, &tport->flags))
|
|
||||||
error = isicom_setup_port(tty);
|
|
||||||
if (error == 0)
|
|
||||||
error = tty_port_block_til_ready(&port->port, tty, filp);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* close et all */
|
/* close et all */
|
||||||
|
|
||||||
static inline void isicom_shutdown_board(struct isi_board *bp)
|
|
||||||
{
|
|
||||||
if (bp->status & BOARD_ACTIVE)
|
|
||||||
bp->status &= ~BOARD_ACTIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* card->lock HAS to be held */
|
/* card->lock HAS to be held */
|
||||||
static void isicom_shutdown_port(struct isi_port *port)
|
static void isicom_shutdown_port(struct isi_port *port)
|
||||||
{
|
{
|
||||||
struct isi_board *card = port->card;
|
struct isi_board *card = port->card;
|
||||||
struct tty_struct *tty;
|
|
||||||
|
|
||||||
tty = tty_port_tty_get(&port->port);
|
|
||||||
|
|
||||||
if (!(port->port.flags & ASYNC_INITIALIZED)) {
|
|
||||||
tty_kref_put(tty);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tty_port_free_xmit_buf(&port->port);
|
|
||||||
port->port.flags &= ~ASYNC_INITIALIZED;
|
|
||||||
/* 3rd October 2000 : Vinayak P Risbud */
|
|
||||||
tty_port_tty_set(&port->port, NULL);
|
|
||||||
|
|
||||||
/*Fix done by Anil .S on 30-04-2001
|
|
||||||
remote login through isi port has dtr toggle problem
|
|
||||||
due to which the carrier drops before the password prompt
|
|
||||||
appears on the remote end. Now we drop the dtr only if the
|
|
||||||
HUPCL(Hangup on close) flag is set for the tty*/
|
|
||||||
|
|
||||||
if (C_HUPCL(tty))
|
|
||||||
/* drop dtr on this port */
|
|
||||||
drop_dtr(port);
|
|
||||||
|
|
||||||
/* any other port uninits */
|
|
||||||
if (tty)
|
|
||||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
|
||||||
|
|
||||||
if (--card->count < 0) {
|
if (--card->count < 0) {
|
||||||
pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
|
pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
|
||||||
card->base, card->count);
|
card->base, card->count);
|
||||||
card->count = 0;
|
card->count = 0;
|
||||||
}
|
}
|
||||||
|
/* last port was closed, shutdown that board too */
|
||||||
/* last port was closed, shutdown that boad too */
|
|
||||||
if (C_HUPCL(tty)) {
|
|
||||||
if (!card->count)
|
if (!card->count)
|
||||||
isicom_shutdown_board(card);
|
card->status &= BOARD_ACTIVE;
|
||||||
}
|
|
||||||
tty_kref_put(tty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void isicom_flush_buffer(struct tty_struct *tty)
|
static void isicom_flush_buffer(struct tty_struct *tty)
|
||||||
|
@ -968,7 +913,7 @@ static void isicom_flush_buffer(struct tty_struct *tty)
|
||||||
tty_wakeup(tty);
|
tty_wakeup(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void isicom_close_port(struct tty_port *port)
|
static void isicom_shutdown(struct tty_port *port)
|
||||||
{
|
{
|
||||||
struct isi_port *ip = container_of(port, struct isi_port, port);
|
struct isi_port *ip = container_of(port, struct isi_port, port);
|
||||||
struct isi_board *card = ip->card;
|
struct isi_board *card = ip->card;
|
||||||
|
@ -977,12 +922,11 @@ static void isicom_close_port(struct tty_port *port)
|
||||||
/* indicate to the card that no more data can be received
|
/* indicate to the card that no more data can be received
|
||||||
on this port */
|
on this port */
|
||||||
spin_lock_irqsave(&card->card_lock, flags);
|
spin_lock_irqsave(&card->card_lock, flags);
|
||||||
if (port->flags & ASYNC_INITIALIZED) {
|
|
||||||
card->port_status &= ~(1 << ip->channel);
|
card->port_status &= ~(1 << ip->channel);
|
||||||
outw(card->port_status, card->base + 0x02);
|
outw(card->port_status, card->base + 0x02);
|
||||||
}
|
|
||||||
isicom_shutdown_port(ip);
|
isicom_shutdown_port(ip);
|
||||||
spin_unlock_irqrestore(&card->card_lock, flags);
|
spin_unlock_irqrestore(&card->card_lock, flags);
|
||||||
|
tty_port_free_xmit_buf(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void isicom_close(struct tty_struct *tty, struct file *filp)
|
static void isicom_close(struct tty_struct *tty, struct file *filp)
|
||||||
|
@ -991,12 +935,7 @@ static void isicom_close(struct tty_struct *tty, struct file *filp)
|
||||||
struct tty_port *port = &ip->port;
|
struct tty_port *port = &ip->port;
|
||||||
if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
|
if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
|
||||||
return;
|
return;
|
||||||
|
tty_port_close(port, tty, filp);
|
||||||
if (tty_port_close_start(port, tty, filp) == 0)
|
|
||||||
return;
|
|
||||||
isicom_close_port(port);
|
|
||||||
isicom_flush_buffer(tty);
|
|
||||||
tty_port_close_end(port, tty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write et all */
|
/* write et all */
|
||||||
|
@ -1326,15 +1265,9 @@ static void isicom_start(struct tty_struct *tty)
|
||||||
static void isicom_hangup(struct tty_struct *tty)
|
static void isicom_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct isi_port *port = tty->driver_data;
|
struct isi_port *port = tty->driver_data;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
|
if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spin_lock_irqsave(&port->card->card_lock, flags);
|
|
||||||
isicom_shutdown_port(port);
|
|
||||||
spin_unlock_irqrestore(&port->card->card_lock, flags);
|
|
||||||
|
|
||||||
tty_port_hangup(&port->port);
|
tty_port_hangup(&port->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1367,6 +1300,8 @@ static const struct tty_operations isicom_ops = {
|
||||||
static const struct tty_port_operations isicom_port_ops = {
|
static const struct tty_port_operations isicom_port_ops = {
|
||||||
.carrier_raised = isicom_carrier_raised,
|
.carrier_raised = isicom_carrier_raised,
|
||||||
.dtr_rts = isicom_dtr_rts,
|
.dtr_rts = isicom_dtr_rts,
|
||||||
|
.activate = isicom_activate,
|
||||||
|
.shutdown = isicom_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __devinit reset_card(struct pci_dev *pdev,
|
static int __devinit reset_card(struct pci_dev *pdev,
|
||||||
|
|
|
@ -213,7 +213,6 @@ static int stli_shared;
|
||||||
* with the slave. Most of them need to be updated atomically, so always
|
* with the slave. Most of them need to be updated atomically, so always
|
||||||
* use the bit setting operations (unless protected by cli/sti).
|
* use the bit setting operations (unless protected by cli/sti).
|
||||||
*/
|
*/
|
||||||
#define ST_INITIALIZING 1
|
|
||||||
#define ST_OPENING 2
|
#define ST_OPENING 2
|
||||||
#define ST_CLOSING 3
|
#define ST_CLOSING 3
|
||||||
#define ST_CMDING 4
|
#define ST_CMDING 4
|
||||||
|
@ -621,7 +620,7 @@ static int stli_brdinit(struct stlibrd *brdp);
|
||||||
static int stli_startbrd(struct stlibrd *brdp);
|
static int stli_startbrd(struct stlibrd *brdp);
|
||||||
static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp);
|
static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp);
|
||||||
static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp);
|
static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp);
|
||||||
static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
|
static long stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg);
|
||||||
static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
|
static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
|
||||||
static void stli_poll(unsigned long arg);
|
static void stli_poll(unsigned long arg);
|
||||||
static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
|
static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
|
||||||
|
@ -704,7 +703,7 @@ static const struct file_operations stli_fsiomem = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.read = stli_memread,
|
.read = stli_memread,
|
||||||
.write = stli_memwrite,
|
.write = stli_memwrite,
|
||||||
.ioctl = stli_memioctl,
|
.unlocked_ioctl = stli_memioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -783,13 +782,32 @@ static int stli_parsebrd(struct stlconf *confp, char **argp)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Locking: protected by the port mutex.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int stli_activate(struct tty_port *port, struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
struct stliport *portp = container_of(port, struct stliport, port);
|
||||||
|
struct stlibrd *brdp = stli_brds[portp->brdnr];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if ((rc = stli_initopen(tty, brdp, portp)) >= 0)
|
||||||
|
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||||
|
wake_up_interruptible(&portp->raw_wait);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static int stli_open(struct tty_struct *tty, struct file *filp)
|
static int stli_open(struct tty_struct *tty, struct file *filp)
|
||||||
{
|
{
|
||||||
struct stlibrd *brdp;
|
struct stlibrd *brdp;
|
||||||
struct stliport *portp;
|
struct stliport *portp;
|
||||||
struct tty_port *port;
|
|
||||||
unsigned int minordev, brdnr, portnr;
|
unsigned int minordev, brdnr, portnr;
|
||||||
int rc;
|
|
||||||
|
|
||||||
minordev = tty->index;
|
minordev = tty->index;
|
||||||
brdnr = MINOR2BRD(minordev);
|
brdnr = MINOR2BRD(minordev);
|
||||||
|
@ -809,95 +827,56 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (portp->devnr < 1)
|
if (portp->devnr < 1)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
port = &portp->port;
|
return tty_port_open(&portp->port, tty, filp);
|
||||||
|
|
||||||
/*
|
|
||||||
* 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(port, tty);
|
|
||||||
tty->driver_data = portp;
|
|
||||||
port->count++;
|
|
||||||
|
|
||||||
wait_event_interruptible(portp->raw_wait,
|
|
||||||
!test_bit(ST_INITIALIZING, &portp->state));
|
|
||||||
if (signal_pending(current))
|
|
||||||
return -ERESTARTSYS;
|
|
||||||
|
|
||||||
if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
|
|
||||||
set_bit(ST_INITIALIZING, &portp->state);
|
|
||||||
if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
|
|
||||||
/* Locking */
|
|
||||||
port->flags |= ASYNC_INITIALIZED;
|
|
||||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
|
||||||
}
|
|
||||||
clear_bit(ST_INITIALIZING, &portp->state);
|
|
||||||
wake_up_interruptible(&portp->raw_wait);
|
|
||||||
if (rc < 0)
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
return tty_port_block_til_ready(&portp->port, tty, filp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void stli_close(struct tty_struct *tty, struct file *filp)
|
static void stli_shutdown(struct tty_port *port)
|
||||||
{
|
{
|
||||||
struct stlibrd *brdp;
|
struct stlibrd *brdp;
|
||||||
struct stliport *portp;
|
unsigned long ftype;
|
||||||
struct tty_port *port;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
struct stliport *portp = container_of(port, struct stliport, port);
|
||||||
|
|
||||||
portp = tty->driver_data;
|
if (portp->brdnr >= stli_nrbrds)
|
||||||
if (portp == NULL)
|
|
||||||
return;
|
return;
|
||||||
port = &portp->port;
|
brdp = stli_brds[portp->brdnr];
|
||||||
|
if (brdp == NULL)
|
||||||
if (tty_port_close_start(port, tty, filp) == 0)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* May want to wait for data to drain before closing. The BUSY flag
|
* May want to wait for data to drain before closing. The BUSY
|
||||||
* keeps track of whether we are still transmitting or not. It is
|
* flag keeps track of whether we are still transmitting or not.
|
||||||
* updated by messages from the slave - indicating when all chars
|
* It is updated by messages from the slave - indicating when all
|
||||||
* really have drained.
|
* chars really have drained.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (!test_bit(ST_CLOSING, &portp->state))
|
||||||
|
stli_rawclose(brdp, portp, 0, 0);
|
||||||
|
|
||||||
spin_lock_irqsave(&stli_lock, flags);
|
spin_lock_irqsave(&stli_lock, flags);
|
||||||
|
clear_bit(ST_TXBUSY, &portp->state);
|
||||||
|
clear_bit(ST_RXSTOP, &portp->state);
|
||||||
|
spin_unlock_irqrestore(&stli_lock, flags);
|
||||||
|
|
||||||
|
ftype = FLUSHTX | FLUSHRX;
|
||||||
|
stli_cmdwait(brdp, portp, A_FLUSH, &ftype, sizeof(u32), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stli_close(struct tty_struct *tty, struct file *filp)
|
||||||
|
{
|
||||||
|
struct stliport *portp = tty->driver_data;
|
||||||
|
unsigned long flags;
|
||||||
|
if (portp == NULL)
|
||||||
|
return;
|
||||||
|
spin_lock_irqsave(&stli_lock, flags);
|
||||||
|
/* Flush any internal buffering out first */
|
||||||
if (tty == stli_txcooktty)
|
if (tty == stli_txcooktty)
|
||||||
stli_flushchars(tty);
|
stli_flushchars(tty);
|
||||||
spin_unlock_irqrestore(&stli_lock, flags);
|
spin_unlock_irqrestore(&stli_lock, flags);
|
||||||
|
tty_port_close(&portp->port, tty, filp);
|
||||||
/* 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);
|
|
||||||
|
|
||||||
/* 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) {
|
|
||||||
stli_mkasysigs(&portp->asig, 0, 0);
|
|
||||||
if (test_bit(ST_CMDING, &portp->state))
|
|
||||||
set_bit(ST_DOSIGS, &portp->state);
|
|
||||||
else
|
|
||||||
stli_sendcmd(brdp, portp, A_SETSIGNALS, &portp->asig,
|
|
||||||
sizeof(asysigs_t), 0);
|
|
||||||
}
|
|
||||||
clear_bit(ST_TXBUSY, &portp->state);
|
|
||||||
clear_bit(ST_RXSTOP, &portp->state);
|
|
||||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
|
||||||
tty_ldisc_flush(tty);
|
|
||||||
set_bit(ST_DOFLUSHRX, &portp->state);
|
|
||||||
stli_flushbuffer(tty);
|
|
||||||
|
|
||||||
tty_port_close_end(port, tty);
|
|
||||||
tty_port_tty_set(port, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -1724,6 +1703,7 @@ static void stli_start(struct tty_struct *tty)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hangup this port. This is pretty much like closing the port, only
|
* Hangup this port. This is pretty much like closing the port, only
|
||||||
* a little more brutal. No waiting for data to drain. Shutdown the
|
* a little more brutal. No waiting for data to drain. Shutdown the
|
||||||
|
@ -1733,47 +1713,8 @@ static void stli_start(struct tty_struct *tty)
|
||||||
|
|
||||||
static void stli_hangup(struct tty_struct *tty)
|
static void stli_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct stliport *portp;
|
struct stliport *portp = tty->driver_data;
|
||||||
struct stlibrd *brdp;
|
tty_port_hangup(&portp->port);
|
||||||
struct tty_port *port;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
portp = tty->driver_data;
|
|
||||||
if (portp == NULL)
|
|
||||||
return;
|
|
||||||
if (portp->brdnr >= stli_nrbrds)
|
|
||||||
return;
|
|
||||||
brdp = stli_brds[portp->brdnr];
|
|
||||||
if (brdp == NULL)
|
|
||||||
return;
|
|
||||||
port = &portp->port;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&stli_lock, flags);
|
|
||||||
if (tty->termios->c_cflag & HUPCL) {
|
|
||||||
stli_mkasysigs(&portp->asig, 0, 0);
|
|
||||||
if (test_bit(ST_CMDING, &portp->state)) {
|
|
||||||
set_bit(ST_DOSIGS, &portp->state);
|
|
||||||
set_bit(ST_DOFLUSHTX, &portp->state);
|
|
||||||
set_bit(ST_DOFLUSHRX, &portp->state);
|
|
||||||
} else {
|
|
||||||
stli_sendcmd(brdp, portp, A_SETSIGNALSF,
|
|
||||||
&portp->asig, sizeof(asysigs_t), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_bit(ST_TXBUSY, &portp->state);
|
|
||||||
clear_bit(ST_RXSTOP, &portp->state);
|
|
||||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
|
||||||
spin_unlock_irqrestore(&stli_lock, flags);
|
|
||||||
|
|
||||||
tty_port_hangup(port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -4311,7 +4252,7 @@ static int stli_getbrdstruct(struct stlibrd __user *arg)
|
||||||
* reset it, and start/stop it.
|
* reset it, and start/stop it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
|
static long stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct stlibrd *brdp;
|
struct stlibrd *brdp;
|
||||||
int brdnr, rc, done;
|
int brdnr, rc, done;
|
||||||
|
@ -4356,7 +4297,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
|
||||||
* Now handle the board specific ioctls. These all depend on the
|
* Now handle the board specific ioctls. These all depend on the
|
||||||
* minor number of the device they were called from.
|
* minor number of the device they were called from.
|
||||||
*/
|
*/
|
||||||
brdnr = iminor(ip);
|
brdnr = iminor(fp->f_dentry->d_inode);
|
||||||
if (brdnr >= STL_MAXBRDS)
|
if (brdnr >= STL_MAXBRDS)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
brdp = stli_brds[brdnr];
|
brdp = stli_brds[brdnr];
|
||||||
|
@ -4420,6 +4361,8 @@ static const struct tty_operations stli_ops = {
|
||||||
static const struct tty_port_operations stli_port_ops = {
|
static const struct tty_port_operations stli_port_ops = {
|
||||||
.carrier_raised = stli_carrier_raised,
|
.carrier_raised = stli_carrier_raised,
|
||||||
.dtr_rts = stli_dtr_rts,
|
.dtr_rts = stli_dtr_rts,
|
||||||
|
.activate = stli_activate,
|
||||||
|
.shutdown = stli_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
#include <linux/tty_flip.h>
|
#include <linux/tty_flip.h>
|
||||||
#include <linux/major.h>
|
#include <linux/major.h>
|
||||||
#include <linux/smp_lock.h>
|
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/fcntl.h>
|
#include <linux/fcntl.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
|
@ -139,7 +138,7 @@ struct moxa_port {
|
||||||
int cflag;
|
int cflag;
|
||||||
unsigned long statusflags;
|
unsigned long statusflags;
|
||||||
|
|
||||||
u8 DCDState;
|
u8 DCDState; /* Protected by the port lock */
|
||||||
u8 lineCtrl;
|
u8 lineCtrl;
|
||||||
u8 lowChkFlag;
|
u8 lowChkFlag;
|
||||||
};
|
};
|
||||||
|
@ -151,10 +150,9 @@ struct mon_str {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* statusflags */
|
/* statusflags */
|
||||||
#define TXSTOPPED 0x1
|
#define TXSTOPPED 1
|
||||||
#define LOWWAIT 0x2
|
#define LOWWAIT 2
|
||||||
#define EMPTYWAIT 0x4
|
#define EMPTYWAIT 3
|
||||||
#define THROTTLE 0x8
|
|
||||||
|
|
||||||
#define SERIAL_DO_RESTART
|
#define SERIAL_DO_RESTART
|
||||||
|
|
||||||
|
@ -165,6 +163,7 @@ static struct mon_str moxaLog;
|
||||||
static unsigned int moxaFuncTout = HZ / 2;
|
static unsigned int moxaFuncTout = HZ / 2;
|
||||||
static unsigned int moxaLowWaterChk;
|
static unsigned int moxaLowWaterChk;
|
||||||
static DEFINE_MUTEX(moxa_openlock);
|
static DEFINE_MUTEX(moxa_openlock);
|
||||||
|
static DEFINE_SPINLOCK(moxa_lock);
|
||||||
/* Variables for insmod */
|
/* Variables for insmod */
|
||||||
#ifdef MODULE
|
#ifdef MODULE
|
||||||
static unsigned long baseaddr[MAX_BOARDS];
|
static unsigned long baseaddr[MAX_BOARDS];
|
||||||
|
@ -194,8 +193,6 @@ static int moxa_write(struct tty_struct *, const unsigned char *, int);
|
||||||
static int moxa_write_room(struct tty_struct *);
|
static int moxa_write_room(struct tty_struct *);
|
||||||
static void moxa_flush_buffer(struct tty_struct *);
|
static void moxa_flush_buffer(struct tty_struct *);
|
||||||
static int moxa_chars_in_buffer(struct tty_struct *);
|
static int moxa_chars_in_buffer(struct tty_struct *);
|
||||||
static void moxa_throttle(struct tty_struct *);
|
|
||||||
static void moxa_unthrottle(struct tty_struct *);
|
|
||||||
static void moxa_set_termios(struct tty_struct *, struct ktermios *);
|
static void moxa_set_termios(struct tty_struct *, struct ktermios *);
|
||||||
static void moxa_stop(struct tty_struct *);
|
static void moxa_stop(struct tty_struct *);
|
||||||
static void moxa_start(struct tty_struct *);
|
static void moxa_start(struct tty_struct *);
|
||||||
|
@ -205,9 +202,9 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
|
||||||
unsigned int set, unsigned int clear);
|
unsigned int set, unsigned int clear);
|
||||||
static void moxa_poll(unsigned long);
|
static void moxa_poll(unsigned long);
|
||||||
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
|
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
|
||||||
static void moxa_setup_empty_event(struct tty_struct *);
|
static void moxa_shutdown(struct tty_port *);
|
||||||
static void moxa_shut_down(struct tty_struct *);
|
|
||||||
static int moxa_carrier_raised(struct tty_port *);
|
static int moxa_carrier_raised(struct tty_port *);
|
||||||
|
static void moxa_dtr_rts(struct tty_port *, int);
|
||||||
/*
|
/*
|
||||||
* moxa board interface functions:
|
* moxa board interface functions:
|
||||||
*/
|
*/
|
||||||
|
@ -234,6 +231,8 @@ static void MoxaSetFifo(struct moxa_port *port, int enable);
|
||||||
* I/O functions
|
* I/O functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(moxafunc_lock);
|
||||||
|
|
||||||
static void moxa_wait_finish(void __iomem *ofsAddr)
|
static void moxa_wait_finish(void __iomem *ofsAddr)
|
||||||
{
|
{
|
||||||
unsigned long end = jiffies + moxaFuncTout;
|
unsigned long end = jiffies + moxaFuncTout;
|
||||||
|
@ -247,9 +246,25 @@ static void moxa_wait_finish(void __iomem *ofsAddr)
|
||||||
|
|
||||||
static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
|
static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
spin_lock_irqsave(&moxafunc_lock, flags);
|
||||||
writew(arg, ofsAddr + FuncArg);
|
writew(arg, ofsAddr + FuncArg);
|
||||||
writew(cmd, ofsAddr + FuncCode);
|
writew(cmd, ofsAddr + FuncCode);
|
||||||
moxa_wait_finish(ofsAddr);
|
moxa_wait_finish(ofsAddr);
|
||||||
|
spin_unlock_irqrestore(&moxafunc_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
u16 ret;
|
||||||
|
spin_lock_irqsave(&moxafunc_lock, flags);
|
||||||
|
writew(arg, ofsAddr + FuncArg);
|
||||||
|
writew(cmd, ofsAddr + FuncCode);
|
||||||
|
moxa_wait_finish(ofsAddr);
|
||||||
|
ret = readw(ofsAddr + FuncArg);
|
||||||
|
spin_unlock_irqrestore(&moxafunc_lock, flags);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moxa_low_water_check(void __iomem *ofsAddr)
|
static void moxa_low_water_check(void __iomem *ofsAddr)
|
||||||
|
@ -299,22 +314,20 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
struct moxa_port *p;
|
struct moxa_port *p;
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
|
|
||||||
mutex_lock(&moxa_openlock);
|
|
||||||
for (i = 0; i < MAX_BOARDS; i++) {
|
for (i = 0; i < MAX_BOARDS; i++) {
|
||||||
p = moxa_boards[i].ports;
|
p = moxa_boards[i].ports;
|
||||||
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
|
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
|
||||||
memset(&tmp, 0, sizeof(tmp));
|
memset(&tmp, 0, sizeof(tmp));
|
||||||
|
spin_lock_bh(&moxa_lock);
|
||||||
if (moxa_boards[i].ready) {
|
if (moxa_boards[i].ready) {
|
||||||
tmp.inq = MoxaPortRxQueue(p);
|
tmp.inq = MoxaPortRxQueue(p);
|
||||||
tmp.outq = MoxaPortTxQueue(p);
|
tmp.outq = MoxaPortTxQueue(p);
|
||||||
}
|
}
|
||||||
if (copy_to_user(argm, &tmp, sizeof(tmp))) {
|
spin_unlock_bh(&moxa_lock);
|
||||||
mutex_unlock(&moxa_openlock);
|
if (copy_to_user(argm, &tmp, sizeof(tmp)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mutex_unlock(&moxa_openlock);
|
|
||||||
break;
|
break;
|
||||||
} case MOXA_GET_OQUEUE:
|
} case MOXA_GET_OQUEUE:
|
||||||
status = MoxaPortTxQueue(ch);
|
status = MoxaPortTxQueue(ch);
|
||||||
|
@ -330,16 +343,20 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
struct moxa_port *p;
|
struct moxa_port *p;
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
|
|
||||||
mutex_lock(&moxa_openlock);
|
|
||||||
for (i = 0; i < MAX_BOARDS; i++) {
|
for (i = 0; i < MAX_BOARDS; i++) {
|
||||||
p = moxa_boards[i].ports;
|
p = moxa_boards[i].ports;
|
||||||
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
|
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
|
||||||
struct tty_struct *ttyp;
|
struct tty_struct *ttyp;
|
||||||
memset(&tmp, 0, sizeof(tmp));
|
memset(&tmp, 0, sizeof(tmp));
|
||||||
if (!moxa_boards[i].ready)
|
spin_lock_bh(&moxa_lock);
|
||||||
|
if (!moxa_boards[i].ready) {
|
||||||
|
spin_unlock_bh(&moxa_lock);
|
||||||
goto copy;
|
goto copy;
|
||||||
|
}
|
||||||
|
|
||||||
status = MoxaPortLineStatus(p);
|
status = MoxaPortLineStatus(p);
|
||||||
|
spin_unlock_bh(&moxa_lock);
|
||||||
|
|
||||||
if (status & 1)
|
if (status & 1)
|
||||||
tmp.cts = 1;
|
tmp.cts = 1;
|
||||||
if (status & 2)
|
if (status & 2)
|
||||||
|
@ -354,24 +371,21 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
tmp.cflag = ttyp->termios->c_cflag;
|
tmp.cflag = ttyp->termios->c_cflag;
|
||||||
tty_kref_put(tty);
|
tty_kref_put(tty);
|
||||||
copy:
|
copy:
|
||||||
if (copy_to_user(argm, &tmp, sizeof(tmp))) {
|
if (copy_to_user(argm, &tmp, sizeof(tmp)))
|
||||||
mutex_unlock(&moxa_openlock);
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mutex_unlock(&moxa_openlock);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TIOCGSERIAL:
|
case TIOCGSERIAL:
|
||||||
mutex_lock(&moxa_openlock);
|
mutex_lock(&ch->port.mutex);
|
||||||
ret = moxa_get_serial_info(ch, argp);
|
ret = moxa_get_serial_info(ch, argp);
|
||||||
mutex_unlock(&moxa_openlock);
|
mutex_unlock(&ch->port.mutex);
|
||||||
break;
|
break;
|
||||||
case TIOCSSERIAL:
|
case TIOCSSERIAL:
|
||||||
mutex_lock(&moxa_openlock);
|
mutex_lock(&ch->port.mutex);
|
||||||
ret = moxa_set_serial_info(ch, argp);
|
ret = moxa_set_serial_info(ch, argp);
|
||||||
mutex_unlock(&moxa_openlock);
|
mutex_unlock(&ch->port.mutex);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENOIOCTLCMD;
|
ret = -ENOIOCTLCMD;
|
||||||
|
@ -396,8 +410,6 @@ static const struct tty_operations moxa_ops = {
|
||||||
.flush_buffer = moxa_flush_buffer,
|
.flush_buffer = moxa_flush_buffer,
|
||||||
.chars_in_buffer = moxa_chars_in_buffer,
|
.chars_in_buffer = moxa_chars_in_buffer,
|
||||||
.ioctl = moxa_ioctl,
|
.ioctl = moxa_ioctl,
|
||||||
.throttle = moxa_throttle,
|
|
||||||
.unthrottle = moxa_unthrottle,
|
|
||||||
.set_termios = moxa_set_termios,
|
.set_termios = moxa_set_termios,
|
||||||
.stop = moxa_stop,
|
.stop = moxa_stop,
|
||||||
.start = moxa_start,
|
.start = moxa_start,
|
||||||
|
@ -409,11 +421,12 @@ static const struct tty_operations moxa_ops = {
|
||||||
|
|
||||||
static const struct tty_port_operations moxa_port_ops = {
|
static const struct tty_port_operations moxa_port_ops = {
|
||||||
.carrier_raised = moxa_carrier_raised,
|
.carrier_raised = moxa_carrier_raised,
|
||||||
|
.dtr_rts = moxa_dtr_rts,
|
||||||
|
.shutdown = moxa_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct tty_driver *moxaDriver;
|
static struct tty_driver *moxaDriver;
|
||||||
static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
|
static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
|
||||||
static DEFINE_SPINLOCK(moxa_lock);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HW init
|
* HW init
|
||||||
|
@ -1112,14 +1125,12 @@ static void __exit moxa_exit(void)
|
||||||
module_init(moxa_init);
|
module_init(moxa_init);
|
||||||
module_exit(moxa_exit);
|
module_exit(moxa_exit);
|
||||||
|
|
||||||
static void moxa_close_port(struct tty_struct *tty)
|
static void moxa_shutdown(struct tty_port *port)
|
||||||
{
|
{
|
||||||
struct moxa_port *ch = tty->driver_data;
|
struct moxa_port *ch = container_of(port, struct moxa_port, port);
|
||||||
moxa_shut_down(tty);
|
MoxaPortDisable(ch);
|
||||||
MoxaPortFlushData(ch, 2);
|
MoxaPortFlushData(ch, 2);
|
||||||
ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
|
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
|
||||||
tty->driver_data = NULL;
|
|
||||||
tty_port_tty_set(&ch->port, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int moxa_carrier_raised(struct tty_port *port)
|
static int moxa_carrier_raised(struct tty_port *port)
|
||||||
|
@ -1127,44 +1138,18 @@ static int moxa_carrier_raised(struct tty_port *port)
|
||||||
struct moxa_port *ch = container_of(port, struct moxa_port, port);
|
struct moxa_port *ch = container_of(port, struct moxa_port, port);
|
||||||
int dcd;
|
int dcd;
|
||||||
|
|
||||||
spin_lock_bh(&moxa_lock);
|
spin_lock_irq(&port->lock);
|
||||||
dcd = ch->DCDState;
|
dcd = ch->DCDState;
|
||||||
spin_unlock_bh(&moxa_lock);
|
spin_unlock_irq(&port->lock);
|
||||||
return dcd;
|
return dcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
|
static void moxa_dtr_rts(struct tty_port *port, int onoff)
|
||||||
struct moxa_port *ch)
|
|
||||||
{
|
{
|
||||||
struct tty_port *port = &ch->port;
|
struct moxa_port *ch = container_of(port, struct moxa_port, port);
|
||||||
DEFINE_WAIT(wait);
|
MoxaPortLineCtrl(ch, onoff, onoff);
|
||||||
int retval = 0;
|
}
|
||||||
u8 dcd;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
|
|
||||||
if (tty_hung_up_p(filp)) {
|
|
||||||
#ifdef SERIAL_DO_RESTART
|
|
||||||
retval = -ERESTARTSYS;
|
|
||||||
#else
|
|
||||||
retval = -EAGAIN;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dcd = tty_port_carrier_raised(port);
|
|
||||||
if (dcd)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (signal_pending(current)) {
|
|
||||||
retval = -ERESTARTSYS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
schedule();
|
|
||||||
}
|
|
||||||
finish_wait(&port->open_wait, &wait);
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int moxa_open(struct tty_struct *tty, struct file *filp)
|
static int moxa_open(struct tty_struct *tty, struct file *filp)
|
||||||
{
|
{
|
||||||
|
@ -1194,6 +1179,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
|
||||||
ch->port.count++;
|
ch->port.count++;
|
||||||
tty->driver_data = ch;
|
tty->driver_data = ch;
|
||||||
tty_port_tty_set(&ch->port, tty);
|
tty_port_tty_set(&ch->port, tty);
|
||||||
|
mutex_lock(&ch->port.mutex);
|
||||||
if (!(ch->port.flags & ASYNC_INITIALIZED)) {
|
if (!(ch->port.flags & ASYNC_INITIALIZED)) {
|
||||||
ch->statusflags = 0;
|
ch->statusflags = 0;
|
||||||
moxa_set_tty_param(tty, tty->termios);
|
moxa_set_tty_param(tty, tty->termios);
|
||||||
|
@ -1202,58 +1188,20 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
|
||||||
MoxaSetFifo(ch, ch->type == PORT_16550A);
|
MoxaSetFifo(ch, ch->type == PORT_16550A);
|
||||||
ch->port.flags |= ASYNC_INITIALIZED;
|
ch->port.flags |= ASYNC_INITIALIZED;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&ch->port.mutex);
|
||||||
mutex_unlock(&moxa_openlock);
|
mutex_unlock(&moxa_openlock);
|
||||||
|
|
||||||
retval = 0;
|
retval = tty_port_block_til_ready(&ch->port, tty, filp);
|
||||||
if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty))
|
if (retval == 0)
|
||||||
retval = moxa_block_till_ready(tty, filp, ch);
|
set_bit(ASYNCB_NORMAL_ACTIVE, &ch->port.flags);
|
||||||
mutex_lock(&moxa_openlock);
|
|
||||||
if (retval) {
|
|
||||||
if (ch->port.count) /* 0 means already hung up... */
|
|
||||||
if (--ch->port.count == 0)
|
|
||||||
moxa_close_port(tty);
|
|
||||||
} else
|
|
||||||
ch->port.flags |= ASYNC_NORMAL_ACTIVE;
|
|
||||||
mutex_unlock(&moxa_openlock);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moxa_close(struct tty_struct *tty, struct file *filp)
|
static void moxa_close(struct tty_struct *tty, struct file *filp)
|
||||||
{
|
{
|
||||||
struct moxa_port *ch;
|
struct moxa_port *ch = tty->driver_data;
|
||||||
int port;
|
|
||||||
|
|
||||||
port = tty->index;
|
|
||||||
if (port == MAX_PORTS || tty_hung_up_p(filp))
|
|
||||||
return;
|
|
||||||
|
|
||||||
mutex_lock(&moxa_openlock);
|
|
||||||
ch = tty->driver_data;
|
|
||||||
if (ch == NULL)
|
|
||||||
goto unlock;
|
|
||||||
if (tty->count == 1 && ch->port.count != 1) {
|
|
||||||
printk(KERN_WARNING "moxa_close: bad serial port count; "
|
|
||||||
"tty->count is 1, ch->port.count is %d\n", ch->port.count);
|
|
||||||
ch->port.count = 1;
|
|
||||||
}
|
|
||||||
if (--ch->port.count < 0) {
|
|
||||||
printk(KERN_WARNING "moxa_close: bad serial port count, "
|
|
||||||
"device=%s\n", tty->name);
|
|
||||||
ch->port.count = 0;
|
|
||||||
}
|
|
||||||
if (ch->port.count)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
ch->cflag = tty->termios->c_cflag;
|
ch->cflag = tty->termios->c_cflag;
|
||||||
if (ch->port.flags & ASYNC_INITIALIZED) {
|
tty_port_close(&ch->port, tty, filp);
|
||||||
moxa_setup_empty_event(tty);
|
|
||||||
tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
|
|
||||||
}
|
|
||||||
|
|
||||||
moxa_close_port(tty);
|
|
||||||
unlock:
|
|
||||||
mutex_unlock(&moxa_openlock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int moxa_write(struct tty_struct *tty,
|
static int moxa_write(struct tty_struct *tty,
|
||||||
|
@ -1269,7 +1217,7 @@ static int moxa_write(struct tty_struct *tty,
|
||||||
len = MoxaPortWriteData(tty, buf, count);
|
len = MoxaPortWriteData(tty, buf, count);
|
||||||
spin_unlock_bh(&moxa_lock);
|
spin_unlock_bh(&moxa_lock);
|
||||||
|
|
||||||
ch->statusflags |= LOWWAIT;
|
set_bit(LOWWAIT, &ch->statusflags);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1300,40 +1248,21 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
|
||||||
struct moxa_port *ch = tty->driver_data;
|
struct moxa_port *ch = tty->driver_data;
|
||||||
int chars;
|
int chars;
|
||||||
|
|
||||||
/*
|
|
||||||
* Sigh...I have to check if driver_data is NULL here, because
|
|
||||||
* if an open() fails, the TTY subsystem eventually calls
|
|
||||||
* tty_wait_until_sent(), which calls the driver's chars_in_buffer()
|
|
||||||
* routine. And since the open() failed, we return 0 here. TDJ
|
|
||||||
*/
|
|
||||||
if (ch == NULL)
|
|
||||||
return 0;
|
|
||||||
lock_kernel();
|
|
||||||
chars = MoxaPortTxQueue(ch);
|
chars = MoxaPortTxQueue(ch);
|
||||||
if (chars) {
|
if (chars)
|
||||||
/*
|
/*
|
||||||
* Make it possible to wakeup anything waiting for output
|
* Make it possible to wakeup anything waiting for output
|
||||||
* in tty_ioctl.c, etc.
|
* in tty_ioctl.c, etc.
|
||||||
*/
|
*/
|
||||||
if (!(ch->statusflags & EMPTYWAIT))
|
set_bit(EMPTYWAIT, &ch->statusflags);
|
||||||
moxa_setup_empty_event(tty);
|
|
||||||
}
|
|
||||||
unlock_kernel();
|
|
||||||
return chars;
|
return chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
|
static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
|
||||||
{
|
{
|
||||||
struct moxa_port *ch;
|
struct moxa_port *ch = tty->driver_data;
|
||||||
int flag = 0, dtr, rts;
|
int flag = 0, dtr, rts;
|
||||||
|
|
||||||
mutex_lock(&moxa_openlock);
|
|
||||||
ch = tty->driver_data;
|
|
||||||
if (!ch) {
|
|
||||||
mutex_unlock(&moxa_openlock);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
MoxaPortGetLineOut(ch, &dtr, &rts);
|
MoxaPortGetLineOut(ch, &dtr, &rts);
|
||||||
if (dtr)
|
if (dtr)
|
||||||
flag |= TIOCM_DTR;
|
flag |= TIOCM_DTR;
|
||||||
|
@ -1346,7 +1275,6 @@ static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
|
||||||
flag |= TIOCM_DSR;
|
flag |= TIOCM_DSR;
|
||||||
if (dtr & 4)
|
if (dtr & 4)
|
||||||
flag |= TIOCM_CD;
|
flag |= TIOCM_CD;
|
||||||
mutex_unlock(&moxa_openlock);
|
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1379,20 +1307,6 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moxa_throttle(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
struct moxa_port *ch = tty->driver_data;
|
|
||||||
|
|
||||||
ch->statusflags |= THROTTLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void moxa_unthrottle(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
struct moxa_port *ch = tty->driver_data;
|
|
||||||
|
|
||||||
ch->statusflags &= ~THROTTLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void moxa_set_termios(struct tty_struct *tty,
|
static void moxa_set_termios(struct tty_struct *tty,
|
||||||
struct ktermios *old_termios)
|
struct ktermios *old_termios)
|
||||||
{
|
{
|
||||||
|
@ -1412,7 +1326,7 @@ static void moxa_stop(struct tty_struct *tty)
|
||||||
if (ch == NULL)
|
if (ch == NULL)
|
||||||
return;
|
return;
|
||||||
MoxaPortTxDisable(ch);
|
MoxaPortTxDisable(ch);
|
||||||
ch->statusflags |= TXSTOPPED;
|
set_bit(TXSTOPPED, &ch->statusflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1427,38 +1341,32 @@ static void moxa_start(struct tty_struct *tty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MoxaPortTxEnable(ch);
|
MoxaPortTxEnable(ch);
|
||||||
ch->statusflags &= ~TXSTOPPED;
|
clear_bit(TXSTOPPED, &ch->statusflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moxa_hangup(struct tty_struct *tty)
|
static void moxa_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct moxa_port *ch;
|
struct moxa_port *ch = tty->driver_data;
|
||||||
|
tty_port_hangup(&ch->port);
|
||||||
mutex_lock(&moxa_openlock);
|
|
||||||
ch = tty->driver_data;
|
|
||||||
if (ch == NULL) {
|
|
||||||
mutex_unlock(&moxa_openlock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ch->port.count = 0;
|
|
||||||
moxa_close_port(tty);
|
|
||||||
mutex_unlock(&moxa_openlock);
|
|
||||||
|
|
||||||
wake_up_interruptible(&ch->port.open_wait);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
|
static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
|
||||||
{
|
{
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
|
unsigned long flags;
|
||||||
dcd = !!dcd;
|
dcd = !!dcd;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&p->port.lock, flags);
|
||||||
if (dcd != p->DCDState) {
|
if (dcd != p->DCDState) {
|
||||||
|
p->DCDState = dcd;
|
||||||
|
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||||
tty = tty_port_tty_get(&p->port);
|
tty = tty_port_tty_get(&p->port);
|
||||||
if (tty && C_CLOCAL(tty) && !dcd)
|
if (tty && C_CLOCAL(tty) && !dcd)
|
||||||
tty_hangup(tty);
|
tty_hangup(tty);
|
||||||
tty_kref_put(tty);
|
tty_kref_put(tty);
|
||||||
}
|
}
|
||||||
p->DCDState = dcd;
|
else
|
||||||
|
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
||||||
|
@ -1470,24 +1378,24 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
||||||
u16 intr;
|
u16 intr;
|
||||||
|
|
||||||
if (tty) {
|
if (tty) {
|
||||||
if ((p->statusflags & EMPTYWAIT) &&
|
if (test_bit(EMPTYWAIT, &p->statusflags) &&
|
||||||
MoxaPortTxQueue(p) == 0) {
|
MoxaPortTxQueue(p) == 0) {
|
||||||
p->statusflags &= ~EMPTYWAIT;
|
clear_bit(EMPTYWAIT, &p->statusflags);
|
||||||
tty_wakeup(tty);
|
tty_wakeup(tty);
|
||||||
}
|
}
|
||||||
if ((p->statusflags & LOWWAIT) && !tty->stopped &&
|
if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped &&
|
||||||
MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
|
MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
|
||||||
p->statusflags &= ~LOWWAIT;
|
clear_bit(LOWWAIT, &p->statusflags);
|
||||||
tty_wakeup(tty);
|
tty_wakeup(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inited && !(p->statusflags & THROTTLE) &&
|
if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
|
||||||
MoxaPortRxQueue(p) > 0) { /* RX */
|
MoxaPortRxQueue(p) > 0) { /* RX */
|
||||||
MoxaPortReadData(p);
|
MoxaPortReadData(p);
|
||||||
tty_schedule_flip(tty);
|
tty_schedule_flip(tty);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
p->statusflags &= ~EMPTYWAIT;
|
clear_bit(EMPTYWAIT, &p->statusflags);
|
||||||
MoxaPortFlushData(p, 0); /* flush RX */
|
MoxaPortFlushData(p, 0); /* flush RX */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1588,35 +1496,6 @@ static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_term
|
||||||
tty_encode_baud_rate(tty, baud, baud);
|
tty_encode_baud_rate(tty, baud, baud);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moxa_setup_empty_event(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
struct moxa_port *ch = tty->driver_data;
|
|
||||||
|
|
||||||
spin_lock_bh(&moxa_lock);
|
|
||||||
ch->statusflags |= EMPTYWAIT;
|
|
||||||
spin_unlock_bh(&moxa_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void moxa_shut_down(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
struct moxa_port *ch = tty->driver_data;
|
|
||||||
|
|
||||||
if (!(ch->port.flags & ASYNC_INITIALIZED))
|
|
||||||
return;
|
|
||||||
|
|
||||||
MoxaPortDisable(ch);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we're a modem control device and HUPCL is on, drop RTS & DTR.
|
|
||||||
*/
|
|
||||||
if (C_HUPCL(tty))
|
|
||||||
MoxaPortLineCtrl(ch, 0, 0);
|
|
||||||
|
|
||||||
spin_lock_bh(&moxa_lock);
|
|
||||||
ch->port.flags &= ~ASYNC_INITIALIZED;
|
|
||||||
spin_unlock_bh(&moxa_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Driver level functions: *
|
* Driver level functions: *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
@ -1918,10 +1797,12 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
|
||||||
baud = MoxaPortSetBaud(port, baud);
|
baud = MoxaPortSetBaud(port, baud);
|
||||||
|
|
||||||
if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
|
if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
|
||||||
|
spin_lock_irq(&moxafunc_lock);
|
||||||
writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
|
writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
|
||||||
writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
|
writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
|
||||||
writeb(FC_SetXonXoff, ofsAddr + FuncCode);
|
writeb(FC_SetXonXoff, ofsAddr + FuncCode);
|
||||||
moxa_wait_finish(ofsAddr);
|
moxa_wait_finish(ofsAddr);
|
||||||
|
spin_unlock_irq(&moxafunc_lock);
|
||||||
|
|
||||||
}
|
}
|
||||||
return baud;
|
return baud;
|
||||||
|
@ -1974,18 +1855,14 @@ static int MoxaPortLineStatus(struct moxa_port *port)
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
ofsAddr = port->tableAddr;
|
ofsAddr = port->tableAddr;
|
||||||
if (MOXA_IS_320(port->board)) {
|
if (MOXA_IS_320(port->board))
|
||||||
moxafunc(ofsAddr, FC_LineStatus, 0);
|
val = moxafuncret(ofsAddr, FC_LineStatus, 0);
|
||||||
val = readw(ofsAddr + FuncArg);
|
else
|
||||||
} else {
|
|
||||||
val = readw(ofsAddr + FlagStat) >> 4;
|
val = readw(ofsAddr + FlagStat) >> 4;
|
||||||
}
|
|
||||||
val &= 0x0B;
|
val &= 0x0B;
|
||||||
if (val & 8)
|
if (val & 8)
|
||||||
val |= 4;
|
val |= 4;
|
||||||
spin_lock_bh(&moxa_lock);
|
|
||||||
moxa_new_dcdstate(port, val & 8);
|
moxa_new_dcdstate(port, val & 8);
|
||||||
spin_unlock_bh(&moxa_lock);
|
|
||||||
val &= 7;
|
val &= 7;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/signal.h>
|
#include <linux/signal.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/smp_lock.h>
|
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
|
@ -856,9 +855,9 @@ static void mxser_check_modem_status(struct tty_struct *tty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mxser_startup(struct tty_struct *tty)
|
static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct mxser_port *info = tty->driver_data;
|
struct mxser_port *info = container_of(port, struct mxser_port, port);
|
||||||
unsigned long page;
|
unsigned long page;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -868,21 +867,12 @@ static int mxser_startup(struct tty_struct *tty)
|
||||||
|
|
||||||
spin_lock_irqsave(&info->slock, flags);
|
spin_lock_irqsave(&info->slock, flags);
|
||||||
|
|
||||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
|
||||||
free_page(page);
|
|
||||||
spin_unlock_irqrestore(&info->slock, flags);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info->ioaddr || !info->type) {
|
if (!info->ioaddr || !info->type) {
|
||||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||||
free_page(page);
|
free_page(page);
|
||||||
spin_unlock_irqrestore(&info->slock, flags);
|
spin_unlock_irqrestore(&info->slock, flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (info->port.xmit_buf)
|
|
||||||
free_page(page);
|
|
||||||
else
|
|
||||||
info->port.xmit_buf = (unsigned char *) page;
|
info->port.xmit_buf = (unsigned char *) page;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -951,24 +941,19 @@ static int mxser_startup(struct tty_struct *tty)
|
||||||
* and set the speed of the serial port
|
* and set the speed of the serial port
|
||||||
*/
|
*/
|
||||||
mxser_change_speed(tty, NULL);
|
mxser_change_speed(tty, NULL);
|
||||||
info->port.flags |= ASYNC_INITIALIZED;
|
|
||||||
spin_unlock_irqrestore(&info->slock, flags);
|
spin_unlock_irqrestore(&info->slock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This routine will shutdown a serial port; interrupts maybe disabled, and
|
* This routine will shutdown a serial port
|
||||||
* DTR is dropped if the hangup on close termio flag is on.
|
|
||||||
*/
|
*/
|
||||||
static void mxser_shutdown(struct tty_struct *tty)
|
static void mxser_shutdown_port(struct tty_port *port)
|
||||||
{
|
{
|
||||||
struct mxser_port *info = tty->driver_data;
|
struct mxser_port *info = container_of(port, struct mxser_port, port);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
|
||||||
return;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&info->slock, flags);
|
spin_lock_irqsave(&info->slock, flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -978,7 +963,7 @@ static void mxser_shutdown(struct tty_struct *tty)
|
||||||
wake_up_interruptible(&info->port.delta_msr_wait);
|
wake_up_interruptible(&info->port.delta_msr_wait);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the IRQ, if necessary
|
* Free the xmit buffer, if necessary
|
||||||
*/
|
*/
|
||||||
if (info->port.xmit_buf) {
|
if (info->port.xmit_buf) {
|
||||||
free_page((unsigned long) info->port.xmit_buf);
|
free_page((unsigned long) info->port.xmit_buf);
|
||||||
|
@ -988,10 +973,6 @@ static void mxser_shutdown(struct tty_struct *tty)
|
||||||
info->IER = 0;
|
info->IER = 0;
|
||||||
outb(0x00, info->ioaddr + UART_IER);
|
outb(0x00, info->ioaddr + UART_IER);
|
||||||
|
|
||||||
if (tty->termios->c_cflag & HUPCL)
|
|
||||||
info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
|
|
||||||
outb(info->MCR, info->ioaddr + UART_MCR);
|
|
||||||
|
|
||||||
/* clear Rx/Tx FIFO's */
|
/* clear Rx/Tx FIFO's */
|
||||||
if (info->board->chip_flag)
|
if (info->board->chip_flag)
|
||||||
outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
|
outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
|
||||||
|
@ -1004,9 +985,6 @@ static void mxser_shutdown(struct tty_struct *tty)
|
||||||
/* read data port to reset things */
|
/* read data port to reset things */
|
||||||
(void) inb(info->ioaddr + UART_RX);
|
(void) inb(info->ioaddr + UART_RX);
|
||||||
|
|
||||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
|
||||||
|
|
||||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
|
||||||
|
|
||||||
if (info->board->chip_flag)
|
if (info->board->chip_flag)
|
||||||
SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
|
SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
|
||||||
|
@ -1023,8 +1001,7 @@ static void mxser_shutdown(struct tty_struct *tty)
|
||||||
static int mxser_open(struct tty_struct *tty, struct file *filp)
|
static int mxser_open(struct tty_struct *tty, struct file *filp)
|
||||||
{
|
{
|
||||||
struct mxser_port *info;
|
struct mxser_port *info;
|
||||||
unsigned long flags;
|
int line;
|
||||||
int retval, line;
|
|
||||||
|
|
||||||
line = tty->index;
|
line = tty->index;
|
||||||
if (line == MXSER_PORTS)
|
if (line == MXSER_PORTS)
|
||||||
|
@ -1035,23 +1012,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
|
||||||
if (!info->ioaddr)
|
if (!info->ioaddr)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
tty->driver_data = info;
|
return tty_port_open(&info->port, tty, filp);
|
||||||
tty_port_tty_set(&info->port, tty);
|
|
||||||
/*
|
|
||||||
* Start up serial port
|
|
||||||
*/
|
|
||||||
spin_lock_irqsave(&info->port.lock, flags);
|
|
||||||
info->port.count++;
|
|
||||||
spin_unlock_irqrestore(&info->port.lock, flags);
|
|
||||||
retval = mxser_startup(tty);
|
|
||||||
if (retval)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
retval = tty_port_block_til_ready(&info->port, tty, filp);
|
|
||||||
if (retval)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mxser_flush_buffer(struct tty_struct *tty)
|
static void mxser_flush_buffer(struct tty_struct *tty)
|
||||||
|
@ -1075,18 +1036,10 @@ static void mxser_flush_buffer(struct tty_struct *tty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void mxser_close_port(struct tty_struct *tty, struct tty_port *port)
|
static void mxser_close_port(struct tty_port *port)
|
||||||
{
|
{
|
||||||
struct mxser_port *info = container_of(port, struct mxser_port, port);
|
struct mxser_port *info = container_of(port, struct mxser_port, port);
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
/*
|
|
||||||
* Save the termios structure, since this port may have
|
|
||||||
* separate termios for callout and dialin.
|
|
||||||
*
|
|
||||||
* FIXME: Can this go ?
|
|
||||||
*/
|
|
||||||
if (port->flags & ASYNC_NORMAL_ACTIVE)
|
|
||||||
info->normal_termios = *tty->termios;
|
|
||||||
/*
|
/*
|
||||||
* At this point we stop accepting input. To do this, we
|
* At this point we stop accepting input. To do this, we
|
||||||
* disable the receive line status interrupts, and tell the
|
* disable the receive line status interrupts, and tell the
|
||||||
|
@ -1097,7 +1050,6 @@ static void mxser_close_port(struct tty_struct *tty, struct tty_port *port)
|
||||||
if (info->board->chip_flag)
|
if (info->board->chip_flag)
|
||||||
info->IER &= ~MOXA_MUST_RECV_ISR;
|
info->IER &= ~MOXA_MUST_RECV_ISR;
|
||||||
|
|
||||||
if (port->flags & ASYNC_INITIALIZED) {
|
|
||||||
outb(info->IER, info->ioaddr + UART_IER);
|
outb(info->IER, info->ioaddr + UART_IER);
|
||||||
/*
|
/*
|
||||||
* Before we drop DTR, make sure the UART transmitter
|
* Before we drop DTR, make sure the UART transmitter
|
||||||
|
@ -1111,9 +1063,6 @@ static void mxser_close_port(struct tty_struct *tty, struct tty_port *port)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mxser_shutdown(tty);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This routine is called when the serial port gets closed. First, we
|
* This routine is called when the serial port gets closed. First, we
|
||||||
|
@ -1130,8 +1079,12 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
|
||||||
return;
|
return;
|
||||||
if (tty_port_close_start(port, tty, filp) == 0)
|
if (tty_port_close_start(port, tty, filp) == 0)
|
||||||
return;
|
return;
|
||||||
mxser_close_port(tty, port);
|
mutex_lock(&port->mutex);
|
||||||
|
mxser_close_port(port);
|
||||||
mxser_flush_buffer(tty);
|
mxser_flush_buffer(tty);
|
||||||
|
mxser_shutdown_port(port);
|
||||||
|
clear_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||||
|
mutex_unlock(&port->mutex);
|
||||||
/* Right now the tty_port set is done outside of the close_end helper
|
/* Right now the tty_port set is done outside of the close_end helper
|
||||||
as we don't yet have everyone using refcounts */
|
as we don't yet have everyone using refcounts */
|
||||||
tty_port_close_end(port, tty);
|
tty_port_close_end(port, tty);
|
||||||
|
@ -1275,6 +1228,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
||||||
struct serial_struct __user *new_info)
|
struct serial_struct __user *new_info)
|
||||||
{
|
{
|
||||||
struct mxser_port *info = tty->driver_data;
|
struct mxser_port *info = tty->driver_data;
|
||||||
|
struct tty_port *port = &info->port;
|
||||||
struct serial_struct new_serial;
|
struct serial_struct new_serial;
|
||||||
speed_t baud;
|
speed_t baud;
|
||||||
unsigned long sl_flags;
|
unsigned long sl_flags;
|
||||||
|
@ -1290,7 +1244,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
||||||
new_serial.port != info->ioaddr)
|
new_serial.port != info->ioaddr)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
flags = info->port.flags & ASYNC_SPD_MASK;
|
flags = port->flags & ASYNC_SPD_MASK;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN)) {
|
if (!capable(CAP_SYS_ADMIN)) {
|
||||||
if ((new_serial.baud_base != info->baud_base) ||
|
if ((new_serial.baud_base != info->baud_base) ||
|
||||||
|
@ -1304,16 +1258,17 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
||||||
* OK, past this point, all the error checking has been done.
|
* OK, past this point, all the error checking has been done.
|
||||||
* At this point, we start making changes.....
|
* At this point, we start making changes.....
|
||||||
*/
|
*/
|
||||||
info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
|
port->flags = ((port->flags & ~ASYNC_FLAGS) |
|
||||||
(new_serial.flags & ASYNC_FLAGS));
|
(new_serial.flags & ASYNC_FLAGS));
|
||||||
info->port.close_delay = new_serial.close_delay * HZ / 100;
|
port->close_delay = new_serial.close_delay * HZ / 100;
|
||||||
info->port.closing_wait = new_serial.closing_wait * HZ / 100;
|
port->closing_wait = new_serial.closing_wait * HZ / 100;
|
||||||
tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
|
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||||
? 1 : 0;
|
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
|
||||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
|
|
||||||
(new_serial.baud_base != info->baud_base ||
|
(new_serial.baud_base != info->baud_base ||
|
||||||
new_serial.custom_divisor !=
|
new_serial.custom_divisor !=
|
||||||
info->custom_divisor)) {
|
info->custom_divisor)) {
|
||||||
|
if (new_serial.custom_divisor == 0)
|
||||||
|
return -EINVAL;
|
||||||
baud = new_serial.baud_base / new_serial.custom_divisor;
|
baud = new_serial.baud_base / new_serial.custom_divisor;
|
||||||
tty_encode_baud_rate(tty, baud, baud);
|
tty_encode_baud_rate(tty, baud, baud);
|
||||||
}
|
}
|
||||||
|
@ -1323,15 +1278,17 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
||||||
|
|
||||||
process_txrx_fifo(info);
|
process_txrx_fifo(info);
|
||||||
|
|
||||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||||
if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
|
if (flags != (port->flags & ASYNC_SPD_MASK)) {
|
||||||
spin_lock_irqsave(&info->slock, sl_flags);
|
spin_lock_irqsave(&info->slock, sl_flags);
|
||||||
mxser_change_speed(tty, NULL);
|
mxser_change_speed(tty, NULL);
|
||||||
spin_unlock_irqrestore(&info->slock, sl_flags);
|
spin_unlock_irqrestore(&info->slock, sl_flags);
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
retval = mxser_startup(tty);
|
retval = mxser_activate(port, tty);
|
||||||
|
if (retval == 0)
|
||||||
|
set_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||||
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1520,7 +1477,8 @@ static int __init mxser_read_register(int port, unsigned short *regs)
|
||||||
|
|
||||||
static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
||||||
{
|
{
|
||||||
struct mxser_port *port;
|
struct mxser_port *ip;
|
||||||
|
struct tty_port *port;
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
int result, status;
|
int result, status;
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
|
@ -1536,38 +1494,39 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
||||||
|
|
||||||
case MOXA_CHKPORTENABLE:
|
case MOXA_CHKPORTENABLE:
|
||||||
result = 0;
|
result = 0;
|
||||||
lock_kernel();
|
|
||||||
for (i = 0; i < MXSER_BOARDS; i++)
|
for (i = 0; i < MXSER_BOARDS; i++)
|
||||||
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
|
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
|
||||||
if (mxser_boards[i].ports[j].ioaddr)
|
if (mxser_boards[i].ports[j].ioaddr)
|
||||||
result |= (1 << i);
|
result |= (1 << i);
|
||||||
unlock_kernel();
|
|
||||||
return put_user(result, (unsigned long __user *)argp);
|
return put_user(result, (unsigned long __user *)argp);
|
||||||
case MOXA_GETDATACOUNT:
|
case MOXA_GETDATACOUNT:
|
||||||
lock_kernel();
|
/* The receive side is locked by port->slock but it isn't
|
||||||
|
clear that an exact snapshot is worth copying here */
|
||||||
if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
|
if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
unlock_kernel();
|
|
||||||
return ret;
|
return ret;
|
||||||
case MOXA_GETMSTATUS: {
|
case MOXA_GETMSTATUS: {
|
||||||
struct mxser_mstatus ms, __user *msu = argp;
|
struct mxser_mstatus ms, __user *msu = argp;
|
||||||
lock_kernel();
|
|
||||||
for (i = 0; i < MXSER_BOARDS; i++)
|
for (i = 0; i < MXSER_BOARDS; i++)
|
||||||
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
|
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
|
||||||
port = &mxser_boards[i].ports[j];
|
ip = &mxser_boards[i].ports[j];
|
||||||
|
port = &ip->port;
|
||||||
memset(&ms, 0, sizeof(ms));
|
memset(&ms, 0, sizeof(ms));
|
||||||
|
|
||||||
if (!port->ioaddr)
|
mutex_lock(&port->mutex);
|
||||||
|
if (!ip->ioaddr)
|
||||||
goto copy;
|
goto copy;
|
||||||
|
|
||||||
tty = tty_port_tty_get(&port->port);
|
tty = tty_port_tty_get(port);
|
||||||
|
|
||||||
if (!tty || !tty->termios)
|
if (!tty || !tty->termios)
|
||||||
ms.cflag = port->normal_termios.c_cflag;
|
ms.cflag = ip->normal_termios.c_cflag;
|
||||||
else
|
else
|
||||||
ms.cflag = tty->termios->c_cflag;
|
ms.cflag = tty->termios->c_cflag;
|
||||||
tty_kref_put(tty);
|
tty_kref_put(tty);
|
||||||
status = inb(port->ioaddr + UART_MSR);
|
spin_lock_irq(&ip->slock);
|
||||||
|
status = inb(ip->ioaddr + UART_MSR);
|
||||||
|
spin_unlock_irq(&ip->slock);
|
||||||
if (status & UART_MSR_DCD)
|
if (status & UART_MSR_DCD)
|
||||||
ms.dcd = 1;
|
ms.dcd = 1;
|
||||||
if (status & UART_MSR_DSR)
|
if (status & UART_MSR_DSR)
|
||||||
|
@ -1575,13 +1534,11 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
||||||
if (status & UART_MSR_CTS)
|
if (status & UART_MSR_CTS)
|
||||||
ms.cts = 1;
|
ms.cts = 1;
|
||||||
copy:
|
copy:
|
||||||
if (copy_to_user(msu, &ms, sizeof(ms))) {
|
mutex_unlock(&port->mutex);
|
||||||
unlock_kernel();
|
if (copy_to_user(msu, &ms, sizeof(ms)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
|
||||||
msu++;
|
msu++;
|
||||||
}
|
}
|
||||||
unlock_kernel();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case MOXA_ASPP_MON_EXT: {
|
case MOXA_ASPP_MON_EXT: {
|
||||||
|
@ -1593,41 +1550,48 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
||||||
if (!me)
|
if (!me)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
lock_kernel();
|
|
||||||
for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
|
for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
|
||||||
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
|
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
|
||||||
if (p >= ARRAY_SIZE(me->rx_cnt)) {
|
if (p >= ARRAY_SIZE(me->rx_cnt)) {
|
||||||
i = MXSER_BOARDS;
|
i = MXSER_BOARDS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
port = &mxser_boards[i].ports[j];
|
ip = &mxser_boards[i].ports[j];
|
||||||
if (!port->ioaddr)
|
port = &ip->port;
|
||||||
continue;
|
|
||||||
|
|
||||||
status = mxser_get_msr(port->ioaddr, 0, p);
|
mutex_lock(&port->mutex);
|
||||||
|
if (!ip->ioaddr) {
|
||||||
|
mutex_unlock(&port->mutex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_irq(&ip->slock);
|
||||||
|
status = mxser_get_msr(ip->ioaddr, 0, p);
|
||||||
|
|
||||||
if (status & UART_MSR_TERI)
|
if (status & UART_MSR_TERI)
|
||||||
port->icount.rng++;
|
ip->icount.rng++;
|
||||||
if (status & UART_MSR_DDSR)
|
if (status & UART_MSR_DDSR)
|
||||||
port->icount.dsr++;
|
ip->icount.dsr++;
|
||||||
if (status & UART_MSR_DDCD)
|
if (status & UART_MSR_DDCD)
|
||||||
port->icount.dcd++;
|
ip->icount.dcd++;
|
||||||
if (status & UART_MSR_DCTS)
|
if (status & UART_MSR_DCTS)
|
||||||
port->icount.cts++;
|
ip->icount.cts++;
|
||||||
|
|
||||||
port->mon_data.modem_status = status;
|
ip->mon_data.modem_status = status;
|
||||||
me->rx_cnt[p] = port->mon_data.rxcnt;
|
me->rx_cnt[p] = ip->mon_data.rxcnt;
|
||||||
me->tx_cnt[p] = port->mon_data.txcnt;
|
me->tx_cnt[p] = ip->mon_data.txcnt;
|
||||||
me->up_rxcnt[p] = port->mon_data.up_rxcnt;
|
me->up_rxcnt[p] = ip->mon_data.up_rxcnt;
|
||||||
me->up_txcnt[p] = port->mon_data.up_txcnt;
|
me->up_txcnt[p] = ip->mon_data.up_txcnt;
|
||||||
me->modem_status[p] =
|
me->modem_status[p] =
|
||||||
port->mon_data.modem_status;
|
ip->mon_data.modem_status;
|
||||||
tty = tty_port_tty_get(&port->port);
|
spin_unlock_irq(&ip->slock);
|
||||||
|
|
||||||
|
tty = tty_port_tty_get(&ip->port);
|
||||||
|
|
||||||
if (!tty || !tty->termios) {
|
if (!tty || !tty->termios) {
|
||||||
cflag = port->normal_termios.c_cflag;
|
cflag = ip->normal_termios.c_cflag;
|
||||||
iflag = port->normal_termios.c_iflag;
|
iflag = ip->normal_termios.c_iflag;
|
||||||
me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
|
me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
|
||||||
} else {
|
} else {
|
||||||
cflag = tty->termios->c_cflag;
|
cflag = tty->termios->c_cflag;
|
||||||
iflag = tty->termios->c_iflag;
|
iflag = tty->termios->c_iflag;
|
||||||
|
@ -1646,16 +1610,15 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
||||||
if (iflag & (IXON | IXOFF))
|
if (iflag & (IXON | IXOFF))
|
||||||
me->flowctrl[p] |= 0x0C;
|
me->flowctrl[p] |= 0x0C;
|
||||||
|
|
||||||
if (port->type == PORT_16550A)
|
if (ip->type == PORT_16550A)
|
||||||
me->fifo[p] = 1;
|
me->fifo[p] = 1;
|
||||||
|
|
||||||
opmode = inb(port->opmode_ioaddr) >>
|
opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
|
||||||
((p % 4) * 2);
|
|
||||||
opmode &= OP_MODE_MASK;
|
opmode &= OP_MODE_MASK;
|
||||||
me->iftype[p] = opmode;
|
me->iftype[p] = opmode;
|
||||||
|
mutex_unlock(&port->mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlock_kernel();
|
|
||||||
if (copy_to_user(argp, me, sizeof(*me)))
|
if (copy_to_user(argp, me, sizeof(*me)))
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
kfree(me);
|
kfree(me);
|
||||||
|
@ -1692,6 +1655,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct mxser_port *info = tty->driver_data;
|
struct mxser_port *info = tty->driver_data;
|
||||||
|
struct tty_port *port = &info->port;
|
||||||
struct async_icount cnow;
|
struct async_icount cnow;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
|
@ -1716,20 +1680,20 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
opmode != RS422_MODE &&
|
opmode != RS422_MODE &&
|
||||||
opmode != RS485_4WIRE_MODE)
|
opmode != RS485_4WIRE_MODE)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
lock_kernel();
|
|
||||||
mask = ModeMask[p];
|
mask = ModeMask[p];
|
||||||
shiftbit = p * 2;
|
shiftbit = p * 2;
|
||||||
|
spin_lock_irq(&info->slock);
|
||||||
val = inb(info->opmode_ioaddr);
|
val = inb(info->opmode_ioaddr);
|
||||||
val &= mask;
|
val &= mask;
|
||||||
val |= (opmode << shiftbit);
|
val |= (opmode << shiftbit);
|
||||||
outb(val, info->opmode_ioaddr);
|
outb(val, info->opmode_ioaddr);
|
||||||
unlock_kernel();
|
spin_unlock_irq(&info->slock);
|
||||||
} else {
|
} else {
|
||||||
lock_kernel();
|
|
||||||
shiftbit = p * 2;
|
shiftbit = p * 2;
|
||||||
|
spin_lock_irq(&info->slock);
|
||||||
opmode = inb(info->opmode_ioaddr) >> shiftbit;
|
opmode = inb(info->opmode_ioaddr) >> shiftbit;
|
||||||
|
spin_unlock_irq(&info->slock);
|
||||||
opmode &= OP_MODE_MASK;
|
opmode &= OP_MODE_MASK;
|
||||||
unlock_kernel();
|
|
||||||
if (put_user(opmode, (int __user *)argp))
|
if (put_user(opmode, (int __user *)argp))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
@ -1742,14 +1706,14 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case TIOCGSERIAL:
|
case TIOCGSERIAL:
|
||||||
lock_kernel();
|
mutex_lock(&port->mutex);
|
||||||
retval = mxser_get_serial_info(tty, argp);
|
retval = mxser_get_serial_info(tty, argp);
|
||||||
unlock_kernel();
|
mutex_unlock(&port->mutex);
|
||||||
return retval;
|
return retval;
|
||||||
case TIOCSSERIAL:
|
case TIOCSSERIAL:
|
||||||
lock_kernel();
|
mutex_lock(&port->mutex);
|
||||||
retval = mxser_set_serial_info(tty, argp);
|
retval = mxser_set_serial_info(tty, argp);
|
||||||
unlock_kernel();
|
mutex_unlock(&port->mutex);
|
||||||
return retval;
|
return retval;
|
||||||
case TIOCSERGETLSR: /* Get line status register */
|
case TIOCSERGETLSR: /* Get line status register */
|
||||||
return mxser_get_lsr_info(info, argp);
|
return mxser_get_lsr_info(info, argp);
|
||||||
|
@ -1795,31 +1759,33 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
case MOXA_HighSpeedOn:
|
case MOXA_HighSpeedOn:
|
||||||
return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
|
return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
|
||||||
case MOXA_SDS_RSTICOUNTER:
|
case MOXA_SDS_RSTICOUNTER:
|
||||||
lock_kernel();
|
spin_lock_irq(&info->slock);
|
||||||
info->mon_data.rxcnt = 0;
|
info->mon_data.rxcnt = 0;
|
||||||
info->mon_data.txcnt = 0;
|
info->mon_data.txcnt = 0;
|
||||||
unlock_kernel();
|
spin_unlock_irq(&info->slock);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case MOXA_ASPP_OQUEUE:{
|
case MOXA_ASPP_OQUEUE:{
|
||||||
int len, lsr;
|
int len, lsr;
|
||||||
|
|
||||||
lock_kernel();
|
|
||||||
len = mxser_chars_in_buffer(tty);
|
len = mxser_chars_in_buffer(tty);
|
||||||
|
spin_lock(&info->slock);
|
||||||
lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
|
lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
|
||||||
|
spin_unlock_irq(&info->slock);
|
||||||
len += (lsr ? 0 : 1);
|
len += (lsr ? 0 : 1);
|
||||||
unlock_kernel();
|
|
||||||
|
|
||||||
return put_user(len, (int __user *)argp);
|
return put_user(len, (int __user *)argp);
|
||||||
}
|
}
|
||||||
case MOXA_ASPP_MON: {
|
case MOXA_ASPP_MON: {
|
||||||
int mcr, status;
|
int mcr, status;
|
||||||
|
|
||||||
lock_kernel();
|
spin_lock(&info->slock);
|
||||||
status = mxser_get_msr(info->ioaddr, 1, tty->index);
|
status = mxser_get_msr(info->ioaddr, 1, tty->index);
|
||||||
mxser_check_modem_status(tty, info, status);
|
mxser_check_modem_status(tty, info, status);
|
||||||
|
|
||||||
mcr = inb(info->ioaddr + UART_MCR);
|
mcr = inb(info->ioaddr + UART_MCR);
|
||||||
|
spin_unlock(&info->slock);
|
||||||
|
|
||||||
if (mcr & MOXA_MUST_MCR_XON_FLAG)
|
if (mcr & MOXA_MUST_MCR_XON_FLAG)
|
||||||
info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
|
info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
|
||||||
else
|
else
|
||||||
|
@ -1834,7 +1800,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
|
info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
|
||||||
else
|
else
|
||||||
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
|
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
|
||||||
unlock_kernel();
|
|
||||||
if (copy_to_user(argp, &info->mon_data,
|
if (copy_to_user(argp, &info->mon_data,
|
||||||
sizeof(struct mxser_mon)))
|
sizeof(struct mxser_mon)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -1993,6 +1959,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||||
{
|
{
|
||||||
struct mxser_port *info = tty->driver_data;
|
struct mxser_port *info = tty->driver_data;
|
||||||
unsigned long orig_jiffies, char_time;
|
unsigned long orig_jiffies, char_time;
|
||||||
|
unsigned long flags;
|
||||||
int lsr;
|
int lsr;
|
||||||
|
|
||||||
if (info->type == PORT_UNKNOWN)
|
if (info->type == PORT_UNKNOWN)
|
||||||
|
@ -2032,19 +1999,21 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||||
timeout, char_time);
|
timeout, char_time);
|
||||||
printk("jiff=%lu...", jiffies);
|
printk("jiff=%lu...", jiffies);
|
||||||
#endif
|
#endif
|
||||||
lock_kernel();
|
spin_lock_irqsave(&info->slock, flags);
|
||||||
while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
|
while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
|
||||||
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
|
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
|
||||||
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
|
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
|
||||||
#endif
|
#endif
|
||||||
|
spin_unlock_irqrestore(&info->slock, flags);
|
||||||
schedule_timeout_interruptible(char_time);
|
schedule_timeout_interruptible(char_time);
|
||||||
|
spin_lock_irqsave(&info->slock, flags);
|
||||||
if (signal_pending(current))
|
if (signal_pending(current))
|
||||||
break;
|
break;
|
||||||
if (timeout && time_after(jiffies, orig_jiffies + timeout))
|
if (timeout && time_after(jiffies, orig_jiffies + timeout))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&info->slock, flags);
|
||||||
set_current_state(TASK_RUNNING);
|
set_current_state(TASK_RUNNING);
|
||||||
unlock_kernel();
|
|
||||||
|
|
||||||
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
|
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
|
||||||
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
|
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
|
||||||
|
@ -2059,7 +2028,6 @@ static void mxser_hangup(struct tty_struct *tty)
|
||||||
struct mxser_port *info = tty->driver_data;
|
struct mxser_port *info = tty->driver_data;
|
||||||
|
|
||||||
mxser_flush_buffer(tty);
|
mxser_flush_buffer(tty);
|
||||||
mxser_shutdown(tty);
|
|
||||||
tty_port_hangup(&info->port);
|
tty_port_hangup(&info->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2363,6 +2331,8 @@ static const struct tty_operations mxser_ops = {
|
||||||
struct tty_port_operations mxser_port_ops = {
|
struct tty_port_operations mxser_port_ops = {
|
||||||
.carrier_raised = mxser_carrier_raised,
|
.carrier_raised = mxser_carrier_raised,
|
||||||
.dtr_rts = mxser_dtr_rts,
|
.dtr_rts = mxser_dtr_rts,
|
||||||
|
.activate = mxser_activate,
|
||||||
|
.shutdown = mxser_shutdown_port,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -603,7 +603,7 @@ void ipwireless_tty_free(struct ipw_tty *tty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct tty_operations tty_ops = {
|
static const struct tty_operations tty_ops = {
|
||||||
.open = ipw_open,
|
.open = ipw_open,
|
||||||
.close = ipw_close,
|
.close = ipw_close,
|
||||||
.hangup = ipw_hangup,
|
.hangup = ipw_hangup,
|
||||||
|
|
|
@ -659,7 +659,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
|
||||||
if (!retval)
|
if (!retval)
|
||||||
return 0;
|
return 0;
|
||||||
out1:
|
out1:
|
||||||
tty_release_dev(filp);
|
tty_release(inode, filp);
|
||||||
return retval;
|
return retval;
|
||||||
out:
|
out:
|
||||||
devpts_kill_index(inode, index);
|
devpts_kill_index(inode, index);
|
||||||
|
|
|
@ -793,26 +793,21 @@ static void rc_change_speed(struct tty_struct *tty, struct riscom_board *bp,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must be called with interrupts enabled */
|
/* Must be called with interrupts enabled */
|
||||||
static int rc_setup_port(struct tty_struct *tty, struct riscom_board *bp,
|
static int rc_activate_port(struct tty_port *port, struct tty_struct *tty)
|
||||||
struct riscom_port *port)
|
|
||||||
{
|
{
|
||||||
|
struct riscom_port *rp = container_of(port, struct riscom_port, port);
|
||||||
|
struct riscom_board *bp = port_Board(rp);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (port->port.flags & ASYNC_INITIALIZED)
|
if (tty_port_alloc_xmit_buf(port) < 0)
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (tty_port_alloc_xmit_buf(&port->port) < 0)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_irqsave(&riscom_lock, flags);
|
spin_lock_irqsave(&riscom_lock, flags);
|
||||||
|
|
||||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||||
if (port->port.count == 1)
|
|
||||||
bp->count++;
|
bp->count++;
|
||||||
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
|
rp->xmit_cnt = rp->xmit_head = rp->xmit_tail = 0;
|
||||||
rc_change_speed(tty, bp, port);
|
rc_change_speed(tty, bp, rp);
|
||||||
port->port.flags |= ASYNC_INITIALIZED;
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&riscom_lock, flags);
|
spin_unlock_irqrestore(&riscom_lock, flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -821,9 +816,6 @@ static int rc_setup_port(struct tty_struct *tty, struct riscom_board *bp,
|
||||||
static void rc_shutdown_port(struct tty_struct *tty,
|
static void rc_shutdown_port(struct tty_struct *tty,
|
||||||
struct riscom_board *bp, struct riscom_port *port)
|
struct riscom_board *bp, struct riscom_port *port)
|
||||||
{
|
{
|
||||||
if (!(port->port.flags & ASYNC_INITIALIZED))
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef RC_REPORT_OVERRUN
|
#ifdef RC_REPORT_OVERRUN
|
||||||
printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
|
printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
|
||||||
board_No(bp), port_No(port), port->overrun);
|
board_No(bp), port_No(port), port->overrun);
|
||||||
|
@ -840,11 +832,6 @@ static void rc_shutdown_port(struct tty_struct *tty,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
tty_port_free_xmit_buf(&port->port);
|
tty_port_free_xmit_buf(&port->port);
|
||||||
if (C_HUPCL(tty)) {
|
|
||||||
/* Drop DTR */
|
|
||||||
bp->DTR |= (1u << port_No(port));
|
|
||||||
rc_out(bp, RC_DTR, bp->DTR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Select port */
|
/* Select port */
|
||||||
rc_out(bp, CD180_CAR, port_No(port));
|
rc_out(bp, CD180_CAR, port_No(port));
|
||||||
|
@ -856,7 +843,6 @@ static void rc_shutdown_port(struct tty_struct *tty,
|
||||||
rc_out(bp, CD180_IER, port->IER);
|
rc_out(bp, CD180_IER, port->IER);
|
||||||
|
|
||||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||||
port->port.flags &= ~ASYNC_INITIALIZED;
|
|
||||||
|
|
||||||
if (--bp->count < 0) {
|
if (--bp->count < 0) {
|
||||||
printk(KERN_INFO "rc%d: rc_shutdown_port: "
|
printk(KERN_INFO "rc%d: rc_shutdown_port: "
|
||||||
|
@ -889,6 +875,20 @@ static int carrier_raised(struct tty_port *port)
|
||||||
return CD;
|
return CD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dtr_rts(struct tty_port *port, int onoff)
|
||||||
|
{
|
||||||
|
struct riscom_port *p = container_of(port, struct riscom_port, port);
|
||||||
|
struct riscom_board *bp = port_Board(p);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&riscom_lock, flags);
|
||||||
|
bp->DTR &= ~(1u << port_No(p));
|
||||||
|
if (onoff == 0)
|
||||||
|
bp->DTR |= (1u << port_No(p));
|
||||||
|
rc_out(bp, RC_DTR, bp->DTR);
|
||||||
|
spin_unlock_irqrestore(&riscom_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
static int rc_open(struct tty_struct *tty, struct file *filp)
|
static int rc_open(struct tty_struct *tty, struct file *filp)
|
||||||
{
|
{
|
||||||
int board;
|
int board;
|
||||||
|
@ -909,14 +909,7 @@ static int rc_open(struct tty_struct *tty, struct file *filp)
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
port->port.count++;
|
return tty_port_open(&port->port, tty, filp);
|
||||||
tty->driver_data = port;
|
|
||||||
tty_port_tty_set(&port->port, tty);
|
|
||||||
|
|
||||||
error = rc_setup_port(tty, bp, port);
|
|
||||||
if (error == 0)
|
|
||||||
error = tty_port_block_til_ready(&port->port, tty, filp);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_flush_buffer(struct tty_struct *tty)
|
static void rc_flush_buffer(struct tty_struct *tty)
|
||||||
|
@ -950,7 +943,7 @@ static void rc_close_port(struct tty_port *port)
|
||||||
|
|
||||||
spin_lock_irqsave(&riscom_lock, flags);
|
spin_lock_irqsave(&riscom_lock, flags);
|
||||||
rp->IER &= ~IER_RXD;
|
rp->IER &= ~IER_RXD;
|
||||||
if (port->flags & ASYNC_INITIALIZED) {
|
|
||||||
rp->IER &= ~IER_TXRDY;
|
rp->IER &= ~IER_TXRDY;
|
||||||
rp->IER |= IER_TXEMPTY;
|
rp->IER |= IER_TXEMPTY;
|
||||||
rc_out(bp, CD180_CAR, port_No(rp));
|
rc_out(bp, CD180_CAR, port_No(rp));
|
||||||
|
@ -968,7 +961,6 @@ static void rc_close_port(struct tty_port *port)
|
||||||
if (time_after(jiffies, timeout))
|
if (time_after(jiffies, timeout))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
rc_shutdown_port(port->tty, bp, rp);
|
rc_shutdown_port(port->tty, bp, rp);
|
||||||
spin_unlock_irqrestore(&riscom_lock, flags);
|
spin_unlock_irqrestore(&riscom_lock, flags);
|
||||||
}
|
}
|
||||||
|
@ -1354,7 +1346,6 @@ static void rc_hangup(struct tty_struct *tty)
|
||||||
if (rc_paranoia_check(port, tty->name, "rc_hangup"))
|
if (rc_paranoia_check(port, tty->name, "rc_hangup"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rc_shutdown_port(tty, port_Board(port), port);
|
|
||||||
tty_port_hangup(&port->port);
|
tty_port_hangup(&port->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1401,7 +1392,9 @@ static const struct tty_operations riscom_ops = {
|
||||||
|
|
||||||
static const struct tty_port_operations riscom_port_ops = {
|
static const struct tty_port_operations riscom_port_ops = {
|
||||||
.carrier_raised = carrier_raised,
|
.carrier_raised = carrier_raised,
|
||||||
|
.dtr_rts = dtr_rts,
|
||||||
.shutdown = rc_close_port,
|
.shutdown = rc_close_port,
|
||||||
|
.activate = rc_activate_port,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -407,7 +407,7 @@ static unsigned int stl_baudrates[] = {
|
||||||
* Declare all those functions in this driver!
|
* Declare all those functions in this driver!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
|
static long stl_memioctl(struct file *fp, unsigned int cmd, unsigned long arg);
|
||||||
static int stl_brdinit(struct stlbrd *brdp);
|
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_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_clrportstats(struct stlport *portp, comstats_t __user *cp);
|
||||||
|
@ -607,7 +607,7 @@ static unsigned int sc26198_baudtable[] = {
|
||||||
*/
|
*/
|
||||||
static const struct file_operations stl_fsiomem = {
|
static const struct file_operations stl_fsiomem = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.ioctl = stl_memioctl,
|
.unlocked_ioctl = stl_memioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct class *stallion_class;
|
static struct class *stallion_class;
|
||||||
|
@ -702,6 +702,24 @@ static struct stlbrd *stl_allocbrd(void)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static int stl_activate(struct tty_port *port, struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
struct stlport *portp = container_of(port, struct stlport, port);
|
||||||
|
if (!portp->tx.buf) {
|
||||||
|
portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
|
||||||
|
if (!portp->tx.buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
portp->tx.head = portp->tx.buf;
|
||||||
|
portp->tx.tail = portp->tx.buf;
|
||||||
|
}
|
||||||
|
stl_setport(portp, tty->termios);
|
||||||
|
portp->sigs = stl_getsignals(portp);
|
||||||
|
stl_setsignals(portp, 1, 1);
|
||||||
|
stl_enablerxtx(portp, 1, 1);
|
||||||
|
stl_startrxtx(portp, 1, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int stl_open(struct tty_struct *tty, struct file *filp)
|
static int stl_open(struct tty_struct *tty, struct file *filp)
|
||||||
{
|
{
|
||||||
struct stlport *portp;
|
struct stlport *portp;
|
||||||
|
@ -737,32 +755,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
|
||||||
if (portp == NULL)
|
if (portp == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
port = &portp->port;
|
port = &portp->port;
|
||||||
|
return tty_port_open(&portp->port, tty, filp);
|
||||||
|
|
||||||
/*
|
|
||||||
* On the first open of the device setup the port hardware, and
|
|
||||||
* initialize the per port data structure.
|
|
||||||
*/
|
|
||||||
tty_port_tty_set(port, tty);
|
|
||||||
tty->driver_data = portp;
|
|
||||||
port->count++;
|
|
||||||
|
|
||||||
if ((port->flags & ASYNC_INITIALIZED) == 0) {
|
|
||||||
if (!portp->tx.buf) {
|
|
||||||
portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
|
|
||||||
if (!portp->tx.buf)
|
|
||||||
return -ENOMEM;
|
|
||||||
portp->tx.head = portp->tx.buf;
|
|
||||||
portp->tx.tail = portp->tx.buf;
|
|
||||||
}
|
|
||||||
stl_setport(portp, tty->termios);
|
|
||||||
portp->sigs = stl_getsignals(portp);
|
|
||||||
stl_setsignals(portp, 1, 1);
|
|
||||||
stl_enablerxtx(portp, 1, 1);
|
|
||||||
stl_startrxtx(portp, 1, 0);
|
|
||||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
|
||||||
port->flags |= ASYNC_INITIALIZED;
|
|
||||||
}
|
|
||||||
return tty_port_block_til_ready(port, tty, filp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -826,38 +820,12 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void stl_close(struct tty_struct *tty, struct file *filp)
|
static void stl_shutdown(struct tty_port *port)
|
||||||
{
|
{
|
||||||
struct stlport *portp;
|
struct stlport *portp = container_of(port, struct stlport, port);
|
||||||
struct tty_port *port;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp);
|
|
||||||
|
|
||||||
portp = tty->driver_data;
|
|
||||||
BUG_ON(portp == NULL);
|
|
||||||
|
|
||||||
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)
|
|
||||||
*/
|
|
||||||
stl_waituntilsent(tty, (HZ / 2));
|
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
|
||||||
portp->port.flags &= ~ASYNC_INITIALIZED;
|
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
|
||||||
|
|
||||||
stl_disableintrs(portp);
|
stl_disableintrs(portp);
|
||||||
if (tty->termios->c_cflag & HUPCL)
|
|
||||||
stl_setsignals(portp, 0, 0);
|
|
||||||
stl_enablerxtx(portp, 0, 0);
|
stl_enablerxtx(portp, 0, 0);
|
||||||
stl_flushbuffer(tty);
|
stl_flush(portp);
|
||||||
portp->istate = 0;
|
portp->istate = 0;
|
||||||
if (portp->tx.buf != NULL) {
|
if (portp->tx.buf != NULL) {
|
||||||
kfree(portp->tx.buf);
|
kfree(portp->tx.buf);
|
||||||
|
@ -865,9 +833,16 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
|
||||||
portp->tx.head = NULL;
|
portp->tx.head = NULL;
|
||||||
portp->tx.tail = NULL;
|
portp->tx.tail = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tty_port_close_end(port, tty);
|
static void stl_close(struct tty_struct *tty, struct file *filp)
|
||||||
tty_port_tty_set(port, NULL);
|
{
|
||||||
|
struct stlport*portp;
|
||||||
|
pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp);
|
||||||
|
|
||||||
|
portp = tty->driver_data;
|
||||||
|
BUG_ON(portp == NULL);
|
||||||
|
tty_port_close(&portp->port, tty, filp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -1314,35 +1289,12 @@ static void stl_stop(struct tty_struct *tty)
|
||||||
|
|
||||||
static void stl_hangup(struct tty_struct *tty)
|
static void stl_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct stlport *portp;
|
struct stlport *portp = tty->driver_data;
|
||||||
struct tty_port *port;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
pr_debug("stl_hangup(tty=%p)\n", tty);
|
pr_debug("stl_hangup(tty=%p)\n", tty);
|
||||||
|
|
||||||
portp = tty->driver_data;
|
|
||||||
if (portp == NULL)
|
if (portp == NULL)
|
||||||
return;
|
return;
|
||||||
port = &portp->port;
|
tty_port_hangup(&portp->port);
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
|
||||||
port->flags &= ~ASYNC_INITIALIZED;
|
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
|
||||||
|
|
||||||
stl_disableintrs(portp);
|
|
||||||
if (tty->termios->c_cflag & HUPCL)
|
|
||||||
stl_setsignals(portp, 0, 0);
|
|
||||||
stl_enablerxtx(portp, 0, 0);
|
|
||||||
stl_flushbuffer(tty);
|
|
||||||
portp->istate = 0;
|
|
||||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
|
||||||
if (portp->tx.buf != NULL) {
|
|
||||||
kfree(portp->tx.buf);
|
|
||||||
portp->tx.buf = NULL;
|
|
||||||
portp->tx.head = NULL;
|
|
||||||
portp->tx.tail = NULL;
|
|
||||||
}
|
|
||||||
tty_port_hangup(port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -2486,18 +2438,19 @@ static int stl_getbrdstruct(struct stlbrd __user *arg)
|
||||||
* collection.
|
* collection.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
|
static long stl_memioctl(struct file *fp, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
int brdnr, rc;
|
int brdnr, rc;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
|
|
||||||
pr_debug("stl_memioctl(ip=%p,fp=%p,cmd=%x,arg=%lx)\n", ip, fp, cmd,arg);
|
pr_debug("stl_memioctl(fp=%p,cmd=%x,arg=%lx)\n", fp, cmd,arg);
|
||||||
|
|
||||||
brdnr = iminor(ip);
|
brdnr = iminor(fp->f_dentry->d_inode);
|
||||||
if (brdnr >= STL_MAXBRDS)
|
if (brdnr >= STL_MAXBRDS)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
|
lock_kernel();
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case COM_GETPORTSTATS:
|
case COM_GETPORTSTATS:
|
||||||
rc = stl_getportstats(NULL, NULL, argp);
|
rc = stl_getportstats(NULL, NULL, argp);
|
||||||
|
@ -2518,7 +2471,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
|
||||||
rc = -ENOIOCTLCMD;
|
rc = -ENOIOCTLCMD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
unlock_kernel();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2549,6 +2502,8 @@ static const struct tty_operations stl_ops = {
|
||||||
static const struct tty_port_operations stl_port_ops = {
|
static const struct tty_port_operations stl_port_ops = {
|
||||||
.carrier_raised = stl_carrier_raised,
|
.carrier_raised = stl_carrier_raised,
|
||||||
.dtr_rts = stl_dtr_rts,
|
.dtr_rts = stl_dtr_rts,
|
||||||
|
.activate = stl_activate,
|
||||||
|
.shutdown = stl_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -142,7 +142,6 @@ ssize_t redirected_tty_write(struct file *, const char __user *,
|
||||||
size_t, loff_t *);
|
size_t, loff_t *);
|
||||||
static unsigned int tty_poll(struct file *, poll_table *);
|
static unsigned int tty_poll(struct file *, poll_table *);
|
||||||
static int tty_open(struct inode *, struct file *);
|
static int tty_open(struct inode *, struct file *);
|
||||||
static int tty_release(struct inode *, struct file *);
|
|
||||||
long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
static long tty_compat_ioctl(struct file *file, unsigned int cmd,
|
static long tty_compat_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
@ -506,8 +505,6 @@ static void do_tty_hangup(struct work_struct *work)
|
||||||
if (!tty)
|
if (!tty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* inuse_filps is protected by the single kernel lock */
|
|
||||||
lock_kernel();
|
|
||||||
|
|
||||||
spin_lock(&redirect_lock);
|
spin_lock(&redirect_lock);
|
||||||
if (redirect && redirect->private_data == tty) {
|
if (redirect && redirect->private_data == tty) {
|
||||||
|
@ -516,7 +513,11 @@ static void do_tty_hangup(struct work_struct *work)
|
||||||
}
|
}
|
||||||
spin_unlock(&redirect_lock);
|
spin_unlock(&redirect_lock);
|
||||||
|
|
||||||
|
/* inuse_filps is protected by the single kernel lock */
|
||||||
|
lock_kernel();
|
||||||
check_tty_count(tty, "do_tty_hangup");
|
check_tty_count(tty, "do_tty_hangup");
|
||||||
|
unlock_kernel();
|
||||||
|
|
||||||
file_list_lock();
|
file_list_lock();
|
||||||
/* This breaks for file handles being sent over AF_UNIX sockets ? */
|
/* This breaks for file handles being sent over AF_UNIX sockets ? */
|
||||||
list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) {
|
list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) {
|
||||||
|
@ -530,6 +531,7 @@ static void do_tty_hangup(struct work_struct *work)
|
||||||
}
|
}
|
||||||
file_list_unlock();
|
file_list_unlock();
|
||||||
|
|
||||||
|
lock_kernel();
|
||||||
tty_ldisc_hangup(tty);
|
tty_ldisc_hangup(tty);
|
||||||
|
|
||||||
read_lock(&tasklist_lock);
|
read_lock(&tasklist_lock);
|
||||||
|
@ -708,6 +710,8 @@ void disassociate_ctty(int on_exit)
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
struct pid *tty_pgrp = NULL;
|
struct pid *tty_pgrp = NULL;
|
||||||
|
|
||||||
|
if (!current->signal->leader)
|
||||||
|
return;
|
||||||
|
|
||||||
tty = get_current_tty();
|
tty = get_current_tty();
|
||||||
if (tty) {
|
if (tty) {
|
||||||
|
@ -773,7 +777,6 @@ void no_tty(void)
|
||||||
{
|
{
|
||||||
struct task_struct *tsk = current;
|
struct task_struct *tsk = current;
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
if (tsk->signal->leader)
|
|
||||||
disassociate_ctty(0);
|
disassociate_ctty(0);
|
||||||
unlock_kernel();
|
unlock_kernel();
|
||||||
proc_clear_tty(tsk);
|
proc_clear_tty(tsk);
|
||||||
|
@ -1017,14 +1020,16 @@ out:
|
||||||
|
|
||||||
void tty_write_message(struct tty_struct *tty, char *msg)
|
void tty_write_message(struct tty_struct *tty, char *msg)
|
||||||
{
|
{
|
||||||
lock_kernel();
|
|
||||||
if (tty) {
|
if (tty) {
|
||||||
mutex_lock(&tty->atomic_write_lock);
|
mutex_lock(&tty->atomic_write_lock);
|
||||||
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags))
|
lock_kernel();
|
||||||
|
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
|
||||||
|
unlock_kernel();
|
||||||
tty->ops->write(tty, msg, strlen(msg));
|
tty->ops->write(tty, msg, strlen(msg));
|
||||||
|
} else
|
||||||
|
unlock_kernel();
|
||||||
tty_write_unlock(tty);
|
tty_write_unlock(tty);
|
||||||
}
|
}
|
||||||
unlock_kernel();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1202,14 +1207,21 @@ static int tty_driver_install_tty(struct tty_driver *driver,
|
||||||
struct tty_struct *tty)
|
struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
int idx = tty->index;
|
int idx = tty->index;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (driver->ops->install)
|
if (driver->ops->install) {
|
||||||
return driver->ops->install(driver, tty);
|
lock_kernel();
|
||||||
|
ret = driver->ops->install(driver, tty);
|
||||||
|
unlock_kernel();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (tty_init_termios(tty) == 0) {
|
if (tty_init_termios(tty) == 0) {
|
||||||
|
lock_kernel();
|
||||||
tty_driver_kref_get(driver);
|
tty_driver_kref_get(driver);
|
||||||
tty->count++;
|
tty->count++;
|
||||||
driver->ttys[idx] = tty;
|
driver->ttys[idx] = tty;
|
||||||
|
unlock_kernel();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1302,10 +1314,14 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
lock_kernel();
|
||||||
/* Check if pty master is being opened multiple times */
|
/* Check if pty master is being opened multiple times */
|
||||||
if (driver->subtype == PTY_TYPE_MASTER &&
|
if (driver->subtype == PTY_TYPE_MASTER &&
|
||||||
(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
|
(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
|
||||||
|
unlock_kernel();
|
||||||
return ERR_PTR(-EIO);
|
return ERR_PTR(-EIO);
|
||||||
|
}
|
||||||
|
unlock_kernel();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First time open is complex, especially for PTY devices.
|
* First time open is complex, especially for PTY devices.
|
||||||
|
@ -1335,7 +1351,6 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
||||||
* If we fail here just call release_tty to clean up. No need
|
* If we fail here just call release_tty to clean up. No need
|
||||||
* to decrement the use counts, as release_tty doesn't care.
|
* to decrement the use counts, as release_tty doesn't care.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
retval = tty_ldisc_setup(tty, tty->link);
|
retval = tty_ldisc_setup(tty, tty->link);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto release_mem_out;
|
goto release_mem_out;
|
||||||
|
@ -1350,7 +1365,9 @@ release_mem_out:
|
||||||
if (printk_ratelimit())
|
if (printk_ratelimit())
|
||||||
printk(KERN_INFO "tty_init_dev: ldisc open failed, "
|
printk(KERN_INFO "tty_init_dev: ldisc open failed, "
|
||||||
"clearing slot %d\n", idx);
|
"clearing slot %d\n", idx);
|
||||||
|
lock_kernel();
|
||||||
release_tty(tty, idx);
|
release_tty(tty, idx);
|
||||||
|
unlock_kernel();
|
||||||
return ERR_PTR(retval);
|
return ERR_PTR(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1464,7 +1481,17 @@ static void release_tty(struct tty_struct *tty, int idx)
|
||||||
tty_kref_put(tty);
|
tty_kref_put(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* tty_release - vfs callback for close
|
||||||
|
* @inode: inode of tty
|
||||||
|
* @filp: file pointer for handle to tty
|
||||||
|
*
|
||||||
|
* Called the last time each file handle is closed that references
|
||||||
|
* this tty. There may however be several such references.
|
||||||
|
*
|
||||||
|
* Locking:
|
||||||
|
* Takes bkl. See tty_release_dev
|
||||||
|
*
|
||||||
* Even releasing the tty structures is a tricky business.. We have
|
* Even releasing the tty structures is a tricky business.. We have
|
||||||
* to be very careful that the structures are all released at the
|
* to be very careful that the structures are all released at the
|
||||||
* same time, as interrupts might otherwise get the wrong pointers.
|
* same time, as interrupts might otherwise get the wrong pointers.
|
||||||
|
@ -1472,20 +1499,20 @@ static void release_tty(struct tty_struct *tty, int idx)
|
||||||
* WSH 09/09/97: rewritten to avoid some nasty race conditions that could
|
* WSH 09/09/97: rewritten to avoid some nasty race conditions that could
|
||||||
* lead to double frees or releasing memory still in use.
|
* lead to double frees or releasing memory still in use.
|
||||||
*/
|
*/
|
||||||
void tty_release_dev(struct file *filp)
|
|
||||||
|
int tty_release(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
struct tty_struct *tty, *o_tty;
|
struct tty_struct *tty, *o_tty;
|
||||||
int pty_master, tty_closing, o_tty_closing, do_sleep;
|
int pty_master, tty_closing, o_tty_closing, do_sleep;
|
||||||
int devpts;
|
int devpts;
|
||||||
int idx;
|
int idx;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
struct inode *inode;
|
|
||||||
|
|
||||||
inode = filp->f_path.dentry->d_inode;
|
|
||||||
tty = (struct tty_struct *)filp->private_data;
|
tty = (struct tty_struct *)filp->private_data;
|
||||||
if (tty_paranoia_check(tty, inode, "tty_release_dev"))
|
if (tty_paranoia_check(tty, inode, "tty_release_dev"))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
|
lock_kernel();
|
||||||
check_tty_count(tty, "tty_release_dev");
|
check_tty_count(tty, "tty_release_dev");
|
||||||
|
|
||||||
tty_fasync(-1, filp, 0);
|
tty_fasync(-1, filp, 0);
|
||||||
|
@ -1500,19 +1527,22 @@ void tty_release_dev(struct file *filp)
|
||||||
if (idx < 0 || idx >= tty->driver->num) {
|
if (idx < 0 || idx >= tty->driver->num) {
|
||||||
printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
|
printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
|
||||||
"free (%s)\n", tty->name);
|
"free (%s)\n", tty->name);
|
||||||
return;
|
unlock_kernel();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (!devpts) {
|
if (!devpts) {
|
||||||
if (tty != tty->driver->ttys[idx]) {
|
if (tty != tty->driver->ttys[idx]) {
|
||||||
|
unlock_kernel();
|
||||||
printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
|
printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
|
||||||
"for (%s)\n", idx, tty->name);
|
"for (%s)\n", idx, tty->name);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
if (tty->termios != tty->driver->termios[idx]) {
|
if (tty->termios != tty->driver->termios[idx]) {
|
||||||
|
unlock_kernel();
|
||||||
printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
|
printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
|
||||||
"for (%s)\n",
|
"for (%s)\n",
|
||||||
idx, tty->name);
|
idx, tty->name);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1526,26 +1556,30 @@ void tty_release_dev(struct file *filp)
|
||||||
if (tty->driver->other &&
|
if (tty->driver->other &&
|
||||||
!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
|
!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
|
||||||
if (o_tty != tty->driver->other->ttys[idx]) {
|
if (o_tty != tty->driver->other->ttys[idx]) {
|
||||||
|
unlock_kernel();
|
||||||
printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
|
printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
|
||||||
"not o_tty for (%s)\n",
|
"not o_tty for (%s)\n",
|
||||||
idx, tty->name);
|
idx, tty->name);
|
||||||
return;
|
return 0 ;
|
||||||
}
|
}
|
||||||
if (o_tty->termios != tty->driver->other->termios[idx]) {
|
if (o_tty->termios != tty->driver->other->termios[idx]) {
|
||||||
|
unlock_kernel();
|
||||||
printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
|
printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
|
||||||
"not o_termios for (%s)\n",
|
"not o_termios for (%s)\n",
|
||||||
idx, tty->name);
|
idx, tty->name);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
if (o_tty->link != tty) {
|
if (o_tty->link != tty) {
|
||||||
|
unlock_kernel();
|
||||||
printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
|
printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (tty->ops->close)
|
if (tty->ops->close)
|
||||||
tty->ops->close(tty, filp);
|
tty->ops->close(tty, filp);
|
||||||
|
|
||||||
|
unlock_kernel();
|
||||||
/*
|
/*
|
||||||
* Sanity check: if tty->count is going to zero, there shouldn't be
|
* Sanity check: if tty->count is going to zero, there shouldn't be
|
||||||
* any waiters on tty->read_wait or tty->write_wait. We test the
|
* any waiters on tty->read_wait or tty->write_wait. We test the
|
||||||
|
@ -1568,6 +1602,7 @@ void tty_release_dev(struct file *filp)
|
||||||
opens on /dev/tty */
|
opens on /dev/tty */
|
||||||
|
|
||||||
mutex_lock(&tty_mutex);
|
mutex_lock(&tty_mutex);
|
||||||
|
lock_kernel();
|
||||||
tty_closing = tty->count <= 1;
|
tty_closing = tty->count <= 1;
|
||||||
o_tty_closing = o_tty &&
|
o_tty_closing = o_tty &&
|
||||||
(o_tty->count <= (pty_master ? 1 : 0));
|
(o_tty->count <= (pty_master ? 1 : 0));
|
||||||
|
@ -1598,6 +1633,7 @@ void tty_release_dev(struct file *filp)
|
||||||
|
|
||||||
printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
|
printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
|
||||||
"active!\n", tty_name(tty, buf));
|
"active!\n", tty_name(tty, buf));
|
||||||
|
unlock_kernel();
|
||||||
mutex_unlock(&tty_mutex);
|
mutex_unlock(&tty_mutex);
|
||||||
schedule();
|
schedule();
|
||||||
}
|
}
|
||||||
|
@ -1661,8 +1697,10 @@ void tty_release_dev(struct file *filp)
|
||||||
mutex_unlock(&tty_mutex);
|
mutex_unlock(&tty_mutex);
|
||||||
|
|
||||||
/* check whether both sides are closing ... */
|
/* check whether both sides are closing ... */
|
||||||
if (!tty_closing || (o_tty && !o_tty_closing))
|
if (!tty_closing || (o_tty && !o_tty_closing)) {
|
||||||
return;
|
unlock_kernel();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef TTY_DEBUG_HANGUP
|
#ifdef TTY_DEBUG_HANGUP
|
||||||
printk(KERN_DEBUG "freeing tty structure...");
|
printk(KERN_DEBUG "freeing tty structure...");
|
||||||
|
@ -1680,10 +1718,12 @@ void tty_release_dev(struct file *filp)
|
||||||
/* Make this pty number available for reallocation */
|
/* Make this pty number available for reallocation */
|
||||||
if (devpts)
|
if (devpts)
|
||||||
devpts_kill_index(inode, idx);
|
devpts_kill_index(inode, idx);
|
||||||
|
unlock_kernel();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __tty_open - open a tty device
|
* tty_open - open a tty device
|
||||||
* @inode: inode of device file
|
* @inode: inode of device file
|
||||||
* @filp: file pointer to tty
|
* @filp: file pointer to tty
|
||||||
*
|
*
|
||||||
|
@ -1703,7 +1743,7 @@ void tty_release_dev(struct file *filp)
|
||||||
* ->siglock protects ->signal/->sighand
|
* ->siglock protects ->signal/->sighand
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int __tty_open(struct inode *inode, struct file *filp)
|
static int tty_open(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
struct tty_struct *tty = NULL;
|
struct tty_struct *tty = NULL;
|
||||||
int noctty, retval;
|
int noctty, retval;
|
||||||
|
@ -1720,10 +1760,12 @@ retry_open:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
||||||
mutex_lock(&tty_mutex);
|
mutex_lock(&tty_mutex);
|
||||||
|
lock_kernel();
|
||||||
|
|
||||||
if (device == MKDEV(TTYAUX_MAJOR, 0)) {
|
if (device == MKDEV(TTYAUX_MAJOR, 0)) {
|
||||||
tty = get_current_tty();
|
tty = get_current_tty();
|
||||||
if (!tty) {
|
if (!tty) {
|
||||||
|
unlock_kernel();
|
||||||
mutex_unlock(&tty_mutex);
|
mutex_unlock(&tty_mutex);
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
@ -1755,12 +1797,14 @@ retry_open:
|
||||||
goto got_driver;
|
goto got_driver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unlock_kernel();
|
||||||
mutex_unlock(&tty_mutex);
|
mutex_unlock(&tty_mutex);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
driver = get_tty_driver(device, &index);
|
driver = get_tty_driver(device, &index);
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
|
unlock_kernel();
|
||||||
mutex_unlock(&tty_mutex);
|
mutex_unlock(&tty_mutex);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -1770,6 +1814,7 @@ got_driver:
|
||||||
tty = tty_driver_lookup_tty(driver, inode, index);
|
tty = tty_driver_lookup_tty(driver, inode, index);
|
||||||
|
|
||||||
if (IS_ERR(tty)) {
|
if (IS_ERR(tty)) {
|
||||||
|
unlock_kernel();
|
||||||
mutex_unlock(&tty_mutex);
|
mutex_unlock(&tty_mutex);
|
||||||
return PTR_ERR(tty);
|
return PTR_ERR(tty);
|
||||||
}
|
}
|
||||||
|
@ -1784,8 +1829,10 @@ got_driver:
|
||||||
|
|
||||||
mutex_unlock(&tty_mutex);
|
mutex_unlock(&tty_mutex);
|
||||||
tty_driver_kref_put(driver);
|
tty_driver_kref_put(driver);
|
||||||
if (IS_ERR(tty))
|
if (IS_ERR(tty)) {
|
||||||
|
unlock_kernel();
|
||||||
return PTR_ERR(tty);
|
return PTR_ERR(tty);
|
||||||
|
}
|
||||||
|
|
||||||
filp->private_data = tty;
|
filp->private_data = tty;
|
||||||
file_move(filp, &tty->tty_files);
|
file_move(filp, &tty->tty_files);
|
||||||
|
@ -1813,11 +1860,15 @@ got_driver:
|
||||||
printk(KERN_DEBUG "error %d in opening %s...", retval,
|
printk(KERN_DEBUG "error %d in opening %s...", retval,
|
||||||
tty->name);
|
tty->name);
|
||||||
#endif
|
#endif
|
||||||
tty_release_dev(filp);
|
tty_release(inode, filp);
|
||||||
if (retval != -ERESTARTSYS)
|
if (retval != -ERESTARTSYS) {
|
||||||
|
unlock_kernel();
|
||||||
return retval;
|
return retval;
|
||||||
if (signal_pending(current))
|
}
|
||||||
|
if (signal_pending(current)) {
|
||||||
|
unlock_kernel();
|
||||||
return retval;
|
return retval;
|
||||||
|
}
|
||||||
schedule();
|
schedule();
|
||||||
/*
|
/*
|
||||||
* Need to reset f_op in case a hangup happened.
|
* Need to reset f_op in case a hangup happened.
|
||||||
|
@ -1826,8 +1877,11 @@ got_driver:
|
||||||
filp->f_op = &tty_fops;
|
filp->f_op = &tty_fops;
|
||||||
goto retry_open;
|
goto retry_open;
|
||||||
}
|
}
|
||||||
|
unlock_kernel();
|
||||||
|
|
||||||
|
|
||||||
mutex_lock(&tty_mutex);
|
mutex_lock(&tty_mutex);
|
||||||
|
lock_kernel();
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
spin_lock_irq(¤t->sighand->siglock);
|
||||||
if (!noctty &&
|
if (!noctty &&
|
||||||
current->signal->leader &&
|
current->signal->leader &&
|
||||||
|
@ -1835,43 +1889,12 @@ got_driver:
|
||||||
tty->session == NULL)
|
tty->session == NULL)
|
||||||
__proc_set_tty(current, tty);
|
__proc_set_tty(current, tty);
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
spin_unlock_irq(¤t->sighand->siglock);
|
||||||
|
unlock_kernel();
|
||||||
mutex_unlock(&tty_mutex);
|
mutex_unlock(&tty_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BKL pushdown: scary code avoidance wrapper */
|
|
||||||
static int tty_open(struct inode *inode, struct file *filp)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
lock_kernel();
|
|
||||||
ret = __tty_open(inode, filp);
|
|
||||||
unlock_kernel();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* tty_release - vfs callback for close
|
|
||||||
* @inode: inode of tty
|
|
||||||
* @filp: file pointer for handle to tty
|
|
||||||
*
|
|
||||||
* Called the last time each file handle is closed that references
|
|
||||||
* this tty. There may however be several such references.
|
|
||||||
*
|
|
||||||
* Locking:
|
|
||||||
* Takes bkl. See tty_release_dev
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int tty_release(struct inode *inode, struct file *filp)
|
|
||||||
{
|
|
||||||
lock_kernel();
|
|
||||||
tty_release_dev(filp);
|
|
||||||
unlock_kernel();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_poll - check tty status
|
* tty_poll - check tty status
|
||||||
|
@ -2317,9 +2340,7 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
|
||||||
if (get_user(ldisc, p))
|
if (get_user(ldisc, p))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
lock_kernel();
|
|
||||||
ret = tty_set_ldisc(tty, ldisc);
|
ret = tty_set_ldisc(tty, ldisc);
|
||||||
unlock_kernel();
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
#include <linux/vt_kern.h>
|
#include <linux/vt_kern.h>
|
||||||
#include <linux/selection.h>
|
#include <linux/selection.h>
|
||||||
|
|
||||||
|
#include <linux/smp_lock.h> /* For the moment */
|
||||||
|
|
||||||
#include <linux/kmod.h>
|
#include <linux/kmod.h>
|
||||||
#include <linux/nsproxy.h>
|
#include <linux/nsproxy.h>
|
||||||
|
|
||||||
|
@ -443,8 +445,14 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
|
||||||
static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
|
static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||||
{
|
{
|
||||||
WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
|
WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
|
||||||
if (ld->ops->open)
|
if (ld->ops->open) {
|
||||||
return ld->ops->open(tty);
|
int ret;
|
||||||
|
/* BKL here locks verus a hangup event */
|
||||||
|
lock_kernel();
|
||||||
|
ret = ld->ops->open(tty);
|
||||||
|
unlock_kernel();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,6 +553,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||||
if (IS_ERR(new_ldisc))
|
if (IS_ERR(new_ldisc))
|
||||||
return PTR_ERR(new_ldisc);
|
return PTR_ERR(new_ldisc);
|
||||||
|
|
||||||
|
lock_kernel();
|
||||||
/*
|
/*
|
||||||
* We need to look at the tty locking here for pty/tty pairs
|
* We need to look at the tty locking here for pty/tty pairs
|
||||||
* when both sides try to change in parallel.
|
* when both sides try to change in parallel.
|
||||||
|
@ -558,10 +567,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (tty->ldisc->ops->num == ldisc) {
|
if (tty->ldisc->ops->num == ldisc) {
|
||||||
|
unlock_kernel();
|
||||||
tty_ldisc_put(new_ldisc);
|
tty_ldisc_put(new_ldisc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unlock_kernel();
|
||||||
/*
|
/*
|
||||||
* Problem: What do we do if this blocks ?
|
* Problem: What do we do if this blocks ?
|
||||||
* We could deadlock here
|
* We could deadlock here
|
||||||
|
@ -582,6 +593,9 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||||
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
|
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
|
||||||
mutex_lock(&tty->ldisc_mutex);
|
mutex_lock(&tty->ldisc_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock_kernel();
|
||||||
|
|
||||||
set_bit(TTY_LDISC_CHANGING, &tty->flags);
|
set_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -592,6 +606,8 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||||
tty->receive_room = 0;
|
tty->receive_room = 0;
|
||||||
|
|
||||||
o_ldisc = tty->ldisc;
|
o_ldisc = tty->ldisc;
|
||||||
|
|
||||||
|
unlock_kernel();
|
||||||
/*
|
/*
|
||||||
* Make sure we don't change while someone holds a
|
* Make sure we don't change while someone holds a
|
||||||
* reference to the line discipline. The TTY_LDISC bit
|
* reference to the line discipline. The TTY_LDISC bit
|
||||||
|
@ -617,12 +633,14 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||||
flush_scheduled_work();
|
flush_scheduled_work();
|
||||||
|
|
||||||
mutex_lock(&tty->ldisc_mutex);
|
mutex_lock(&tty->ldisc_mutex);
|
||||||
|
lock_kernel();
|
||||||
if (test_bit(TTY_HUPPED, &tty->flags)) {
|
if (test_bit(TTY_HUPPED, &tty->flags)) {
|
||||||
/* We were raced by the hangup method. It will have stomped
|
/* We were raced by the hangup method. It will have stomped
|
||||||
the ldisc data and closed the ldisc down */
|
the ldisc data and closed the ldisc down */
|
||||||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||||
mutex_unlock(&tty->ldisc_mutex);
|
mutex_unlock(&tty->ldisc_mutex);
|
||||||
tty_ldisc_put(new_ldisc);
|
tty_ldisc_put(new_ldisc);
|
||||||
|
unlock_kernel();
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,6 +682,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||||
if (o_work)
|
if (o_work)
|
||||||
schedule_delayed_work(&o_tty->buf.work, 1);
|
schedule_delayed_work(&o_tty->buf.work, 1);
|
||||||
mutex_unlock(&tty->ldisc_mutex);
|
mutex_unlock(&tty->ldisc_mutex);
|
||||||
|
unlock_kernel();
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,19 +25,21 @@ void tty_port_init(struct tty_port *port)
|
||||||
init_waitqueue_head(&port->close_wait);
|
init_waitqueue_head(&port->close_wait);
|
||||||
init_waitqueue_head(&port->delta_msr_wait);
|
init_waitqueue_head(&port->delta_msr_wait);
|
||||||
mutex_init(&port->mutex);
|
mutex_init(&port->mutex);
|
||||||
|
mutex_init(&port->buf_mutex);
|
||||||
spin_lock_init(&port->lock);
|
spin_lock_init(&port->lock);
|
||||||
port->close_delay = (50 * HZ) / 100;
|
port->close_delay = (50 * HZ) / 100;
|
||||||
port->closing_wait = (3000 * HZ) / 100;
|
port->closing_wait = (3000 * HZ) / 100;
|
||||||
|
kref_init(&port->kref);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tty_port_init);
|
EXPORT_SYMBOL(tty_port_init);
|
||||||
|
|
||||||
int tty_port_alloc_xmit_buf(struct tty_port *port)
|
int tty_port_alloc_xmit_buf(struct tty_port *port)
|
||||||
{
|
{
|
||||||
/* We may sleep in get_zeroed_page() */
|
/* We may sleep in get_zeroed_page() */
|
||||||
mutex_lock(&port->mutex);
|
mutex_lock(&port->buf_mutex);
|
||||||
if (port->xmit_buf == NULL)
|
if (port->xmit_buf == NULL)
|
||||||
port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
|
port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
|
||||||
mutex_unlock(&port->mutex);
|
mutex_unlock(&port->buf_mutex);
|
||||||
if (port->xmit_buf == NULL)
|
if (port->xmit_buf == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -46,15 +48,32 @@ EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
|
||||||
|
|
||||||
void tty_port_free_xmit_buf(struct tty_port *port)
|
void tty_port_free_xmit_buf(struct tty_port *port)
|
||||||
{
|
{
|
||||||
mutex_lock(&port->mutex);
|
mutex_lock(&port->buf_mutex);
|
||||||
if (port->xmit_buf != NULL) {
|
if (port->xmit_buf != NULL) {
|
||||||
free_page((unsigned long)port->xmit_buf);
|
free_page((unsigned long)port->xmit_buf);
|
||||||
port->xmit_buf = NULL;
|
port->xmit_buf = NULL;
|
||||||
}
|
}
|
||||||
mutex_unlock(&port->mutex);
|
mutex_unlock(&port->buf_mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tty_port_free_xmit_buf);
|
EXPORT_SYMBOL(tty_port_free_xmit_buf);
|
||||||
|
|
||||||
|
static void tty_port_destructor(struct kref *kref)
|
||||||
|
{
|
||||||
|
struct tty_port *port = container_of(kref, struct tty_port, kref);
|
||||||
|
if (port->xmit_buf)
|
||||||
|
free_page((unsigned long)port->xmit_buf);
|
||||||
|
if (port->ops->destruct)
|
||||||
|
port->ops->destruct(port);
|
||||||
|
else
|
||||||
|
kfree(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_port_put(struct tty_port *port)
|
||||||
|
{
|
||||||
|
if (port)
|
||||||
|
kref_put(&port->kref, tty_port_destructor);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(tty_port_put);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_port_tty_get - get a tty reference
|
* tty_port_tty_get - get a tty reference
|
||||||
|
@ -99,10 +118,11 @@ EXPORT_SYMBOL(tty_port_tty_set);
|
||||||
|
|
||||||
static void tty_port_shutdown(struct tty_port *port)
|
static void tty_port_shutdown(struct tty_port *port)
|
||||||
{
|
{
|
||||||
|
mutex_lock(&port->mutex);
|
||||||
if (port->ops->shutdown &&
|
if (port->ops->shutdown &&
|
||||||
test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
|
test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||||
port->ops->shutdown(port);
|
port->ops->shutdown(port);
|
||||||
|
mutex_unlock(&port->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,8 +140,10 @@ void tty_port_hangup(struct tty_port *port)
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
port->count = 0;
|
port->count = 0;
|
||||||
port->flags &= ~ASYNC_NORMAL_ACTIVE;
|
port->flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||||
if (port->tty)
|
if (port->tty) {
|
||||||
|
set_bit(TTY_IO_ERROR, &port->tty->flags);
|
||||||
tty_kref_put(port->tty);
|
tty_kref_put(port->tty);
|
||||||
|
}
|
||||||
port->tty = NULL;
|
port->tty = NULL;
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
wake_up_interruptible(&port->open_wait);
|
wake_up_interruptible(&port->open_wait);
|
||||||
|
@ -253,7 +275,8 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||||
tty_port_raise_dtr_rts(port);
|
tty_port_raise_dtr_rts(port);
|
||||||
|
|
||||||
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
|
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
|
||||||
/* Check for a hangup or uninitialised port. Return accordingly */
|
/* Check for a hangup or uninitialised port.
|
||||||
|
Return accordingly */
|
||||||
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
|
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
|
||||||
if (port->flags & ASYNC_HUP_NOTIFY)
|
if (port->flags & ASYNC_HUP_NOTIFY)
|
||||||
retval = -EAGAIN;
|
retval = -EAGAIN;
|
||||||
|
@ -285,11 +308,11 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tty_port_block_til_ready);
|
EXPORT_SYMBOL(tty_port_block_til_ready);
|
||||||
|
|
||||||
int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
|
int tty_port_close_start(struct tty_port *port,
|
||||||
|
struct tty_struct *tty, struct file *filp)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -331,12 +354,20 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
|
||||||
long timeout;
|
long timeout;
|
||||||
|
|
||||||
if (bps > 1200)
|
if (bps > 1200)
|
||||||
timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
|
timeout = max_t(long,
|
||||||
HZ / 10);
|
(HZ * 10 * port->drain_delay) / bps, HZ / 10);
|
||||||
else
|
else
|
||||||
timeout = 2 * HZ;
|
timeout = 2 * HZ;
|
||||||
schedule_timeout_interruptible(timeout);
|
schedule_timeout_interruptible(timeout);
|
||||||
}
|
}
|
||||||
|
/* Flush the ldisc buffering */
|
||||||
|
tty_ldisc_flush(tty);
|
||||||
|
|
||||||
|
/* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
|
||||||
|
hang up the line */
|
||||||
|
if (tty->termios->c_cflag & HUPCL)
|
||||||
|
tty_port_lower_dtr_rts(port);
|
||||||
|
|
||||||
/* Don't call port->drop for the last reference. Callers will want
|
/* Don't call port->drop for the last reference. Callers will want
|
||||||
to drop the last active reference in ->shutdown() or the tty
|
to drop the last active reference in ->shutdown() or the tty
|
||||||
shutdown path */
|
shutdown path */
|
||||||
|
@ -348,11 +379,6 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
tty_ldisc_flush(tty);
|
|
||||||
|
|
||||||
if (tty->termios->c_cflag & HUPCL)
|
|
||||||
tty_port_lower_dtr_rts(port);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
tty->closing = 0;
|
tty->closing = 0;
|
||||||
|
|
||||||
|
@ -377,7 +403,42 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
|
||||||
if (tty_port_close_start(port, tty, filp) == 0)
|
if (tty_port_close_start(port, tty, filp) == 0)
|
||||||
return;
|
return;
|
||||||
tty_port_shutdown(port);
|
tty_port_shutdown(port);
|
||||||
|
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||||
tty_port_close_end(port, tty);
|
tty_port_close_end(port, tty);
|
||||||
tty_port_tty_set(port, NULL);
|
tty_port_tty_set(port, NULL);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tty_port_close);
|
EXPORT_SYMBOL(tty_port_close);
|
||||||
|
|
||||||
|
int tty_port_open(struct tty_port *port, struct tty_struct *tty,
|
||||||
|
struct file *filp)
|
||||||
|
{
|
||||||
|
spin_lock_irq(&port->lock);
|
||||||
|
if (!tty_hung_up_p(filp))
|
||||||
|
++port->count;
|
||||||
|
spin_unlock_irq(&port->lock);
|
||||||
|
tty_port_tty_set(port, tty);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do the device-specific open only if the hardware isn't
|
||||||
|
* already initialized. Serialize open and shutdown using the
|
||||||
|
* port mutex.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mutex_lock(&port->mutex);
|
||||||
|
|
||||||
|
if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||||
|
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||||
|
if (port->ops->activate) {
|
||||||
|
int retval = port->ops->activate(port, tty);
|
||||||
|
if (retval) {
|
||||||
|
mutex_unlock(&port->mutex);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||||
|
}
|
||||||
|
mutex_unlock(&port->mutex);
|
||||||
|
return tty_port_block_til_ready(port, tty, filp);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(tty_port_open);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/serial_reg.h>
|
#include <linux/serial_reg.h>
|
||||||
|
@ -73,11 +74,10 @@ struct uart_icount {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sdio_uart_port {
|
struct sdio_uart_port {
|
||||||
|
struct tty_port port;
|
||||||
struct kref kref;
|
struct kref kref;
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
unsigned int opened;
|
|
||||||
struct mutex open_lock;
|
|
||||||
struct sdio_func *func;
|
struct sdio_func *func;
|
||||||
struct mutex func_lock;
|
struct mutex func_lock;
|
||||||
struct task_struct *in_sdio_uart_irq;
|
struct task_struct *in_sdio_uart_irq;
|
||||||
|
@ -87,6 +87,7 @@ struct sdio_uart_port {
|
||||||
struct uart_icount icount;
|
struct uart_icount icount;
|
||||||
unsigned int uartclk;
|
unsigned int uartclk;
|
||||||
unsigned int mctrl;
|
unsigned int mctrl;
|
||||||
|
unsigned int rx_mctrl;
|
||||||
unsigned int read_status_mask;
|
unsigned int read_status_mask;
|
||||||
unsigned int ignore_status_mask;
|
unsigned int ignore_status_mask;
|
||||||
unsigned char x_char;
|
unsigned char x_char;
|
||||||
|
@ -102,7 +103,6 @@ static int sdio_uart_add_port(struct sdio_uart_port *port)
|
||||||
int index, ret = -EBUSY;
|
int index, ret = -EBUSY;
|
||||||
|
|
||||||
kref_init(&port->kref);
|
kref_init(&port->kref);
|
||||||
mutex_init(&port->open_lock);
|
|
||||||
mutex_init(&port->func_lock);
|
mutex_init(&port->func_lock);
|
||||||
spin_lock_init(&port->write_lock);
|
spin_lock_init(&port->write_lock);
|
||||||
|
|
||||||
|
@ -151,6 +151,7 @@ static void sdio_uart_port_put(struct sdio_uart_port *port)
|
||||||
static void sdio_uart_port_remove(struct sdio_uart_port *port)
|
static void sdio_uart_port_remove(struct sdio_uart_port *port)
|
||||||
{
|
{
|
||||||
struct sdio_func *func;
|
struct sdio_func *func;
|
||||||
|
struct tty_struct *tty;
|
||||||
|
|
||||||
BUG_ON(sdio_uart_table[port->index] != port);
|
BUG_ON(sdio_uart_table[port->index] != port);
|
||||||
|
|
||||||
|
@ -165,15 +166,19 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
|
||||||
* give up on that port ASAP.
|
* give up on that port ASAP.
|
||||||
* Beware: the lock ordering is critical.
|
* Beware: the lock ordering is critical.
|
||||||
*/
|
*/
|
||||||
mutex_lock(&port->open_lock);
|
mutex_lock(&port->port.mutex);
|
||||||
mutex_lock(&port->func_lock);
|
mutex_lock(&port->func_lock);
|
||||||
func = port->func;
|
func = port->func;
|
||||||
sdio_claim_host(func);
|
sdio_claim_host(func);
|
||||||
port->func = NULL;
|
port->func = NULL;
|
||||||
mutex_unlock(&port->func_lock);
|
mutex_unlock(&port->func_lock);
|
||||||
if (port->opened)
|
tty = tty_port_tty_get(&port->port);
|
||||||
tty_hangup(port->tty);
|
/* tty_hangup is async so is this safe as is ?? */
|
||||||
mutex_unlock(&port->open_lock);
|
if (tty) {
|
||||||
|
tty_hangup(tty);
|
||||||
|
tty_kref_put(tty);
|
||||||
|
}
|
||||||
|
mutex_unlock(&port->port.mutex);
|
||||||
sdio_release_irq(func);
|
sdio_release_irq(func);
|
||||||
sdio_disable_func(func);
|
sdio_disable_func(func);
|
||||||
sdio_release_host(func);
|
sdio_release_host(func);
|
||||||
|
@ -217,6 +222,8 @@ static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
|
||||||
unsigned char status;
|
unsigned char status;
|
||||||
unsigned int ret;
|
unsigned int ret;
|
||||||
|
|
||||||
|
/* FIXME: What stops this losing the delta bits and breaking
|
||||||
|
sdio_uart_check_modem_status ? */
|
||||||
status = sdio_in(port, UART_MSR);
|
status = sdio_in(port, UART_MSR);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -391,7 +398,7 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port)
|
||||||
static void sdio_uart_receive_chars(struct sdio_uart_port *port,
|
static void sdio_uart_receive_chars(struct sdio_uart_port *port,
|
||||||
unsigned int *status)
|
unsigned int *status)
|
||||||
{
|
{
|
||||||
struct tty_struct *tty = port->tty;
|
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||||
unsigned int ch, flag;
|
unsigned int ch, flag;
|
||||||
int max_count = 256;
|
int max_count = 256;
|
||||||
|
|
||||||
|
@ -428,6 +435,7 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
|
if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
|
||||||
|
if (tty)
|
||||||
tty_insert_flip_char(tty, ch, flag);
|
tty_insert_flip_char(tty, ch, flag);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -435,17 +443,22 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
|
||||||
* it doesn't affect the current character.
|
* it doesn't affect the current character.
|
||||||
*/
|
*/
|
||||||
if (*status & ~port->ignore_status_mask & UART_LSR_OE)
|
if (*status & ~port->ignore_status_mask & UART_LSR_OE)
|
||||||
|
if (tty)
|
||||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||||
|
|
||||||
*status = sdio_in(port, UART_LSR);
|
*status = sdio_in(port, UART_LSR);
|
||||||
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
|
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
|
||||||
|
if (tty) {
|
||||||
tty_flip_buffer_push(tty);
|
tty_flip_buffer_push(tty);
|
||||||
|
tty_kref_put(tty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
|
static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
|
||||||
{
|
{
|
||||||
struct circ_buf *xmit = &port->xmit;
|
struct circ_buf *xmit = &port->xmit;
|
||||||
int count;
|
int count;
|
||||||
|
struct tty_struct *tty;
|
||||||
|
|
||||||
if (port->x_char) {
|
if (port->x_char) {
|
||||||
sdio_out(port, UART_TX, port->x_char);
|
sdio_out(port, UART_TX, port->x_char);
|
||||||
|
@ -453,8 +466,13 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
|
||||||
port->x_char = 0;
|
port->x_char = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (circ_empty(xmit) || port->tty->stopped || port->tty->hw_stopped) {
|
|
||||||
|
tty = tty_port_tty_get(&port->port);
|
||||||
|
|
||||||
|
if (tty == NULL || circ_empty(xmit) ||
|
||||||
|
tty->stopped || tty->hw_stopped) {
|
||||||
sdio_uart_stop_tx(port);
|
sdio_uart_stop_tx(port);
|
||||||
|
tty_kref_put(tty);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,15 +486,17 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
|
||||||
} while (--count > 0);
|
} while (--count > 0);
|
||||||
|
|
||||||
if (circ_chars_pending(xmit) < WAKEUP_CHARS)
|
if (circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||||
tty_wakeup(port->tty);
|
tty_wakeup(tty);
|
||||||
|
|
||||||
if (circ_empty(xmit))
|
if (circ_empty(xmit))
|
||||||
sdio_uart_stop_tx(port);
|
sdio_uart_stop_tx(port);
|
||||||
|
tty_kref_put(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
|
static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
struct tty_struct *tty;
|
||||||
|
|
||||||
status = sdio_in(port, UART_MSR);
|
status = sdio_in(port, UART_MSR);
|
||||||
|
|
||||||
|
@ -487,25 +507,39 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
|
||||||
port->icount.rng++;
|
port->icount.rng++;
|
||||||
if (status & UART_MSR_DDSR)
|
if (status & UART_MSR_DDSR)
|
||||||
port->icount.dsr++;
|
port->icount.dsr++;
|
||||||
if (status & UART_MSR_DDCD)
|
if (status & UART_MSR_DDCD) {
|
||||||
port->icount.dcd++;
|
port->icount.dcd++;
|
||||||
|
/* DCD raise - wake for open */
|
||||||
|
if (status & UART_MSR_DCD)
|
||||||
|
wake_up_interruptible(&port->port.open_wait);
|
||||||
|
else {
|
||||||
|
/* DCD drop - hang up if tty attached */
|
||||||
|
tty = tty_port_tty_get(&port->port);
|
||||||
|
if (tty) {
|
||||||
|
tty_hangup(tty);
|
||||||
|
tty_kref_put(tty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (status & UART_MSR_DCTS) {
|
if (status & UART_MSR_DCTS) {
|
||||||
port->icount.cts++;
|
port->icount.cts++;
|
||||||
if (port->tty->termios->c_cflag & CRTSCTS) {
|
tty = tty_port_tty_get(&port->port);
|
||||||
|
if (tty && (tty->termios->c_cflag & CRTSCTS)) {
|
||||||
int cts = (status & UART_MSR_CTS);
|
int cts = (status & UART_MSR_CTS);
|
||||||
if (port->tty->hw_stopped) {
|
if (tty->hw_stopped) {
|
||||||
if (cts) {
|
if (cts) {
|
||||||
port->tty->hw_stopped = 0;
|
tty->hw_stopped = 0;
|
||||||
sdio_uart_start_tx(port);
|
sdio_uart_start_tx(port);
|
||||||
tty_wakeup(port->tty);
|
tty_wakeup(tty);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!cts) {
|
if (!cts) {
|
||||||
port->tty->hw_stopped = 1;
|
tty->hw_stopped = 1;
|
||||||
sdio_uart_stop_tx(port);
|
sdio_uart_stop_tx(port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tty_kref_put(tty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,8 +576,62 @@ static void sdio_uart_irq(struct sdio_func *func)
|
||||||
port->in_sdio_uart_irq = NULL;
|
port->in_sdio_uart_irq = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdio_uart_startup(struct sdio_uart_port *port)
|
static int uart_carrier_raised(struct tty_port *tport)
|
||||||
{
|
{
|
||||||
|
struct sdio_uart_port *port =
|
||||||
|
container_of(tport, struct sdio_uart_port, port);
|
||||||
|
unsigned int ret = sdio_uart_claim_func(port);
|
||||||
|
if (ret) /* Missing hardware shoudn't block for carrier */
|
||||||
|
return 1;
|
||||||
|
ret = sdio_uart_get_mctrl(port);
|
||||||
|
sdio_uart_release_func(port);
|
||||||
|
if (ret & TIOCM_CAR)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uart_dtr_rts - port helper to set uart signals
|
||||||
|
* @tport: tty port to be updated
|
||||||
|
* @onoff: set to turn on DTR/RTS
|
||||||
|
*
|
||||||
|
* Called by the tty port helpers when the modem signals need to be
|
||||||
|
* adjusted during an open, close and hangup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void uart_dtr_rts(struct tty_port *tport, int onoff)
|
||||||
|
{
|
||||||
|
struct sdio_uart_port *port =
|
||||||
|
container_of(tport, struct sdio_uart_port, port);
|
||||||
|
int ret = sdio_uart_claim_func(port);
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
|
if (onoff == 0)
|
||||||
|
sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
|
||||||
|
else
|
||||||
|
sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
|
||||||
|
sdio_uart_release_func(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sdio_uart_activate - start up hardware
|
||||||
|
* @tport: tty port to activate
|
||||||
|
* @tty: tty bound to this port
|
||||||
|
*
|
||||||
|
* Activate a tty port. The port locking guarantees us this will be
|
||||||
|
* run exactly once per set of opens, and if successful will see the
|
||||||
|
* shutdown method run exactly once to match. Start up and shutdown are
|
||||||
|
* protected from each other by the internal locking and will not run
|
||||||
|
* at the same time even during a hangup event.
|
||||||
|
*
|
||||||
|
* If we successfully start up the port we take an extra kref as we
|
||||||
|
* will keep it around until shutdown when the kref is dropped.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
struct sdio_uart_port *port =
|
||||||
|
container_of(tport, struct sdio_uart_port, port);
|
||||||
unsigned long page;
|
unsigned long page;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -551,7 +639,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
|
||||||
* Set the TTY IO error marker - we will only clear this
|
* Set the TTY IO error marker - we will only clear this
|
||||||
* once we have successfully opened the port.
|
* once we have successfully opened the port.
|
||||||
*/
|
*/
|
||||||
set_bit(TTY_IO_ERROR, &port->tty->flags);
|
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||||
|
|
||||||
/* Initialise and allocate the transmit buffer. */
|
/* Initialise and allocate the transmit buffer. */
|
||||||
page = __get_free_page(GFP_KERNEL);
|
page = __get_free_page(GFP_KERNEL);
|
||||||
|
@ -595,16 +683,16 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
|
||||||
port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
|
port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
|
||||||
port->mctrl = TIOCM_OUT2;
|
port->mctrl = TIOCM_OUT2;
|
||||||
|
|
||||||
sdio_uart_change_speed(port, port->tty->termios, NULL);
|
sdio_uart_change_speed(port, tty->termios, NULL);
|
||||||
|
|
||||||
if (port->tty->termios->c_cflag & CBAUD)
|
if (tty->termios->c_cflag & CBAUD)
|
||||||
sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
|
sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
|
||||||
|
|
||||||
if (port->tty->termios->c_cflag & CRTSCTS)
|
if (tty->termios->c_cflag & CRTSCTS)
|
||||||
if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
|
if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
|
||||||
port->tty->hw_stopped = 1;
|
tty->hw_stopped = 1;
|
||||||
|
|
||||||
clear_bit(TTY_IO_ERROR, &port->tty->flags);
|
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||||
|
|
||||||
/* Kick the IRQ handler once while we're still holding the host lock */
|
/* Kick the IRQ handler once while we're still holding the host lock */
|
||||||
sdio_uart_irq(port->func);
|
sdio_uart_irq(port->func);
|
||||||
|
@ -621,8 +709,20 @@ err1:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdio_uart_shutdown(struct sdio_uart_port *port)
|
/**
|
||||||
|
* sdio_uart_shutdown - stop hardware
|
||||||
|
* @tport: tty port to shut down
|
||||||
|
*
|
||||||
|
* Deactivate a tty port. The port locking guarantees us this will be
|
||||||
|
* run only if a successful matching activate already ran. The two are
|
||||||
|
* protected from each other by the internal locking and will not run
|
||||||
|
* at the same time even during a hangup event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void sdio_uart_shutdown(struct tty_port *tport)
|
||||||
{
|
{
|
||||||
|
struct sdio_uart_port *port =
|
||||||
|
container_of(tport, struct sdio_uart_port, port);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = sdio_uart_claim_func(port);
|
ret = sdio_uart_claim_func(port);
|
||||||
|
@ -631,12 +731,6 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port)
|
||||||
|
|
||||||
sdio_uart_stop_rx(port);
|
sdio_uart_stop_rx(port);
|
||||||
|
|
||||||
/* TODO: wait here for TX FIFO to drain */
|
|
||||||
|
|
||||||
/* Turn off DTR and RTS early. */
|
|
||||||
if (port->tty->termios->c_cflag & HUPCL)
|
|
||||||
sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
|
|
||||||
|
|
||||||
/* Disable interrupts from this port */
|
/* Disable interrupts from this port */
|
||||||
sdio_release_irq(port->func);
|
sdio_release_irq(port->func);
|
||||||
port->ier = 0;
|
port->ier = 0;
|
||||||
|
@ -661,74 +755,67 @@ skip:
|
||||||
free_page((unsigned long)port->xmit.buf);
|
free_page((unsigned long)port->xmit.buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
|
/**
|
||||||
{
|
* sdio_uart_install - install method
|
||||||
struct sdio_uart_port *port;
|
* @driver: the driver in use (sdio_uart in our case)
|
||||||
int ret;
|
* @tty: the tty being bound
|
||||||
|
*
|
||||||
port = sdio_uart_port_get(tty->index);
|
* Look up and bind the tty and the driver together. Initialize
|
||||||
if (!port)
|
* any needed private data (in our case the termios)
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
mutex_lock(&port->open_lock);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure not to mess up with a dead port
|
|
||||||
* which has not been closed yet.
|
|
||||||
*/
|
*/
|
||||||
if (tty->driver_data && tty->driver_data != port) {
|
|
||||||
mutex_unlock(&port->open_lock);
|
|
||||||
sdio_uart_port_put(port);
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!port->opened) {
|
static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
int idx = tty->index;
|
||||||
|
struct sdio_uart_port *port = sdio_uart_port_get(idx);
|
||||||
|
int ret = tty_init_termios(tty);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
tty_driver_kref_get(driver);
|
||||||
|
tty->count++;
|
||||||
|
/* This is the ref sdio_uart_port get provided */
|
||||||
tty->driver_data = port;
|
tty->driver_data = port;
|
||||||
port->tty = tty;
|
driver->ttys[idx] = tty;
|
||||||
ret = sdio_uart_startup(port);
|
} else
|
||||||
if (ret) {
|
|
||||||
tty->driver_data = NULL;
|
|
||||||
port->tty = NULL;
|
|
||||||
mutex_unlock(&port->open_lock);
|
|
||||||
sdio_uart_port_put(port);
|
sdio_uart_port_put(port);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sdio_uart_cleanup - called on the last tty kref drop
|
||||||
|
* @tty: the tty being destroyed
|
||||||
|
*
|
||||||
|
* Called asynchronously when the last reference to the tty is dropped.
|
||||||
|
* We cannot destroy the tty->driver_data port kref until this point
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void sdio_uart_cleanup(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
struct sdio_uart_port *port = tty->driver_data;
|
||||||
|
tty->driver_data = NULL; /* Bug trap */
|
||||||
|
sdio_uart_port_put(port);
|
||||||
}
|
}
|
||||||
port->opened++;
|
|
||||||
mutex_unlock(&port->open_lock);
|
/*
|
||||||
return 0;
|
* Open/close/hangup is now entirely boilerplate
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
|
||||||
|
{
|
||||||
|
struct sdio_uart_port *port = tty->driver_data;
|
||||||
|
return tty_port_open(&port->port, tty, filp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
|
static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
|
||||||
{
|
{
|
||||||
struct sdio_uart_port *port = tty->driver_data;
|
struct sdio_uart_port *port = tty->driver_data;
|
||||||
|
tty_port_close(&port->port, tty, filp);
|
||||||
if (!port)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mutex_lock(&port->open_lock);
|
|
||||||
BUG_ON(!port->opened);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is messy. The tty layer calls us even when open()
|
|
||||||
* returned an error. Ignore this close request if tty->count
|
|
||||||
* is larger than port->count.
|
|
||||||
*/
|
|
||||||
if (tty->count > port->opened) {
|
|
||||||
mutex_unlock(&port->open_lock);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (--port->opened == 0) {
|
static void sdio_uart_hangup(struct tty_struct *tty)
|
||||||
tty->closing = 1;
|
{
|
||||||
sdio_uart_shutdown(port);
|
struct sdio_uart_port *port = tty->driver_data;
|
||||||
tty_ldisc_flush(tty);
|
tty_port_hangup(&port->port);
|
||||||
port->tty = NULL;
|
|
||||||
tty->driver_data = NULL;
|
|
||||||
tty->closing = 0;
|
|
||||||
}
|
|
||||||
mutex_unlock(&port->open_lock);
|
|
||||||
sdio_uart_port_put(port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
|
static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
|
||||||
|
@ -843,17 +930,12 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
|
||||||
sdio_uart_release_func(port);
|
sdio_uart_release_func(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
static void sdio_uart_set_termios(struct tty_struct *tty,
|
||||||
|
struct ktermios *old_termios)
|
||||||
{
|
{
|
||||||
struct sdio_uart_port *port = tty->driver_data;
|
struct sdio_uart_port *port = tty->driver_data;
|
||||||
unsigned int cflag = tty->termios->c_cflag;
|
unsigned int cflag = tty->termios->c_cflag;
|
||||||
|
|
||||||
#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
|
|
||||||
|
|
||||||
if ((cflag ^ old_termios->c_cflag) == 0 &&
|
|
||||||
RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sdio_uart_claim_func(port) != 0)
|
if (sdio_uart_claim_func(port) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -994,6 +1076,13 @@ static const struct file_operations sdio_uart_proc_fops = {
|
||||||
.release = single_release,
|
.release = single_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct tty_port_operations sdio_uart_port_ops = {
|
||||||
|
.dtr_rts = uart_dtr_rts,
|
||||||
|
.carrier_raised = uart_carrier_raised,
|
||||||
|
.shutdown = sdio_uart_shutdown,
|
||||||
|
.activate = sdio_uart_activate,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct tty_operations sdio_uart_ops = {
|
static const struct tty_operations sdio_uart_ops = {
|
||||||
.open = sdio_uart_open,
|
.open = sdio_uart_open,
|
||||||
.close = sdio_uart_close,
|
.close = sdio_uart_close,
|
||||||
|
@ -1004,9 +1093,12 @@ static const struct tty_operations sdio_uart_ops = {
|
||||||
.throttle = sdio_uart_throttle,
|
.throttle = sdio_uart_throttle,
|
||||||
.unthrottle = sdio_uart_unthrottle,
|
.unthrottle = sdio_uart_unthrottle,
|
||||||
.set_termios = sdio_uart_set_termios,
|
.set_termios = sdio_uart_set_termios,
|
||||||
|
.hangup = sdio_uart_hangup,
|
||||||
.break_ctl = sdio_uart_break_ctl,
|
.break_ctl = sdio_uart_break_ctl,
|
||||||
.tiocmget = sdio_uart_tiocmget,
|
.tiocmget = sdio_uart_tiocmget,
|
||||||
.tiocmset = sdio_uart_tiocmset,
|
.tiocmset = sdio_uart_tiocmset,
|
||||||
|
.install = sdio_uart_install,
|
||||||
|
.cleanup = sdio_uart_cleanup,
|
||||||
.proc_fops = &sdio_uart_proc_fops,
|
.proc_fops = &sdio_uart_proc_fops,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1068,13 +1160,16 @@ static int sdio_uart_probe(struct sdio_func *func,
|
||||||
|
|
||||||
port->func = func;
|
port->func = func;
|
||||||
sdio_set_drvdata(func, port);
|
sdio_set_drvdata(func, port);
|
||||||
|
tty_port_init(&port->port);
|
||||||
|
port->port.ops = &sdio_uart_port_ops;
|
||||||
|
|
||||||
ret = sdio_uart_add_port(port);
|
ret = sdio_uart_add_port(port);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kfree(port);
|
kfree(port);
|
||||||
} else {
|
} else {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
dev = tty_register_device(sdio_uart_tty_driver, port->index, &func->dev);
|
dev = tty_register_device(sdio_uart_tty_driver,
|
||||||
|
port->index, &func->dev);
|
||||||
if (IS_ERR(dev)) {
|
if (IS_ERR(dev)) {
|
||||||
sdio_uart_port_remove(port);
|
sdio_uart_port_remove(port);
|
||||||
ret = PTR_ERR(dev);
|
ret = PTR_ERR(dev);
|
||||||
|
|
|
@ -1339,14 +1339,12 @@ static void serial8250_start_tx(struct uart_port *port)
|
||||||
serial_out(up, UART_IER, up->ier);
|
serial_out(up, UART_IER, up->ier);
|
||||||
|
|
||||||
if (up->bugs & UART_BUG_TXEN) {
|
if (up->bugs & UART_BUG_TXEN) {
|
||||||
unsigned char lsr, iir;
|
unsigned char lsr;
|
||||||
lsr = serial_in(up, UART_LSR);
|
lsr = serial_in(up, UART_LSR);
|
||||||
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
||||||
iir = serial_in(up, UART_IIR) & 0x0f;
|
|
||||||
if ((up->port.type == PORT_RM9000) ?
|
if ((up->port.type == PORT_RM9000) ?
|
||||||
(lsr & UART_LSR_THRE &&
|
(lsr & UART_LSR_THRE) :
|
||||||
(iir == UART_IIR_NO_INT || iir == UART_IIR_THRI)) :
|
(lsr & UART_LSR_TEMT))
|
||||||
(lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT))
|
|
||||||
transmit_chars(up);
|
transmit_chars(up);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2646,7 +2644,7 @@ static void __init serial8250_isa_init_ports(void)
|
||||||
{
|
{
|
||||||
struct uart_8250_port *up;
|
struct uart_8250_port *up;
|
||||||
static int first = 1;
|
static int first = 1;
|
||||||
int i;
|
int i, irqflag = 0;
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
return;
|
return;
|
||||||
|
@ -2670,6 +2668,9 @@ static void __init serial8250_isa_init_ports(void)
|
||||||
up->port.ops = &serial8250_pops;
|
up->port.ops = &serial8250_pops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (share_irqs)
|
||||||
|
irqflag = IRQF_SHARED;
|
||||||
|
|
||||||
for (i = 0, up = serial8250_ports;
|
for (i = 0, up = serial8250_ports;
|
||||||
i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
|
i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
|
||||||
i++, up++) {
|
i++, up++) {
|
||||||
|
@ -2683,8 +2684,7 @@ static void __init serial8250_isa_init_ports(void)
|
||||||
up->port.iotype = old_serial_port[i].io_type;
|
up->port.iotype = old_serial_port[i].io_type;
|
||||||
up->port.regshift = old_serial_port[i].iomem_reg_shift;
|
up->port.regshift = old_serial_port[i].iomem_reg_shift;
|
||||||
set_io_from_upio(&up->port);
|
set_io_from_upio(&up->port);
|
||||||
if (share_irqs)
|
up->port.irqflags |= irqflag;
|
||||||
up->port.irqflags |= IRQF_SHARED;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2940,10 +2940,13 @@ static int __devinit serial8250_probe(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
struct plat_serial8250_port *p = dev->dev.platform_data;
|
struct plat_serial8250_port *p = dev->dev.platform_data;
|
||||||
struct uart_port port;
|
struct uart_port port;
|
||||||
int ret, i;
|
int ret, i, irqflag = 0;
|
||||||
|
|
||||||
memset(&port, 0, sizeof(struct uart_port));
|
memset(&port, 0, sizeof(struct uart_port));
|
||||||
|
|
||||||
|
if (share_irqs)
|
||||||
|
irqflag = IRQF_SHARED;
|
||||||
|
|
||||||
for (i = 0; p && p->flags != 0; p++, i++) {
|
for (i = 0; p && p->flags != 0; p++, i++) {
|
||||||
port.iobase = p->iobase;
|
port.iobase = p->iobase;
|
||||||
port.membase = p->membase;
|
port.membase = p->membase;
|
||||||
|
@ -2960,8 +2963,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
|
||||||
port.serial_in = p->serial_in;
|
port.serial_in = p->serial_in;
|
||||||
port.serial_out = p->serial_out;
|
port.serial_out = p->serial_out;
|
||||||
port.dev = &dev->dev;
|
port.dev = &dev->dev;
|
||||||
if (share_irqs)
|
port.irqflags |= irqflag;
|
||||||
port.irqflags |= IRQF_SHARED;
|
|
||||||
ret = serial8250_register_port(&port);
|
ret = serial8250_register_port(&port);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&dev->dev, "unable to register port at index %d "
|
dev_err(&dev->dev, "unable to register port at index %d "
|
||||||
|
|
|
@ -138,7 +138,6 @@ struct jsm_board
|
||||||
u32 nasync; /* Number of ports on card */
|
u32 nasync; /* Number of ports on card */
|
||||||
|
|
||||||
u32 irq; /* Interrupt request number */
|
u32 irq; /* Interrupt request number */
|
||||||
u64 intr_count; /* Count of interrupts */
|
|
||||||
|
|
||||||
u64 membase; /* Start of base memory of the card */
|
u64 membase; /* Start of base memory of the card */
|
||||||
u64 membase_end; /* End of base memory of the card */
|
u64 membase_end; /* End of base memory of the card */
|
||||||
|
@ -206,8 +205,6 @@ struct jsm_channel {
|
||||||
|
|
||||||
u64 ch_close_delay; /* How long we should drop RTS/DTR for */
|
u64 ch_close_delay; /* How long we should drop RTS/DTR for */
|
||||||
|
|
||||||
u64 ch_cpstime; /* Time for CPS calculations */
|
|
||||||
|
|
||||||
tcflag_t ch_c_iflag; /* channel iflags */
|
tcflag_t ch_c_iflag; /* channel iflags */
|
||||||
tcflag_t ch_c_cflag; /* channel cflags */
|
tcflag_t ch_c_cflag; /* channel cflags */
|
||||||
tcflag_t ch_c_oflag; /* channel oflags */
|
tcflag_t ch_c_oflag; /* channel oflags */
|
||||||
|
@ -215,11 +212,6 @@ struct jsm_channel {
|
||||||
u8 ch_stopc; /* Stop character */
|
u8 ch_stopc; /* Stop character */
|
||||||
u8 ch_startc; /* Start character */
|
u8 ch_startc; /* Start character */
|
||||||
|
|
||||||
u32 ch_old_baud; /* Cache of the current baud */
|
|
||||||
u32 ch_custom_speed;/* Custom baud, if set */
|
|
||||||
|
|
||||||
u32 ch_wopen; /* Waiting for open process cnt */
|
|
||||||
|
|
||||||
u8 ch_mostat; /* FEP output modem status */
|
u8 ch_mostat; /* FEP output modem status */
|
||||||
u8 ch_mistat; /* FEP input modem status */
|
u8 ch_mistat; /* FEP input modem status */
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,17 @@ struct uart_driver jsm_uart_driver = {
|
||||||
.nr = NR_PORTS,
|
.nr = NR_PORTS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
|
||||||
|
pci_channel_state_t state);
|
||||||
|
static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
|
||||||
|
static void jsm_io_resume(struct pci_dev *pdev);
|
||||||
|
|
||||||
|
static struct pci_error_handlers jsm_err_handler = {
|
||||||
|
.error_detected = jsm_io_error_detected,
|
||||||
|
.slot_reset = jsm_io_slot_reset,
|
||||||
|
.resume = jsm_io_resume,
|
||||||
|
};
|
||||||
|
|
||||||
int jsm_debug;
|
int jsm_debug;
|
||||||
module_param(jsm_debug, int, 0);
|
module_param(jsm_debug, int, 0);
|
||||||
MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
|
MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
|
||||||
|
@ -123,7 +134,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = request_irq(brd->irq, brd->bd_ops->intr,
|
rc = request_irq(brd->irq, brd->bd_ops->intr,
|
||||||
IRQF_DISABLED|IRQF_SHARED, "JSM", brd);
|
IRQF_SHARED, "JSM", brd);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
|
printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
|
||||||
goto out_iounmap;
|
goto out_iounmap;
|
||||||
|
@ -164,6 +175,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_set_drvdata(pdev, brd);
|
pci_set_drvdata(pdev, brd);
|
||||||
|
pci_save_state(pdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out_free_irq:
|
out_free_irq:
|
||||||
|
@ -222,8 +234,42 @@ static struct pci_driver jsm_driver = {
|
||||||
.id_table = jsm_pci_tbl,
|
.id_table = jsm_pci_tbl,
|
||||||
.probe = jsm_probe_one,
|
.probe = jsm_probe_one,
|
||||||
.remove = __devexit_p(jsm_remove_one),
|
.remove = __devexit_p(jsm_remove_one),
|
||||||
|
.err_handler = &jsm_err_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
|
||||||
|
pci_channel_state_t state)
|
||||||
|
{
|
||||||
|
struct jsm_board *brd = pci_get_drvdata(pdev);
|
||||||
|
|
||||||
|
jsm_remove_uart_port(brd);
|
||||||
|
|
||||||
|
return PCI_ERS_RESULT_NEED_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = pci_enable_device(pdev);
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
return PCI_ERS_RESULT_DISCONNECT;
|
||||||
|
|
||||||
|
pci_set_master(pdev);
|
||||||
|
|
||||||
|
return PCI_ERS_RESULT_RECOVERED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jsm_io_resume(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
struct jsm_board *brd = pci_get_drvdata(pdev);
|
||||||
|
|
||||||
|
pci_restore_state(pdev);
|
||||||
|
|
||||||
|
jsm_uart_port_init(brd);
|
||||||
|
}
|
||||||
|
|
||||||
static int __init jsm_init_module(void)
|
static int __init jsm_init_module(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
|
@ -954,13 +954,8 @@ static void neo_param(struct jsm_channel *ch)
|
||||||
ch->ch_flags |= (CH_BAUD0);
|
ch->ch_flags |= (CH_BAUD0);
|
||||||
ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
|
ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
|
||||||
neo_assert_modem_signals(ch);
|
neo_assert_modem_signals(ch);
|
||||||
ch->ch_old_baud = 0;
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else if (ch->ch_custom_speed) {
|
|
||||||
baud = ch->ch_custom_speed;
|
|
||||||
if (ch->ch_flags & CH_BAUD0)
|
|
||||||
ch->ch_flags &= ~(CH_BAUD0);
|
|
||||||
} else {
|
} else {
|
||||||
int i;
|
int i;
|
||||||
unsigned int cflag;
|
unsigned int cflag;
|
||||||
|
@ -1045,7 +1040,6 @@ static void neo_param(struct jsm_channel *ch)
|
||||||
quot = ch->ch_bd->bd_dividend / baud;
|
quot = ch->ch_bd->bd_dividend / baud;
|
||||||
|
|
||||||
if (quot != 0) {
|
if (quot != 0) {
|
||||||
ch->ch_old_baud = baud;
|
|
||||||
writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
|
writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
|
||||||
writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
|
writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
|
||||||
writeb((quot >> 8), &ch->ch_neo_uart->ier);
|
writeb((quot >> 8), &ch->ch_neo_uart->ier);
|
||||||
|
@ -1123,8 +1117,6 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
|
||||||
unsigned long lock_flags2;
|
unsigned long lock_flags2;
|
||||||
int outofloop_count = 0;
|
int outofloop_count = 0;
|
||||||
|
|
||||||
brd->intr_count++;
|
|
||||||
|
|
||||||
/* Lock out the slow poller from running on this board. */
|
/* Lock out the slow poller from running on this board. */
|
||||||
spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
|
spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
|
||||||
|
|
||||||
|
|
|
@ -296,8 +296,6 @@ static void jsm_tty_close(struct uart_port *port)
|
||||||
bd->bd_ops->assert_modem_signals(channel);
|
bd->bd_ops->assert_modem_signals(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
channel->ch_old_baud = 0;
|
|
||||||
|
|
||||||
/* Turn off UART interrupts for this port */
|
/* Turn off UART interrupts for this port */
|
||||||
channel->ch_bd->bd_ops->uart_off(channel);
|
channel->ch_bd->bd_ops->uart_off(channel);
|
||||||
|
|
||||||
|
@ -432,7 +430,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __devinit jsm_uart_port_init(struct jsm_board *brd)
|
int jsm_uart_port_init(struct jsm_board *brd)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
|
@ -472,7 +470,7 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd)
|
||||||
if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
|
if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
|
||||||
printk(KERN_INFO "jsm: add device failed\n");
|
printk(KERN_INFO "jsm: add device failed\n");
|
||||||
else
|
else
|
||||||
printk(KERN_INFO "Added device \n");
|
printk(KERN_INFO "jsm: Port %d added\n", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
|
jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
|
||||||
|
|
|
@ -438,6 +438,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
unsigned char cval, fcr = 0;
|
unsigned char cval, fcr = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int baud, quot;
|
unsigned int baud, quot;
|
||||||
|
unsigned int dll;
|
||||||
|
|
||||||
switch (termios->c_cflag & CSIZE) {
|
switch (termios->c_cflag & CSIZE) {
|
||||||
case CS5:
|
case CS5:
|
||||||
|
@ -536,6 +537,14 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
|
|
||||||
serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
|
serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
|
||||||
serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
|
serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* work around Errata #75 according to Intel(R) PXA27x Processor Family
|
||||||
|
* Specification Update (Nov 2005)
|
||||||
|
*/
|
||||||
|
dll = serial_in(up, UART_DLL);
|
||||||
|
WARN_ON(dll != (quot & 0xff));
|
||||||
|
|
||||||
serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
|
serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
|
||||||
serial_out(up, UART_LCR, cval); /* reset DLAB */
|
serial_out(up, UART_LCR, cval); /* reset DLAB */
|
||||||
up->lcr = cval; /* Save LCR */
|
up->lcr = cval; /* Save LCR */
|
||||||
|
|
|
@ -342,11 +342,11 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
|
||||||
|
|
||||||
if (flags == UPF_SPD_HI)
|
if (flags == UPF_SPD_HI)
|
||||||
altbaud = 57600;
|
altbaud = 57600;
|
||||||
if (flags == UPF_SPD_VHI)
|
else if (flags == UPF_SPD_VHI)
|
||||||
altbaud = 115200;
|
altbaud = 115200;
|
||||||
if (flags == UPF_SPD_SHI)
|
else if (flags == UPF_SPD_SHI)
|
||||||
altbaud = 230400;
|
altbaud = 230400;
|
||||||
if (flags == UPF_SPD_WARP)
|
else if (flags == UPF_SPD_WARP)
|
||||||
altbaud = 460800;
|
altbaud = 460800;
|
||||||
|
|
||||||
for (try = 0; try < 2; try++) {
|
for (try = 0; try < 2; try++) {
|
||||||
|
@ -1217,9 +1217,8 @@ static void uart_set_termios(struct tty_struct *tty,
|
||||||
/* Handle transition to B0 status */
|
/* Handle transition to B0 status */
|
||||||
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
|
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
|
||||||
uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
|
uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
|
||||||
|
|
||||||
/* Handle transition away from B0 status */
|
/* Handle transition away from B0 status */
|
||||||
if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
|
else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
|
||||||
unsigned int mask = TIOCM_DTR;
|
unsigned int mask = TIOCM_DTR;
|
||||||
if (!(cflag & CRTSCTS) ||
|
if (!(cflag & CRTSCTS) ||
|
||||||
!test_bit(TTY_THROTTLED, &tty->flags))
|
!test_bit(TTY_THROTTLED, &tty->flags))
|
||||||
|
@ -1234,9 +1233,8 @@ static void uart_set_termios(struct tty_struct *tty,
|
||||||
__uart_start(tty);
|
__uart_start(tty);
|
||||||
spin_unlock_irqrestore(&state->uart_port->lock, flags);
|
spin_unlock_irqrestore(&state->uart_port->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle turning on CRTSCTS */
|
/* Handle turning on CRTSCTS */
|
||||||
if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
|
else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
|
||||||
spin_lock_irqsave(&state->uart_port->lock, flags);
|
spin_lock_irqsave(&state->uart_port->lock, flags);
|
||||||
if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
|
if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
|
||||||
tty->hw_stopped = 1;
|
tty->hw_stopped = 1;
|
||||||
|
@ -2344,7 +2342,7 @@ static const struct tty_operations uart_ops = {
|
||||||
*/
|
*/
|
||||||
int uart_register_driver(struct uart_driver *drv)
|
int uart_register_driver(struct uart_driver *drv)
|
||||||
{
|
{
|
||||||
struct tty_driver *normal = NULL;
|
struct tty_driver *normal;
|
||||||
int i, retval;
|
int i, retval;
|
||||||
|
|
||||||
BUG_ON(drv->state);
|
BUG_ON(drv->state);
|
||||||
|
@ -2354,13 +2352,12 @@ int uart_register_driver(struct uart_driver *drv)
|
||||||
* we have a large number of ports to handle.
|
* we have a large number of ports to handle.
|
||||||
*/
|
*/
|
||||||
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
|
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
|
||||||
retval = -ENOMEM;
|
|
||||||
if (!drv->state)
|
if (!drv->state)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
normal = alloc_tty_driver(drv->nr);
|
normal = alloc_tty_driver(drv->nr);
|
||||||
if (!normal)
|
if (!normal)
|
||||||
goto out;
|
goto out_kfree;
|
||||||
|
|
||||||
drv->tty_driver = normal;
|
drv->tty_driver = normal;
|
||||||
|
|
||||||
|
@ -2393,12 +2390,14 @@ int uart_register_driver(struct uart_driver *drv)
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = tty_register_driver(normal);
|
retval = tty_register_driver(normal);
|
||||||
out:
|
if (retval >= 0)
|
||||||
if (retval < 0) {
|
|
||||||
put_tty_driver(normal);
|
|
||||||
kfree(drv->state);
|
|
||||||
}
|
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
put_tty_driver(normal);
|
||||||
|
out_kfree:
|
||||||
|
kfree(drv->state);
|
||||||
|
out:
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -501,12 +501,13 @@ static int opticon_resume(struct usb_interface *intf)
|
||||||
struct usb_serial_port *port = serial->port[0];
|
struct usb_serial_port *port = serial->port[0];
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
mutex_lock(&port->mutex);
|
mutex_lock(&port->port.mutex);
|
||||||
if (port->port.count)
|
/* This is protected by the port mutex against close/open */
|
||||||
|
if (test_bit(ASYNCB_INITIALIZED, &port->port.flags))
|
||||||
result = usb_submit_urb(priv->bulk_read_urb, GFP_NOIO);
|
result = usb_submit_urb(priv->bulk_read_urb, GFP_NOIO);
|
||||||
else
|
else
|
||||||
result = 0;
|
result = 0;
|
||||||
mutex_unlock(&port->mutex);
|
mutex_unlock(&port->port.mutex);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,96 +247,66 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int serial_open(struct tty_struct *tty, struct file *filp)
|
static int serial_activate(struct tty_port *tport, struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct usb_serial_port *port = tty->driver_data;
|
struct usb_serial_port *port =
|
||||||
|
container_of(tport, struct usb_serial_port, port);
|
||||||
struct usb_serial *serial = port->serial;
|
struct usb_serial *serial = port->serial;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
dbg("%s - port %d", __func__, port->number);
|
|
||||||
|
|
||||||
spin_lock_irq(&port->port.lock);
|
|
||||||
if (!tty_hung_up_p(filp))
|
|
||||||
++port->port.count;
|
|
||||||
spin_unlock_irq(&port->port.lock);
|
|
||||||
tty_port_tty_set(&port->port, tty);
|
|
||||||
|
|
||||||
/* Do the device-specific open only if the hardware isn't
|
|
||||||
* already initialized.
|
|
||||||
*/
|
|
||||||
if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
|
|
||||||
if (mutex_lock_interruptible(&port->mutex))
|
|
||||||
return -ERESTARTSYS;
|
|
||||||
mutex_lock(&serial->disc_mutex);
|
mutex_lock(&serial->disc_mutex);
|
||||||
if (serial->disconnected)
|
if (serial->disconnected)
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
else
|
else
|
||||||
retval = port->serial->type->open(tty, port);
|
retval = port->serial->type->open(tty, port);
|
||||||
mutex_unlock(&serial->disc_mutex);
|
mutex_unlock(&serial->disc_mutex);
|
||||||
mutex_unlock(&port->mutex);
|
|
||||||
if (retval)
|
|
||||||
return retval;
|
return retval;
|
||||||
set_bit(ASYNCB_INITIALIZED, &port->port.flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now do the correct tty layer semantics */
|
static int serial_open(struct tty_struct *tty, struct file *filp)
|
||||||
retval = tty_port_block_til_ready(&port->port, tty, filp);
|
{
|
||||||
return retval;
|
struct usb_serial_port *port = tty->driver_data;
|
||||||
|
|
||||||
|
dbg("%s - port %d", __func__, port->number);
|
||||||
|
return tty_port_open(&port->port, tty, filp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* serial_down - shut down hardware
|
* serial_down - shut down hardware
|
||||||
* @port: port to shut down
|
* @tport: tty port to shut down
|
||||||
*
|
*
|
||||||
* Shut down a USB serial port unless it is the console. We never
|
* Shut down a USB serial port unless it is the console. We never
|
||||||
* shut down the console hardware as it will always be in use.
|
* shut down the console hardware as it will always be in use. Serialized
|
||||||
|
* against activate by the tport mutex and kept to matching open/close pairs
|
||||||
|
* of calls by the ASYNCB_INITIALIZED flag.
|
||||||
*/
|
*/
|
||||||
static void serial_down(struct usb_serial_port *port)
|
static void serial_down(struct tty_port *tport)
|
||||||
{
|
{
|
||||||
|
struct usb_serial_port *port =
|
||||||
|
container_of(tport, struct usb_serial_port, port);
|
||||||
struct usb_serial_driver *drv = port->serial->type;
|
struct usb_serial_driver *drv = port->serial->type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The console is magical. Do not hang up the console hardware
|
* The console is magical. Do not hang up the console hardware
|
||||||
* or there will be tears.
|
* or there will be tears.
|
||||||
*/
|
*/
|
||||||
if (port->console)
|
if (port->console)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Don't call the close method if the hardware hasn't been
|
|
||||||
* initialized.
|
|
||||||
*/
|
|
||||||
if (!test_and_clear_bit(ASYNCB_INITIALIZED, &port->port.flags))
|
|
||||||
return;
|
|
||||||
|
|
||||||
mutex_lock(&port->mutex);
|
|
||||||
if (drv->close)
|
if (drv->close)
|
||||||
drv->close(port);
|
drv->close(port);
|
||||||
mutex_unlock(&port->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_hangup(struct tty_struct *tty)
|
static void serial_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct usb_serial_port *port = tty->driver_data;
|
struct usb_serial_port *port = tty->driver_data;
|
||||||
|
|
||||||
dbg("%s - port %d", __func__, port->number);
|
dbg("%s - port %d", __func__, port->number);
|
||||||
|
|
||||||
serial_down(port);
|
|
||||||
tty_port_hangup(&port->port);
|
tty_port_hangup(&port->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_close(struct tty_struct *tty, struct file *filp)
|
static void serial_close(struct tty_struct *tty, struct file *filp)
|
||||||
{
|
{
|
||||||
struct usb_serial_port *port = tty->driver_data;
|
struct usb_serial_port *port = tty->driver_data;
|
||||||
|
|
||||||
dbg("%s - port %d", __func__, port->number);
|
dbg("%s - port %d", __func__, port->number);
|
||||||
|
tty_port_close(&port->port, tty, filp);
|
||||||
if (tty_hung_up_p(filp))
|
|
||||||
return;
|
|
||||||
if (tty_port_close_start(&port->port, tty, filp) == 0)
|
|
||||||
return;
|
|
||||||
serial_down(port);
|
|
||||||
tty_port_close_end(&port->port, tty);
|
|
||||||
tty_port_tty_set(&port->port, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -725,6 +695,8 @@ static void serial_dtr_rts(struct tty_port *port, int on)
|
||||||
static const struct tty_port_operations serial_port_ops = {
|
static const struct tty_port_operations serial_port_ops = {
|
||||||
.carrier_raised = serial_carrier_raised,
|
.carrier_raised = serial_carrier_raised,
|
||||||
.dtr_rts = serial_dtr_rts,
|
.dtr_rts = serial_dtr_rts,
|
||||||
|
.activate = serial_activate,
|
||||||
|
.shutdown = serial_down,
|
||||||
};
|
};
|
||||||
|
|
||||||
int usb_serial_probe(struct usb_interface *interface,
|
int usb_serial_probe(struct usb_interface *interface,
|
||||||
|
@ -923,7 +895,8 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
port->port.ops = &serial_port_ops;
|
port->port.ops = &serial_port_ops;
|
||||||
port->serial = serial;
|
port->serial = serial;
|
||||||
spin_lock_init(&port->lock);
|
spin_lock_init(&port->lock);
|
||||||
mutex_init(&port->mutex);
|
/* Keep this for private driver use for the moment but
|
||||||
|
should probably go away */
|
||||||
INIT_WORK(&port->work, usb_serial_port_work);
|
INIT_WORK(&port->work, usb_serial_port_work);
|
||||||
serial->port[i] = port;
|
serial->port[i] = port;
|
||||||
port->dev.parent = &interface->dev;
|
port->dev.parent = &interface->dev;
|
||||||
|
|
|
@ -517,11 +517,23 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
|
||||||
|
|
||||||
struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
|
struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
|
||||||
{
|
{
|
||||||
|
struct dentry *dentry;
|
||||||
|
struct tty_struct *tty;
|
||||||
|
|
||||||
BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
|
BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
|
||||||
|
|
||||||
if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
|
/* Ensure dentry has not been deleted by devpts_pty_kill() */
|
||||||
return (struct tty_struct *)pts_inode->i_private;
|
dentry = d_find_alias(pts_inode);
|
||||||
|
if (!dentry)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
tty = NULL;
|
||||||
|
if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
|
||||||
|
tty = (struct tty_struct *)pts_inode->i_private;
|
||||||
|
|
||||||
|
dput(dentry);
|
||||||
|
|
||||||
|
return tty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void devpts_pty_kill(struct tty_struct *tty)
|
void devpts_pty_kill(struct tty_struct *tty)
|
||||||
|
|
|
@ -214,7 +214,6 @@ unifdef-y += futex.h
|
||||||
unifdef-y += fs.h
|
unifdef-y += fs.h
|
||||||
unifdef-y += gameport.h
|
unifdef-y += gameport.h
|
||||||
unifdef-y += generic_serial.h
|
unifdef-y += generic_serial.h
|
||||||
unifdef-y += hayesesp.h
|
|
||||||
unifdef-y += hdlcdrv.h
|
unifdef-y += hdlcdrv.h
|
||||||
unifdef-y += hdlc.h
|
unifdef-y += hdlc.h
|
||||||
unifdef-y += hdreg.h
|
unifdef-y += hdreg.h
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
#ifndef HAYESESP_H
|
|
||||||
#define HAYESESP_H
|
|
||||||
|
|
||||||
struct hayes_esp_config {
|
|
||||||
short flow_on;
|
|
||||||
short flow_off;
|
|
||||||
short rx_trigger;
|
|
||||||
short tx_trigger;
|
|
||||||
short pio_threshold;
|
|
||||||
unsigned char rx_timeout;
|
|
||||||
char dma_channel;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
|
||||||
|
|
||||||
#define ESP_DMA_CHANNEL 0
|
|
||||||
#define ESP_RX_TRIGGER 768
|
|
||||||
#define ESP_TX_TRIGGER 768
|
|
||||||
#define ESP_FLOW_OFF 1016
|
|
||||||
#define ESP_FLOW_ON 944
|
|
||||||
#define ESP_RX_TMOUT 128
|
|
||||||
#define ESP_PIO_THRESHOLD 32
|
|
||||||
|
|
||||||
#define ESP_IN_MAJOR 57 /* major dev # for dial in */
|
|
||||||
#define ESP_OUT_MAJOR 58 /* major dev # for dial out */
|
|
||||||
#define ESPC_SCALE 3
|
|
||||||
#define UART_ESI_BASE 0x00
|
|
||||||
#define UART_ESI_SID 0x01
|
|
||||||
#define UART_ESI_RX 0x02
|
|
||||||
#define UART_ESI_TX 0x02
|
|
||||||
#define UART_ESI_CMD1 0x04
|
|
||||||
#define UART_ESI_CMD2 0x05
|
|
||||||
#define UART_ESI_STAT1 0x04
|
|
||||||
#define UART_ESI_STAT2 0x05
|
|
||||||
#define UART_ESI_RWS 0x07
|
|
||||||
|
|
||||||
#define UART_IER_DMA_TMOUT 0x80
|
|
||||||
#define UART_IER_DMA_TC 0x08
|
|
||||||
|
|
||||||
#define ESI_SET_IRQ 0x04
|
|
||||||
#define ESI_SET_DMA_TMOUT 0x05
|
|
||||||
#define ESI_SET_SRV_MASK 0x06
|
|
||||||
#define ESI_SET_ERR_MASK 0x07
|
|
||||||
#define ESI_SET_FLOW_CNTL 0x08
|
|
||||||
#define ESI_SET_FLOW_CHARS 0x09
|
|
||||||
#define ESI_SET_FLOW_LVL 0x0a
|
|
||||||
#define ESI_SET_TRIGGER 0x0b
|
|
||||||
#define ESI_SET_RX_TIMEOUT 0x0c
|
|
||||||
#define ESI_SET_FLOW_TMOUT 0x0d
|
|
||||||
#define ESI_WRITE_UART 0x0e
|
|
||||||
#define ESI_READ_UART 0x0f
|
|
||||||
#define ESI_SET_MODE 0x10
|
|
||||||
#define ESI_GET_ERR_STAT 0x12
|
|
||||||
#define ESI_GET_UART_STAT 0x13
|
|
||||||
#define ESI_GET_RX_AVAIL 0x14
|
|
||||||
#define ESI_GET_TX_AVAIL 0x15
|
|
||||||
#define ESI_START_DMA_RX 0x16
|
|
||||||
#define ESI_START_DMA_TX 0x17
|
|
||||||
#define ESI_ISSUE_BREAK 0x1a
|
|
||||||
#define ESI_FLUSH_RX 0x1b
|
|
||||||
#define ESI_FLUSH_TX 0x1c
|
|
||||||
#define ESI_SET_BAUD 0x1d
|
|
||||||
#define ESI_SET_ENH_IRQ 0x1f
|
|
||||||
#define ESI_SET_REINTR 0x20
|
|
||||||
#define ESI_SET_PRESCALAR 0x23
|
|
||||||
#define ESI_NO_COMMAND 0xff
|
|
||||||
|
|
||||||
#define ESP_STAT_RX_TIMEOUT 0x01
|
|
||||||
#define ESP_STAT_DMA_RX 0x02
|
|
||||||
#define ESP_STAT_DMA_TX 0x04
|
|
||||||
#define ESP_STAT_NEVER_DMA 0x08
|
|
||||||
#define ESP_STAT_USE_PIO 0x10
|
|
||||||
|
|
||||||
#define ESP_MAGIC 0x53ee
|
|
||||||
#define ESP_XMIT_SIZE 4096
|
|
||||||
|
|
||||||
struct esp_struct {
|
|
||||||
int magic;
|
|
||||||
struct tty_port port;
|
|
||||||
spinlock_t lock;
|
|
||||||
int io_port;
|
|
||||||
int irq;
|
|
||||||
int read_status_mask;
|
|
||||||
int ignore_status_mask;
|
|
||||||
int timeout;
|
|
||||||
int stat_flags;
|
|
||||||
int custom_divisor;
|
|
||||||
int close_delay;
|
|
||||||
unsigned short closing_wait;
|
|
||||||
unsigned short closing_wait2;
|
|
||||||
int IER; /* Interrupt Enable Register */
|
|
||||||
int MCR; /* Modem control register */
|
|
||||||
unsigned long last_active;
|
|
||||||
int line;
|
|
||||||
unsigned char *xmit_buf;
|
|
||||||
int xmit_head;
|
|
||||||
int xmit_tail;
|
|
||||||
int xmit_cnt;
|
|
||||||
wait_queue_head_t break_wait;
|
|
||||||
struct async_icount icount; /* kernel counters for the 4 input interrupts */
|
|
||||||
struct hayes_esp_config config; /* port configuration */
|
|
||||||
struct esp_struct *next_port; /* For the linked list */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct esp_pio_buffer {
|
|
||||||
unsigned char data[1024];
|
|
||||||
struct esp_pio_buffer *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ESP_H */
|
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
|
|
||||||
#define FIRMWARE_LOADED 0x0001
|
#define FIRMWARE_LOADED 0x0001
|
||||||
#define BOARD_ACTIVE 0x0002
|
#define BOARD_ACTIVE 0x0002
|
||||||
|
#define BOARD_INIT 0x0004
|
||||||
|
|
||||||
/* isi_port status bitmap */
|
/* isi_port status bitmap */
|
||||||
|
|
||||||
|
|
|
@ -190,9 +190,17 @@ struct tty_port_operations {
|
||||||
/* Control the DTR line */
|
/* Control the DTR line */
|
||||||
void (*dtr_rts)(struct tty_port *port, int raise);
|
void (*dtr_rts)(struct tty_port *port, int raise);
|
||||||
/* Called when the last close completes or a hangup finishes
|
/* Called when the last close completes or a hangup finishes
|
||||||
IFF the port was initialized. Do not use to free resources */
|
IFF the port was initialized. Do not use to free resources. Called
|
||||||
|
under the port mutex to serialize against activate/shutdowns */
|
||||||
void (*shutdown)(struct tty_port *port);
|
void (*shutdown)(struct tty_port *port);
|
||||||
void (*drop)(struct tty_port *port);
|
void (*drop)(struct tty_port *port);
|
||||||
|
/* Called under the port mutex from tty_port_open, serialized using
|
||||||
|
the port mutex */
|
||||||
|
/* FIXME: long term getting the tty argument *out* of this would be
|
||||||
|
good for consoles */
|
||||||
|
int (*activate)(struct tty_port *port, struct tty_struct *tty);
|
||||||
|
/* Called on the final put of a port */
|
||||||
|
void (*destruct)(struct tty_port *port);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tty_port {
|
struct tty_port {
|
||||||
|
@ -206,12 +214,14 @@ struct tty_port {
|
||||||
wait_queue_head_t delta_msr_wait; /* Modem status change */
|
wait_queue_head_t delta_msr_wait; /* Modem status change */
|
||||||
unsigned long flags; /* TTY flags ASY_*/
|
unsigned long flags; /* TTY flags ASY_*/
|
||||||
struct mutex mutex; /* Locking */
|
struct mutex mutex; /* Locking */
|
||||||
|
struct mutex buf_mutex; /* Buffer alloc lock */
|
||||||
unsigned char *xmit_buf; /* Optional buffer */
|
unsigned char *xmit_buf; /* Optional buffer */
|
||||||
unsigned int close_delay; /* Close port delay */
|
unsigned int close_delay; /* Close port delay */
|
||||||
unsigned int closing_wait; /* Delay for output */
|
unsigned int closing_wait; /* Delay for output */
|
||||||
int drain_delay; /* Set to zero if no pure time
|
int drain_delay; /* Set to zero if no pure time
|
||||||
based drain is needed else
|
based drain is needed else
|
||||||
set to size of fifo */
|
set to size of fifo */
|
||||||
|
struct kref kref; /* Ref counter */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -439,7 +449,7 @@ extern void initialize_tty_struct(struct tty_struct *tty,
|
||||||
struct tty_driver *driver, int idx);
|
struct tty_driver *driver, int idx);
|
||||||
extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
||||||
int first_ok);
|
int first_ok);
|
||||||
extern void tty_release_dev(struct file *filp);
|
extern int tty_release(struct inode *inode, struct file *filp);
|
||||||
extern int tty_init_termios(struct tty_struct *tty);
|
extern int tty_init_termios(struct tty_struct *tty);
|
||||||
|
|
||||||
extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
|
extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
|
||||||
|
@ -454,6 +464,15 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
|
||||||
extern void tty_port_init(struct tty_port *port);
|
extern void tty_port_init(struct tty_port *port);
|
||||||
extern int tty_port_alloc_xmit_buf(struct tty_port *port);
|
extern int tty_port_alloc_xmit_buf(struct tty_port *port);
|
||||||
extern void tty_port_free_xmit_buf(struct tty_port *port);
|
extern void tty_port_free_xmit_buf(struct tty_port *port);
|
||||||
|
extern void tty_port_put(struct tty_port *port);
|
||||||
|
|
||||||
|
extern inline struct tty_port *tty_port_get(struct tty_port *port)
|
||||||
|
{
|
||||||
|
if (port)
|
||||||
|
kref_get(&port->kref);
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
extern struct tty_struct *tty_port_tty_get(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 void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
|
||||||
extern int tty_port_carrier_raised(struct tty_port *port);
|
extern int tty_port_carrier_raised(struct tty_port *port);
|
||||||
|
@ -467,6 +486,8 @@ extern int tty_port_close_start(struct tty_port *port,
|
||||||
extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
|
extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
|
||||||
extern void tty_port_close(struct tty_port *port,
|
extern void tty_port_close(struct tty_port *port,
|
||||||
struct tty_struct *tty, struct file *filp);
|
struct tty_struct *tty, struct file *filp);
|
||||||
|
extern int tty_port_open(struct tty_port *port,
|
||||||
|
struct tty_struct *tty, struct file *filp);
|
||||||
extern inline int tty_port_users(struct tty_port *port)
|
extern inline int tty_port_users(struct tty_port *port)
|
||||||
{
|
{
|
||||||
return port->count + port->blocked_open;
|
return port->count + port->blocked_open;
|
||||||
|
|
|
@ -39,8 +39,6 @@ enum port_dev_state {
|
||||||
* @serial: pointer back to the struct usb_serial owner of this port.
|
* @serial: pointer back to the struct usb_serial owner of this port.
|
||||||
* @port: pointer to the corresponding tty_port for this port.
|
* @port: pointer to the corresponding tty_port for this port.
|
||||||
* @lock: spinlock to grab when updating portions of this structure.
|
* @lock: spinlock to grab when updating portions of this structure.
|
||||||
* @mutex: mutex used to synchronize serial_open() and serial_close()
|
|
||||||
* access for this port.
|
|
||||||
* @number: the number of the port (the minor number).
|
* @number: the number of the port (the minor number).
|
||||||
* @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
|
* @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
|
||||||
* @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
|
* @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
|
||||||
|
@ -77,7 +75,6 @@ struct usb_serial_port {
|
||||||
struct usb_serial *serial;
|
struct usb_serial *serial;
|
||||||
struct tty_port port;
|
struct tty_port port;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct mutex mutex;
|
|
||||||
unsigned char number;
|
unsigned char number;
|
||||||
|
|
||||||
unsigned char *interrupt_in_buffer;
|
unsigned char *interrupt_in_buffer;
|
||||||
|
|
|
@ -971,7 +971,7 @@ NORET_TYPE void do_exit(long code)
|
||||||
exit_thread();
|
exit_thread();
|
||||||
cgroup_exit(tsk, 1);
|
cgroup_exit(tsk, 1);
|
||||||
|
|
||||||
if (group_dead && tsk->signal->leader)
|
if (group_dead)
|
||||||
disassociate_ctty(1);
|
disassociate_ctty(1);
|
||||||
|
|
||||||
module_put(task_thread_info(tsk)->exec_domain->module);
|
module_put(task_thread_info(tsk)->exec_domain->module);
|
||||||
|
|
Loading…
Add table
Reference in a new issue