Commit 0f4974c4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
  ...
parents 3126c136 36ba782e
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,
};
......
/*
* esp.c - driver for Hayes ESP serial cards
*
* --- Notices from serial.c, upon which this driver is based ---
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now
* much more extensible to support other serial cards based on the
* 16450/16550A UART's. Added support for the AST FourPort and the
* Accent Async board.
*
* set_serial_info fixed to set the flags, custom divisor, and uart
* type fields. Fix suggested by Michael K. Johnson 12/12/92.
*
* 11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk>
*
* 03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk>
*
* rs_set_termios fixed to look also for changes of the input
* flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
* Bernd Anhäupl 05/17/96.
*
* --- End of notices from serial.c ---
*
* Support for the ESP serial card by Andrew J. Robinson
* <arobinso@nyx.net> (Card detection routine taken from a patch
* by Dennis J. Boylan). Patches to allow use with 2.1.x contributed
* by Chris Faylor.
*
* Most recent changes: (Andrew J. Robinson)
* Support for PIO mode. This allows the driver to work properly with
* multiport cards.
*
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> -
* several cleanups, use module_init/module_exit, etc
*
* This module exports the following rs232 io functions:
*
* int espserial_init(void);
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/serial_reg.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <asm/system.h>
#include <linux/io.h>
#include <asm/dma.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/hayesesp.h>
#define NR_PORTS 64 /* maximum number of ports */
#define NR_PRIMARY 8 /* maximum number of primary ports */
#define REGION_SIZE 8 /* size of io region to request */
/* The following variables can be set by giving module options */
static int irq[NR_PRIMARY]; /* IRQ for each base port */
static unsigned int divisor[NR_PRIMARY]; /* custom divisor for each port */
static unsigned int dma = ESP_DMA_CHANNEL; /* DMA channel */
static unsigned int rx_trigger = ESP_RX_TRIGGER;
static unsigned int tx_trigger = ESP_TX_TRIGGER;
static unsigned int flow_off = ESP_FLOW_OFF;
static unsigned int flow_on = ESP_FLOW_ON;
static unsigned int rx_timeout = ESP_RX_TMOUT;
static unsigned int pio_threshold = ESP_PIO_THRESHOLD;
MODULE_LICENSE("GPL");
module_param_array(irq, int, NULL, 0);
module_param_array(divisor, uint, NULL, 0);
module_param(dma, uint, 0);
module_param(rx_trigger, uint, 0);
module_param(tx_trigger, uint, 0);
module_param(flow_off, uint, 0);
module_param(flow_on, uint, 0);
module_param(rx_timeout, uint, 0);
module_param(pio_threshold, uint, 0);
/* END */
static char *dma_buffer;
static int dma_bytes;
static struct esp_pio_buffer *free_pio_buf;
#define DMA_BUFFER_SZ 1024
#define WAKEUP_CHARS 1024
static char serial_name[] __initdata = "ESP serial driver";
static char serial_version[] __initdata = "2.2";
static struct tty_driver *esp_driver;
/*
* Serial driver configuration section. Here are the various options:
*
* SERIAL_PARANOIA_CHECK
* Check the magic number for the esp_structure where
* ever possible.
*/
#undef SERIAL_PARANOIA_CHECK
#define SERIAL_DO_RESTART
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
tty->name, info->port.flags, \
serial_driver.refcount, \
info->port.count, tty->count, s)
#else
#define DBG_CNT(s)
#endif
static struct esp_struct *ports;
static void change_speed(struct esp_struct *info);
static void rs_wait_until_sent(struct tty_struct *, int);
/*
* The ESP card has a clock rate of 14.7456 MHz (that is, 2**ESPC_SCALE
* times the normal 1.8432 Mhz clock of most serial boards).
*/
#define BASE_BAUD ((1843200 / 16) * (1 << ESPC_SCALE))
/* Standard COM flags (except for COM4, because of the 8514 problem) */
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
static inline int serial_paranoia_check(struct esp_struct *info,
char *name, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
static const char badmagic[] = KERN_WARNING
"Warning: bad magic number for serial struct (%s) in %s\n";
static const char badinfo[] = KERN_WARNING
"Warning: null esp_struct for (%s) in %s\n";
if (!info) {
printk(badinfo, name, routine);
return 1;
}
if (info->magic != ESP_MAGIC) {
printk(badmagic, name, routine);
return 1;
}
#endif
return 0;
}
static inline unsigned int serial_in(struct esp_struct *info, int offset)
{
return inb(info->io_port + offset);
}
static inline void serial_out(struct esp_struct *info, int offset,
unsigned char value)
{
outb(value, info->io_port+offset);
}
/*
* ------------------------------------------------------------
* rs_stop() and rs_start()
*
* This routines are called before setting or resetting tty->stopped.
* They enable or disable transmitter interrupts, as necessary.
* ------------------------------------------------------------
*/
static void rs_stop(struct tty_struct *tty)
{
struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_stop"))
return;
spin_lock_irqsave(&info->lock, flags);
if (info->IER & UART_IER_THRI) {
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
}
spin_unlock_irqrestore(&info->lock, flags);
}
static void rs_start(struct tty_struct *tty)
{
struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_start"))
return;
spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
}
spin_unlock_irqrestore(&info->lock, flags);
}
/*
* ----------------------------------------------------------------------
*
* Here starts the interrupt handling routines. All of the following
* subroutines are declared as inline and are folded into
* rs_interrupt(). They were separated out for readability's sake.
*
* Note: rs_interrupt() is a "fast" interrupt, which means that it
* runs with interrupts turned off. People who may want to modify
* rs_interrupt() should try to keep the interrupt handler as fast as
* possible. After you are done making modifications, it is not a bad
* idea to do:
*
* gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
*
* and look at the resulting assemble code in serial.s.
*
* - Ted Ts'o (tytso@mit.edu), 7-Mar-93
* -----------------------------------------------------------------------
*/
static DEFINE_SPINLOCK(pio_lock);
static inline struct esp_pio_buffer *get_pio_buffer(void)
{
struct esp_pio_buffer *buf;
unsigned long flags;
spin_lock_irqsave(&pio_lock, flags);
if (free_pio_buf) {
buf = free_pio_buf;
free_pio_buf = buf->next;
} else {
buf = kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC);
}
spin_unlock_irqrestore(&pio_lock, flags);
return buf;
}
static inline void release_pio_buffer(struct esp_pio_buffer *buf)
{
unsigned long flags;
spin_lock_irqsave(&pio_lock, flags);
buf->next = free_pio_buf;
free_pio_buf = buf;
spin_unlock_irqrestore(&pio_lock, flags);
}
static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
{
struct tty_struct *tty = info->port.tty;
int i;
struct esp_pio_buffer *pio_buf;
struct esp_pio_buffer *err_buf;
unsigned char status_mask;
pio_buf = get_pio_buffer();
if (!pio_buf)
return;
err_buf = get_pio_buffer();
if (!err_buf) {
release_pio_buffer(pio_buf);
return;
}
status_mask = (info->read_status_mask >> 2) & 0x07;
for (i = 0; i < num_bytes - 1; i += 2) {
*((unsigned short *)(pio_buf->data + i)) =
inw(info->io_port + UART_ESI_RX);
err_buf->data[i] = serial_in(info, UART_ESI_RWS);
err_buf->data[i + 1] = (err_buf->data[i] >> 3) & status_mask;
err_buf->data[i] &= status_mask;
}
if (num_bytes & 0x0001) {
pio_buf->data[num_bytes - 1] = serial_in(info, UART_ESI_RX);
err_buf->data[num_bytes - 1] =
(serial_in(info, UART_ESI_RWS) >> 3) & status_mask;
}
/* make sure everything is still ok since interrupts were enabled */
tty = info->port.tty;
if (!tty) {
release_pio_buffer(pio_buf);
release_pio_buffer(err_buf);
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
return;
}
status_mask = (info->ignore_status_mask >> 2) & 0x07;
for (i = 0; i < num_bytes; i++) {
if (!(err_buf->data[i] & status_mask)) {
int flag = 0;
if (err_buf->data[i] & 0x04) {
flag = TTY_BREAK;
if (info->port.flags & ASYNC_SAK)
do_SAK(tty);
} else if (err_buf->data[i] & 0x02)
flag = TTY_FRAME;
else if (err_buf->data[i] & 0x01)
flag = TTY_PARITY;
tty_insert_flip_char(tty, pio_buf->data[i], flag);
}
}
tty_schedule_flip(tty);
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
release_pio_buffer(pio_buf);
release_pio_buffer(err_buf);
}
static void program_isa_dma(int dma, int dir, unsigned long addr, int len)
{
unsigned long flags;
flags = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma, dir);
set_dma_addr(dma, addr);
set_dma_count(dma, len);
enable_dma(dma);
release_dma_lock(flags);
}
static void receive_chars_dma(struct esp_struct *info, int num_bytes)
{
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
dma_bytes = num_bytes;
info->stat_flags |= ESP_STAT_DMA_RX;
program_isa_dma(dma, DMA_MODE_READ, isa_virt_to_bus(dma_buffer),
dma_bytes);
serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
}
static inline void receive_chars_dma_done(struct esp_struct *info,
int status)
{
struct tty_struct *tty = info->port.tty;
int num_bytes;
unsigned long flags;
flags = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
info->stat_flags &= ~ESP_STAT_DMA_RX;
num_bytes = dma_bytes - get_dma_residue(dma);
release_dma_lock(flags);
info->icount.rx += num_bytes;
if (num_bytes > 0) {
tty_insert_flip_string(tty, dma_buffer, num_bytes - 1);
status &= (0x1c & info->read_status_mask);
/* Is the status significant or do we throw the last byte ? */
if