mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 11:16:11 +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
|
||||
the terminal. No other call into the line
|
||||
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
|
||||
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.
|
||||
The line discipline should cease I/O to the tty.
|
||||
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
|
||||
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
|
||||
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:
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
static struct tty_operations serial_ops = {
|
||||
static const struct tty_operations serial_ops = {
|
||||
.open = rs_open,
|
||||
.close = rs_close,
|
||||
.write = rs_write,
|
||||
|
|
|
@ -201,19 +201,6 @@ config DIGIEPCA
|
|||
To compile this driver as a module, choose M here: the
|
||||
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
|
||||
tristate "Moxa Intellio support"
|
||||
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_AUDIT) += tty_audit.o
|
||||
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
|
||||
obj-$(CONFIG_ESPSERIAL) += esp.o
|
||||
obj-$(CONFIG_MVME147_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
|
||||
|
|
|
@ -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,
|
||||
.close = bfin_jc_close,
|
||||
.write = bfin_jc_write,
|
||||
|
|
|
@ -935,7 +935,7 @@ static int info_open(struct tty_struct *tty, struct file *filp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct tty_operations info_ops = {
|
||||
static const struct tty_operations info_ops = {
|
||||
.open = info_open,
|
||||
.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;
|
||||
struct isi_port *port;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bp->card_lock, flags);
|
||||
if (bp->status & BOARD_ACTIVE) {
|
||||
spin_unlock_irqrestore(&bp->card_lock, flags);
|
||||
return;
|
||||
bp->count++;
|
||||
if (!(bp->status & BOARD_INIT)) {
|
||||
port = bp->ports;
|
||||
for (channel = 0; channel < bp->port_count; channel++, port++)
|
||||
drop_dtr_rts(port);
|
||||
}
|
||||
port = bp->ports;
|
||||
bp->status |= BOARD_ACTIVE;
|
||||
for (channel = 0; channel < bp->port_count; channel++, 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;
|
||||
unsigned long flags;
|
||||
|
||||
if (port->port.flags & ASYNC_INITIALIZED)
|
||||
return 0;
|
||||
if (tty_port_alloc_xmit_buf(&port->port) < 0)
|
||||
if (tty_port_alloc_xmit_buf(tport) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
if (port->port.count == 1)
|
||||
card->count++;
|
||||
isicom_setup_board(card);
|
||||
|
||||
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);
|
||||
InterruptTheCard(card->base);
|
||||
}
|
||||
|
||||
isicom_config_port(tty);
|
||||
port->port.flags |= ASYNC_INITIALIZED;
|
||||
spin_unlock_irqrestore(&card->card_lock, flags);
|
||||
|
||||
return 0;
|
||||
|
@ -871,85 +864,37 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty)
|
|||
|
||||
return &port->port;
|
||||
}
|
||||
|
||||
|
||||
static int isicom_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct isi_port *port;
|
||||
struct isi_board *card;
|
||||
struct tty_port *tport;
|
||||
int error = 0;
|
||||
|
||||
tport = isicom_find_port(tty);
|
||||
if (tport == NULL)
|
||||
return -ENODEV;
|
||||
port = container_of(tport, struct isi_port, port);
|
||||
card = &isi_card[BOARD(tty->index)];
|
||||
isicom_setup_board(card);
|
||||
|
||||
/* FIXME: locking on port.count etc */
|
||||
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;
|
||||
return tty_port_open(tport, tty, filp);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
static void isicom_shutdown_port(struct isi_port *port)
|
||||
{
|
||||
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) {
|
||||
pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
|
||||
card->base, card->count);
|
||||
card->count = 0;
|
||||
}
|
||||
|
||||
/* last port was closed, shutdown that boad too */
|
||||
if (C_HUPCL(tty)) {
|
||||
if (!card->count)
|
||||
isicom_shutdown_board(card);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
/* last port was closed, shutdown that board too */
|
||||
if (!card->count)
|
||||
card->status &= BOARD_ACTIVE;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_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
|
||||
on this port */
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
if (port->flags & ASYNC_INITIALIZED) {
|
||||
card->port_status &= ~(1 << ip->channel);
|
||||
outw(card->port_status, card->base + 0x02);
|
||||
}
|
||||
card->port_status &= ~(1 << ip->channel);
|
||||
outw(card->port_status, card->base + 0x02);
|
||||
isicom_shutdown_port(ip);
|
||||
spin_unlock_irqrestore(&card->card_lock, flags);
|
||||
tty_port_free_xmit_buf(port);
|
||||
}
|
||||
|
||||
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;
|
||||
if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
|
||||
return;
|
||||
|
||||
if (tty_port_close_start(port, tty, filp) == 0)
|
||||
return;
|
||||
isicom_close_port(port);
|
||||
isicom_flush_buffer(tty);
|
||||
tty_port_close_end(port, tty);
|
||||
tty_port_close(port, tty, filp);
|
||||
}
|
||||
|
||||
/* write et all */
|
||||
|
@ -1326,15 +1265,9 @@ static void isicom_start(struct tty_struct *tty)
|
|||
static void isicom_hangup(struct tty_struct *tty)
|
||||
{
|
||||
struct isi_port *port = tty->driver_data;
|
||||
unsigned long flags;
|
||||
|
||||
if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1367,6 +1300,8 @@ static const struct tty_operations isicom_ops = {
|
|||
static const struct tty_port_operations isicom_port_ops = {
|
||||
.carrier_raised = isicom_carrier_raised,
|
||||
.dtr_rts = isicom_dtr_rts,
|
||||
.activate = isicom_activate,
|
||||
.shutdown = isicom_shutdown,
|
||||
};
|
||||
|
||||
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
|
||||
* use the bit setting operations (unless protected by cli/sti).
|
||||
*/
|
||||
#define ST_INITIALIZING 1
|
||||
#define ST_OPENING 2
|
||||
#define ST_CLOSING 3
|
||||
#define ST_CMDING 4
|
||||
|
@ -621,7 +620,7 @@ static int stli_brdinit(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_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_poll(unsigned long arg);
|
||||
static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
|
||||
|
@ -704,7 +703,7 @@ static const struct file_operations stli_fsiomem = {
|
|||
.owner = THIS_MODULE,
|
||||
.read = stli_memread,
|
||||
.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)
|
||||
{
|
||||
struct stlibrd *brdp;
|
||||
struct stliport *portp;
|
||||
struct tty_port *port;
|
||||
unsigned int minordev, brdnr, portnr;
|
||||
int rc;
|
||||
|
||||
minordev = tty->index;
|
||||
brdnr = MINOR2BRD(minordev);
|
||||
|
@ -809,95 +827,56 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
|
|||
return -ENODEV;
|
||||
if (portp->devnr < 1)
|
||||
return -ENODEV;
|
||||
port = &portp->port;
|
||||
|
||||
/*
|
||||
* On the first open of the device setup the port hardware, and
|
||||
* initialize the per port data structure. Since initializing the port
|
||||
* requires several commands to the board we will need to wait for any
|
||||
* other open that is already initializing the port.
|
||||
*
|
||||
* Review - locking
|
||||
*/
|
||||
tty_port_tty_set(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);
|
||||
return tty_port_open(&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 stliport *portp;
|
||||
struct tty_port *port;
|
||||
unsigned long ftype;
|
||||
unsigned long flags;
|
||||
struct stliport *portp = container_of(port, struct stliport, port);
|
||||
|
||||
portp = tty->driver_data;
|
||||
if (portp->brdnr >= stli_nrbrds)
|
||||
return;
|
||||
brdp = stli_brds[portp->brdnr];
|
||||
if (brdp == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* May want to wait for data to drain before closing. The BUSY
|
||||
* flag keeps track of whether we are still transmitting or not.
|
||||
* It is updated by messages from the slave - indicating when all
|
||||
* chars really have drained.
|
||||
*/
|
||||
|
||||
if (!test_bit(ST_CLOSING, &portp->state))
|
||||
stli_rawclose(brdp, portp, 0, 0);
|
||||
|
||||
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;
|
||||
port = &portp->port;
|
||||
|
||||
if (tty_port_close_start(port, tty, filp) == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* May want to wait for data to drain before closing. The BUSY flag
|
||||
* keeps track of whether we are still transmitting or not. It is
|
||||
* updated by messages from the slave - indicating when all chars
|
||||
* really have drained.
|
||||
*/
|
||||
spin_lock_irqsave(&stli_lock, flags);
|
||||
/* Flush any internal buffering out first */
|
||||
if (tty == stli_txcooktty)
|
||||
stli_flushchars(tty);
|
||||
spin_unlock_irqrestore(&stli_lock, flags);
|
||||
|
||||
/* We end up doing this twice for the moment. This needs looking at
|
||||
eventually. Note we still use portp->closing_wait as a result */
|
||||
if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent(tty, portp->closing_wait);
|
||||
|
||||
/* 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);
|
||||
tty_port_close(&portp->port, tty, filp);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -1724,6 +1703,7 @@ static void stli_start(struct tty_struct *tty)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
* Hangup this port. This is pretty much like closing the port, only
|
||||
* 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)
|
||||
{
|
||||
struct stliport *portp;
|
||||
struct stlibrd *brdp;
|
||||
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);
|
||||
struct stliport *portp = tty->driver_data;
|
||||
tty_port_hangup(&portp->port);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -4311,7 +4252,7 @@ static int stli_getbrdstruct(struct stlibrd __user *arg)
|
|||
* 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;
|
||||
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
|
||||
* minor number of the device they were called from.
|
||||
*/
|
||||
brdnr = iminor(ip);
|
||||
brdnr = iminor(fp->f_dentry->d_inode);
|
||||
if (brdnr >= STL_MAXBRDS)
|
||||
return -ENODEV;
|
||||
brdp = stli_brds[brdnr];
|
||||
|
@ -4420,6 +4361,8 @@ static const struct tty_operations stli_ops = {
|
|||
static const struct tty_port_operations stli_port_ops = {
|
||||
.carrier_raised = stli_carrier_raised,
|
||||
.dtr_rts = stli_dtr_rts,
|
||||
.activate = stli_activate,
|
||||
.shutdown = stli_shutdown,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/ptrace.h>
|
||||
|
@ -139,7 +138,7 @@ struct moxa_port {
|
|||
int cflag;
|
||||
unsigned long statusflags;
|
||||
|
||||
u8 DCDState;
|
||||
u8 DCDState; /* Protected by the port lock */
|
||||
u8 lineCtrl;
|
||||
u8 lowChkFlag;
|
||||
};
|
||||
|
@ -151,10 +150,9 @@ struct mon_str {
|
|||
};
|
||||
|
||||
/* statusflags */
|
||||
#define TXSTOPPED 0x1
|
||||
#define LOWWAIT 0x2
|
||||
#define EMPTYWAIT 0x4
|
||||
#define THROTTLE 0x8
|
||||
#define TXSTOPPED 1
|
||||
#define LOWWAIT 2
|
||||
#define EMPTYWAIT 3
|
||||
|
||||
#define SERIAL_DO_RESTART
|
||||
|
||||
|
@ -165,6 +163,7 @@ static struct mon_str moxaLog;
|
|||
static unsigned int moxaFuncTout = HZ / 2;
|
||||
static unsigned int moxaLowWaterChk;
|
||||
static DEFINE_MUTEX(moxa_openlock);
|
||||
static DEFINE_SPINLOCK(moxa_lock);
|
||||
/* Variables for insmod */
|
||||
#ifdef MODULE
|
||||
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 void moxa_flush_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_stop(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);
|
||||
static void moxa_poll(unsigned long);
|
||||
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
|
||||
static void moxa_setup_empty_event(struct tty_struct *);
|
||||
static void moxa_shut_down(struct tty_struct *);
|
||||
static void moxa_shutdown(struct tty_port *);
|
||||
static int moxa_carrier_raised(struct tty_port *);
|
||||
static void moxa_dtr_rts(struct tty_port *, int);
|
||||
/*
|
||||
* moxa board interface functions:
|
||||
*/
|
||||
|
@ -234,6 +231,8 @@ static void MoxaSetFifo(struct moxa_port *port, int enable);
|
|||
* I/O functions
|
||||
*/
|
||||
|
||||
static DEFINE_SPINLOCK(moxafunc_lock);
|
||||
|
||||
static void moxa_wait_finish(void __iomem *ofsAddr)
|
||||
{
|
||||
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)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&moxafunc_lock, flags);
|
||||
writew(arg, ofsAddr + FuncArg);
|
||||
writew(cmd, ofsAddr + FuncCode);
|
||||
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)
|
||||
|
@ -299,22 +314,20 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
|
|||
struct moxa_port *p;
|
||||
unsigned int i, j;
|
||||
|
||||
mutex_lock(&moxa_openlock);
|
||||
for (i = 0; i < MAX_BOARDS; i++) {
|
||||
p = moxa_boards[i].ports;
|
||||
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
spin_lock_bh(&moxa_lock);
|
||||
if (moxa_boards[i].ready) {
|
||||
tmp.inq = MoxaPortRxQueue(p);
|
||||
tmp.outq = MoxaPortTxQueue(p);
|
||||
}
|
||||
if (copy_to_user(argm, &tmp, sizeof(tmp))) {
|
||||
mutex_unlock(&moxa_openlock);
|
||||
spin_unlock_bh(&moxa_lock);
|
||||
if (copy_to_user(argm, &tmp, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&moxa_openlock);
|
||||
break;
|
||||
} case MOXA_GET_OQUEUE:
|
||||
status = MoxaPortTxQueue(ch);
|
||||
|
@ -330,16 +343,20 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
|
|||
struct moxa_port *p;
|
||||
unsigned int i, j;
|
||||
|
||||
mutex_lock(&moxa_openlock);
|
||||
for (i = 0; i < MAX_BOARDS; i++) {
|
||||
p = moxa_boards[i].ports;
|
||||
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
|
||||
struct tty_struct *ttyp;
|
||||
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;
|
||||
}
|
||||
|
||||
status = MoxaPortLineStatus(p);
|
||||
spin_unlock_bh(&moxa_lock);
|
||||
|
||||
if (status & 1)
|
||||
tmp.cts = 1;
|
||||
if (status & 2)
|
||||
|
@ -354,24 +371,21 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
|
|||
tmp.cflag = ttyp->termios->c_cflag;
|
||||
tty_kref_put(tty);
|
||||
copy:
|
||||
if (copy_to_user(argm, &tmp, sizeof(tmp))) {
|
||||
mutex_unlock(&moxa_openlock);
|
||||
if (copy_to_user(argm, &tmp, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&moxa_openlock);
|
||||
break;
|
||||
}
|
||||
case TIOCGSERIAL:
|
||||
mutex_lock(&moxa_openlock);
|
||||
mutex_lock(&ch->port.mutex);
|
||||
ret = moxa_get_serial_info(ch, argp);
|
||||
mutex_unlock(&moxa_openlock);
|
||||
mutex_unlock(&ch->port.mutex);
|
||||
break;
|
||||
case TIOCSSERIAL:
|
||||
mutex_lock(&moxa_openlock);
|
||||
mutex_lock(&ch->port.mutex);
|
||||
ret = moxa_set_serial_info(ch, argp);
|
||||
mutex_unlock(&moxa_openlock);
|
||||
mutex_unlock(&ch->port.mutex);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
|
@ -396,8 +410,6 @@ static const struct tty_operations moxa_ops = {
|
|||
.flush_buffer = moxa_flush_buffer,
|
||||
.chars_in_buffer = moxa_chars_in_buffer,
|
||||
.ioctl = moxa_ioctl,
|
||||
.throttle = moxa_throttle,
|
||||
.unthrottle = moxa_unthrottle,
|
||||
.set_termios = moxa_set_termios,
|
||||
.stop = moxa_stop,
|
||||
.start = moxa_start,
|
||||
|
@ -409,11 +421,12 @@ static const struct tty_operations moxa_ops = {
|
|||
|
||||
static const struct tty_port_operations moxa_port_ops = {
|
||||
.carrier_raised = moxa_carrier_raised,
|
||||
.dtr_rts = moxa_dtr_rts,
|
||||
.shutdown = moxa_shutdown,
|
||||
};
|
||||
|
||||
static struct tty_driver *moxaDriver;
|
||||
static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
|
||||
static DEFINE_SPINLOCK(moxa_lock);
|
||||
|
||||
/*
|
||||
* HW init
|
||||
|
@ -1112,14 +1125,12 @@ static void __exit moxa_exit(void)
|
|||
module_init(moxa_init);
|
||||
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;
|
||||
moxa_shut_down(tty);
|
||||
struct moxa_port *ch = container_of(port, struct moxa_port, port);
|
||||
MoxaPortDisable(ch);
|
||||
MoxaPortFlushData(ch, 2);
|
||||
ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
tty->driver_data = NULL;
|
||||
tty_port_tty_set(&ch->port, NULL);
|
||||
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
|
||||
}
|
||||
|
||||
static int moxa_carrier_raised(struct tty_port *port)
|
||||
|
@ -1127,45 +1138,19 @@ static int moxa_carrier_raised(struct tty_port *port)
|
|||
struct moxa_port *ch = container_of(port, struct moxa_port, port);
|
||||
int dcd;
|
||||
|
||||
spin_lock_bh(&moxa_lock);
|
||||
spin_lock_irq(&port->lock);
|
||||
dcd = ch->DCDState;
|
||||
spin_unlock_bh(&moxa_lock);
|
||||
spin_unlock_irq(&port->lock);
|
||||
return dcd;
|
||||
}
|
||||
|
||||
static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
|
||||
struct moxa_port *ch)
|
||||
static void moxa_dtr_rts(struct tty_port *port, int onoff)
|
||||
{
|
||||
struct tty_port *port = &ch->port;
|
||||
DEFINE_WAIT(wait);
|
||||
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;
|
||||
struct moxa_port *ch = container_of(port, struct moxa_port, port);
|
||||
MoxaPortLineCtrl(ch, onoff, onoff);
|
||||
}
|
||||
|
||||
|
||||
static int moxa_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct moxa_board_conf *brd;
|
||||
|
@ -1194,6 +1179,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
|
|||
ch->port.count++;
|
||||
tty->driver_data = ch;
|
||||
tty_port_tty_set(&ch->port, tty);
|
||||
mutex_lock(&ch->port.mutex);
|
||||
if (!(ch->port.flags & ASYNC_INITIALIZED)) {
|
||||
ch->statusflags = 0;
|
||||
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);
|
||||
ch->port.flags |= ASYNC_INITIALIZED;
|
||||
}
|
||||
mutex_unlock(&ch->port.mutex);
|
||||
mutex_unlock(&moxa_openlock);
|
||||
|
||||
retval = 0;
|
||||
if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty))
|
||||
retval = moxa_block_till_ready(tty, filp, ch);
|
||||
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);
|
||||
|
||||
retval = tty_port_block_til_ready(&ch->port, tty, filp);
|
||||
if (retval == 0)
|
||||
set_bit(ASYNCB_NORMAL_ACTIVE, &ch->port.flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void moxa_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct moxa_port *ch;
|
||||
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;
|
||||
|
||||
struct moxa_port *ch = tty->driver_data;
|
||||
ch->cflag = tty->termios->c_cflag;
|
||||
if (ch->port.flags & ASYNC_INITIALIZED) {
|
||||
moxa_setup_empty_event(tty);
|
||||
tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
|
||||
}
|
||||
|
||||
moxa_close_port(tty);
|
||||
unlock:
|
||||
mutex_unlock(&moxa_openlock);
|
||||
tty_port_close(&ch->port, tty, filp);
|
||||
}
|
||||
|
||||
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);
|
||||
spin_unlock_bh(&moxa_lock);
|
||||
|
||||
ch->statusflags |= LOWWAIT;
|
||||
set_bit(LOWWAIT, &ch->statusflags);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -1300,40 +1248,21 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
|
|||
struct moxa_port *ch = tty->driver_data;
|
||||
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);
|
||||
if (chars) {
|
||||
if (chars)
|
||||
/*
|
||||
* Make it possible to wakeup anything waiting for output
|
||||
* in tty_ioctl.c, etc.
|
||||
*/
|
||||
if (!(ch->statusflags & EMPTYWAIT))
|
||||
moxa_setup_empty_event(tty);
|
||||
}
|
||||
unlock_kernel();
|
||||
set_bit(EMPTYWAIT, &ch->statusflags);
|
||||
return chars;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
mutex_lock(&moxa_openlock);
|
||||
ch = tty->driver_data;
|
||||
if (!ch) {
|
||||
mutex_unlock(&moxa_openlock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
MoxaPortGetLineOut(ch, &dtr, &rts);
|
||||
if (dtr)
|
||||
flag |= TIOCM_DTR;
|
||||
|
@ -1346,7 +1275,6 @@ static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
|
|||
flag |= TIOCM_DSR;
|
||||
if (dtr & 4)
|
||||
flag |= TIOCM_CD;
|
||||
mutex_unlock(&moxa_openlock);
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
@ -1379,20 +1307,6 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
|
|||
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,
|
||||
struct ktermios *old_termios)
|
||||
{
|
||||
|
@ -1412,7 +1326,7 @@ static void moxa_stop(struct tty_struct *tty)
|
|||
if (ch == NULL)
|
||||
return;
|
||||
MoxaPortTxDisable(ch);
|
||||
ch->statusflags |= TXSTOPPED;
|
||||
set_bit(TXSTOPPED, &ch->statusflags);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1427,38 +1341,32 @@ static void moxa_start(struct tty_struct *tty)
|
|||
return;
|
||||
|
||||
MoxaPortTxEnable(ch);
|
||||
ch->statusflags &= ~TXSTOPPED;
|
||||
clear_bit(TXSTOPPED, &ch->statusflags);
|
||||
}
|
||||
|
||||
static void moxa_hangup(struct tty_struct *tty)
|
||||
{
|
||||
struct moxa_port *ch;
|
||||
|
||||
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);
|
||||
struct moxa_port *ch = tty->driver_data;
|
||||
tty_port_hangup(&ch->port);
|
||||
}
|
||||
|
||||
static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
dcd = !!dcd;
|
||||
|
||||
spin_lock_irqsave(&p->port.lock, flags);
|
||||
if (dcd != p->DCDState) {
|
||||
p->DCDState = dcd;
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
tty = tty_port_tty_get(&p->port);
|
||||
if (tty && C_CLOCAL(tty) && !dcd)
|
||||
tty_hangup(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,
|
||||
|
@ -1470,24 +1378,24 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
|||
u16 intr;
|
||||
|
||||
if (tty) {
|
||||
if ((p->statusflags & EMPTYWAIT) &&
|
||||
if (test_bit(EMPTYWAIT, &p->statusflags) &&
|
||||
MoxaPortTxQueue(p) == 0) {
|
||||
p->statusflags &= ~EMPTYWAIT;
|
||||
clear_bit(EMPTYWAIT, &p->statusflags);
|
||||
tty_wakeup(tty);
|
||||
}
|
||||
if ((p->statusflags & LOWWAIT) && !tty->stopped &&
|
||||
if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped &&
|
||||
MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
|
||||
p->statusflags &= ~LOWWAIT;
|
||||
clear_bit(LOWWAIT, &p->statusflags);
|
||||
tty_wakeup(tty);
|
||||
}
|
||||
|
||||
if (inited && !(p->statusflags & THROTTLE) &&
|
||||
if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
|
||||
MoxaPortRxQueue(p) > 0) { /* RX */
|
||||
MoxaPortReadData(p);
|
||||
tty_schedule_flip(tty);
|
||||
}
|
||||
} else {
|
||||
p->statusflags &= ~EMPTYWAIT;
|
||||
clear_bit(EMPTYWAIT, &p->statusflags);
|
||||
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);
|
||||
}
|
||||
|
||||
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: *
|
||||
*****************************************************************************/
|
||||
|
@ -1918,10 +1797,12 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
|
|||
baud = MoxaPortSetBaud(port, baud);
|
||||
|
||||
if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
|
||||
spin_lock_irq(&moxafunc_lock);
|
||||
writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
|
||||
writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
|
||||
writeb(FC_SetXonXoff, ofsAddr + FuncCode);
|
||||
moxa_wait_finish(ofsAddr);
|
||||
spin_unlock_irq(&moxafunc_lock);
|
||||
|
||||
}
|
||||
return baud;
|
||||
|
@ -1974,18 +1855,14 @@ static int MoxaPortLineStatus(struct moxa_port *port)
|
|||
int val;
|
||||
|
||||
ofsAddr = port->tableAddr;
|
||||
if (MOXA_IS_320(port->board)) {
|
||||
moxafunc(ofsAddr, FC_LineStatus, 0);
|
||||
val = readw(ofsAddr + FuncArg);
|
||||
} else {
|
||||
if (MOXA_IS_320(port->board))
|
||||
val = moxafuncret(ofsAddr, FC_LineStatus, 0);
|
||||
else
|
||||
val = readw(ofsAddr + FlagStat) >> 4;
|
||||
}
|
||||
val &= 0x0B;
|
||||
if (val & 8)
|
||||
val |= 4;
|
||||
spin_lock_bh(&moxa_lock);
|
||||
moxa_new_dcdstate(port, val & 8);
|
||||
spin_unlock_bh(&moxa_lock);
|
||||
val &= 7;
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/interrupt.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 flags;
|
||||
|
||||
|
@ -868,22 +867,13 @@ static int mxser_startup(struct tty_struct *tty)
|
|||
|
||||
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) {
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
free_page(page);
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
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;
|
||||
|
||||
/*
|
||||
* Clear the FIFO buffers and disable them
|
||||
|
@ -951,24 +941,19 @@ static int mxser_startup(struct tty_struct *tty)
|
|||
* and set the speed of the serial port
|
||||
*/
|
||||
mxser_change_speed(tty, NULL);
|
||||
info->port.flags |= ASYNC_INITIALIZED;
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine will shutdown a serial port; interrupts maybe disabled, and
|
||||
* DTR is dropped if the hangup on close termio flag is on.
|
||||
* This routine will shutdown a serial port
|
||||
*/
|
||||
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;
|
||||
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* Free the IRQ, if necessary
|
||||
* Free the xmit buffer, if necessary
|
||||
*/
|
||||
if (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;
|
||||
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 */
|
||||
if (info->board->chip_flag)
|
||||
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 */
|
||||
(void) inb(info->ioaddr + UART_RX);
|
||||
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
|
||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
||||
|
||||
if (info->board->chip_flag)
|
||||
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)
|
||||
{
|
||||
struct mxser_port *info;
|
||||
unsigned long flags;
|
||||
int retval, line;
|
||||
int line;
|
||||
|
||||
line = tty->index;
|
||||
if (line == MXSER_PORTS)
|
||||
|
@ -1035,23 +1012,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
|
|||
if (!info->ioaddr)
|
||||
return -ENODEV;
|
||||
|
||||
tty->driver_data = info;
|
||||
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;
|
||||
return tty_port_open(&info->port, tty, filp);
|
||||
}
|
||||
|
||||
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);
|
||||
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
|
||||
* disable the receive line status interrupts, and tell the
|
||||
|
@ -1097,22 +1050,18 @@ static void mxser_close_port(struct tty_struct *tty, struct tty_port *port)
|
|||
if (info->board->chip_flag)
|
||||
info->IER &= ~MOXA_MUST_RECV_ISR;
|
||||
|
||||
if (port->flags & ASYNC_INITIALIZED) {
|
||||
outb(info->IER, info->ioaddr + UART_IER);
|
||||
/*
|
||||
* Before we drop DTR, make sure the UART transmitter
|
||||
* has completely drained; this is especially
|
||||
* important if there is a transmit FIFO!
|
||||
*/
|
||||
timeout = jiffies + HZ;
|
||||
while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
|
||||
schedule_timeout_interruptible(5);
|
||||
if (time_after(jiffies, timeout))
|
||||
break;
|
||||
}
|
||||
outb(info->IER, info->ioaddr + UART_IER);
|
||||
/*
|
||||
* Before we drop DTR, make sure the UART transmitter
|
||||
* has completely drained; this is especially
|
||||
* important if there is a transmit FIFO!
|
||||
*/
|
||||
timeout = jiffies + HZ;
|
||||
while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
|
||||
schedule_timeout_interruptible(5);
|
||||
if (time_after(jiffies, timeout))
|
||||
break;
|
||||
}
|
||||
mxser_shutdown(tty);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1130,8 +1079,12 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
|
|||
return;
|
||||
if (tty_port_close_start(port, tty, filp) == 0)
|
||||
return;
|
||||
mxser_close_port(tty, port);
|
||||
mutex_lock(&port->mutex);
|
||||
mxser_close_port(port);
|
||||
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
|
||||
as we don't yet have everyone using refcounts */
|
||||
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 mxser_port *info = tty->driver_data;
|
||||
struct tty_port *port = &info->port;
|
||||
struct serial_struct new_serial;
|
||||
speed_t baud;
|
||||
unsigned long sl_flags;
|
||||
|
@ -1290,7 +1244,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
|||
new_serial.port != info->ioaddr)
|
||||
return -EINVAL;
|
||||
|
||||
flags = info->port.flags & ASYNC_SPD_MASK;
|
||||
flags = port->flags & ASYNC_SPD_MASK;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
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.
|
||||
* 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));
|
||||
info->port.close_delay = new_serial.close_delay * HZ / 100;
|
||||
info->port.closing_wait = new_serial.closing_wait * HZ / 100;
|
||||
tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
|
||||
? 1 : 0;
|
||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
|
||||
port->close_delay = new_serial.close_delay * HZ / 100;
|
||||
port->closing_wait = new_serial.closing_wait * HZ / 100;
|
||||
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
|
||||
(new_serial.baud_base != info->baud_base ||
|
||||
new_serial.custom_divisor !=
|
||||
info->custom_divisor)) {
|
||||
if (new_serial.custom_divisor == 0)
|
||||
return -EINVAL;
|
||||
baud = new_serial.baud_base / new_serial.custom_divisor;
|
||||
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);
|
||||
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
|
||||
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
if (flags != (port->flags & ASYNC_SPD_MASK)) {
|
||||
spin_lock_irqsave(&info->slock, sl_flags);
|
||||
mxser_change_speed(tty, NULL);
|
||||
spin_unlock_irqrestore(&info->slock, sl_flags);
|
||||
}
|
||||
} else
|
||||
retval = mxser_startup(tty);
|
||||
|
||||
} else {
|
||||
retval = mxser_activate(port, tty);
|
||||
if (retval == 0)
|
||||
set_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct mxser_port *port;
|
||||
struct mxser_port *ip;
|
||||
struct tty_port *port;
|
||||
struct tty_struct *tty;
|
||||
int result, status;
|
||||
unsigned int i, j;
|
||||
|
@ -1536,38 +1494,39 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
|||
|
||||
case MOXA_CHKPORTENABLE:
|
||||
result = 0;
|
||||
lock_kernel();
|
||||
for (i = 0; i < MXSER_BOARDS; i++)
|
||||
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
|
||||
if (mxser_boards[i].ports[j].ioaddr)
|
||||
result |= (1 << i);
|
||||
unlock_kernel();
|
||||
return put_user(result, (unsigned long __user *)argp);
|
||||
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)))
|
||||
ret = -EFAULT;
|
||||
unlock_kernel();
|
||||
return ret;
|
||||
case MOXA_GETMSTATUS: {
|
||||
struct mxser_mstatus ms, __user *msu = argp;
|
||||
lock_kernel();
|
||||
for (i = 0; i < MXSER_BOARDS; i++)
|
||||
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));
|
||||
|
||||
if (!port->ioaddr)
|
||||
mutex_lock(&port->mutex);
|
||||
if (!ip->ioaddr)
|
||||
goto copy;
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
tty = tty_port_tty_get(port);
|
||||
|
||||
if (!tty || !tty->termios)
|
||||
ms.cflag = port->normal_termios.c_cflag;
|
||||
ms.cflag = ip->normal_termios.c_cflag;
|
||||
else
|
||||
ms.cflag = tty->termios->c_cflag;
|
||||
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)
|
||||
ms.dcd = 1;
|
||||
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)
|
||||
ms.cts = 1;
|
||||
copy:
|
||||
if (copy_to_user(msu, &ms, sizeof(ms))) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&port->mutex);
|
||||
if (copy_to_user(msu, &ms, sizeof(ms)))
|
||||
return -EFAULT;
|
||||
}
|
||||
msu++;
|
||||
}
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
case MOXA_ASPP_MON_EXT: {
|
||||
|
@ -1593,41 +1550,48 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
|||
if (!me)
|
||||
return -ENOMEM;
|
||||
|
||||
lock_kernel();
|
||||
for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
|
||||
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
|
||||
if (p >= ARRAY_SIZE(me->rx_cnt)) {
|
||||
i = MXSER_BOARDS;
|
||||
break;
|
||||
}
|
||||
port = &mxser_boards[i].ports[j];
|
||||
if (!port->ioaddr)
|
||||
continue;
|
||||
ip = &mxser_boards[i].ports[j];
|
||||
port = &ip->port;
|
||||
|
||||
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)
|
||||
port->icount.rng++;
|
||||
ip->icount.rng++;
|
||||
if (status & UART_MSR_DDSR)
|
||||
port->icount.dsr++;
|
||||
ip->icount.dsr++;
|
||||
if (status & UART_MSR_DDCD)
|
||||
port->icount.dcd++;
|
||||
ip->icount.dcd++;
|
||||
if (status & UART_MSR_DCTS)
|
||||
port->icount.cts++;
|
||||
ip->icount.cts++;
|
||||
|
||||
port->mon_data.modem_status = status;
|
||||
me->rx_cnt[p] = port->mon_data.rxcnt;
|
||||
me->tx_cnt[p] = port->mon_data.txcnt;
|
||||
me->up_rxcnt[p] = port->mon_data.up_rxcnt;
|
||||
me->up_txcnt[p] = port->mon_data.up_txcnt;
|
||||
ip->mon_data.modem_status = status;
|
||||
me->rx_cnt[p] = ip->mon_data.rxcnt;
|
||||
me->tx_cnt[p] = ip->mon_data.txcnt;
|
||||
me->up_rxcnt[p] = ip->mon_data.up_rxcnt;
|
||||
me->up_txcnt[p] = ip->mon_data.up_txcnt;
|
||||
me->modem_status[p] =
|
||||
port->mon_data.modem_status;
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
ip->mon_data.modem_status;
|
||||
spin_unlock_irq(&ip->slock);
|
||||
|
||||
tty = tty_port_tty_get(&ip->port);
|
||||
|
||||
if (!tty || !tty->termios) {
|
||||
cflag = port->normal_termios.c_cflag;
|
||||
iflag = port->normal_termios.c_iflag;
|
||||
me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
|
||||
cflag = ip->normal_termios.c_cflag;
|
||||
iflag = ip->normal_termios.c_iflag;
|
||||
me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
|
||||
} else {
|
||||
cflag = tty->termios->c_cflag;
|
||||
iflag = tty->termios->c_iflag;
|
||||
|
@ -1646,16 +1610,15 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
|||
if (iflag & (IXON | IXOFF))
|
||||
me->flowctrl[p] |= 0x0C;
|
||||
|
||||
if (port->type == PORT_16550A)
|
||||
if (ip->type == PORT_16550A)
|
||||
me->fifo[p] = 1;
|
||||
|
||||
opmode = inb(port->opmode_ioaddr) >>
|
||||
((p % 4) * 2);
|
||||
opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
|
||||
opmode &= OP_MODE_MASK;
|
||||
me->iftype[p] = opmode;
|
||||
mutex_unlock(&port->mutex);
|
||||
}
|
||||
}
|
||||
unlock_kernel();
|
||||
if (copy_to_user(argp, me, sizeof(*me)))
|
||||
ret = -EFAULT;
|
||||
kfree(me);
|
||||
|
@ -1692,6 +1655,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
|||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct mxser_port *info = tty->driver_data;
|
||||
struct tty_port *port = &info->port;
|
||||
struct async_icount cnow;
|
||||
unsigned long flags;
|
||||
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 != RS485_4WIRE_MODE)
|
||||
return -EFAULT;
|
||||
lock_kernel();
|
||||
mask = ModeMask[p];
|
||||
shiftbit = p * 2;
|
||||
spin_lock_irq(&info->slock);
|
||||
val = inb(info->opmode_ioaddr);
|
||||
val &= mask;
|
||||
val |= (opmode << shiftbit);
|
||||
outb(val, info->opmode_ioaddr);
|
||||
unlock_kernel();
|
||||
spin_unlock_irq(&info->slock);
|
||||
} else {
|
||||
lock_kernel();
|
||||
shiftbit = p * 2;
|
||||
spin_lock_irq(&info->slock);
|
||||
opmode = inb(info->opmode_ioaddr) >> shiftbit;
|
||||
spin_unlock_irq(&info->slock);
|
||||
opmode &= OP_MODE_MASK;
|
||||
unlock_kernel();
|
||||
if (put_user(opmode, (int __user *)argp))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
@ -1742,14 +1706,14 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
|||
|
||||
switch (cmd) {
|
||||
case TIOCGSERIAL:
|
||||
lock_kernel();
|
||||
mutex_lock(&port->mutex);
|
||||
retval = mxser_get_serial_info(tty, argp);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&port->mutex);
|
||||
return retval;
|
||||
case TIOCSSERIAL:
|
||||
lock_kernel();
|
||||
mutex_lock(&port->mutex);
|
||||
retval = mxser_set_serial_info(tty, argp);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&port->mutex);
|
||||
return retval;
|
||||
case TIOCSERGETLSR: /* Get line status register */
|
||||
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:
|
||||
return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
|
||||
case MOXA_SDS_RSTICOUNTER:
|
||||
lock_kernel();
|
||||
spin_lock_irq(&info->slock);
|
||||
info->mon_data.rxcnt = 0;
|
||||
info->mon_data.txcnt = 0;
|
||||
unlock_kernel();
|
||||
spin_unlock_irq(&info->slock);
|
||||
return 0;
|
||||
|
||||
case MOXA_ASPP_OQUEUE:{
|
||||
int len, lsr;
|
||||
|
||||
lock_kernel();
|
||||
len = mxser_chars_in_buffer(tty);
|
||||
spin_lock(&info->slock);
|
||||
lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
|
||||
spin_unlock_irq(&info->slock);
|
||||
len += (lsr ? 0 : 1);
|
||||
unlock_kernel();
|
||||
|
||||
return put_user(len, (int __user *)argp);
|
||||
}
|
||||
case MOXA_ASPP_MON: {
|
||||
int mcr, status;
|
||||
|
||||
lock_kernel();
|
||||
spin_lock(&info->slock);
|
||||
status = mxser_get_msr(info->ioaddr, 1, tty->index);
|
||||
mxser_check_modem_status(tty, info, status);
|
||||
|
||||
mcr = inb(info->ioaddr + UART_MCR);
|
||||
spin_unlock(&info->slock);
|
||||
|
||||
if (mcr & MOXA_MUST_MCR_XON_FLAG)
|
||||
info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
|
||||
else
|
||||
|
@ -1834,7 +1800,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
|||
info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
|
||||
else
|
||||
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
|
||||
unlock_kernel();
|
||||
|
||||
if (copy_to_user(argp, &info->mon_data,
|
||||
sizeof(struct mxser_mon)))
|
||||
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;
|
||||
unsigned long orig_jiffies, char_time;
|
||||
unsigned long flags;
|
||||
int lsr;
|
||||
|
||||
if (info->type == PORT_UNKNOWN)
|
||||
|
@ -2032,19 +1999,21 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
|
|||
timeout, char_time);
|
||||
printk("jiff=%lu...", jiffies);
|
||||
#endif
|
||||
lock_kernel();
|
||||
spin_lock_irqsave(&info->slock, flags);
|
||||
while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
|
||||
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
|
||||
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
|
||||
#endif
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
schedule_timeout_interruptible(char_time);
|
||||
spin_lock_irqsave(&info->slock, flags);
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
if (timeout && time_after(jiffies, orig_jiffies + timeout))
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
set_current_state(TASK_RUNNING);
|
||||
unlock_kernel();
|
||||
|
||||
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
|
||||
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;
|
||||
|
||||
mxser_flush_buffer(tty);
|
||||
mxser_shutdown(tty);
|
||||
tty_port_hangup(&info->port);
|
||||
}
|
||||
|
||||
|
@ -2363,6 +2331,8 @@ static const struct tty_operations mxser_ops = {
|
|||
struct tty_port_operations mxser_port_ops = {
|
||||
.carrier_raised = mxser_carrier_raised,
|
||||
.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,
|
||||
.close = ipw_close,
|
||||
.hangup = ipw_hangup,
|
||||
|
|
|
@ -659,7 +659,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
|
|||
if (!retval)
|
||||
return 0;
|
||||
out1:
|
||||
tty_release_dev(filp);
|
||||
tty_release(inode, filp);
|
||||
return retval;
|
||||
out:
|
||||
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 */
|
||||
static int rc_setup_port(struct tty_struct *tty, struct riscom_board *bp,
|
||||
struct riscom_port *port)
|
||||
static int rc_activate_port(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
struct riscom_port *rp = container_of(port, struct riscom_port, port);
|
||||
struct riscom_board *bp = port_Board(rp);
|
||||
unsigned long flags;
|
||||
|
||||
if (port->port.flags & ASYNC_INITIALIZED)
|
||||
return 0;
|
||||
|
||||
if (tty_port_alloc_xmit_buf(&port->port) < 0)
|
||||
if (tty_port_alloc_xmit_buf(port) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&riscom_lock, flags);
|
||||
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
if (port->port.count == 1)
|
||||
bp->count++;
|
||||
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
|
||||
rc_change_speed(tty, bp, port);
|
||||
port->port.flags |= ASYNC_INITIALIZED;
|
||||
|
||||
bp->count++;
|
||||
rp->xmit_cnt = rp->xmit_head = rp->xmit_tail = 0;
|
||||
rc_change_speed(tty, bp, rp);
|
||||
spin_unlock_irqrestore(&riscom_lock, flags);
|
||||
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,
|
||||
struct riscom_board *bp, struct riscom_port *port)
|
||||
{
|
||||
if (!(port->port.flags & ASYNC_INITIALIZED))
|
||||
return;
|
||||
|
||||
#ifdef RC_REPORT_OVERRUN
|
||||
printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
|
||||
board_No(bp), port_No(port), port->overrun);
|
||||
|
@ -840,11 +832,6 @@ static void rc_shutdown_port(struct tty_struct *tty,
|
|||
}
|
||||
#endif
|
||||
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 */
|
||||
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);
|
||||
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
port->port.flags &= ~ASYNC_INITIALIZED;
|
||||
|
||||
if (--bp->count < 0) {
|
||||
printk(KERN_INFO "rc%d: rc_shutdown_port: "
|
||||
|
@ -889,6 +875,20 @@ static int carrier_raised(struct tty_port *port)
|
|||
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)
|
||||
{
|
||||
int board;
|
||||
|
@ -909,14 +909,7 @@ static int rc_open(struct tty_struct *tty, struct file *filp)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
port->port.count++;
|
||||
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;
|
||||
return tty_port_open(&port->port, tty, filp);
|
||||
}
|
||||
|
||||
static void rc_flush_buffer(struct tty_struct *tty)
|
||||
|
@ -950,24 +943,23 @@ static void rc_close_port(struct tty_port *port)
|
|||
|
||||
spin_lock_irqsave(&riscom_lock, flags);
|
||||
rp->IER &= ~IER_RXD;
|
||||
if (port->flags & ASYNC_INITIALIZED) {
|
||||
rp->IER &= ~IER_TXRDY;
|
||||
rp->IER |= IER_TXEMPTY;
|
||||
rc_out(bp, CD180_CAR, port_No(rp));
|
||||
rc_out(bp, CD180_IER, rp->IER);
|
||||
/*
|
||||
* Before we drop DTR, make sure the UART transmitter
|
||||
* has completely drained; this is especially
|
||||
* important if there is a transmit FIFO!
|
||||
*/
|
||||
timeout = jiffies + HZ;
|
||||
while (rp->IER & IER_TXEMPTY) {
|
||||
spin_unlock_irqrestore(&riscom_lock, flags);
|
||||
msleep_interruptible(jiffies_to_msecs(rp->timeout));
|
||||
spin_lock_irqsave(&riscom_lock, flags);
|
||||
if (time_after(jiffies, timeout))
|
||||
break;
|
||||
}
|
||||
|
||||
rp->IER &= ~IER_TXRDY;
|
||||
rp->IER |= IER_TXEMPTY;
|
||||
rc_out(bp, CD180_CAR, port_No(rp));
|
||||
rc_out(bp, CD180_IER, rp->IER);
|
||||
/*
|
||||
* Before we drop DTR, make sure the UART transmitter
|
||||
* has completely drained; this is especially
|
||||
* important if there is a transmit FIFO!
|
||||
*/
|
||||
timeout = jiffies + HZ;
|
||||
while (rp->IER & IER_TXEMPTY) {
|
||||
spin_unlock_irqrestore(&riscom_lock, flags);
|
||||
msleep_interruptible(jiffies_to_msecs(rp->timeout));
|
||||
spin_lock_irqsave(&riscom_lock, flags);
|
||||
if (time_after(jiffies, timeout))
|
||||
break;
|
||||
}
|
||||
rc_shutdown_port(port->tty, bp, rp);
|
||||
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"))
|
||||
return;
|
||||
|
||||
rc_shutdown_port(tty, port_Board(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 = {
|
||||
.carrier_raised = carrier_raised,
|
||||
.dtr_rts = dtr_rts,
|
||||
.shutdown = rc_close_port,
|
||||
.activate = rc_activate_port,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -407,7 +407,7 @@ static unsigned int stl_baudrates[] = {
|
|||
* 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_getportstats(struct tty_struct *tty, 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 = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = stl_memioctl,
|
||||
.unlocked_ioctl = stl_memioctl,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
struct stlport *portp;
|
||||
|
@ -737,32 +755,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
|
|||
if (portp == NULL)
|
||||
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.
|
||||
*/
|
||||
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 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);
|
||||
|
||||
struct stlport *portp = container_of(port, struct stlport, port);
|
||||
stl_disableintrs(portp);
|
||||
if (tty->termios->c_cflag & HUPCL)
|
||||
stl_setsignals(portp, 0, 0);
|
||||
stl_enablerxtx(portp, 0, 0);
|
||||
stl_flushbuffer(tty);
|
||||
stl_flush(portp);
|
||||
portp->istate = 0;
|
||||
if (portp->tx.buf != NULL) {
|
||||
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.tail = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
tty_port_close_end(port, tty);
|
||||
tty_port_tty_set(port, NULL);
|
||||
static void stl_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct stlport *portp;
|
||||
struct tty_port *port;
|
||||
unsigned long flags;
|
||||
|
||||
struct stlport *portp = tty->driver_data;
|
||||
pr_debug("stl_hangup(tty=%p)\n", tty);
|
||||
|
||||
portp = tty->driver_data;
|
||||
if (portp == NULL)
|
||||
return;
|
||||
port = &portp->port;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->flags &= ~ASYNC_INITIALIZED;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
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);
|
||||
tty_port_hangup(&portp->port);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -2486,18 +2438,19 @@ static int stl_getbrdstruct(struct stlbrd __user *arg)
|
|||
* 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;
|
||||
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)
|
||||
return -ENODEV;
|
||||
rc = 0;
|
||||
|
||||
lock_kernel();
|
||||
switch (cmd) {
|
||||
case COM_GETPORTSTATS:
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_kernel();
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -2549,6 +2502,8 @@ static const struct tty_operations stl_ops = {
|
|||
static const struct tty_port_operations stl_port_ops = {
|
||||
.carrier_raised = stl_carrier_raised,
|
||||
.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 *);
|
||||
static unsigned int tty_poll(struct file *, poll_table *);
|
||||
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);
|
||||
#ifdef CONFIG_COMPAT
|
||||
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)
|
||||
return;
|
||||
|
||||
/* inuse_filps is protected by the single kernel lock */
|
||||
lock_kernel();
|
||||
|
||||
spin_lock(&redirect_lock);
|
||||
if (redirect && redirect->private_data == tty) {
|
||||
|
@ -516,7 +513,11 @@ static void do_tty_hangup(struct work_struct *work)
|
|||
}
|
||||
spin_unlock(&redirect_lock);
|
||||
|
||||
/* inuse_filps is protected by the single kernel lock */
|
||||
lock_kernel();
|
||||
check_tty_count(tty, "do_tty_hangup");
|
||||
unlock_kernel();
|
||||
|
||||
file_list_lock();
|
||||
/* This breaks for file handles being sent over AF_UNIX sockets ? */
|
||||
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();
|
||||
|
||||
lock_kernel();
|
||||
tty_ldisc_hangup(tty);
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
|
@ -708,6 +710,8 @@ void disassociate_ctty(int on_exit)
|
|||
struct tty_struct *tty;
|
||||
struct pid *tty_pgrp = NULL;
|
||||
|
||||
if (!current->signal->leader)
|
||||
return;
|
||||
|
||||
tty = get_current_tty();
|
||||
if (tty) {
|
||||
|
@ -773,8 +777,7 @@ void no_tty(void)
|
|||
{
|
||||
struct task_struct *tsk = current;
|
||||
lock_kernel();
|
||||
if (tsk->signal->leader)
|
||||
disassociate_ctty(0);
|
||||
disassociate_ctty(0);
|
||||
unlock_kernel();
|
||||
proc_clear_tty(tsk);
|
||||
}
|
||||
|
@ -1017,14 +1020,16 @@ out:
|
|||
|
||||
void tty_write_message(struct tty_struct *tty, char *msg)
|
||||
{
|
||||
lock_kernel();
|
||||
if (tty) {
|
||||
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));
|
||||
} else
|
||||
unlock_kernel();
|
||||
tty_write_unlock(tty);
|
||||
}
|
||||
unlock_kernel();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1202,14 +1207,21 @@ static int tty_driver_install_tty(struct tty_driver *driver,
|
|||
struct tty_struct *tty)
|
||||
{
|
||||
int idx = tty->index;
|
||||
int ret;
|
||||
|
||||
if (driver->ops->install)
|
||||
return driver->ops->install(driver, tty);
|
||||
if (driver->ops->install) {
|
||||
lock_kernel();
|
||||
ret = driver->ops->install(driver, tty);
|
||||
unlock_kernel();
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tty_init_termios(tty) == 0) {
|
||||
lock_kernel();
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
driver->ttys[idx] = tty;
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
return -ENOMEM;
|
||||
|
@ -1302,10 +1314,14 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
|||
struct tty_struct *tty;
|
||||
int retval;
|
||||
|
||||
lock_kernel();
|
||||
/* Check if pty master is being opened multiple times */
|
||||
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);
|
||||
}
|
||||
unlock_kernel();
|
||||
|
||||
/*
|
||||
* 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
|
||||
* to decrement the use counts, as release_tty doesn't care.
|
||||
*/
|
||||
|
||||
retval = tty_ldisc_setup(tty, tty->link);
|
||||
if (retval)
|
||||
goto release_mem_out;
|
||||
|
@ -1350,7 +1365,9 @@ release_mem_out:
|
|||
if (printk_ratelimit())
|
||||
printk(KERN_INFO "tty_init_dev: ldisc open failed, "
|
||||
"clearing slot %d\n", idx);
|
||||
lock_kernel();
|
||||
release_tty(tty, idx);
|
||||
unlock_kernel();
|
||||
return ERR_PTR(retval);
|
||||
}
|
||||
|
||||
|
@ -1464,7 +1481,17 @@ static void release_tty(struct tty_struct *tty, int idx)
|
|||
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
|
||||
* to be very careful that the structures are all released at the
|
||||
* 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
|
||||
* 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;
|
||||
int pty_master, tty_closing, o_tty_closing, do_sleep;
|
||||
int devpts;
|
||||
int idx;
|
||||
char buf[64];
|
||||
struct inode *inode;
|
||||
|
||||
inode = filp->f_path.dentry->d_inode;
|
||||
tty = (struct tty_struct *)filp->private_data;
|
||||
if (tty_paranoia_check(tty, inode, "tty_release_dev"))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
lock_kernel();
|
||||
check_tty_count(tty, "tty_release_dev");
|
||||
|
||||
tty_fasync(-1, filp, 0);
|
||||
|
@ -1500,19 +1527,22 @@ void tty_release_dev(struct file *filp)
|
|||
if (idx < 0 || idx >= tty->driver->num) {
|
||||
printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
|
||||
"free (%s)\n", tty->name);
|
||||
return;
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
if (!devpts) {
|
||||
if (tty != tty->driver->ttys[idx]) {
|
||||
unlock_kernel();
|
||||
printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
|
||||
"for (%s)\n", idx, tty->name);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
if (tty->termios != tty->driver->termios[idx]) {
|
||||
unlock_kernel();
|
||||
printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
|
||||
"for (%s)\n",
|
||||
idx, tty->name);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1526,26 +1556,30 @@ void tty_release_dev(struct file *filp)
|
|||
if (tty->driver->other &&
|
||||
!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
|
||||
if (o_tty != tty->driver->other->ttys[idx]) {
|
||||
unlock_kernel();
|
||||
printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
|
||||
"not o_tty for (%s)\n",
|
||||
idx, tty->name);
|
||||
return;
|
||||
return 0 ;
|
||||
}
|
||||
if (o_tty->termios != tty->driver->other->termios[idx]) {
|
||||
unlock_kernel();
|
||||
printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
|
||||
"not o_termios for (%s)\n",
|
||||
idx, tty->name);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
if (o_tty->link != tty) {
|
||||
unlock_kernel();
|
||||
printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (tty->ops->close)
|
||||
tty->ops->close(tty, filp);
|
||||
|
||||
unlock_kernel();
|
||||
/*
|
||||
* 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
|
||||
|
@ -1568,6 +1602,7 @@ void tty_release_dev(struct file *filp)
|
|||
opens on /dev/tty */
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
lock_kernel();
|
||||
tty_closing = tty->count <= 1;
|
||||
o_tty_closing = o_tty &&
|
||||
(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 "
|
||||
"active!\n", tty_name(tty, buf));
|
||||
unlock_kernel();
|
||||
mutex_unlock(&tty_mutex);
|
||||
schedule();
|
||||
}
|
||||
|
@ -1661,8 +1697,10 @@ void tty_release_dev(struct file *filp)
|
|||
mutex_unlock(&tty_mutex);
|
||||
|
||||
/* check whether both sides are closing ... */
|
||||
if (!tty_closing || (o_tty && !o_tty_closing))
|
||||
return;
|
||||
if (!tty_closing || (o_tty && !o_tty_closing)) {
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "freeing tty structure...");
|
||||
|
@ -1680,10 +1718,12 @@ void tty_release_dev(struct file *filp)
|
|||
/* Make this pty number available for reallocation */
|
||||
if (devpts)
|
||||
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
|
||||
* @filp: file pointer to tty
|
||||
*
|
||||
|
@ -1703,7 +1743,7 @@ void tty_release_dev(struct file *filp)
|
|||
* ->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;
|
||||
int noctty, retval;
|
||||
|
@ -1720,10 +1760,12 @@ retry_open:
|
|||
retval = 0;
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
lock_kernel();
|
||||
|
||||
if (device == MKDEV(TTYAUX_MAJOR, 0)) {
|
||||
tty = get_current_tty();
|
||||
if (!tty) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&tty_mutex);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
@ -1755,12 +1797,14 @@ retry_open:
|
|||
goto got_driver;
|
||||
}
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&tty_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
driver = get_tty_driver(device, &index);
|
||||
if (!driver) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&tty_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -1770,6 +1814,7 @@ got_driver:
|
|||
tty = tty_driver_lookup_tty(driver, inode, index);
|
||||
|
||||
if (IS_ERR(tty)) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&tty_mutex);
|
||||
return PTR_ERR(tty);
|
||||
}
|
||||
|
@ -1784,8 +1829,10 @@ got_driver:
|
|||
|
||||
mutex_unlock(&tty_mutex);
|
||||
tty_driver_kref_put(driver);
|
||||
if (IS_ERR(tty))
|
||||
if (IS_ERR(tty)) {
|
||||
unlock_kernel();
|
||||
return PTR_ERR(tty);
|
||||
}
|
||||
|
||||
filp->private_data = tty;
|
||||
file_move(filp, &tty->tty_files);
|
||||
|
@ -1813,11 +1860,15 @@ got_driver:
|
|||
printk(KERN_DEBUG "error %d in opening %s...", retval,
|
||||
tty->name);
|
||||
#endif
|
||||
tty_release_dev(filp);
|
||||
if (retval != -ERESTARTSYS)
|
||||
tty_release(inode, filp);
|
||||
if (retval != -ERESTARTSYS) {
|
||||
unlock_kernel();
|
||||
return retval;
|
||||
if (signal_pending(current))
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
unlock_kernel();
|
||||
return retval;
|
||||
}
|
||||
schedule();
|
||||
/*
|
||||
* Need to reset f_op in case a hangup happened.
|
||||
|
@ -1826,8 +1877,11 @@ got_driver:
|
|||
filp->f_op = &tty_fops;
|
||||
goto retry_open;
|
||||
}
|
||||
unlock_kernel();
|
||||
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
lock_kernel();
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
if (!noctty &&
|
||||
current->signal->leader &&
|
||||
|
@ -1835,43 +1889,12 @@ got_driver:
|
|||
tty->session == NULL)
|
||||
__proc_set_tty(current, tty);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&tty_mutex);
|
||||
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
|
||||
|
@ -2317,9 +2340,7 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
|
|||
if (get_user(ldisc, p))
|
||||
return -EFAULT;
|
||||
|
||||
lock_kernel();
|
||||
ret = tty_set_ldisc(tty, ldisc);
|
||||
unlock_kernel();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <linux/vt_kern.h>
|
||||
#include <linux/selection.h>
|
||||
|
||||
#include <linux/smp_lock.h> /* For the moment */
|
||||
|
||||
#include <linux/kmod.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)
|
||||
{
|
||||
WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
|
||||
if (ld->ops->open)
|
||||
return ld->ops->open(tty);
|
||||
if (ld->ops->open) {
|
||||
int ret;
|
||||
/* BKL here locks verus a hangup event */
|
||||
lock_kernel();
|
||||
ret = ld->ops->open(tty);
|
||||
unlock_kernel();
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -545,6 +553,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
if (IS_ERR(new_ldisc))
|
||||
return PTR_ERR(new_ldisc);
|
||||
|
||||
lock_kernel();
|
||||
/*
|
||||
* We need to look at the tty locking here for pty/tty pairs
|
||||
* 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) {
|
||||
unlock_kernel();
|
||||
tty_ldisc_put(new_ldisc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unlock_kernel();
|
||||
/*
|
||||
* Problem: What do we do if this blocks ?
|
||||
* 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);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
}
|
||||
|
||||
lock_kernel();
|
||||
|
||||
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;
|
||||
|
||||
o_ldisc = tty->ldisc;
|
||||
|
||||
unlock_kernel();
|
||||
/*
|
||||
* Make sure we don't change while someone holds a
|
||||
* 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();
|
||||
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
lock_kernel();
|
||||
if (test_bit(TTY_HUPPED, &tty->flags)) {
|
||||
/* We were raced by the hangup method. It will have stomped
|
||||
the ldisc data and closed the ldisc down */
|
||||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_ldisc_put(new_ldisc);
|
||||
unlock_kernel();
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -664,6 +682,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
if (o_work)
|
||||
schedule_delayed_work(&o_tty->buf.work, 1);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
unlock_kernel();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,19 +25,21 @@ void tty_port_init(struct tty_port *port)
|
|||
init_waitqueue_head(&port->close_wait);
|
||||
init_waitqueue_head(&port->delta_msr_wait);
|
||||
mutex_init(&port->mutex);
|
||||
mutex_init(&port->buf_mutex);
|
||||
spin_lock_init(&port->lock);
|
||||
port->close_delay = (50 * HZ) / 100;
|
||||
port->closing_wait = (3000 * HZ) / 100;
|
||||
kref_init(&port->kref);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_init);
|
||||
|
||||
int tty_port_alloc_xmit_buf(struct tty_port *port)
|
||||
{
|
||||
/* We may sleep in get_zeroed_page() */
|
||||
mutex_lock(&port->mutex);
|
||||
mutex_lock(&port->buf_mutex);
|
||||
if (port->xmit_buf == NULL)
|
||||
port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
|
||||
mutex_unlock(&port->mutex);
|
||||
mutex_unlock(&port->buf_mutex);
|
||||
if (port->xmit_buf == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
|
@ -46,15 +48,32 @@ EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
|
|||
|
||||
void tty_port_free_xmit_buf(struct tty_port *port)
|
||||
{
|
||||
mutex_lock(&port->mutex);
|
||||
mutex_lock(&port->buf_mutex);
|
||||
if (port->xmit_buf != NULL) {
|
||||
free_page((unsigned long)port->xmit_buf);
|
||||
port->xmit_buf = NULL;
|
||||
}
|
||||
mutex_unlock(&port->mutex);
|
||||
mutex_unlock(&port->buf_mutex);
|
||||
}
|
||||
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
|
||||
|
@ -99,10 +118,11 @@ EXPORT_SYMBOL(tty_port_tty_set);
|
|||
|
||||
static void tty_port_shutdown(struct tty_port *port)
|
||||
{
|
||||
mutex_lock(&port->mutex);
|
||||
if (port->ops->shutdown &&
|
||||
test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
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);
|
||||
port->count = 0;
|
||||
port->flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
if (port->tty)
|
||||
if (port->tty) {
|
||||
set_bit(TTY_IO_ERROR, &port->tty->flags);
|
||||
tty_kref_put(port->tty);
|
||||
}
|
||||
port->tty = NULL;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
|
@ -198,7 +220,7 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts);
|
|||
* management of these lines. Note that the dtr/rts raise is done each
|
||||
* iteration as a hangup may have previously dropped them while we wait.
|
||||
*/
|
||||
|
||||
|
||||
int tty_port_block_til_ready(struct tty_port *port,
|
||||
struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
|
@ -253,7 +275,8 @@ int tty_port_block_til_ready(struct tty_port *port,
|
|||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
|
||||
/* Check for a hangup or uninitialised port. Return accordingly */
|
||||
/* Check for a hangup or uninitialised port.
|
||||
Return accordingly */
|
||||
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
|
||||
if (port->flags & ASYNC_HUP_NOTIFY)
|
||||
retval = -EAGAIN;
|
||||
|
@ -285,11 +308,11 @@ int tty_port_block_til_ready(struct tty_port *port,
|
|||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
return retval;
|
||||
|
||||
}
|
||||
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;
|
||||
|
||||
|
@ -299,7 +322,7 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
|
|||
return 0;
|
||||
}
|
||||
|
||||
if( tty->count == 1 && port->count != 1) {
|
||||
if (tty->count == 1 && port->count != 1) {
|
||||
printk(KERN_WARNING
|
||||
"tty_port_close_start: tty->count = 1 port count = %d.\n",
|
||||
port->count);
|
||||
|
@ -331,12 +354,20 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
|
|||
long timeout;
|
||||
|
||||
if (bps > 1200)
|
||||
timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
|
||||
HZ / 10);
|
||||
timeout = max_t(long,
|
||||
(HZ * 10 * port->drain_delay) / bps, HZ / 10);
|
||||
else
|
||||
timeout = 2 * HZ;
|
||||
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
|
||||
to drop the last active reference in ->shutdown() or the tty
|
||||
shutdown path */
|
||||
|
@ -348,11 +379,6 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
|
|||
{
|
||||
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);
|
||||
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)
|
||||
return;
|
||||
tty_port_shutdown(port);
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
tty_port_close_end(port, tty);
|
||||
tty_port_tty_set(port, NULL);
|
||||
}
|
||||
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/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/serial_reg.h>
|
||||
|
@ -73,11 +74,10 @@ struct uart_icount {
|
|||
};
|
||||
|
||||
struct sdio_uart_port {
|
||||
struct tty_port port;
|
||||
struct kref kref;
|
||||
struct tty_struct *tty;
|
||||
unsigned int index;
|
||||
unsigned int opened;
|
||||
struct mutex open_lock;
|
||||
struct sdio_func *func;
|
||||
struct mutex func_lock;
|
||||
struct task_struct *in_sdio_uart_irq;
|
||||
|
@ -87,6 +87,7 @@ struct sdio_uart_port {
|
|||
struct uart_icount icount;
|
||||
unsigned int uartclk;
|
||||
unsigned int mctrl;
|
||||
unsigned int rx_mctrl;
|
||||
unsigned int read_status_mask;
|
||||
unsigned int ignore_status_mask;
|
||||
unsigned char x_char;
|
||||
|
@ -102,7 +103,6 @@ static int sdio_uart_add_port(struct sdio_uart_port *port)
|
|||
int index, ret = -EBUSY;
|
||||
|
||||
kref_init(&port->kref);
|
||||
mutex_init(&port->open_lock);
|
||||
mutex_init(&port->func_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)
|
||||
{
|
||||
struct sdio_func *func;
|
||||
struct tty_struct *tty;
|
||||
|
||||
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.
|
||||
* Beware: the lock ordering is critical.
|
||||
*/
|
||||
mutex_lock(&port->open_lock);
|
||||
mutex_lock(&port->port.mutex);
|
||||
mutex_lock(&port->func_lock);
|
||||
func = port->func;
|
||||
sdio_claim_host(func);
|
||||
port->func = NULL;
|
||||
mutex_unlock(&port->func_lock);
|
||||
if (port->opened)
|
||||
tty_hangup(port->tty);
|
||||
mutex_unlock(&port->open_lock);
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
/* tty_hangup is async so is this safe as is ?? */
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
mutex_unlock(&port->port.mutex);
|
||||
sdio_release_irq(func);
|
||||
sdio_disable_func(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 int ret;
|
||||
|
||||
/* FIXME: What stops this losing the delta bits and breaking
|
||||
sdio_uart_check_modem_status ? */
|
||||
status = sdio_in(port, UART_MSR);
|
||||
|
||||
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,
|
||||
unsigned int *status)
|
||||
{
|
||||
struct tty_struct *tty = port->tty;
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
unsigned int ch, flag;
|
||||
int max_count = 256;
|
||||
|
||||
|
@ -428,24 +435,30 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
|
|||
}
|
||||
|
||||
if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
if (tty)
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
|
||||
/*
|
||||
* Overrun is special. Since it's reported immediately,
|
||||
* it doesn't affect the current character.
|
||||
*/
|
||||
if (*status & ~port->ignore_status_mask & UART_LSR_OE)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
if (tty)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
|
||||
*status = sdio_in(port, UART_LSR);
|
||||
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
|
||||
tty_flip_buffer_push(tty);
|
||||
if (tty) {
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->xmit;
|
||||
int count;
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (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;
|
||||
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);
|
||||
tty_kref_put(tty);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -468,15 +486,17 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
|
|||
} while (--count > 0);
|
||||
|
||||
if (circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
tty_wakeup(port->tty);
|
||||
tty_wakeup(tty);
|
||||
|
||||
if (circ_empty(xmit))
|
||||
sdio_uart_stop_tx(port);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
|
||||
{
|
||||
int status;
|
||||
struct tty_struct *tty;
|
||||
|
||||
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++;
|
||||
if (status & UART_MSR_DDSR)
|
||||
port->icount.dsr++;
|
||||
if (status & UART_MSR_DDCD)
|
||||
if (status & UART_MSR_DDCD) {
|
||||
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) {
|
||||
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);
|
||||
if (port->tty->hw_stopped) {
|
||||
if (tty->hw_stopped) {
|
||||
if (cts) {
|
||||
port->tty->hw_stopped = 0;
|
||||
tty->hw_stopped = 0;
|
||||
sdio_uart_start_tx(port);
|
||||
tty_wakeup(port->tty);
|
||||
tty_wakeup(tty);
|
||||
}
|
||||
} else {
|
||||
if (!cts) {
|
||||
port->tty->hw_stopped = 1;
|
||||
tty->hw_stopped = 1;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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
|
||||
* 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. */
|
||||
page = __get_free_page(GFP_KERNEL);
|
||||
|
@ -592,19 +680,19 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
|
|||
*/
|
||||
sdio_out(port, UART_LCR, UART_LCR_WLEN8);
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
if (port->tty->termios->c_cflag & CRTSCTS)
|
||||
if (tty->termios->c_cflag & CRTSCTS)
|
||||
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 */
|
||||
sdio_uart_irq(port->func);
|
||||
|
@ -621,8 +709,20 @@ err1:
|
|||
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;
|
||||
|
||||
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);
|
||||
|
||||
/* 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 */
|
||||
sdio_release_irq(port->func);
|
||||
port->ier = 0;
|
||||
|
@ -661,77 +755,70 @@ skip:
|
|||
free_page((unsigned long)port->xmit.buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* sdio_uart_install - install method
|
||||
* @driver: the driver in use (sdio_uart in our case)
|
||||
* @tty: the tty being bound
|
||||
*
|
||||
* Look up and bind the tty and the driver together. Initialize
|
||||
* any needed private data (in our case the termios)
|
||||
*/
|
||||
|
||||
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;
|
||||
driver->ttys[idx] = tty;
|
||||
} else
|
||||
sdio_uart_port_put(port);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open/close/hangup is now entirely boilerplate
|
||||
*/
|
||||
|
||||
static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct sdio_uart_port *port;
|
||||
int ret;
|
||||
|
||||
port = sdio_uart_port_get(tty->index);
|
||||
if (!port)
|
||||
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) {
|
||||
tty->driver_data = port;
|
||||
port->tty = tty;
|
||||
ret = sdio_uart_startup(port);
|
||||
if (ret) {
|
||||
tty->driver_data = NULL;
|
||||
port->tty = NULL;
|
||||
mutex_unlock(&port->open_lock);
|
||||
sdio_uart_port_put(port);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
port->opened++;
|
||||
mutex_unlock(&port->open_lock);
|
||||
return 0;
|
||||
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)
|
||||
{
|
||||
struct sdio_uart_port *port = tty->driver_data;
|
||||
|
||||
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) {
|
||||
tty->closing = 1;
|
||||
sdio_uart_shutdown(port);
|
||||
tty_ldisc_flush(tty);
|
||||
port->tty = NULL;
|
||||
tty->driver_data = NULL;
|
||||
tty->closing = 0;
|
||||
}
|
||||
mutex_unlock(&port->open_lock);
|
||||
sdio_uart_port_put(port);
|
||||
tty_port_close(&port->port, tty, filp);
|
||||
}
|
||||
|
||||
static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
|
||||
static void sdio_uart_hangup(struct tty_struct *tty)
|
||||
{
|
||||
struct sdio_uart_port *port = tty->driver_data;
|
||||
tty_port_hangup(&port->port);
|
||||
}
|
||||
|
||||
static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
|
||||
int count)
|
||||
{
|
||||
struct sdio_uart_port *port = tty->driver_data;
|
||||
|
@ -756,7 +843,7 @@ static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
|
|||
}
|
||||
spin_unlock(&port->write_lock);
|
||||
|
||||
if ( !(port->ier & UART_IER_THRI)) {
|
||||
if (!(port->ier & UART_IER_THRI)) {
|
||||
int err = sdio_uart_claim_func(port);
|
||||
if (!err) {
|
||||
sdio_uart_start_tx(port);
|
||||
|
@ -843,17 +930,12 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
|
|||
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;
|
||||
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)
|
||||
return;
|
||||
|
||||
|
@ -928,7 +1010,7 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
|
|||
int result;
|
||||
|
||||
result = sdio_uart_claim_func(port);
|
||||
if(!result) {
|
||||
if (!result) {
|
||||
sdio_uart_update_mctrl(port, set, clear);
|
||||
sdio_uart_release_func(port);
|
||||
}
|
||||
|
@ -946,7 +1028,7 @@ static int sdio_uart_proc_show(struct seq_file *m, void *v)
|
|||
struct sdio_uart_port *port = sdio_uart_port_get(i);
|
||||
if (port) {
|
||||
seq_printf(m, "%d: uart:SDIO", i);
|
||||
if(capable(CAP_SYS_ADMIN)) {
|
||||
if (capable(CAP_SYS_ADMIN)) {
|
||||
seq_printf(m, " tx:%d rx:%d",
|
||||
port->icount.tx, port->icount.rx);
|
||||
if (port->icount.frame)
|
||||
|
@ -994,6 +1076,13 @@ static const struct file_operations sdio_uart_proc_fops = {
|
|||
.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 = {
|
||||
.open = sdio_uart_open,
|
||||
.close = sdio_uart_close,
|
||||
|
@ -1004,9 +1093,12 @@ static const struct tty_operations sdio_uart_ops = {
|
|||
.throttle = sdio_uart_throttle,
|
||||
.unthrottle = sdio_uart_unthrottle,
|
||||
.set_termios = sdio_uart_set_termios,
|
||||
.hangup = sdio_uart_hangup,
|
||||
.break_ctl = sdio_uart_break_ctl,
|
||||
.tiocmget = sdio_uart_tiocmget,
|
||||
.tiocmset = sdio_uart_tiocmset,
|
||||
.install = sdio_uart_install,
|
||||
.cleanup = sdio_uart_cleanup,
|
||||
.proc_fops = &sdio_uart_proc_fops,
|
||||
};
|
||||
|
||||
|
@ -1043,7 +1135,7 @@ static int sdio_uart_probe(struct sdio_func *func,
|
|||
}
|
||||
if (!tpl) {
|
||||
printk(KERN_WARNING
|
||||
"%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
|
||||
"%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
|
||||
sdio_func_id(func));
|
||||
kfree(port);
|
||||
return -EINVAL;
|
||||
|
@ -1068,13 +1160,16 @@ static int sdio_uart_probe(struct sdio_func *func,
|
|||
|
||||
port->func = func;
|
||||
sdio_set_drvdata(func, port);
|
||||
tty_port_init(&port->port);
|
||||
port->port.ops = &sdio_uart_port_ops;
|
||||
|
||||
ret = sdio_uart_add_port(port);
|
||||
if (ret) {
|
||||
kfree(port);
|
||||
} else {
|
||||
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)) {
|
||||
sdio_uart_port_remove(port);
|
||||
ret = PTR_ERR(dev);
|
||||
|
|
|
@ -1339,14 +1339,12 @@ static void serial8250_start_tx(struct uart_port *port)
|
|||
serial_out(up, UART_IER, up->ier);
|
||||
|
||||
if (up->bugs & UART_BUG_TXEN) {
|
||||
unsigned char lsr, iir;
|
||||
unsigned char lsr;
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
||||
iir = serial_in(up, UART_IIR) & 0x0f;
|
||||
if ((up->port.type == PORT_RM9000) ?
|
||||
(lsr & UART_LSR_THRE &&
|
||||
(iir == UART_IIR_NO_INT || iir == UART_IIR_THRI)) :
|
||||
(lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT))
|
||||
(lsr & UART_LSR_THRE) :
|
||||
(lsr & UART_LSR_TEMT))
|
||||
transmit_chars(up);
|
||||
}
|
||||
}
|
||||
|
@ -2646,7 +2644,7 @@ static void __init serial8250_isa_init_ports(void)
|
|||
{
|
||||
struct uart_8250_port *up;
|
||||
static int first = 1;
|
||||
int i;
|
||||
int i, irqflag = 0;
|
||||
|
||||
if (!first)
|
||||
return;
|
||||
|
@ -2670,6 +2668,9 @@ static void __init serial8250_isa_init_ports(void)
|
|||
up->port.ops = &serial8250_pops;
|
||||
}
|
||||
|
||||
if (share_irqs)
|
||||
irqflag = IRQF_SHARED;
|
||||
|
||||
for (i = 0, up = serial8250_ports;
|
||||
i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
|
||||
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.regshift = old_serial_port[i].iomem_reg_shift;
|
||||
set_io_from_upio(&up->port);
|
||||
if (share_irqs)
|
||||
up->port.irqflags |= IRQF_SHARED;
|
||||
up->port.irqflags |= irqflag;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2940,10 +2940,13 @@ static int __devinit serial8250_probe(struct platform_device *dev)
|
|||
{
|
||||
struct plat_serial8250_port *p = dev->dev.platform_data;
|
||||
struct uart_port port;
|
||||
int ret, i;
|
||||
int ret, i, irqflag = 0;
|
||||
|
||||
memset(&port, 0, sizeof(struct uart_port));
|
||||
|
||||
if (share_irqs)
|
||||
irqflag = IRQF_SHARED;
|
||||
|
||||
for (i = 0; p && p->flags != 0; p++, i++) {
|
||||
port.iobase = p->iobase;
|
||||
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_out = p->serial_out;
|
||||
port.dev = &dev->dev;
|
||||
if (share_irqs)
|
||||
port.irqflags |= IRQF_SHARED;
|
||||
port.irqflags |= irqflag;
|
||||
ret = serial8250_register_port(&port);
|
||||
if (ret < 0) {
|
||||
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 irq; /* Interrupt request number */
|
||||
u64 intr_count; /* Count of interrupts */
|
||||
|
||||
u64 membase; /* Start 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_cpstime; /* Time for CPS calculations */
|
||||
|
||||
tcflag_t ch_c_iflag; /* channel iflags */
|
||||
tcflag_t ch_c_cflag; /* channel cflags */
|
||||
tcflag_t ch_c_oflag; /* channel oflags */
|
||||
|
@ -215,11 +212,6 @@ struct jsm_channel {
|
|||
u8 ch_stopc; /* Stop 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_mistat; /* FEP input modem status */
|
||||
|
||||
|
|
|
@ -48,6 +48,17 @@ struct uart_driver jsm_uart_driver = {
|
|||
.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;
|
||||
module_param(jsm_debug, int, 0);
|
||||
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,
|
||||
IRQF_DISABLED|IRQF_SHARED, "JSM", brd);
|
||||
IRQF_SHARED, "JSM", brd);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
|
||||
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_save_state(pdev);
|
||||
|
||||
return 0;
|
||||
out_free_irq:
|
||||
|
@ -222,8 +234,42 @@ static struct pci_driver jsm_driver = {
|
|||
.id_table = jsm_pci_tbl,
|
||||
.probe = jsm_probe_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)
|
||||
{
|
||||
int rc;
|
||||
|
|
|
@ -954,13 +954,8 @@ static void neo_param(struct jsm_channel *ch)
|
|||
ch->ch_flags |= (CH_BAUD0);
|
||||
ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
|
||||
neo_assert_modem_signals(ch);
|
||||
ch->ch_old_baud = 0;
|
||||
return;
|
||||
|
||||
} else if (ch->ch_custom_speed) {
|
||||
baud = ch->ch_custom_speed;
|
||||
if (ch->ch_flags & CH_BAUD0)
|
||||
ch->ch_flags &= ~(CH_BAUD0);
|
||||
} else {
|
||||
int i;
|
||||
unsigned int cflag;
|
||||
|
@ -1045,7 +1040,6 @@ static void neo_param(struct jsm_channel *ch)
|
|||
quot = ch->ch_bd->bd_dividend / baud;
|
||||
|
||||
if (quot != 0) {
|
||||
ch->ch_old_baud = baud;
|
||||
writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
|
||||
writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
|
||||
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;
|
||||
int outofloop_count = 0;
|
||||
|
||||
brd->intr_count++;
|
||||
|
||||
/* Lock out the slow poller from running on this board. */
|
||||
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);
|
||||
}
|
||||
|
||||
channel->ch_old_baud = 0;
|
||||
|
||||
/* Turn off UART interrupts for this port */
|
||||
channel->ch_bd->bd_ops->uart_off(channel);
|
||||
|
||||
|
@ -432,7 +430,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __devinit jsm_uart_port_init(struct jsm_board *brd)
|
||||
int jsm_uart_port_init(struct jsm_board *brd)
|
||||
{
|
||||
int i;
|
||||
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))
|
||||
printk(KERN_INFO "jsm: add device failed\n");
|
||||
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");
|
||||
|
|
|
@ -438,6 +438,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
unsigned char cval, fcr = 0;
|
||||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
unsigned int dll;
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
|
@ -534,10 +535,18 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
else
|
||||
up->mcr &= ~UART_MCR_AFE;
|
||||
|
||||
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 */
|
||||
|
||||
/*
|
||||
* 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_LCR, cval); /* reset DLAB */
|
||||
serial_out(up, UART_LCR, cval); /* reset DLAB */
|
||||
up->lcr = cval; /* Save LCR */
|
||||
serial_pxa_set_mctrl(&up->port, up->port.mctrl);
|
||||
serial_out(up, UART_FCR, fcr);
|
||||
|
|
|
@ -342,11 +342,11 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
|
|||
|
||||
if (flags == UPF_SPD_HI)
|
||||
altbaud = 57600;
|
||||
if (flags == UPF_SPD_VHI)
|
||||
else if (flags == UPF_SPD_VHI)
|
||||
altbaud = 115200;
|
||||
if (flags == UPF_SPD_SHI)
|
||||
else if (flags == UPF_SPD_SHI)
|
||||
altbaud = 230400;
|
||||
if (flags == UPF_SPD_WARP)
|
||||
else if (flags == UPF_SPD_WARP)
|
||||
altbaud = 460800;
|
||||
|
||||
for (try = 0; try < 2; try++) {
|
||||
|
@ -1217,9 +1217,8 @@ static void uart_set_termios(struct tty_struct *tty,
|
|||
/* Handle transition to B0 status */
|
||||
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
|
||||
uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
|
||||
|
||||
/* 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;
|
||||
if (!(cflag & CRTSCTS) ||
|
||||
!test_bit(TTY_THROTTLED, &tty->flags))
|
||||
|
@ -1234,9 +1233,8 @@ static void uart_set_termios(struct tty_struct *tty,
|
|||
__uart_start(tty);
|
||||
spin_unlock_irqrestore(&state->uart_port->lock, flags);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
|
||||
tty->hw_stopped = 1;
|
||||
|
@ -2344,7 +2342,7 @@ static const struct tty_operations uart_ops = {
|
|||
*/
|
||||
int uart_register_driver(struct uart_driver *drv)
|
||||
{
|
||||
struct tty_driver *normal = NULL;
|
||||
struct tty_driver *normal;
|
||||
int i, retval;
|
||||
|
||||
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.
|
||||
*/
|
||||
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
|
||||
retval = -ENOMEM;
|
||||
if (!drv->state)
|
||||
goto out;
|
||||
|
||||
normal = alloc_tty_driver(drv->nr);
|
||||
normal = alloc_tty_driver(drv->nr);
|
||||
if (!normal)
|
||||
goto out;
|
||||
goto out_kfree;
|
||||
|
||||
drv->tty_driver = normal;
|
||||
|
||||
|
@ -2393,12 +2390,14 @@ int uart_register_driver(struct uart_driver *drv)
|
|||
}
|
||||
|
||||
retval = tty_register_driver(normal);
|
||||
out:
|
||||
if (retval < 0) {
|
||||
put_tty_driver(normal);
|
||||
kfree(drv->state);
|
||||
}
|
||||
return retval;
|
||||
if (retval >= 0)
|
||||
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];
|
||||
int result;
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
if (port->port.count)
|
||||
mutex_lock(&port->port.mutex);
|
||||
/* 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);
|
||||
else
|
||||
result = 0;
|
||||
mutex_unlock(&port->mutex);
|
||||
mutex_unlock(&port->port.mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -247,96 +247,66 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
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;
|
||||
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);
|
||||
if (serial->disconnected)
|
||||
retval = -ENODEV;
|
||||
else
|
||||
retval = port->serial->type->open(tty, port);
|
||||
mutex_unlock(&serial->disc_mutex);
|
||||
mutex_unlock(&port->mutex);
|
||||
if (retval)
|
||||
return retval;
|
||||
set_bit(ASYNCB_INITIALIZED, &port->port.flags);
|
||||
}
|
||||
|
||||
/* Now do the correct tty layer semantics */
|
||||
retval = tty_port_block_til_ready(&port->port, tty, filp);
|
||||
mutex_lock(&serial->disc_mutex);
|
||||
if (serial->disconnected)
|
||||
retval = -ENODEV;
|
||||
else
|
||||
retval = port->serial->type->open(tty, port);
|
||||
mutex_unlock(&serial->disc_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int serial_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
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
|
||||
* @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 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;
|
||||
|
||||
/*
|
||||
* The console is magical. Do not hang up the console hardware
|
||||
* or there will be tears.
|
||||
*/
|
||||
if (port->console)
|
||||
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)
|
||||
drv->close(port);
|
||||
mutex_unlock(&port->mutex);
|
||||
}
|
||||
|
||||
static void serial_hangup(struct tty_struct *tty)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
serial_down(port);
|
||||
tty_port_hangup(&port->port);
|
||||
}
|
||||
|
||||
static void serial_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
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);
|
||||
tty_port_close(&port->port, tty, filp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -725,6 +695,8 @@ static void serial_dtr_rts(struct tty_port *port, int on)
|
|||
static const struct tty_port_operations serial_port_ops = {
|
||||
.carrier_raised = serial_carrier_raised,
|
||||
.dtr_rts = serial_dtr_rts,
|
||||
.activate = serial_activate,
|
||||
.shutdown = serial_down,
|
||||
};
|
||||
|
||||
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->serial = serial;
|
||||
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);
|
||||
serial->port[i] = port;
|
||||
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 dentry *dentry;
|
||||
struct tty_struct *tty;
|
||||
|
||||
BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
|
||||
|
||||
/* Ensure dentry has not been deleted by devpts_pty_kill() */
|
||||
dentry = d_find_alias(pts_inode);
|
||||
if (!dentry)
|
||||
return NULL;
|
||||
|
||||
tty = NULL;
|
||||
if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
|
||||
return (struct tty_struct *)pts_inode->i_private;
|
||||
return NULL;
|
||||
tty = (struct tty_struct *)pts_inode->i_private;
|
||||
|
||||
dput(dentry);
|
||||
|
||||
return tty;
|
||||
}
|
||||
|
||||
void devpts_pty_kill(struct tty_struct *tty)
|
||||
|
|
|
@ -214,7 +214,6 @@ unifdef-y += futex.h
|
|||
unifdef-y += fs.h
|
||||
unifdef-y += gameport.h
|
||||
unifdef-y += generic_serial.h
|
||||
unifdef-y += hayesesp.h
|
||||
unifdef-y += hdlcdrv.h
|
||||
unifdef-y += hdlc.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 BOARD_ACTIVE 0x0002
|
||||
#define BOARD_INIT 0x0004
|
||||
|
||||
/* isi_port status bitmap */
|
||||
|
||||
|
|
|
@ -190,9 +190,17 @@ struct tty_port_operations {
|
|||
/* Control the DTR line */
|
||||
void (*dtr_rts)(struct tty_port *port, int raise);
|
||||
/* 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 (*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 {
|
||||
|
@ -206,12 +214,14 @@ struct tty_port {
|
|||
wait_queue_head_t delta_msr_wait; /* Modem status change */
|
||||
unsigned long flags; /* TTY flags ASY_*/
|
||||
struct mutex mutex; /* Locking */
|
||||
struct mutex buf_mutex; /* Buffer alloc lock */
|
||||
unsigned char *xmit_buf; /* Optional buffer */
|
||||
unsigned int close_delay; /* Close port delay */
|
||||
unsigned int closing_wait; /* Delay for output */
|
||||
int drain_delay; /* Set to zero if no pure time
|
||||
based drain is needed else
|
||||
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);
|
||||
extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
||||
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 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 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_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 void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
|
||||
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(struct tty_port *port,
|
||||
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)
|
||||
{
|
||||
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.
|
||||
* @port: pointer to the corresponding tty_port for this port.
|
||||
* @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).
|
||||
* @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.
|
||||
|
@ -77,7 +75,6 @@ struct usb_serial_port {
|
|||
struct usb_serial *serial;
|
||||
struct tty_port port;
|
||||
spinlock_t lock;
|
||||
struct mutex mutex;
|
||||
unsigned char number;
|
||||
|
||||
unsigned char *interrupt_in_buffer;
|
||||
|
|
|
@ -971,7 +971,7 @@ NORET_TYPE void do_exit(long code)
|
|||
exit_thread();
|
||||
cgroup_exit(tsk, 1);
|
||||
|
||||
if (group_dead && tsk->signal->leader)
|
||||
if (group_dead)
|
||||
disassociate_ctty(1);
|
||||
|
||||
module_put(task_thread_info(tsk)->exec_domain->module);
|
||||
|
|
Loading…
Reference in a new issue