Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into sh-latest

This commit is contained in:
Paul Mundt 2011-03-17 16:44:08 +09:00
commit 1d2a1959fe
4568 changed files with 286714 additions and 174809 deletions

321
drivers/tty/Kconfig Normal file
View file

@ -0,0 +1,321 @@
config VT
bool "Virtual terminal" if EXPERT
depends on !S390
select INPUT
default y
---help---
If you say Y here, you will get support for terminal devices with
display and keyboard devices. These are called "virtual" because you
can run several virtual terminals (also called virtual consoles) on
one physical terminal. This is rather useful, for example one
virtual terminal can collect system messages and warnings, another
one can be used for a text-mode user session, and a third could run
an X session, all in parallel. Switching between virtual terminals
is done with certain key combinations, usually Alt-<function key>.
The setterm command ("man setterm") can be used to change the
properties (such as colors or beeping) of a virtual terminal. The
man page console_codes(4) ("man console_codes") contains the special
character sequences that can be used to change those properties
directly. The fonts used on virtual terminals can be changed with
the setfont ("man setfont") command and the key bindings are defined
with the loadkeys ("man loadkeys") command.
You need at least one virtual terminal device in order to make use
of your keyboard and monitor. Therefore, only people configuring an
embedded system would want to say N here in order to save some
memory; the only way to log into such a system is then via a serial
or network connection.
If unsure, say Y, or else you won't be able to do much with your new
shiny Linux system :-)
config CONSOLE_TRANSLATIONS
depends on VT
default y
bool "Enable character translations in console" if EXPERT
---help---
This enables support for font mapping and Unicode translation
on virtual consoles.
config VT_CONSOLE
bool "Support for console on virtual terminal" if EXPERT
depends on VT
default y
---help---
The system console is the device which receives all kernel messages
and warnings and which allows logins in single user mode. If you
answer Y here, a virtual terminal (the device used to interact with
a physical terminal) can be used as system console. This is the most
common mode of operations, so you should say Y here unless you want
the kernel messages be output only to a serial port (in which case
you should say Y to "Console on serial port", below).
If you do say Y here, by default the currently visible virtual
terminal (/dev/tty0) will be used as system console. You can change
that with a kernel command line option such as "console=tty3" which
would use the third virtual terminal as system console. (Try "man
bootparam" or see the documentation of your boot loader (lilo or
loadlin) about how to pass options to the kernel at boot time.)
If unsure, say Y.
config HW_CONSOLE
bool
depends on VT && !S390 && !UML
default y
config VT_HW_CONSOLE_BINDING
bool "Support for binding and unbinding console drivers"
depends on HW_CONSOLE
default n
---help---
The virtual terminal is the device that interacts with the physical
terminal through console drivers. On these systems, at least one
console driver is loaded. In other configurations, additional console
drivers may be enabled, such as the framebuffer console. If more than
1 console driver is enabled, setting this to 'y' will allow you to
select the console driver that will serve as the backend for the
virtual terminals.
See <file:Documentation/console/console.txt> for more
information. For framebuffer console users, please refer to
<file:Documentation/fb/fbcon.txt>.
config UNIX98_PTYS
bool "Unix98 PTY support" if EXPERT
default y
---help---
A pseudo terminal (PTY) is a software device consisting of two
halves: a master and a slave. The slave device behaves identical to
a physical terminal; the master device is used by a process to
read data from and write data to the slave, thereby emulating a
terminal. Typical programs for the master side are telnet servers
and xterms.
Linux has traditionally used the BSD-like names /dev/ptyxx for
masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
has a number of problems. The GNU C library glibc 2.1 and later,
however, supports the Unix98 naming standard: in order to acquire a
pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
terminal is then made available to the process and the pseudo
terminal slave can be accessed as /dev/pts/<number>. What was
traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
All modern Linux systems use the Unix98 ptys. Say Y unless
you're on an embedded system and want to conserve memory.
config DEVPTS_MULTIPLE_INSTANCES
bool "Support multiple instances of devpts"
depends on UNIX98_PTYS
default n
---help---
Enable support for multiple instances of devpts filesystem.
If you want to have isolated PTY namespaces (eg: in containers),
say Y here. Otherwise, say N. If enabled, each mount of devpts
filesystem with the '-o newinstance' option will create an
independent PTY namespace.
config LEGACY_PTYS
bool "Legacy (BSD) PTY support"
default y
---help---
A pseudo terminal (PTY) is a software device consisting of two
halves: a master and a slave. The slave device behaves identical to
a physical terminal; the master device is used by a process to
read data from and write data to the slave, thereby emulating a
terminal. Typical programs for the master side are telnet servers
and xterms.
Linux has traditionally used the BSD-like names /dev/ptyxx
for masters and /dev/ttyxx for slaves of pseudo
terminals. This scheme has a number of problems, including
security. This option enables these legacy devices; on most
systems, it is safe to say N.
config LEGACY_PTY_COUNT
int "Maximum number of legacy PTY in use"
depends on LEGACY_PTYS
range 0 256
default "256"
---help---
The maximum number of legacy PTYs that can be used at any one time.
The default is 256, and should be more than enough. Embedded
systems may want to reduce this to save memory.
When not in use, each legacy PTY occupies 12 bytes on 32-bit
architectures and 24 bytes on 64-bit architectures.
config BFIN_JTAG_COMM
tristate "Blackfin JTAG Communication"
depends on BLACKFIN
help
Add support for emulating a TTY device over the Blackfin JTAG.
To compile this driver as a module, choose M here: the
module will be called bfin_jtag_comm.
config BFIN_JTAG_COMM_CONSOLE
bool "Console on Blackfin JTAG"
depends on BFIN_JTAG_COMM=y
config SERIAL_NONSTANDARD
bool "Non-standard serial port support"
depends on HAS_IOMEM
---help---
Say Y here if you have any non-standard serial boards -- boards
which aren't supported using the standard "dumb" serial driver.
This includes intelligent serial boards such as Cyclades,
Digiboards, etc. These are usually used for systems that need many
serial ports because they serve many terminals or dial-in
connections.
Note that the answer to this question won't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about non-standard serial boards.
Most people can say N here.
config ROCKETPORT
tristate "Comtrol RocketPort support"
depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
help
This driver supports Comtrol RocketPort and RocketModem PCI boards.
These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or
modems. For information about the RocketPort/RocketModem boards
and this driver read <file:Documentation/serial/rocket.txt>.
To compile this driver as a module, choose M here: the
module will be called rocket.
If you want to compile this driver into the kernel, say Y here. If
you don't have a Comtrol RocketPort/RocketModem card installed, say N.
config CYCLADES
tristate "Cyclades async mux support"
depends on SERIAL_NONSTANDARD && (PCI || ISA)
select FW_LOADER
---help---
This driver supports Cyclades Z and Y multiserial boards.
You would need something like this to connect more than two modems to
your Linux box, for instance in order to become a dial-in server.
For information about the Cyclades-Z card, read
<file:Documentation/serial/README.cycladesZ>.
To compile this driver as a module, choose M here: the
module will be called cyclades.
If you haven't heard about it, it's safe to say N.
config CYZ_INTR
bool "Cyclades-Z interrupt mode operation (EXPERIMENTAL)"
depends on EXPERIMENTAL && CYCLADES
help
The Cyclades-Z family of multiport cards allows 2 (two) driver op
modes: polling and interrupt. In polling mode, the driver will check
the status of the Cyclades-Z ports every certain amount of time
(which is called polling cycle and is configurable). In interrupt
mode, it will use an interrupt line (IRQ) in order to check the
status of the Cyclades-Z ports. The default op mode is polling. If
unsure, say N.
config MOXA_INTELLIO
tristate "Moxa Intellio support"
depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
select FW_LOADER
help
Say Y here if you have a Moxa Intellio multiport serial card.
To compile this driver as a module, choose M here: the
module will be called moxa.
config MOXA_SMARTIO
tristate "Moxa SmartIO support v. 2.0"
depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
help
Say Y here if you have a Moxa SmartIO multiport serial card and/or
want to help develop a new version of this driver.
This is upgraded (1.9.1) driver from original Moxa drivers with
changes finally resulting in PCI probing.
This driver can also be built as a module. The module will be called
mxser. If you want to do that, say M here.
config SYNCLINK
tristate "Microgate SyncLink card support"
depends on SERIAL_NONSTANDARD && PCI && ISA_DMA_API
help
Provides support for the SyncLink ISA and PCI multiprotocol serial
adapters. These adapters support asynchronous and HDLC bit
synchronous communication up to 10Mbps (PCI adapter).
This driver can only be built as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called synclink. If you want to do that, say M
here.
config SYNCLINKMP
tristate "SyncLink Multiport support"
depends on SERIAL_NONSTANDARD && PCI
help
Enable support for the SyncLink Multiport (2 or 4 ports)
serial adapter, running asynchronous and HDLC communications up
to 2.048Mbps. Each ports is independently selectable for
RS-232, V.35, RS-449, RS-530, and X.21
This driver may be built as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called synclinkmp. If you want to do that, say M
here.
config SYNCLINK_GT
tristate "SyncLink GT/AC support"
depends on SERIAL_NONSTANDARD && PCI
help
Support for SyncLink GT and SyncLink AC families of
synchronous and asynchronous serial adapters
manufactured by Microgate Systems, Ltd. (www.microgate.com)
config NOZOMI
tristate "HSDPA Broadband Wireless Data Card - Globe Trotter"
depends on PCI && EXPERIMENTAL
help
If you have a HSDPA driver Broadband Wireless Data Card -
Globe Trotter PCMCIA card, say Y here.
To compile this driver as a module, choose M here, the module
will be called nozomi.
config ISI
tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
depends on SERIAL_NONSTANDARD && PCI
select FW_LOADER
help
This is a driver for the Multi-Tech cards which provide several
serial ports. The driver is experimental and can currently only be
built as a module. The module will be called isicom.
If you want to do that, choose M here.
config N_HDLC
tristate "HDLC line discipline support"
depends on SERIAL_NONSTANDARD
help
Allows synchronous HDLC communications with tty device drivers that
support synchronous HDLC such as the Microgate SyncLink adapter.
This driver can be built as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called n_hdlc. If you want to do that, say M
here.
config N_GSM
tristate "GSM MUX line discipline support (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on NET
help
This line discipline provides support for the GSM MUX protocol and
presents the mux as a set of 61 individual tty devices.

View file

@ -11,3 +11,18 @@ obj-$(CONFIG_R3964) += n_r3964.o
obj-y += vt/
obj-$(CONFIG_HVC_DRIVER) += hvc/
obj-y += serial/
# tty drivers
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o
obj-$(CONFIG_CYCLADES) += cyclades.o
obj-$(CONFIG_ISI) += isicom.o
obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
obj-$(CONFIG_NOZOMI) += nozomi.o
obj-$(CONFIG_ROCKETPORT) += rocket.o
obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
obj-$(CONFIG_SYNCLINK) += synclink.o
obj-y += ipwireless/

2178
drivers/tty/amiserial.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,366 @@
/*
* TTY over Blackfin JTAG Communication
*
* Copyright 2008-2009 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#define DRV_NAME "bfin-jtag-comm"
#define DEV_NAME "ttyBFJC"
#define pr_fmt(fmt) DRV_NAME ": " fmt
#include <linux/circ_buf.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <asm/atomic.h>
#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); })
/* See the Debug/Emulation chapter in the HRM */
#define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */
#define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */
#define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */
#define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */
static inline uint32_t bfin_write_emudat(uint32_t emudat)
{
__asm__ __volatile__("emudat = %0;" : : "d"(emudat));
return emudat;
}
static inline uint32_t bfin_read_emudat(void)
{
uint32_t emudat;
__asm__ __volatile__("%0 = emudat;" : "=d"(emudat));
return emudat;
}
static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
{
return bfin_write_emudat((a << 0) | (b << 8) | (c << 16) | (d << 24));
}
#define CIRC_SIZE 2048 /* see comment in tty_io.c:do_tty_write() */
#define CIRC_MASK (CIRC_SIZE - 1)
#define circ_empty(circ) ((circ)->head == (circ)->tail)
#define circ_free(circ) CIRC_SPACE((circ)->head, (circ)->tail, CIRC_SIZE)
#define circ_cnt(circ) CIRC_CNT((circ)->head, (circ)->tail, CIRC_SIZE)
#define circ_byte(circ, idx) ((circ)->buf[(idx) & CIRC_MASK])
static struct tty_driver *bfin_jc_driver;
static struct task_struct *bfin_jc_kthread;
static struct tty_struct * volatile bfin_jc_tty;
static unsigned long bfin_jc_count;
static DEFINE_MUTEX(bfin_jc_tty_mutex);
static volatile struct circ_buf bfin_jc_write_buf;
static int
bfin_jc_emudat_manager(void *arg)
{
uint32_t inbound_len = 0, outbound_len = 0;
while (!kthread_should_stop()) {
/* no one left to give data to, so sleep */
if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
pr_debug("waiting for readers\n");
__set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
__set_current_state(TASK_RUNNING);
}
/* no data available, so just chill */
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
if (inbound_len)
schedule();
else
schedule_timeout_interruptible(HZ);
continue;
}
/* if incoming data is ready, eat it */
if (bfin_read_DBGSTAT() & EMUDIF) {
struct tty_struct *tty;
mutex_lock(&bfin_jc_tty_mutex);
tty = (struct tty_struct *)bfin_jc_tty;
if (tty != NULL) {
uint32_t emudat = bfin_read_emudat();
if (inbound_len == 0) {
pr_debug("incoming length: 0x%08x\n", emudat);
inbound_len = emudat;
} else {
size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
inbound_len -= num_chars;
tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars);
tty_flip_buffer_push(tty);
}
}
mutex_unlock(&bfin_jc_tty_mutex);
}
/* if outgoing data is ready, post it */
if (!(bfin_read_DBGSTAT() & EMUDOF) && !circ_empty(&bfin_jc_write_buf)) {
if (outbound_len == 0) {
outbound_len = circ_cnt(&bfin_jc_write_buf);
bfin_write_emudat(outbound_len);
pr_debug("outgoing length: 0x%08x\n", outbound_len);
} else {
struct tty_struct *tty;
int tail = bfin_jc_write_buf.tail;
size_t ate = (4 <= outbound_len ? 4 : outbound_len);
uint32_t emudat =
bfin_write_emudat_chars(
circ_byte(&bfin_jc_write_buf, tail + 0),
circ_byte(&bfin_jc_write_buf, tail + 1),
circ_byte(&bfin_jc_write_buf, tail + 2),
circ_byte(&bfin_jc_write_buf, tail + 3)
);
bfin_jc_write_buf.tail += ate;
outbound_len -= ate;
mutex_lock(&bfin_jc_tty_mutex);
tty = (struct tty_struct *)bfin_jc_tty;
if (tty)
tty_wakeup(tty);
mutex_unlock(&bfin_jc_tty_mutex);
pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
}
}
}
__set_current_state(TASK_RUNNING);
return 0;
}
static int
bfin_jc_open(struct tty_struct *tty, struct file *filp)
{
mutex_lock(&bfin_jc_tty_mutex);
pr_debug("open %lu\n", bfin_jc_count);
++bfin_jc_count;
bfin_jc_tty = tty;
wake_up_process(bfin_jc_kthread);
mutex_unlock(&bfin_jc_tty_mutex);
return 0;
}
static void
bfin_jc_close(struct tty_struct *tty, struct file *filp)
{
mutex_lock(&bfin_jc_tty_mutex);
pr_debug("close %lu\n", bfin_jc_count);
if (--bfin_jc_count == 0)
bfin_jc_tty = NULL;
wake_up_process(bfin_jc_kthread);
mutex_unlock(&bfin_jc_tty_mutex);
}
/* XXX: we dont handle the put_char() case where we must handle count = 1 */
static int
bfin_jc_circ_write(const unsigned char *buf, int count)
{
int i;
count = min(count, circ_free(&bfin_jc_write_buf));
pr_debug("going to write chunk of %i bytes\n", count);
for (i = 0; i < count; ++i)
circ_byte(&bfin_jc_write_buf, bfin_jc_write_buf.head + i) = buf[i];
bfin_jc_write_buf.head += i;
return i;
}
#ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE
# define console_lock()
# define console_unlock()
#endif
static int
bfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
int i;
console_lock();
i = bfin_jc_circ_write(buf, count);
console_unlock();
wake_up_process(bfin_jc_kthread);
return i;
}
static void
bfin_jc_flush_chars(struct tty_struct *tty)
{
wake_up_process(bfin_jc_kthread);
}
static int
bfin_jc_write_room(struct tty_struct *tty)
{
return circ_free(&bfin_jc_write_buf);
}
static int
bfin_jc_chars_in_buffer(struct tty_struct *tty)
{
return circ_cnt(&bfin_jc_write_buf);
}
static void
bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
{
unsigned long expire = jiffies + timeout;
while (!circ_empty(&bfin_jc_write_buf)) {
if (signal_pending(current))
break;
if (time_after(jiffies, expire))
break;
}
}
static const struct tty_operations bfin_jc_ops = {
.open = bfin_jc_open,
.close = bfin_jc_close,
.write = bfin_jc_write,
/*.put_char = bfin_jc_put_char,*/
.flush_chars = bfin_jc_flush_chars,
.write_room = bfin_jc_write_room,
.chars_in_buffer = bfin_jc_chars_in_buffer,
.wait_until_sent = bfin_jc_wait_until_sent,
};
static int __init bfin_jc_init(void)
{
int ret;
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
if (IS_ERR(bfin_jc_kthread))
return PTR_ERR(bfin_jc_kthread);
ret = -ENOMEM;
bfin_jc_write_buf.head = bfin_jc_write_buf.tail = 0;
bfin_jc_write_buf.buf = kmalloc(CIRC_SIZE, GFP_KERNEL);
if (!bfin_jc_write_buf.buf)
goto err;
bfin_jc_driver = alloc_tty_driver(1);
if (!bfin_jc_driver)
goto err;
bfin_jc_driver->owner = THIS_MODULE;
bfin_jc_driver->driver_name = DRV_NAME;
bfin_jc_driver->name = DEV_NAME;
bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL;
bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL;
bfin_jc_driver->init_termios = tty_std_termios;
tty_set_operations(bfin_jc_driver, &bfin_jc_ops);
ret = tty_register_driver(bfin_jc_driver);
if (ret)
goto err;
pr_init(KERN_INFO DRV_NAME ": initialized\n");
return 0;
err:
put_tty_driver(bfin_jc_driver);
kfree(bfin_jc_write_buf.buf);
kthread_stop(bfin_jc_kthread);
return ret;
}
module_init(bfin_jc_init);
static void __exit bfin_jc_exit(void)
{
kthread_stop(bfin_jc_kthread);
kfree(bfin_jc_write_buf.buf);
tty_unregister_driver(bfin_jc_driver);
put_tty_driver(bfin_jc_driver);
}
module_exit(bfin_jc_exit);
#if defined(CONFIG_BFIN_JTAG_COMM_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
static void
bfin_jc_straight_buffer_write(const char *buf, unsigned count)
{
unsigned ate = 0;
while (bfin_read_DBGSTAT() & EMUDOF)
continue;
bfin_write_emudat(count);
while (ate < count) {
while (bfin_read_DBGSTAT() & EMUDOF)
continue;
bfin_write_emudat_chars(buf[ate], buf[ate+1], buf[ate+2], buf[ate+3]);
ate += 4;
}
}
#endif
#ifdef CONFIG_BFIN_JTAG_COMM_CONSOLE
static void
bfin_jc_console_write(struct console *co, const char *buf, unsigned count)
{
if (bfin_jc_kthread == NULL)
bfin_jc_straight_buffer_write(buf, count);
else
bfin_jc_circ_write(buf, count);
}
static struct tty_driver *
bfin_jc_console_device(struct console *co, int *index)
{
*index = co->index;
return bfin_jc_driver;
}
static struct console bfin_jc_console = {
.name = DEV_NAME,
.write = bfin_jc_console_write,
.device = bfin_jc_console_device,
.flags = CON_ANYTIME | CON_PRINTBUFFER,
.index = -1,
};
static int __init bfin_jc_console_init(void)
{
register_console(&bfin_jc_console);
return 0;
}
console_initcall(bfin_jc_console_init);
#endif
#ifdef CONFIG_EARLY_PRINTK
static void __init
bfin_jc_early_write(struct console *co, const char *buf, unsigned int count)
{
bfin_jc_straight_buffer_write(buf, count);
}
static struct __initdata console bfin_jc_early_console = {
.name = "early_BFJC",
.write = bfin_jc_early_write,
.flags = CON_ANYTIME | CON_PRINTBUFFER,
.index = -1,
};
struct console * __init
bfin_jc_early_init(unsigned int port, unsigned int cflag)
{
return &bfin_jc_early_console;
}
#endif
MODULE_AUTHOR("Mike Frysinger <[email protected]>");
MODULE_DESCRIPTION("TTY over Blackfin JTAG Communication");
MODULE_LICENSE("GPL");

4200
drivers/tty/cyclades.c Normal file

File diff suppressed because it is too large Load diff

105
drivers/tty/hvc/Kconfig Normal file
View file

@ -0,0 +1,105 @@
config HVC_DRIVER
bool
help
Generic "hypervisor virtual console" infrastructure for various
hypervisors (pSeries, iSeries, Xen, lguest).
It will automatically be selected if one of the back-end console drivers
is selected.
config HVC_IRQ
bool
config HVC_CONSOLE
bool "pSeries Hypervisor Virtual Console support"
depends on PPC_PSERIES
select HVC_DRIVER
select HVC_IRQ
help
pSeries machines when partitioned support a hypervisor virtual
console. This driver allows each pSeries partition to have a console
which is accessed via the HMC.
config HVC_ISERIES
bool "iSeries Hypervisor Virtual Console support"
depends on PPC_ISERIES
default y
select HVC_DRIVER
select HVC_IRQ
select VIOPATH
help
iSeries machines support a hypervisor virtual console.
config HVC_RTAS
bool "IBM RTAS Console support"
depends on PPC_RTAS
select HVC_DRIVER
help
IBM Console device driver which makes use of RTAS
config HVC_BEAT
bool "Toshiba's Beat Hypervisor Console support"
depends on PPC_CELLEB
select HVC_DRIVER
help
Toshiba's Cell Reference Set Beat Console device driver
config HVC_IUCV
bool "z/VM IUCV Hypervisor console support (VM only)"
depends on S390
select HVC_DRIVER
select IUCV
default y
help
This driver provides a Hypervisor console (HVC) back-end to access
a Linux (console) terminal via a z/VM IUCV communication path.
config HVC_XEN
bool "Xen Hypervisor Console support"
depends on XEN
select HVC_DRIVER
select HVC_IRQ
default y
help
Xen virtual console device driver
config HVC_UDBG
bool "udbg based fake hypervisor console"
depends on PPC && EXPERIMENTAL
select HVC_DRIVER
default n
config HVC_DCC
bool "ARM JTAG DCC console"
depends on ARM
select HVC_DRIVER
help
This console uses the JTAG DCC on ARM to create a console under the HVC
driver. This console is used through a JTAG only on ARM. If you don't have
a JTAG then you probably don't want this option.
config HVC_BFIN_JTAG
bool "Blackfin JTAG console"
depends on BLACKFIN
select HVC_DRIVER
help
This console uses the Blackfin JTAG to create a console under the
the HVC driver. If you don't have JTAG, then you probably don't
want this option.
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
depends on PPC_PSERIES && HVC_CONSOLE
help
Partitionable IBM Power5 ppc64 machines allow hosting of
firmware virtual consoles from one Linux partition by
another Linux partition. This driver allows console data
from Linux partitions to be accessed through TTY device
interfaces in the device tree of a Linux partition running
this driver.
To compile this driver as a module, choose M here: the
module will be called hvcs. Additionally, this module
will depend on arch specific APIs exported from hvcserver.ko
which will also be compiled when this driver is built as a
module.

View file

@ -9,4 +9,5 @@ obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
obj-$(CONFIG_HVC_XEN) += hvc_xen.o
obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o
obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o
obj-$(CONFIG_HVC_BFIN_JTAG) += hvc_bfin_jtag.o
obj-$(CONFIG_HVCS) += hvcs.o

View file

@ -0,0 +1,105 @@
/*
* Console via Blackfin JTAG Communication
*
* Copyright 2008-2011 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include "hvc_console.h"
/* See the Debug/Emulation chapter in the HRM */
#define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */
#define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */
#define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */
#define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */
/* Helper functions to glue the register API to simple C operations */
static inline uint32_t bfin_write_emudat(uint32_t emudat)
{
__asm__ __volatile__("emudat = %0;" : : "d"(emudat));
return emudat;
}
static inline uint32_t bfin_read_emudat(void)
{
uint32_t emudat;
__asm__ __volatile__("%0 = emudat;" : "=d"(emudat));
return emudat;
}
/* Send data to the host */
static int hvc_bfin_put_chars(uint32_t vt, const char *buf, int count)
{
static uint32_t outbound_len;
uint32_t emudat;
int ret;
if (bfin_read_DBGSTAT() & EMUDOF)
return 0;
if (!outbound_len) {
outbound_len = count;
bfin_write_emudat(outbound_len);
return 0;
}
ret = min(outbound_len, (uint32_t)4);
memcpy(&emudat, buf, ret);
bfin_write_emudat(emudat);
outbound_len -= ret;
return ret;
}
/* Receive data from the host */
static int hvc_bfin_get_chars(uint32_t vt, char *buf, int count)
{
static uint32_t inbound_len;
uint32_t emudat;
int ret;
if (!(bfin_read_DBGSTAT() & EMUDIF))
return 0;
emudat = bfin_read_emudat();
if (!inbound_len) {
inbound_len = emudat;
return 0;
}
ret = min(inbound_len, (uint32_t)4);
memcpy(buf, &emudat, ret);
inbound_len -= ret;
return ret;
}
/* Glue the HVC layers to the Blackfin layers */
static const struct hv_ops hvc_bfin_get_put_ops = {
.get_chars = hvc_bfin_get_chars,
.put_chars = hvc_bfin_put_chars,
};
static int __init hvc_bfin_console_init(void)
{
hvc_instantiate(0, 0, &hvc_bfin_get_put_ops);
return 0;
}
console_initcall(hvc_bfin_console_init);
static int __init hvc_bfin_init(void)
{
hvc_alloc(0, 0, &hvc_bfin_get_put_ops, 128);
return 0;
}
device_initcall(hvc_bfin_init);

View file

@ -33,54 +33,29 @@
static inline u32 __dcc_getstatus(void)
{
u32 __ret;
asm("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
asm volatile("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
: "=r" (__ret) : : "cc");
return __ret;
}
#if defined(CONFIG_CPU_V7)
static inline char __dcc_getchar(void)
{
char __c;
asm("get_wait: mrc p14, 0, pc, c0, c1, 0 \n\
bne get_wait \n\
mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
: "=r" (__c) : : "cc");
return __c;
}
#else
static inline char __dcc_getchar(void)
{
char __c;
asm("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
: "=r" (__c));
return __c;
}
#endif
#if defined(CONFIG_CPU_V7)
static inline void __dcc_putchar(char c)
{
asm("put_wait: mrc p14, 0, pc, c0, c1, 0 \n\
bcs put_wait \n\
mcr p14, 0, %0, c0, c5, 0 "
: : "r" (c) : "cc");
}
#else
static inline void __dcc_putchar(char c)
{
asm("mcr p14, 0, %0, c0, c5, 0 @ write a char"
asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char"
: /* no output register */
: "r" (c));
}
#endif
static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
{
@ -90,7 +65,7 @@ static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
while (__dcc_getstatus() & DCC_STATUS_TX)
cpu_relax();
__dcc_putchar((char)(buf[i] & 0xFF));
__dcc_putchar(buf[i]);
}
return count;
@ -100,15 +75,11 @@ static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
{
int i;
for (i = 0; i < count; ++i) {
int c = -1;
for (i = 0; i < count; ++i)
if (__dcc_getstatus() & DCC_STATUS_RX)
c = __dcc_getchar();
if (c < 0)
buf[i] = __dcc_getchar();
else
break;
buf[i] = c;
}
return i;
}

View file

@ -1095,7 +1095,7 @@ static void hvsi_unthrottle(struct tty_struct *tty)
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
}
static int hvsi_tiocmget(struct tty_struct *tty, struct file *file)
static int hvsi_tiocmget(struct tty_struct *tty)
{
struct hvsi_struct *hp = tty->driver_data;
@ -1103,8 +1103,8 @@ static int hvsi_tiocmget(struct tty_struct *tty, struct file *file)
return hp->mctrl;
}
static int hvsi_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
static int hvsi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;

View file

@ -0,0 +1,10 @@
#
# drivers/char/pcmcia/ipwireless/Makefile
#
# Makefile for the IPWireless driver
#
obj-$(CONFIG_IPWIRELESS) += ipwireless.o
ipwireless-y := hardware.o main.o network.o tty.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#ifndef _IPWIRELESS_CS_HARDWARE_H_
#define _IPWIRELESS_CS_HARDWARE_H_
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#define IPW_CONTROL_LINE_CTS 0x0001
#define IPW_CONTROL_LINE_DCD 0x0002
#define IPW_CONTROL_LINE_DSR 0x0004
#define IPW_CONTROL_LINE_RI 0x0008
#define IPW_CONTROL_LINE_DTR 0x0010
#define IPW_CONTROL_LINE_RTS 0x0020
struct ipw_hardware;
struct ipw_network;
struct ipw_hardware *ipwireless_hardware_create(void);
void ipwireless_hardware_free(struct ipw_hardware *hw);
irqreturn_t ipwireless_interrupt(int irq, void *dev_id);
int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx,
int state);
int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx,
int state);
int ipwireless_send_packet(struct ipw_hardware *hw,
unsigned int channel_idx,
const unsigned char *data,
unsigned int length,
void (*packet_sent_callback) (void *cb,
unsigned int length),
void *sent_cb_data);
void ipwireless_associate_network(struct ipw_hardware *hw,
struct ipw_network *net);
void ipwireless_stop_interrupts(struct ipw_hardware *hw);
void ipwireless_init_hardware_v1(struct ipw_hardware *hw,
unsigned int base_port,
void __iomem *attr_memory,
void __iomem *common_memory,
int is_v2_card,
void (*reboot_cb) (void *data),
void *reboot_cb_data);
void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw);
void ipwireless_sleep(unsigned int tenths);
#endif

View file

@ -0,0 +1,347 @@
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#include "hardware.h"
#include "network.h"
#include "main.h"
#include "tty.h"
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/device_id.h>
#include <pcmcia/ss.h>
#include <pcmcia/ds.h>
static struct pcmcia_device_id ipw_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100),
PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, ipw_ids);
static void ipwireless_detach(struct pcmcia_device *link);
/*
* Module params
*/
/* Debug mode: more verbose, print sent/recv bytes */
int ipwireless_debug;
int ipwireless_loopback;
int ipwireless_out_queue = 10;
module_param_named(debug, ipwireless_debug, int, 0);
module_param_named(loopback, ipwireless_loopback, int, 0);
module_param_named(out_queue, ipwireless_out_queue, int, 0);
MODULE_PARM_DESC(debug, "switch on debug messages [0]");
MODULE_PARM_DESC(loopback,
"debug: enable ras_raw channel [0]");
MODULE_PARM_DESC(out_queue, "debug: set size of outgoing PPP queue [10]");
/* Executes in process context. */
static void signalled_reboot_work(struct work_struct *work_reboot)
{
struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev,
work_reboot);
struct pcmcia_device *link = ipw->link;
pcmcia_reset_card(link->socket);
}
static void signalled_reboot_callback(void *callback_data)
{
struct ipw_dev *ipw = (struct ipw_dev *) callback_data;
/* Delegate to process context. */
schedule_work(&ipw->work_reboot);
}
static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
{
struct ipw_dev *ipw = priv_data;
int ret;
p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
/* 0x40 causes it to generate level mode interrupts. */
/* 0x04 enables IREQ pin. */
p_dev->config_index |= 0x44;
p_dev->io_lines = 16;
ret = pcmcia_request_io(p_dev);
if (ret)
return ret;
if (!request_region(p_dev->resource[0]->start,
resource_size(p_dev->resource[0]),
IPWIRELESS_PCCARD_NAME)) {
ret = -EBUSY;
goto exit;
}
p_dev->resource[2]->flags |=
WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
ret = pcmcia_request_window(p_dev, p_dev->resource[2], 0);
if (ret != 0)
goto exit1;
ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr);
if (ret != 0)
goto exit1;
ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100;
ipw->common_memory = ioremap(p_dev->resource[2]->start,
resource_size(p_dev->resource[2]));
if (!request_mem_region(p_dev->resource[2]->start,
resource_size(p_dev->resource[2]),
IPWIRELESS_PCCARD_NAME)) {
ret = -EBUSY;
goto exit2;
}
p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM |
WIN_ENABLE;
p_dev->resource[3]->end = 0; /* this used to be 0x1000 */
ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0);
if (ret != 0)
goto exit3;
ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0);
if (ret != 0)
goto exit3;
ipw->attr_memory = ioremap(p_dev->resource[3]->start,
resource_size(p_dev->resource[3]));
if (!request_mem_region(p_dev->resource[3]->start,
resource_size(p_dev->resource[3]),
IPWIRELESS_PCCARD_NAME)) {
ret = -EBUSY;
goto exit4;
}
return 0;
exit4:
iounmap(ipw->attr_memory);
exit3:
release_mem_region(p_dev->resource[2]->start,
resource_size(p_dev->resource[2]));
exit2:
iounmap(ipw->common_memory);
exit1:
release_region(p_dev->resource[0]->start,
resource_size(p_dev->resource[0]));
exit:
pcmcia_disable_device(p_dev);
return ret;
}
static int config_ipwireless(struct ipw_dev *ipw)
{
struct pcmcia_device *link = ipw->link;
int ret = 0;
ipw->is_v2_card = 0;
link->config_flags |= CONF_AUTO_SET_IO | CONF_AUTO_SET_IOMEM |
CONF_ENABLE_IRQ;
ret = pcmcia_loop_config(link, ipwireless_probe, ipw);
if (ret != 0)
return ret;
INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start,
ipw->attr_memory, ipw->common_memory,
ipw->is_v2_card, signalled_reboot_callback,
ipw);
ret = pcmcia_request_irq(link, ipwireless_interrupt);
if (ret != 0)
goto exit;
printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
ipw->is_v2_card ? "V2/V3" : "V1");
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": I/O ports %pR, irq %d\n", link->resource[0],
(unsigned int) link->irq);
if (ipw->attr_memory && ipw->common_memory)
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": attr memory %pR, common memory %pR\n",
link->resource[3],
link->resource[2]);
ipw->network = ipwireless_network_create(ipw->hardware);
if (!ipw->network)
goto exit;
ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network);
if (!ipw->tty)
goto exit;
ipwireless_init_hardware_v2_v3(ipw->hardware);
/*
* Do the RequestConfiguration last, because it enables interrupts.
* Then we don't get any interrupts before we're ready for them.
*/
ret = pcmcia_enable_device(link);
if (ret != 0)
goto exit;
return 0;
exit:
if (ipw->common_memory) {
release_mem_region(link->resource[2]->start,
resource_size(link->resource[2]));
iounmap(ipw->common_memory);
}
if (ipw->attr_memory) {
release_mem_region(link->resource[3]->start,
resource_size(link->resource[3]));
iounmap(ipw->attr_memory);
}
pcmcia_disable_device(link);
return -1;
}
static void release_ipwireless(struct ipw_dev *ipw)
{
release_region(ipw->link->resource[0]->start,
resource_size(ipw->link->resource[0]));
if (ipw->common_memory) {
release_mem_region(ipw->link->resource[2]->start,
resource_size(ipw->link->resource[2]));
iounmap(ipw->common_memory);
}
if (ipw->attr_memory) {
release_mem_region(ipw->link->resource[3]->start,
resource_size(ipw->link->resource[3]));
iounmap(ipw->attr_memory);
}
pcmcia_disable_device(ipw->link);
}
/*
* ipwireless_attach() creates an "instance" of the driver, allocating
* local data structures for one device (one interface). The device
* is registered with Card Services.
*
* The pcmcia_device structure is initialized, but we don't actually
* configure the card at this point -- we wait until we receive a
* card insertion event.
*/
static int ipwireless_attach(struct pcmcia_device *link)
{
struct ipw_dev *ipw;
int ret;
ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL);
if (!ipw)
return -ENOMEM;
ipw->link = link;
link->priv = ipw;
ipw->hardware = ipwireless_hardware_create();
if (!ipw->hardware) {
kfree(ipw);
return -ENOMEM;
}
/* RegisterClient will call config_ipwireless */
ret = config_ipwireless(ipw);
if (ret != 0) {
ipwireless_detach(link);
return ret;
}
return 0;
}
/*
* This deletes a driver "instance". The device is de-registered with
* Card Services. If it has been released, all local data structures
* are freed. Otherwise, the structures will be freed when the device
* is released.
*/
static void ipwireless_detach(struct pcmcia_device *link)
{
struct ipw_dev *ipw = link->priv;
release_ipwireless(ipw);
if (ipw->tty != NULL)
ipwireless_tty_free(ipw->tty);
if (ipw->network != NULL)
ipwireless_network_free(ipw->network);
if (ipw->hardware != NULL)
ipwireless_hardware_free(ipw->hardware);
kfree(ipw);
}
static struct pcmcia_driver me = {
.owner = THIS_MODULE,
.probe = ipwireless_attach,
.remove = ipwireless_detach,
.name = IPWIRELESS_PCCARD_NAME,
.id_table = ipw_ids
};
/*
* Module insertion : initialisation of the module.
* Register the card with cardmgr...
*/
static int __init init_ipwireless(void)
{
int ret;
ret = ipwireless_tty_init();
if (ret != 0)
return ret;
ret = pcmcia_register_driver(&me);
if (ret != 0)
ipwireless_tty_release();
return ret;
}
/*
* Module removal
*/
static void __exit exit_ipwireless(void)
{
pcmcia_unregister_driver(&me);
ipwireless_tty_release();
}
module_init(init_ipwireless);
module_exit(exit_ipwireless);
MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR);
MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION);
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,68 @@
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#ifndef _IPWIRELESS_CS_H_
#define _IPWIRELESS_CS_H_
#include <linux/sched.h>
#include <linux/types.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include "hardware.h"
#define IPWIRELESS_PCCARD_NAME "ipwireless"
#define IPWIRELESS_PCMCIA_VERSION "1.1"
#define IPWIRELESS_PCMCIA_AUTHOR \
"Stephen Blackheath, Ben Martel, Jiri Kosina and David Sterba"
#define IPWIRELESS_TX_QUEUE_SIZE 262144
#define IPWIRELESS_RX_QUEUE_SIZE 262144
#define IPWIRELESS_STATE_DEBUG
struct ipw_hardware;
struct ipw_network;
struct ipw_tty;
struct ipw_dev {
struct pcmcia_device *link;
int is_v2_card;
void __iomem *attr_memory;
void __iomem *common_memory;
/* Reference to attribute memory, containing CIS data */
void *attribute_memory;
/* Hardware context */
struct ipw_hardware *hardware;
/* Network layer context */
struct ipw_network *network;
/* TTY device context */
struct ipw_tty *tty;
struct work_struct work_reboot;
};
/* Module parametres */
extern int ipwireless_debug;
extern int ipwireless_loopback;
extern int ipwireless_out_queue;
#endif

View file

@ -0,0 +1,508 @@
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/ppp_channel.h>
#include <linux/ppp_defs.h>
#include <linux/slab.h>
#include <linux/if_ppp.h>
#include <linux/skbuff.h>
#include "network.h"
#include "hardware.h"
#include "main.h"
#include "tty.h"
#define MAX_ASSOCIATED_TTYS 2
#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
struct ipw_network {
/* Hardware context, used for calls to hardware layer. */
struct ipw_hardware *hardware;
/* Context for kernel 'generic_ppp' functionality */
struct ppp_channel *ppp_channel;
/* tty context connected with IPW console */
struct ipw_tty *associated_ttys[NO_OF_IPW_CHANNELS][MAX_ASSOCIATED_TTYS];
/* True if ppp needs waking up once we're ready to xmit */
int ppp_blocked;
/* Number of packets queued up in hardware module. */
int outgoing_packets_queued;
/* Spinlock to avoid interrupts during shutdown */
spinlock_t lock;
struct mutex close_lock;
/* PPP ioctl data, not actually used anywere */
unsigned int flags;
unsigned int rbits;
u32 xaccm[8];
u32 raccm;
int mru;
int shutting_down;
unsigned int ras_control_lines;
struct work_struct work_go_online;
struct work_struct work_go_offline;
};
static void notify_packet_sent(void *callback_data, unsigned int packet_length)
{
struct ipw_network *network = callback_data;
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
network->outgoing_packets_queued--;
if (network->ppp_channel != NULL) {
if (network->ppp_blocked) {
network->ppp_blocked = 0;
spin_unlock_irqrestore(&network->lock, flags);
ppp_output_wakeup(network->ppp_channel);
if (ipwireless_debug)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
": ppp unblocked\n");
} else
spin_unlock_irqrestore(&network->lock, flags);
} else
spin_unlock_irqrestore(&network->lock, flags);
}
/*
* Called by the ppp system when it has a packet to send to the hardware.
*/
static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel,
struct sk_buff *skb)
{
struct ipw_network *network = ppp_channel->private;
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
if (network->outgoing_packets_queued < ipwireless_out_queue) {
unsigned char *buf;
static unsigned char header[] = {
PPP_ALLSTATIONS, /* 0xff */
PPP_UI, /* 0x03 */
};
int ret;
network->outgoing_packets_queued++;
spin_unlock_irqrestore(&network->lock, flags);
/*
* If we have the requested amount of headroom in the skb we
* were handed, then we can add the header efficiently.
*/
if (skb_headroom(skb) >= 2) {
memcpy(skb_push(skb, 2), header, 2);
ret = ipwireless_send_packet(network->hardware,
IPW_CHANNEL_RAS, skb->data,
skb->len,
notify_packet_sent,
network);
if (ret == -1) {
skb_pull(skb, 2);
return 0;
}
} else {
/* Otherwise (rarely) we do it inefficiently. */
buf = kmalloc(skb->len + 2, GFP_ATOMIC);
if (!buf)
return 0;
memcpy(buf + 2, skb->data, skb->len);
memcpy(buf, header, 2);
ret = ipwireless_send_packet(network->hardware,
IPW_CHANNEL_RAS, buf,
skb->len + 2,
notify_packet_sent,
network);
kfree(buf);
if (ret == -1)
return 0;
}
kfree_skb(skb);
return 1;
} else {
/*
* Otherwise reject the packet, and flag that the ppp system
* needs to be unblocked once we are ready to send.
*/
network->ppp_blocked = 1;
spin_unlock_irqrestore(&network->lock, flags);
if (ipwireless_debug)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": ppp blocked\n");
return 0;
}
}
/* Handle an ioctl call that has come in via ppp. (copy of ppp_async_ioctl() */
static int ipwireless_ppp_ioctl(struct ppp_channel *ppp_channel,
unsigned int cmd, unsigned long arg)
{
struct ipw_network *network = ppp_channel->private;
int err, val;
u32 accm[8];
int __user *user_arg = (int __user *) arg;
err = -EFAULT;
switch (cmd) {
case PPPIOCGFLAGS:
val = network->flags | network->rbits;
if (put_user(val, user_arg))
break;
err = 0;
break;
case PPPIOCSFLAGS:
if (get_user(val, user_arg))
break;
network->flags = val & ~SC_RCV_BITS;
network->rbits = val & SC_RCV_BITS;
err = 0;
break;
case PPPIOCGASYNCMAP:
if (put_user(network->xaccm[0], user_arg))
break;
err = 0;
break;
case PPPIOCSASYNCMAP:
if (get_user(network->xaccm[0], user_arg))
break;
err = 0;
break;
case PPPIOCGRASYNCMAP:
if (put_user(network->raccm, user_arg))
break;
err = 0;
break;
case PPPIOCSRASYNCMAP:
if (get_user(network->raccm, user_arg))
break;
err = 0;
break;
case PPPIOCGXASYNCMAP:
if (copy_to_user((void __user *) arg, network->xaccm,
sizeof(network->xaccm)))
break;
err = 0;
break;
case PPPIOCSXASYNCMAP:
if (copy_from_user(accm, (void __user *) arg, sizeof(accm)))
break;
accm[2] &= ~0x40000000U; /* can't escape 0x5e */
accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */
memcpy(network->xaccm, accm, sizeof(network->xaccm));
err = 0;
break;
case PPPIOCGMRU:
if (put_user(network->mru, user_arg))
break;
err = 0;
break;
case PPPIOCSMRU:
if (get_user(val, user_arg))
break;
if (val < PPP_MRU)
val = PPP_MRU;
network->mru = val;
err = 0;
break;
default:
err = -ENOTTY;
}
return err;
}
static const struct ppp_channel_ops ipwireless_ppp_channel_ops = {
.start_xmit = ipwireless_ppp_start_xmit,
.ioctl = ipwireless_ppp_ioctl
};
static void do_go_online(struct work_struct *work_go_online)
{
struct ipw_network *network =
container_of(work_go_online, struct ipw_network,
work_go_online);
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
if (!network->ppp_channel) {
struct ppp_channel *channel;
spin_unlock_irqrestore(&network->lock, flags);
channel = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL);
if (!channel) {
printk(KERN_ERR IPWIRELESS_PCCARD_NAME
": unable to allocate PPP channel\n");
return;
}
channel->private = network;
channel->mtu = 16384; /* Wild guess */
channel->hdrlen = 2;
channel->ops = &ipwireless_ppp_channel_ops;
network->flags = 0;
network->rbits = 0;
network->mru = PPP_MRU;
memset(network->xaccm, 0, sizeof(network->xaccm));
network->xaccm[0] = ~0U;
network->xaccm[3] = 0x60000000U;
network->raccm = ~0U;
ppp_register_channel(channel);
spin_lock_irqsave(&network->lock, flags);
network->ppp_channel = channel;
}
spin_unlock_irqrestore(&network->lock, flags);
}
static void do_go_offline(struct work_struct *work_go_offline)
{
struct ipw_network *network =
container_of(work_go_offline, struct ipw_network,
work_go_offline);
unsigned long flags;
mutex_lock(&network->close_lock);
spin_lock_irqsave(&network->lock, flags);
if (network->ppp_channel != NULL) {
struct ppp_channel *channel = network->ppp_channel;
network->ppp_channel = NULL;
spin_unlock_irqrestore(&network->lock, flags);
mutex_unlock(&network->close_lock);
ppp_unregister_channel(channel);
} else {
spin_unlock_irqrestore(&network->lock, flags);
mutex_unlock(&network->close_lock);
}
}
void ipwireless_network_notify_control_line_change(struct ipw_network *network,
unsigned int channel_idx,
unsigned int control_lines,
unsigned int changed_mask)
{
int i;
if (channel_idx == IPW_CHANNEL_RAS)
network->ras_control_lines = control_lines;
for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) {
struct ipw_tty *tty =
network->associated_ttys[channel_idx][i];
/*
* If it's associated with a tty (other than the RAS channel
* when we're online), then send the data to that tty. The RAS
* channel's data is handled above - it always goes through
* ppp_generic.
*/
if (tty)
ipwireless_tty_notify_control_line_change(tty,
channel_idx,
control_lines,
changed_mask);
}
}
/*
* Some versions of firmware stuff packets with 0xff 0x03 (PPP: ALLSTATIONS, UI)
* bytes, which are required on sent packet, but not always present on received
* packets
*/
static struct sk_buff *ipw_packet_received_skb(unsigned char *data,
unsigned int length)
{
struct sk_buff *skb;
if (length > 2 && data[0] == PPP_ALLSTATIONS && data[1] == PPP_UI) {
length -= 2;
data += 2;
}
skb = dev_alloc_skb(length + 4);
skb_reserve(skb, 2);
memcpy(skb_put(skb, length), data, length);
return skb;
}
void ipwireless_network_packet_received(struct ipw_network *network,
unsigned int channel_idx,
unsigned char *data,
unsigned int length)
{
int i;
unsigned long flags;
for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) {
struct ipw_tty *tty = network->associated_ttys[channel_idx][i];
if (!tty)
continue;
/*
* If it's associated with a tty (other than the RAS channel
* when we're online), then send the data to that tty. The RAS
* channel's data is handled above - it always goes through
* ppp_generic.
*/
if (channel_idx == IPW_CHANNEL_RAS
&& (network->ras_control_lines &
IPW_CONTROL_LINE_DCD) != 0
&& ipwireless_tty_is_modem(tty)) {
/*
* If data came in on the RAS channel and this tty is
* the modem tty, and we are online, then we send it to
* the PPP layer.
*/
mutex_lock(&network->close_lock);
spin_lock_irqsave(&network->lock, flags);
if (network->ppp_channel != NULL) {
struct sk_buff *skb;
spin_unlock_irqrestore(&network->lock,
flags);
/* Send the data to the ppp_generic module. */
skb = ipw_packet_received_skb(data, length);
ppp_input(network->ppp_channel, skb);
} else
spin_unlock_irqrestore(&network->lock,
flags);
mutex_unlock(&network->close_lock);
}
/* Otherwise we send it out the tty. */
else
ipwireless_tty_received(tty, data, length);
}
}
struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw)
{
struct ipw_network *network =
kzalloc(sizeof(struct ipw_network), GFP_ATOMIC);
if (!network)
return NULL;
spin_lock_init(&network->lock);
mutex_init(&network->close_lock);
network->hardware = hw;
INIT_WORK(&network->work_go_online, do_go_online);
INIT_WORK(&network->work_go_offline, do_go_offline);
ipwireless_associate_network(hw, network);
return network;
}
void ipwireless_network_free(struct ipw_network *network)
{
network->shutting_down = 1;
ipwireless_ppp_close(network);
flush_work_sync(&network->work_go_online);
flush_work_sync(&network->work_go_offline);
ipwireless_stop_interrupts(network->hardware);
ipwireless_associate_network(network->hardware, NULL);
kfree(network);
}
void ipwireless_associate_network_tty(struct ipw_network *network,
unsigned int channel_idx,
struct ipw_tty *tty)
{
int i;
for (i = 0; i < MAX_ASSOCIATED_TTYS; i++)
if (network->associated_ttys[channel_idx][i] == NULL) {
network->associated_ttys[channel_idx][i] = tty;
break;
}
}
void ipwireless_disassociate_network_ttys(struct ipw_network *network,
unsigned int channel_idx)
{
int i;
for (i = 0; i < MAX_ASSOCIATED_TTYS; i++)
network->associated_ttys[channel_idx][i] = NULL;
}
void ipwireless_ppp_open(struct ipw_network *network)
{
if (ipwireless_debug)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": online\n");
schedule_work(&network->work_go_online);
}
void ipwireless_ppp_close(struct ipw_network *network)
{
/* Disconnect from the wireless network. */
if (ipwireless_debug)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": offline\n");
schedule_work(&network->work_go_offline);
}
int ipwireless_ppp_channel_index(struct ipw_network *network)
{
int ret = -1;
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
if (network->ppp_channel != NULL)
ret = ppp_channel_index(network->ppp_channel);
spin_unlock_irqrestore(&network->lock, flags);
return ret;
}
int ipwireless_ppp_unit_number(struct ipw_network *network)
{
int ret = -1;
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
if (network->ppp_channel != NULL)
ret = ppp_unit_number(network->ppp_channel);
spin_unlock_irqrestore(&network->lock, flags);
return ret;
}
int ipwireless_ppp_mru(const struct ipw_network *network)
{
return network->mru;
}

View file

@ -0,0 +1,53 @@
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#ifndef _IPWIRELESS_CS_NETWORK_H_
#define _IPWIRELESS_CS_NETWORK_H_
#include <linux/types.h>
struct ipw_network;
struct ipw_tty;
struct ipw_hardware;
/* Definitions of the different channels on the PCMCIA UE */
#define IPW_CHANNEL_RAS 0
#define IPW_CHANNEL_DIALLER 1
#define IPW_CHANNEL_CONSOLE 2
#define NO_OF_IPW_CHANNELS 5
void ipwireless_network_notify_control_line_change(struct ipw_network *net,
unsigned int channel_idx, unsigned int control_lines,
unsigned int control_mask);
void ipwireless_network_packet_received(struct ipw_network *net,
unsigned int channel_idx, unsigned char *data,
unsigned int length);
struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw);
void ipwireless_network_free(struct ipw_network *net);
void ipwireless_associate_network_tty(struct ipw_network *net,
unsigned int channel_idx, struct ipw_tty *tty);
void ipwireless_disassociate_network_ttys(struct ipw_network *net,
unsigned int channel_idx);
void ipwireless_ppp_open(struct ipw_network *net);
void ipwireless_ppp_close(struct ipw_network *net);
int ipwireless_ppp_channel_index(struct ipw_network *net);
int ipwireless_ppp_unit_number(struct ipw_network *net);
int ipwireless_ppp_mru(const struct ipw_network *net);
#endif

View file

@ -0,0 +1,108 @@
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#ifndef _IPWIRELESS_CS_SETUP_PROTOCOL_H_
#define _IPWIRELESS_CS_SETUP_PROTOCOL_H_
/* Version of the setup protocol and transport protocols */
#define TL_SETUP_VERSION 1
#define TL_SETUP_VERSION_QRY_TMO 1000
#define TL_SETUP_MAX_VERSION_QRY 30
/* Message numbers 0-9 are obsoleted and must not be reused! */
#define TL_SETUP_SIGNO_GET_VERSION_QRY 10
#define TL_SETUP_SIGNO_GET_VERSION_RSP 11
#define TL_SETUP_SIGNO_CONFIG_MSG 12
#define TL_SETUP_SIGNO_CONFIG_DONE_MSG 13
#define TL_SETUP_SIGNO_OPEN_MSG 14
#define TL_SETUP_SIGNO_CLOSE_MSG 15
#define TL_SETUP_SIGNO_INFO_MSG 20
#define TL_SETUP_SIGNO_INFO_MSG_ACK 21
#define TL_SETUP_SIGNO_REBOOT_MSG 22
#define TL_SETUP_SIGNO_REBOOT_MSG_ACK 23
/* Synchronous start-messages */
struct tl_setup_get_version_qry {
unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_QRY */
} __attribute__ ((__packed__));
struct tl_setup_get_version_rsp {
unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_RSP */
unsigned char version; /* TL_SETUP_VERSION */
} __attribute__ ((__packed__));
struct tl_setup_config_msg {
unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_MSG */
unsigned char port_no;
unsigned char prio_data;
unsigned char prio_ctrl;
} __attribute__ ((__packed__));
struct tl_setup_config_done_msg {
unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_DONE_MSG */
} __attribute__ ((__packed__));
/* Asyncronous messages */
struct tl_setup_open_msg {
unsigned char sig_no; /* TL_SETUP_SIGNO_OPEN_MSG */
unsigned char port_no;
} __attribute__ ((__packed__));
struct tl_setup_close_msg {
unsigned char sig_no; /* TL_SETUP_SIGNO_CLOSE_MSG */
unsigned char port_no;
} __attribute__ ((__packed__));
/* Driver type - for use in tl_setup_info_msg.driver_type */
#define COMM_DRIVER 0
#define NDISWAN_DRIVER 1
#define NDISWAN_DRIVER_MAJOR_VERSION 2
#define NDISWAN_DRIVER_MINOR_VERSION 0
/*
* It should not matter when this message comes over as we just store the
* results and send the ACK.
*/
struct tl_setup_info_msg {
unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG */
unsigned char driver_type;
unsigned char major_version;
unsigned char minor_version;
} __attribute__ ((__packed__));
struct tl_setup_info_msgAck {
unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG_ACK */
} __attribute__ ((__packed__));
struct TlSetupRebootMsgAck {
unsigned char sig_no; /* TL_SETUP_SIGNO_REBOOT_MSG_ACK */
} __attribute__ ((__packed__));
/* Define a union of all the msgs that the driver can receive from the card.*/
union ipw_setup_rx_msg {
unsigned char sig_no;
struct tl_setup_get_version_rsp version_rsp_msg;
struct tl_setup_open_msg open_msg;
struct tl_setup_close_msg close_msg;
struct tl_setup_info_msg InfoMsg;
struct tl_setup_info_msgAck info_msg_ack;
} __attribute__ ((__packed__));
#endif /* _IPWIRELESS_CS_SETUP_PROTOCOL_H_ */

View file

@ -0,0 +1,679 @@
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/ppp_defs.h>
#include <linux/if.h>
#include <linux/if_ppp.h>
#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/uaccess.h>
#include "tty.h"
#include "network.h"
#include "hardware.h"
#include "main.h"
#define IPWIRELESS_PCMCIA_START (0)
#define IPWIRELESS_PCMCIA_MINORS (24)
#define IPWIRELESS_PCMCIA_MINOR_RANGE (8)
#define TTYTYPE_MODEM (0)
#define TTYTYPE_MONITOR (1)
#define TTYTYPE_RAS_RAW (2)
struct ipw_tty {
int index;
struct ipw_hardware *hardware;
unsigned int channel_idx;
unsigned int secondary_channel_idx;
int tty_type;
struct ipw_network *network;
struct tty_struct *linux_tty;
int open_count;
unsigned int control_lines;
struct mutex ipw_tty_mutex;
int tx_bytes_queued;
int closing;
};
static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS];
static struct tty_driver *ipw_tty_driver;
static char *tty_type_name(int tty_type)
{
static char *channel_names[] = {
"modem",
"monitor",
"RAS-raw"
};
return channel_names[tty_type];
}
static void report_registering(struct ipw_tty *tty)
{
char *iftype = tty_type_name(tty->tty_type);
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": registering %s device ttyIPWp%d\n", iftype, tty->index);
}
static void report_deregistering(struct ipw_tty *tty)
{
char *iftype = tty_type_name(tty->tty_type);
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": deregistering %s device ttyIPWp%d\n", iftype,
tty->index);
}
static struct ipw_tty *get_tty(int minor)
{
if (minor < ipw_tty_driver->minor_start
|| minor >= ipw_tty_driver->minor_start +
IPWIRELESS_PCMCIA_MINORS)
return NULL;
else {
int minor_offset = minor - ipw_tty_driver->minor_start;
/*
* The 'ras_raw' channel is only available when 'loopback' mode
* is enabled.
* Number of minor starts with 16 (_RANGE * _RAS_RAW).
*/
if (!ipwireless_loopback &&
minor_offset >=
IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
return NULL;
return ttys[minor_offset];
}
}
static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
{
int minor = linux_tty->index;
struct ipw_tty *tty = get_tty(minor);
if (!tty)
return -ENODEV;
mutex_lock(&tty->ipw_tty_mutex);
if (tty->closing) {
mutex_unlock(&tty->ipw_tty_mutex);
return -ENODEV;
}
if (tty->open_count == 0)
tty->tx_bytes_queued = 0;
tty->open_count++;
tty->linux_tty = linux_tty;
linux_tty->driver_data = tty;
linux_tty->low_latency = 1;
if (tty->tty_type == TTYTYPE_MODEM)
ipwireless_ppp_open(tty->network);
mutex_unlock(&tty->ipw_tty_mutex);
return 0;
}
static void do_ipw_close(struct ipw_tty *tty)
{
tty->open_count--;
if (tty->open_count == 0) {
struct tty_struct *linux_tty = tty->linux_tty;
if (linux_tty != NULL) {
tty->linux_tty = NULL;
linux_tty->driver_data = NULL;
if (tty->tty_type == TTYTYPE_MODEM)
ipwireless_ppp_close(tty->network);
}
}
}
static void ipw_hangup(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
if (!tty)
return;
mutex_lock(&tty->ipw_tty_mutex);
if (tty->open_count == 0) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
do_ipw_close(tty);
mutex_unlock(&tty->ipw_tty_mutex);
}
static void ipw_close(struct tty_struct *linux_tty, struct file *filp)
{
ipw_hangup(linux_tty);
}
/* Take data received from hardware, and send it out the tty */
void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
unsigned int length)
{
struct tty_struct *linux_tty;
int work = 0;
mutex_lock(&tty->ipw_tty_mutex);
linux_tty = tty->linux_tty;
if (linux_tty == NULL) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
if (!tty->open_count) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
mutex_unlock(&tty->ipw_tty_mutex);
work = tty_insert_flip_string(linux_tty, data, length);
if (work != length)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
": %d chars not inserted to flip buffer!\n",
length - work);
/*
* This may sleep if ->low_latency is set
*/
if (work)
tty_flip_buffer_push(linux_tty);
}
static void ipw_write_packet_sent_callback(void *callback_data,
unsigned int packet_length)
{
struct ipw_tty *tty = callback_data;
/*
* Packet has been sent, so we subtract the number of bytes from our
* tally of outstanding TX bytes.
*/
tty->tx_bytes_queued -= packet_length;
}
static int ipw_write(struct tty_struct *linux_tty,
const unsigned char *buf, int count)
{
struct ipw_tty *tty = linux_tty->driver_data;
int room, ret;
if (!tty)
return -ENODEV;
mutex_lock(&tty->ipw_tty_mutex);
if (!tty->open_count) {
mutex_unlock(&tty->ipw_tty_mutex);
return -EINVAL;
}
room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
if (room < 0)
room = 0;
/* Don't allow caller to write any more than we have room for */
if (count > room)
count = room;
if (count == 0) {
mutex_unlock(&tty->ipw_tty_mutex);
return 0;
}
ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS,
buf, count,
ipw_write_packet_sent_callback, tty);
if (ret == -1) {
mutex_unlock(&tty->ipw_tty_mutex);
return 0;
}
tty->tx_bytes_queued += count;
mutex_unlock(&tty->ipw_tty_mutex);
return count;
}
static int ipw_write_room(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
int room;
/* FIXME: Exactly how is the tty object locked here .. */
if (!tty)
return -ENODEV;
if (!tty->open_count)
return -EINVAL;
room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
if (room < 0)
room = 0;
return room;
}
static int ipwireless_get_serial_info(struct ipw_tty *tty,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
if (!retinfo)
return (-EFAULT);
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_UNKNOWN;
tmp.line = tty->index;
tmp.port = 0;
tmp.irq = 0;
tmp.flags = 0;
tmp.baud_base = 115200;
tmp.close_delay = 0;
tmp.closing_wait = 0;
tmp.custom_divisor = 0;
tmp.hub6 = 0;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
return 0;
}
static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
if (!tty)
return 0;
if (!tty->open_count)
return 0;
return tty->tx_bytes_queued;
}
static int get_control_lines(struct ipw_tty *tty)
{
unsigned int my = tty->control_lines;
unsigned int out = 0;
if (my & IPW_CONTROL_LINE_RTS)
out |= TIOCM_RTS;
if (my & IPW_CONTROL_LINE_DTR)
out |= TIOCM_DTR;
if (my & IPW_CONTROL_LINE_CTS)
out |= TIOCM_CTS;
if (my & IPW_CONTROL_LINE_DSR)
out |= TIOCM_DSR;
if (my & IPW_CONTROL_LINE_DCD)
out |= TIOCM_CD;
return out;
}
static int set_control_lines(struct ipw_tty *tty, unsigned int set,
unsigned int clear)
{
int ret;
if (set & TIOCM_RTS) {
ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1);
if (ret)
return ret;
if (tty->secondary_channel_idx != -1) {
ret = ipwireless_set_RTS(tty->hardware,
tty->secondary_channel_idx, 1);
if (ret)
return ret;
}
}
if (set & TIOCM_DTR) {
ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1);
if (ret)
return ret;
if (tty->secondary_channel_idx != -1) {
ret = ipwireless_set_DTR(tty->hardware,
tty->secondary_channel_idx, 1);
if (ret)
return ret;
}
}
if (clear & TIOCM_RTS) {
ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0);
if (tty->secondary_channel_idx != -1) {
ret = ipwireless_set_RTS(tty->hardware,
tty->secondary_channel_idx, 0);
if (ret)
return ret;
}
}
if (clear & TIOCM_DTR) {
ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0);
if (tty->secondary_channel_idx != -1) {
ret = ipwireless_set_DTR(tty->hardware,
tty->secondary_channel_idx, 0);
if (ret)
return ret;
}
}
return 0;
}
static int ipw_tiocmget(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
/* FIXME: Exactly how is the tty object locked here .. */
if (!tty)
return -ENODEV;
if (!tty->open_count)
return -EINVAL;
return get_control_lines(tty);
}
static int
ipw_tiocmset(struct tty_struct *linux_tty,
unsigned int set, unsigned int clear)
{
struct ipw_tty *tty = linux_tty->driver_data;
/* FIXME: Exactly how is the tty object locked here .. */
if (!tty)
return -ENODEV;
if (!tty->open_count)
return -EINVAL;
return set_control_lines(tty, set, clear);
}
static int ipw_ioctl(struct tty_struct *linux_tty,
unsigned int cmd, unsigned long arg)
{
struct ipw_tty *tty = linux_tty->driver_data;
if (!tty)
return -ENODEV;
if (!tty->open_count)
return -EINVAL;
/* FIXME: Exactly how is the tty object locked here .. */
switch (cmd) {
case TIOCGSERIAL:
return ipwireless_get_serial_info(tty, (void __user *) arg);
case TIOCSSERIAL:
return 0; /* Keeps the PCMCIA scripts happy. */
}
if (tty->tty_type == TTYTYPE_MODEM) {
switch (cmd) {
case PPPIOCGCHAN:
{
int chan = ipwireless_ppp_channel_index(
tty->network);
if (chan < 0)
return -ENODEV;
if (put_user(chan, (int __user *) arg))
return -EFAULT;
}
return 0;
case PPPIOCGUNIT:
{
int unit = ipwireless_ppp_unit_number(
tty->network);
if (unit < 0)
return -ENODEV;
if (put_user(unit, (int __user *) arg))
return -EFAULT;
}
return 0;
case FIONREAD:
{
int val = 0;
if (put_user(val, (int __user *) arg))
return -EFAULT;
}
return 0;
case TCFLSH:
return tty_perform_flush(linux_tty, arg);
}
}
return -ENOIOCTLCMD;
}
static int add_tty(int j,
struct ipw_hardware *hardware,
struct ipw_network *network, int channel_idx,
int secondary_channel_idx, int tty_type)
{
ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL);
if (!ttys[j])
return -ENOMEM;
ttys[j]->index = j;
ttys[j]->hardware = hardware;
ttys[j]->channel_idx = channel_idx;
ttys[j]->secondary_channel_idx = secondary_channel_idx;
ttys[j]->network = network;
ttys[j]->tty_type = tty_type;
mutex_init(&ttys[j]->ipw_tty_mutex);
tty_register_device(ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
if (secondary_channel_idx != -1)
ipwireless_associate_network_tty(network,
secondary_channel_idx,
ttys[j]);
if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j])
report_registering(ttys[j]);
return 0;
}
struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware,
struct ipw_network *network)
{
int i, j;
for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) {
int allfree = 1;
for (j = i; j < IPWIRELESS_PCMCIA_MINORS;
j += IPWIRELESS_PCMCIA_MINOR_RANGE)
if (ttys[j] != NULL) {
allfree = 0;
break;
}
if (allfree) {
j = i;
if (add_tty(j, hardware, network,
IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS,
TTYTYPE_MODEM))
return NULL;
j += IPWIRELESS_PCMCIA_MINOR_RANGE;
if (add_tty(j, hardware, network,
IPW_CHANNEL_DIALLER, -1,
TTYTYPE_MONITOR))
return NULL;
j += IPWIRELESS_PCMCIA_MINOR_RANGE;
if (add_tty(j, hardware, network,
IPW_CHANNEL_RAS, -1,
TTYTYPE_RAS_RAW))
return NULL;
return ttys[i];
}
}
return NULL;
}
/*
* Must be called before ipwireless_network_free().
*/
void ipwireless_tty_free(struct ipw_tty *tty)
{
int j;
struct ipw_network *network = ttys[tty->index]->network;
for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS;
j += IPWIRELESS_PCMCIA_MINOR_RANGE) {
struct ipw_tty *ttyj = ttys[j];
if (ttyj) {
mutex_lock(&ttyj->ipw_tty_mutex);
if (get_tty(j + ipw_tty_driver->minor_start) == ttyj)
report_deregistering(ttyj);
ttyj->closing = 1;
if (ttyj->linux_tty != NULL) {
mutex_unlock(&ttyj->ipw_tty_mutex);
tty_hangup(ttyj->linux_tty);
/* Wait till the tty_hangup has completed */
flush_work_sync(&ttyj->linux_tty->hangup_work);
/* FIXME: Exactly how is the tty object locked here
against a parallel ioctl etc */
mutex_lock(&ttyj->ipw_tty_mutex);
}
while (ttyj->open_count)
do_ipw_close(ttyj);
ipwireless_disassociate_network_ttys(network,
ttyj->channel_idx);
tty_unregister_device(ipw_tty_driver, j);
ttys[j] = NULL;
mutex_unlock(&ttyj->ipw_tty_mutex);
kfree(ttyj);
}
}
}
static const struct tty_operations tty_ops = {
.open = ipw_open,
.close = ipw_close,
.hangup = ipw_hangup,
.write = ipw_write,
.write_room = ipw_write_room,
.ioctl = ipw_ioctl,
.chars_in_buffer = ipw_chars_in_buffer,
.tiocmget = ipw_tiocmget,
.tiocmset = ipw_tiocmset,
};
int ipwireless_tty_init(void)
{
int result;
ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS);
if (!ipw_tty_driver)
return -ENOMEM;
ipw_tty_driver->owner = THIS_MODULE;
ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
ipw_tty_driver->name = "ttyIPWp";
ipw_tty_driver->major = 0;
ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START;
ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL;
ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
ipw_tty_driver->init_termios = tty_std_termios;
ipw_tty_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
ipw_tty_driver->init_termios.c_ispeed = 9600;
ipw_tty_driver->init_termios.c_ospeed = 9600;
tty_set_operations(ipw_tty_driver, &tty_ops);
result = tty_register_driver(ipw_tty_driver);
if (result) {
printk(KERN_ERR IPWIRELESS_PCCARD_NAME
": failed to register tty driver\n");
put_tty_driver(ipw_tty_driver);
return result;
}
return 0;
}
void ipwireless_tty_release(void)
{
int ret;
ret = tty_unregister_driver(ipw_tty_driver);
put_tty_driver(ipw_tty_driver);
if (ret != 0)
printk(KERN_ERR IPWIRELESS_PCCARD_NAME
": tty_unregister_driver failed with code %d\n", ret);
}
int ipwireless_tty_is_modem(struct ipw_tty *tty)
{
return tty->tty_type == TTYTYPE_MODEM;
}
void
ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
unsigned int channel_idx,
unsigned int control_lines,
unsigned int changed_mask)
{
unsigned int old_control_lines = tty->control_lines;
tty->control_lines = (tty->control_lines & ~changed_mask)
| (control_lines & changed_mask);
/*
* If DCD is de-asserted, we close the tty so pppd can tell that we
* have gone offline.
*/
if ((old_control_lines & IPW_CONTROL_LINE_DCD)
&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
&& tty->linux_tty) {
tty_hangup(tty->linux_tty);
}
}

View file

@ -0,0 +1,45 @@
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#ifndef _IPWIRELESS_CS_TTY_H_
#define _IPWIRELESS_CS_TTY_H_
#include <linux/types.h>
#include <linux/sched.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
struct ipw_tty;
struct ipw_network;
struct ipw_hardware;
int ipwireless_tty_init(void);
void ipwireless_tty_release(void);
struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hw,
struct ipw_network *net);
void ipwireless_tty_free(struct ipw_tty *tty);
void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
unsigned int length);
int ipwireless_tty_is_modem(struct ipw_tty *tty);
void ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
unsigned int channel_idx,
unsigned int control_lines,
unsigned int changed_mask);
#endif

1736
drivers/tty/isicom.c Normal file

File diff suppressed because it is too large Load diff

2092
drivers/tty/moxa.c Normal file

File diff suppressed because it is too large Load diff

304
drivers/tty/moxa.h Normal file
View file

@ -0,0 +1,304 @@
#ifndef MOXA_H_FILE
#define MOXA_H_FILE
#define MOXA 0x400
#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
#define MOXA_GETDATACOUNT (MOXA + 23)
#define MOXA_GET_IOQUEUE (MOXA + 27)
#define MOXA_FLUSH_QUEUE (MOXA + 28)
#define MOXA_GETMSTATUS (MOXA + 65)
/*
* System Configuration
*/
#define Magic_code 0x404
/*
* for C218 BIOS initialization
*/
#define C218_ConfBase 0x800
#define C218_status (C218_ConfBase + 0) /* BIOS running status */
#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
#define C218check_sum (C218_ConfBase + 8) /* BYTE */
#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
#define C218_LoadBuf 0x0F00
#define C218_KeyCode 0x218
#define CP204J_KeyCode 0x204
/*
* for C320 BIOS initialization
*/
#define C320_ConfBase 0x800
#define C320_LoadBuf 0x0f00
#define STS_init 0x05 /* for C320_status */
#define C320_status C320_ConfBase + 0 /* BIOS running status */
#define C320_diag C320_ConfBase + 2 /* diagnostic status */
#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
#define C320DLoad_len C320_ConfBase + 6 /* WORD */
#define C320check_sum C320_ConfBase + 8 /* WORD */
#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
#define C320UART_no C320_ConfBase + 0x0e /* WORD */
#define C320_KeyCode 0x320
#define FixPage_addr 0x0000 /* starting addr of static page */
#define DynPage_addr 0x2000 /* starting addr of dynamic page */
#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
#define Control_reg 0x1ff0 /* select page and reset control */
#define HW_reset 0x80
/*
* Function Codes
*/
#define FC_CardReset 0x80
#define FC_ChannelReset 1 /* C320 firmware not supported */
#define FC_EnableCH 2
#define FC_DisableCH 3
#define FC_SetParam 4
#define FC_SetMode 5
#define FC_SetRate 6
#define FC_LineControl 7
#define FC_LineStatus 8
#define FC_XmitControl 9
#define FC_FlushQueue 10
#define FC_SendBreak 11
#define FC_StopBreak 12
#define FC_LoopbackON 13
#define FC_LoopbackOFF 14
#define FC_ClrIrqTable 15
#define FC_SendXon 16
#define FC_SetTermIrq 17 /* C320 firmware not supported */
#define FC_SetCntIrq 18 /* C320 firmware not supported */
#define FC_SetBreakIrq 19
#define FC_SetLineIrq 20
#define FC_SetFlowCtl 21
#define FC_GenIrq 22
#define FC_InCD180 23
#define FC_OutCD180 24
#define FC_InUARTreg 23
#define FC_OutUARTreg 24
#define FC_SetXonXoff 25
#define FC_OutCD180CCR 26
#define FC_ExtIQueue 27
#define FC_ExtOQueue 28
#define FC_ClrLineIrq 29
#define FC_HWFlowCtl 30
#define FC_GetClockRate 35
#define FC_SetBaud 36
#define FC_SetDataMode 41
#define FC_GetCCSR 43
#define FC_GetDataError 45
#define FC_RxControl 50
#define FC_ImmSend 51
#define FC_SetXonState 52
#define FC_SetXoffState 53
#define FC_SetRxFIFOTrig 54
#define FC_SetTxFIFOCnt 55
#define FC_UnixRate 56
#define FC_UnixResetTimer 57
#define RxFIFOTrig1 0
#define RxFIFOTrig4 1
#define RxFIFOTrig8 2
#define RxFIFOTrig14 3
/*
* Dual-Ported RAM
*/
#define DRAM_global 0
#define INT_data (DRAM_global + 0)
#define Config_base (DRAM_global + 0x108)
#define IRQindex (INT_data + 0)
#define IRQpending (INT_data + 4)
#define IRQtable (INT_data + 8)
/*
* Interrupt Status
*/
#define IntrRx 0x01 /* receiver data O.K. */
#define IntrTx 0x02 /* transmit buffer empty */
#define IntrFunc 0x04 /* function complete */
#define IntrBreak 0x08 /* received break */
#define IntrLine 0x10 /* line status change
for transmitter */
#define IntrIntr 0x20 /* received INTR code */
#define IntrQuit 0x40 /* received QUIT code */
#define IntrEOF 0x80 /* received EOF code */
#define IntrRxTrigger 0x100 /* rx data count reach tigger value */
#define IntrTxTrigger 0x200 /* tx data count below trigger value */
#define Magic_no (Config_base + 0)
#define Card_model_no (Config_base + 2)
#define Total_ports (Config_base + 4)
#define Module_cnt (Config_base + 8)
#define Module_no (Config_base + 10)
#define Timer_10ms (Config_base + 14)
#define Disable_IRQ (Config_base + 20)
#define TMS320_PORT1 (Config_base + 22)
#define TMS320_PORT2 (Config_base + 24)
#define TMS320_CLOCK (Config_base + 26)
/*
* DATA BUFFER in DRAM
*/
#define Extern_table 0x400 /* Base address of the external table
(24 words * 64) total 3K bytes
(24 words * 128) total 6K bytes */
#define Extern_size 0x60 /* 96 bytes */
#define RXrptr 0x00 /* read pointer for RX buffer */
#define RXwptr 0x02 /* write pointer for RX buffer */
#define TXrptr 0x04 /* read pointer for TX buffer */
#define TXwptr 0x06 /* write pointer for TX buffer */
#define HostStat 0x08 /* IRQ flag and general flag */
#define FlagStat 0x0A
#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
/* x x x x | | | | */
/* | | | + CTS flow */
/* | | +--- RTS flow */
/* | +------ TX Xon/Xoff */
/* +--------- RX Xon/Xoff */
#define Break_cnt 0x0E /* received break count */
#define CD180TXirq 0x10 /* if non-0: enable TX irq */
#define RX_mask 0x12
#define TX_mask 0x14
#define Ofs_rxb 0x16
#define Ofs_txb 0x18
#define Page_rxb 0x1A
#define Page_txb 0x1C
#define EndPage_rxb 0x1E
#define EndPage_txb 0x20
#define Data_error 0x22
#define RxTrigger 0x28
#define TxTrigger 0x2a
#define rRXwptr 0x34
#define Low_water 0x36
#define FuncCode 0x40
#define FuncArg 0x42
#define FuncArg1 0x44
#define C218rx_size 0x2000 /* 8K bytes */
#define C218tx_size 0x8000 /* 32K bytes */
#define C218rx_mask (C218rx_size - 1)
#define C218tx_mask (C218tx_size - 1)
#define C320p8rx_size 0x2000
#define C320p8tx_size 0x8000
#define C320p8rx_mask (C320p8rx_size - 1)
#define C320p8tx_mask (C320p8tx_size - 1)
#define C320p16rx_size 0x2000
#define C320p16tx_size 0x4000
#define C320p16rx_mask (C320p16rx_size - 1)
#define C320p16tx_mask (C320p16tx_size - 1)
#define C320p24rx_size 0x2000
#define C320p24tx_size 0x2000
#define C320p24rx_mask (C320p24rx_size - 1)
#define C320p24tx_mask (C320p24tx_size - 1)
#define C320p32rx_size 0x1000
#define C320p32tx_size 0x1000
#define C320p32rx_mask (C320p32rx_size - 1)
#define C320p32tx_mask (C320p32tx_size - 1)
#define Page_size 0x2000U
#define Page_mask (Page_size - 1)
#define C218rx_spage 3
#define C218tx_spage 4
#define C218rx_pageno 1
#define C218tx_pageno 4
#define C218buf_pageno 5
#define C320p8rx_spage 3
#define C320p8tx_spage 4
#define C320p8rx_pgno 1
#define C320p8tx_pgno 4
#define C320p8buf_pgno 5
#define C320p16rx_spage 3
#define C320p16tx_spage 4
#define C320p16rx_pgno 1
#define C320p16tx_pgno 2
#define C320p16buf_pgno 3
#define C320p24rx_spage 3
#define C320p24tx_spage 4
#define C320p24rx_pgno 1
#define C320p24tx_pgno 1
#define C320p24buf_pgno 2
#define C320p32rx_spage 3
#define C320p32tx_ofs C320p32rx_size
#define C320p32tx_spage 3
#define C320p32buf_pgno 1
/*
* Host Status
*/
#define WakeupRx 0x01
#define WakeupTx 0x02
#define WakeupBreak 0x08
#define WakeupLine 0x10
#define WakeupIntr 0x20
#define WakeupQuit 0x40
#define WakeupEOF 0x80 /* used in VTIME control */
#define WakeupRxTrigger 0x100
#define WakeupTxTrigger 0x200
/*
* Flag status
*/
#define Rx_over 0x01
#define Xoff_state 0x02
#define Tx_flowOff 0x04
#define Tx_enable 0x08
#define CTS_state 0x10
#define DSR_state 0x20
#define DCD_state 0x80
/*
* FlowControl
*/
#define CTS_FlowCtl 1
#define RTS_FlowCtl 2
#define Tx_FlowCtl 4
#define Rx_FlowCtl 8
#define IXM_IXANY 0x10
#define LowWater 128
#define DTR_ON 1
#define RTS_ON 2
#define CTS_ON 1
#define DSR_ON 2
#define DCD_ON 8
/* mode definition */
#define MX_CS8 0x03
#define MX_CS7 0x02
#define MX_CS6 0x01
#define MX_CS5 0x00
#define MX_STOP1 0x00
#define MX_STOP15 0x04
#define MX_STOP2 0x08
#define MX_PARNONE 0x00
#define MX_PAREVEN 0x40
#define MX_PARODD 0xC0
#endif

2757
drivers/tty/mxser.c Normal file

File diff suppressed because it is too large Load diff

150
drivers/tty/mxser.h Normal file
View file

@ -0,0 +1,150 @@
#ifndef _MXSER_H
#define _MXSER_H
/*
* Semi-public control interfaces
*/
/*
* MOXA ioctls
*/
#define MOXA 0x400
#define MOXA_GETDATACOUNT (MOXA + 23)
#define MOXA_DIAGNOSE (MOXA + 50)
#define MOXA_CHKPORTENABLE (MOXA + 60)
#define MOXA_HighSpeedOn (MOXA + 61)
#define MOXA_GET_MAJOR (MOXA + 63)
#define MOXA_GETMSTATUS (MOXA + 65)
#define MOXA_SET_OP_MODE (MOXA + 66)
#define MOXA_GET_OP_MODE (MOXA + 67)
#define RS232_MODE 0
#define RS485_2WIRE_MODE 1
#define RS422_MODE 2
#define RS485_4WIRE_MODE 3
#define OP_MODE_MASK 3
#define MOXA_SDS_RSTICOUNTER (MOXA + 69)
#define MOXA_ASPP_OQUEUE (MOXA + 70)
#define MOXA_ASPP_MON (MOXA + 73)
#define MOXA_ASPP_LSTATUS (MOXA + 74)
#define MOXA_ASPP_MON_EXT (MOXA + 75)
#define MOXA_SET_BAUD_METHOD (MOXA + 76)
/* --------------------------------------------------- */
#define NPPI_NOTIFY_PARITY 0x01
#define NPPI_NOTIFY_FRAMING 0x02
#define NPPI_NOTIFY_HW_OVERRUN 0x04
#define NPPI_NOTIFY_SW_OVERRUN 0x08
#define NPPI_NOTIFY_BREAK 0x10
#define NPPI_NOTIFY_CTSHOLD 0x01 /* Tx hold by CTS low */
#define NPPI_NOTIFY_DSRHOLD 0x02 /* Tx hold by DSR low */
#define NPPI_NOTIFY_XOFFHOLD 0x08 /* Tx hold by Xoff received */
#define NPPI_NOTIFY_XOFFXENT 0x10 /* Xoff Sent */
/* follow just for Moxa Must chip define. */
/* */
/* when LCR register (offset 0x03) write following value, */
/* the Must chip will enter enchance mode. And write value */
/* on EFR (offset 0x02) bit 6,7 to change bank. */
#define MOXA_MUST_ENTER_ENCHANCE 0xBF
/* when enhance mode enable, access on general bank register */
#define MOXA_MUST_GDL_REGISTER 0x07
#define MOXA_MUST_GDL_MASK 0x7F
#define MOXA_MUST_GDL_HAS_BAD_DATA 0x80
#define MOXA_MUST_LSR_RERR 0x80 /* error in receive FIFO */
/* enchance register bank select and enchance mode setting register */
/* when LCR register equal to 0xBF */
#define MOXA_MUST_EFR_REGISTER 0x02
/* enchance mode enable */
#define MOXA_MUST_EFR_EFRB_ENABLE 0x10
/* enchance reister bank set 0, 1, 2 */
#define MOXA_MUST_EFR_BANK0 0x00
#define MOXA_MUST_EFR_BANK1 0x40
#define MOXA_MUST_EFR_BANK2 0x80
#define MOXA_MUST_EFR_BANK3 0xC0
#define MOXA_MUST_EFR_BANK_MASK 0xC0
/* set XON1 value register, when LCR=0xBF and change to bank0 */
#define MOXA_MUST_XON1_REGISTER 0x04
/* set XON2 value register, when LCR=0xBF and change to bank0 */
#define MOXA_MUST_XON2_REGISTER 0x05
/* set XOFF1 value register, when LCR=0xBF and change to bank0 */
#define MOXA_MUST_XOFF1_REGISTER 0x06
/* set XOFF2 value register, when LCR=0xBF and change to bank0 */
#define MOXA_MUST_XOFF2_REGISTER 0x07
#define MOXA_MUST_RBRTL_REGISTER 0x04
#define MOXA_MUST_RBRTH_REGISTER 0x05
#define MOXA_MUST_RBRTI_REGISTER 0x06
#define MOXA_MUST_THRTL_REGISTER 0x07
#define MOXA_MUST_ENUM_REGISTER 0x04
#define MOXA_MUST_HWID_REGISTER 0x05
#define MOXA_MUST_ECR_REGISTER 0x06
#define MOXA_MUST_CSR_REGISTER 0x07
/* good data mode enable */
#define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20
/* only good data put into RxFIFO */
#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10
/* enable CTS interrupt */
#define MOXA_MUST_IER_ECTSI 0x80
/* enable RTS interrupt */
#define MOXA_MUST_IER_ERTSI 0x40
/* enable Xon/Xoff interrupt */
#define MOXA_MUST_IER_XINT 0x20
/* enable GDA interrupt */
#define MOXA_MUST_IER_EGDAI 0x10
#define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
/* GDA interrupt pending */
#define MOXA_MUST_IIR_GDA 0x1C
#define MOXA_MUST_IIR_RDA 0x04
#define MOXA_MUST_IIR_RTO 0x0C
#define MOXA_MUST_IIR_LSR 0x06
/* recieved Xon/Xoff or specical interrupt pending */
#define MOXA_MUST_IIR_XSC 0x10
/* RTS/CTS change state interrupt pending */
#define MOXA_MUST_IIR_RTSCTS 0x20
#define MOXA_MUST_IIR_MASK 0x3E
#define MOXA_MUST_MCR_XON_FLAG 0x40
#define MOXA_MUST_MCR_XON_ANY 0x80
#define MOXA_MUST_MCR_TX_XON 0x08
/* software flow control on chip mask value */
#define MOXA_MUST_EFR_SF_MASK 0x0F
/* send Xon1/Xoff1 */
#define MOXA_MUST_EFR_SF_TX1 0x08
/* send Xon2/Xoff2 */
#define MOXA_MUST_EFR_SF_TX2 0x04
/* send Xon1,Xon2/Xoff1,Xoff2 */
#define MOXA_MUST_EFR_SF_TX12 0x0C
/* don't send Xon/Xoff */
#define MOXA_MUST_EFR_SF_TX_NO 0x00
/* Tx software flow control mask */
#define MOXA_MUST_EFR_SF_TX_MASK 0x0C
/* don't receive Xon/Xoff */
#define MOXA_MUST_EFR_SF_RX_NO 0x00
/* receive Xon1/Xoff1 */
#define MOXA_MUST_EFR_SF_RX1 0x02
/* receive Xon2/Xoff2 */
#define MOXA_MUST_EFR_SF_RX2 0x01
/* receive Xon1,Xon2/Xoff1,Xoff2 */
#define MOXA_MUST_EFR_SF_RX12 0x03
/* Rx software flow control mask */
#define MOXA_MUST_EFR_SF_RX_MASK 0x03
#endif

View file

@ -1250,8 +1250,7 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
{
struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1,
gsm->ftype|PF);
struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1, gsm->ftype);
if (msg == NULL)
return;
msg->data[0] = (ctrl->cmd << 1) | 2 | EA; /* command */
@ -2649,13 +2648,13 @@ static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
to do here */
}
static int gsmtty_tiocmget(struct tty_struct *tty, struct file *filp)
static int gsmtty_tiocmget(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
return dlci->modem_rx;
}
static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp,
static int gsmtty_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct gsm_dlci *dlci = tty->driver_data;
@ -2672,7 +2671,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp,
}
static int gsmtty_ioctl(struct tty_struct *tty, struct file *filp,
static int gsmtty_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
return -ENOIOCTLCMD;

View file

@ -97,7 +97,6 @@
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/string.h> /* used in new tty drivers */
#include <linux/signal.h> /* used in new tty drivers */
#include <linux/if.h>

View file

@ -57,7 +57,6 @@
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/string.h> /* used in new tty drivers */

1991
drivers/tty/nozomi.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,6 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/sysctl.h>
#include <linux/device.h>
#include <linux/uaccess.h>
@ -334,7 +333,7 @@ free_mem_out:
return -ENOMEM;
}
static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
static int pty_bsd_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
@ -489,7 +488,7 @@ static struct ctl_table pty_root_table[] = {
};
static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
static int pty_unix98_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {

3199
drivers/tty/rocket.c Normal file

File diff suppressed because it is too large Load diff

111
drivers/tty/rocket.h Normal file
View file

@ -0,0 +1,111 @@
/*
* rocket.h --- the exported interface of the rocket driver to its configuration program.
*
* Written by Theodore Ts'o, Copyright 1997.
* Copyright 1997 Comtrol Corporation.
*
*/
/* Model Information Struct */
typedef struct {
unsigned long model;
char modelString[80];
unsigned long numPorts;
int loadrm2;
int startingPortNumber;
} rocketModel_t;
struct rocket_config {
int line;
int flags;
int closing_wait;
int close_delay;
int port;
int reserved[32];
};
struct rocket_ports {
int tty_major;
int callout_major;
rocketModel_t rocketModel[8];
};
struct rocket_version {
char rocket_version[32];
char rocket_date[32];
char reserved[64];
};
/*
* Rocketport flags
*/
/*#define ROCKET_CALLOUT_NOHUP 0x00000001 */
#define ROCKET_FORCE_CD 0x00000002
#define ROCKET_HUP_NOTIFY 0x00000004
#define ROCKET_SPLIT_TERMIOS 0x00000008
#define ROCKET_SPD_MASK 0x00000070
#define ROCKET_SPD_HI 0x00000010 /* Use 56000 instead of 38400 bps */
#define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps */
#define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps */
#define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps */
#define ROCKET_SAK 0x00000080
#define ROCKET_SESSION_LOCKOUT 0x00000100
#define ROCKET_PGRP_LOCKOUT 0x00000200
#define ROCKET_RTS_TOGGLE 0x00000400
#define ROCKET_MODE_MASK 0x00003000
#define ROCKET_MODE_RS232 0x00000000
#define ROCKET_MODE_RS485 0x00001000
#define ROCKET_MODE_RS422 0x00002000
#define ROCKET_FLAGS 0x00003FFF
#define ROCKET_USR_MASK 0x0071 /* Legal flags that non-privileged
* users can set or reset */
/*
* For closing_wait and closing_wait2
*/
#define ROCKET_CLOSING_WAIT_NONE ASYNC_CLOSING_WAIT_NONE
#define ROCKET_CLOSING_WAIT_INF ASYNC_CLOSING_WAIT_INF
/*
* Rocketport ioctls -- "RP"
*/
#define RCKP_GET_STRUCT 0x00525001
#define RCKP_GET_CONFIG 0x00525002
#define RCKP_SET_CONFIG 0x00525003
#define RCKP_GET_PORTS 0x00525004
#define RCKP_RESET_RM2 0x00525005
#define RCKP_GET_VERSION 0x00525006
/* Rocketport Models */
#define MODEL_RP32INTF 0x0001 /* RP 32 port w/external I/F */
#define MODEL_RP8INTF 0x0002 /* RP 8 port w/external I/F */
#define MODEL_RP16INTF 0x0003 /* RP 16 port w/external I/F */
#define MODEL_RP8OCTA 0x0005 /* RP 8 port w/octa cable */
#define MODEL_RP4QUAD 0x0004 /* RP 4 port w/quad cable */
#define MODEL_RP8J 0x0006 /* RP 8 port w/RJ11 connectors */
#define MODEL_RP4J 0x0007 /* RP 4 port w/RJ45 connectors */
#define MODEL_RP8SNI 0x0008 /* RP 8 port w/ DB78 SNI connector */
#define MODEL_RP16SNI 0x0009 /* RP 16 port w/ DB78 SNI connector */
#define MODEL_RPP4 0x000A /* RP Plus 4 port */
#define MODEL_RPP8 0x000B /* RP Plus 8 port */
#define MODEL_RP2_232 0x000E /* RP Plus 2 port RS232 */
#define MODEL_RP2_422 0x000F /* RP Plus 2 port RS232 */
/* Rocketmodem II Models */
#define MODEL_RP6M 0x000C /* RM 6 port */
#define MODEL_RP4M 0x000D /* RM 4 port */
/* Universal PCI boards */
#define MODEL_UPCI_RP32INTF 0x0801 /* RP UPCI 32 port w/external I/F */
#define MODEL_UPCI_RP8INTF 0x0802 /* RP UPCI 8 port w/external I/F */
#define MODEL_UPCI_RP16INTF 0x0803 /* RP UPCI 16 port w/external I/F */
#define MODEL_UPCI_RP8OCTA 0x0805 /* RP UPCI 8 port w/octa cable */
#define MODEL_UPCI_RM3_8PORT 0x080C /* RP UPCI Rocketmodem III 8 port */
#define MODEL_UPCI_RM3_4PORT 0x080C /* RP UPCI Rocketmodem III 4 port */
/* Compact PCI 16 port */
#define MODEL_CPCI_RP16INTF 0x0903 /* RP Compact PCI 16 port w/external I/F */
/* All ISA boards */
#define MODEL_ISA 0x1000

1214
drivers/tty/rocket_int.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -262,7 +262,7 @@ static void status_handle(struct m68k_serial *info, unsigned short status)
static void receive_chars(struct m68k_serial *info, unsigned short rx)
{
struct tty_struct *tty = info->port.tty;
struct tty_struct *tty = info->tty;
m68328_uart *uart = &uart_addr[info->line];
unsigned char ch, flag;
@ -329,7 +329,7 @@ static void transmit_chars(struct m68k_serial *info)
goto clear_and_return;
}
if((info->xmit_cnt <= 0) || info->port.tty->stopped) {
if((info->xmit_cnt <= 0) || info->tty->stopped) {
/* That's peculiar... TX ints off */
uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
goto clear_and_return;
@ -383,7 +383,7 @@ static void do_softint(struct work_struct *work)
struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue);
struct tty_struct *tty;
tty = info->port.tty;
tty = info->tty;
if (!tty)
return;
#if 0
@ -393,28 +393,6 @@ static void do_softint(struct work_struct *work)
#endif
}
/*
* This routine is called from the scheduler tqueue when the interrupt
* routine has signalled that a hangup has occurred. The path of
* hangup processing is:
*
* serial interrupt routine -> (scheduler tqueue) ->
* do_serial_hangup() -> tty->hangup() -> rs_hangup()
*
*/
static void do_serial_hangup(struct work_struct *work)
{
struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue_hangup);
struct tty_struct *tty;
tty = info->port.tty;
if (!tty)
return;
tty_hangup(tty);
}
static int startup(struct m68k_serial * info)
{
m68328_uart *uart = &uart_addr[info->line];
@ -451,8 +429,8 @@ static int startup(struct m68k_serial * info)
uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
#endif
if (info->port.tty)
clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
/*
@ -486,8 +464,8 @@ static void shutdown(struct m68k_serial * info)
info->xmit_buf = 0;
}
if (info->port.tty)
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags &= ~S_INITIALIZED;
local_irq_restore(flags);
@ -553,9 +531,9 @@ static void change_speed(struct m68k_serial *info)
unsigned cflag;
int i;
if (!info->port.tty || !info->port.tty->termios)
if (!info->tty || !info->tty->termios)
return;
cflag = info->port.tty->termios->c_cflag;
cflag = info->tty->termios->c_cflag;
if (!(port = info->port))
return;
@ -967,10 +945,9 @@ static void send_break(struct m68k_serial * info, unsigned int duration)
local_irq_restore(flags);
}
static int rs_ioctl(struct tty_struct *tty, struct file * file,
static int rs_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
int error;
struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
int retval;
@ -1104,7 +1081,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
tty_ldisc_flush(tty);
tty->closing = 0;
info->event = 0;
info->port.tty = NULL;
info->tty = NULL;
#warning "This is not and has never been valid so fix it"
#if 0
if (tty->ldisc.num != ldiscs[N_TTY].num) {
@ -1142,7 +1119,7 @@ void rs_hangup(struct tty_struct *tty)
info->event = 0;
info->count = 0;
info->flags &= ~S_NORMAL_ACTIVE;
info->port.tty = NULL;
info->tty = NULL;
wake_up_interruptible(&info->open_wait);
}
@ -1261,7 +1238,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
info->count++;
tty->driver_data = info;
info->port.tty = tty;
info->tty = tty;
/*
* Start up serial port
@ -1338,7 +1315,7 @@ rs68328_init(void)
info = &m68k_soft[i];
info->magic = SERIAL_MAGIC;
info->port = (int) &uart_addr[i];
info->port.tty = NULL;
info->tty = NULL;
info->irq = uart_irqs[i];
info->custom_divisor = 16;
info->close_delay = 50;
@ -1348,7 +1325,6 @@ rs68328_init(void)
info->count = 0;
info->blocked_open = 0;
INIT_WORK(&info->tqueue, do_softint);
INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
info->line = i;

View file

@ -159,7 +159,6 @@ struct m68k_serial {
int xmit_tail;
int xmit_cnt;
struct work_struct tqueue;
struct work_struct tqueue_hangup;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
};

View file

@ -1240,7 +1240,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int *value)
}
#endif
static int rs_360_tiocmget(struct tty_struct *tty, struct file *file)
static int rs_360_tiocmget(struct tty_struct *tty)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
unsigned int result = 0;
@ -1271,7 +1271,7 @@ static int rs_360_tiocmget(struct tty_struct *tty, struct file *file)
return result;
}
static int rs_360_tiocmset(struct tty_struct *tty, struct file *file,
static int rs_360_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
#ifdef modem_control
@ -1405,7 +1405,7 @@ static int rs_360_get_icount(struct tty_struct *tty,
return 0;
}
static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
static int rs_360_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
int error;

View file

@ -954,6 +954,23 @@ static int broken_efr(struct uart_8250_port *up)
return 0;
}
static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
{
unsigned char status;
status = serial_in(up, 0x04); /* EXCR2 */
#define PRESL(x) ((x) & 0x30)
if (PRESL(status) == 0x10) {
/* already in high speed mode */
return 0;
} else {
status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
serial_outp(up, 0x04, status);
}
return 1;
}
/*
* We know that the chip has FIFOs. Does it have an EFR? The
* EFR is located in the same register position as the IIR and
@ -1025,12 +1042,8 @@ static void autoconfig_16550a(struct uart_8250_port *up)
quot = serial_dl_read(up);
quot <<= 3;
status1 = serial_in(up, 0x04); /* EXCR2 */
status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
serial_outp(up, 0x04, status1);
serial_dl_write(up, quot);
if (ns16550a_goto_highspeed(up))
serial_dl_write(up, quot);
serial_outp(up, UART_LCR, 0);
@ -3025,17 +3038,13 @@ void serial8250_resume_port(int line)
struct uart_8250_port *up = &serial8250_ports[line];
if (up->capabilities & UART_NATSEMI) {
unsigned char tmp;
/* Ensure it's still in high speed mode */
serial_outp(up, UART_LCR, 0xE0);
tmp = serial_in(up, 0x04); /* EXCR2 */
tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
tmp |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
serial_outp(up, 0x04, tmp);
ns16550a_goto_highspeed(up);
serial_outp(up, UART_LCR, 0);
up->port.uartclk = 921600*16;
}
uart_resume_port(&serial8250_reg, &up->port);
}

View file

@ -1110,29 +1110,6 @@ config SERIAL_PMACZILOG_CONSOLE
on your (Power)Mac as the console, you can do so by answering
Y to this option.
config SERIAL_LH7A40X
tristate "Sharp LH7A40X embedded UART support"
depends on ARM && ARCH_LH7A40X
select SERIAL_CORE
help
This enables support for the three on-board UARTs of the
Sharp LH7A40X series CPUs. Choose Y or M.
config SERIAL_LH7A40X_CONSOLE
bool "Support for console on Sharp LH7A40X serial port"
depends on SERIAL_LH7A40X=y
select SERIAL_CORE_CONSOLE
help
Say Y here if you wish to use one of the serial ports as the
system console--the system console is the device which
receives all kernel messages and warnings and which allows
logins in single user mode.
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the default system console, but
you can alter that using a kernel command line, for example
"console=ttyAM1".
config SERIAL_CPM
tristate "CPM SCC/SMC serial port support"
depends on CPM2 || 8xx
@ -1319,6 +1296,18 @@ config SERIAL_MSM_CONSOLE
depends on SERIAL_MSM=y
select SERIAL_CORE_CONSOLE
config SERIAL_MSM_HS
tristate "MSM UART High Speed: Serial Driver"
depends on ARCH_MSM
select SERIAL_CORE
help
If you have a machine based on MSM family of SoCs, you
can enable its onboard high speed serial port by enabling
this option.
Choose M here to compile it as a module. The module will be
called msm_serial_hs.
config SERIAL_VT8500
bool "VIA VT8500 on-chip serial port support"
depends on ARM && ARCH_VT8500
@ -1588,12 +1577,25 @@ config SERIAL_IFX6X60
Support for the IFX6x60 modem devices on Intel MID platforms.
config SERIAL_PCH_UART
tristate "Intel EG20T PCH UART"
depends on PCI && DMADEVICES
tristate "Intel EG20T PCH UART/OKI SEMICONDUCTOR ML7213 IOH"
depends on PCI
select SERIAL_CORE
select PCH_DMA
help
This driver is for PCH(Platform controller Hub) UART of Intel EG20T
which is an IOH(Input/Output Hub) for x86 embedded processor.
Enabling PCH_DMA, this PCH UART works as DMA mode.
This driver also can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/
Output Hub) which is for IVI(In-Vehicle Infotainment) use.
ML7213 is companion chip for Intel Atom E6xx series.
ML7213 is completely compatible for Intel EG20T PCH.
config SERIAL_MSM_SMD
bool "Enable tty device interface for some SMD ports"
default n
depends on MSM_SMD
help
Enables userspace clients to read and write to some streaming SMD
ports via tty device interface for MSM chipset.
endmenu

View file

@ -54,7 +54,6 @@ obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_68360) += 68360serial.o
obj-$(CONFIG_SERIAL_MCF) += mcf.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
obj-$(CONFIG_SERIAL_DZ) += dz.o
obj-$(CONFIG_SERIAL_ZS) += zs.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
@ -76,6 +75,7 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
obj-$(CONFIG_SERIAL_MSM_HS) += msm_serial_hs.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
@ -92,3 +92,4 @@ obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o

View file

@ -305,28 +305,6 @@ static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart
*platp)
{
struct uart_port *port;
int i;
for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_jtaguart_ports[i].port;
port->line = i;
port->type = PORT_ALTERA_JTAGUART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->flags = ASYNC_BOOT_AUTOCONF;
port->ops = &altera_jtaguart_ops;
}
return 0;
}
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
static void altera_jtaguart_console_putc(struct console *co, const char c)
{
@ -384,7 +362,7 @@ static int __init altera_jtaguart_console_setup(struct console *co,
if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
return -EINVAL;
port = &altera_jtaguart_ports[co->index].port;
if (port->membase == 0)
if (port->membase == NULL)
return -ENODEV;
return 0;
}
@ -431,22 +409,45 @@ static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
{
struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
struct uart_port *port;
int i;
struct resource *res_irq, *res_mem;
int i = pdev->id;
for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_jtaguart_ports[i].port;
/* -1 emphasizes that the platform must have one port, no .N suffix */
if (i == -1)
i = 0;
port->line = i;
port->type = PORT_ALTERA_JTAGUART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->ops = &altera_jtaguart_ops;
port->flags = ASYNC_BOOT_AUTOCONF;
if (i >= ALTERA_JTAGUART_MAXPORTS)
return -EINVAL;
uart_add_one_port(&altera_jtaguart_driver, port);
}
port = &altera_jtaguart_ports[i].port;
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res_mem)
port->mapbase = res_mem->start;
else if (platp)
port->mapbase = platp->mapbase;
else
return -ENODEV;
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res_irq)
port->irq = res_irq->start;
else if (platp)
port->irq = platp->irq;
else
return -ENODEV;
port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
if (!port->membase)
return -ENOMEM;
port->line = i;
port->type = PORT_ALTERA_JTAGUART;
port->iotype = SERIAL_IO_MEM;
port->ops = &altera_jtaguart_ops;
port->flags = UPF_BOOT_AUTOCONF;
uart_add_one_port(&altera_jtaguart_driver, port);
return 0;
}
@ -454,23 +455,34 @@ static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
static int __devexit altera_jtaguart_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i;
int i = pdev->id;
for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) {
port = &altera_jtaguart_ports[i].port;
if (port)
uart_remove_one_port(&altera_jtaguart_driver, port);
}
if (i == -1)
i = 0;
port = &altera_jtaguart_ports[i].port;
uart_remove_one_port(&altera_jtaguart_driver, port);
return 0;
}
#ifdef CONFIG_OF
static struct of_device_id altera_jtaguart_match[] = {
{ .compatible = "ALTR,juart-1.0", },
{},
};
MODULE_DEVICE_TABLE(of, altera_jtaguart_match);
#else
#define altera_jtaguart_match NULL
#endif /* CONFIG_OF */
static struct platform_driver altera_jtaguart_platform_driver = {
.probe = altera_jtaguart_probe,
.remove = __devexit_p(altera_jtaguart_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = altera_jtaguart_match,
},
};

View file

@ -24,6 +24,7 @@
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/io.h>
#include <linux/altera_uart.h>
@ -86,16 +87,12 @@ struct altera_uart {
static u32 altera_uart_readl(struct uart_port *port, int reg)
{
struct altera_uart_platform_uart *platp = port->private_data;
return readl(port->membase + (reg << platp->bus_shift));
return readl(port->membase + (reg << port->regshift));
}
static void altera_uart_writel(struct uart_port *port, u32 dat, int reg)
{
struct altera_uart_platform_uart *platp = port->private_data;
writel(dat, port->membase + (reg << platp->bus_shift));
writel(dat, port->membase + (reg << port->regshift));
}
static unsigned int altera_uart_tx_empty(struct uart_port *port)
@ -511,6 +508,29 @@ static struct uart_driver altera_uart_driver = {
.cons = ALTERA_UART_CONSOLE,
};
#ifdef CONFIG_OF
static int altera_uart_get_of_uartclk(struct platform_device *pdev,
struct uart_port *port)
{
int len;
const __be32 *clk;
clk = of_get_property(pdev->dev.of_node, "clock-frequency", &len);
if (!clk || len < sizeof(__be32))
return -ENODEV;
port->uartclk = be32_to_cpup(clk);
return 0;
}
#else
static int altera_uart_get_of_uartclk(struct platform_device *pdev,
struct uart_port *port)
{
return -ENODEV;
}
#endif /* CONFIG_OF */
static int __devinit altera_uart_probe(struct platform_device *pdev)
{
struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
@ -518,6 +538,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
struct resource *res_mem;
struct resource *res_irq;
int i = pdev->id;
int ret;
/* -1 emphasizes that the platform must have one port, no .N suffix */
if (i == -1)
@ -542,17 +563,29 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
else if (platp->irq)
port->irq = platp->irq;
/* Check platform data first so we can override device node data */
if (platp)
port->uartclk = platp->uartclk;
else {
ret = altera_uart_get_of_uartclk(pdev, port);
if (ret)
return ret;
}
port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
if (!port->membase)
return -ENOMEM;
if (platp)
port->regshift = platp->bus_shift;
else
port->regshift = 0;
port->line = i;
port->type = PORT_ALTERA_UART;
port->iotype = SERIAL_IO_MEM;
port->uartclk = platp->uartclk;
port->ops = &altera_uart_ops;
port->flags = UPF_BOOT_AUTOCONF;
port->private_data = platp;
uart_add_one_port(&altera_uart_driver, port);
@ -561,19 +594,35 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
static int __devexit altera_uart_remove(struct platform_device *pdev)
{
struct uart_port *port = &altera_uart_ports[pdev->id].port;
struct uart_port *port;
int i = pdev->id;
if (i == -1)
i = 0;
port = &altera_uart_ports[i].port;
uart_remove_one_port(&altera_uart_driver, port);
return 0;
}
#ifdef CONFIG_OF
static struct of_device_id altera_uart_match[] = {
{ .compatible = "ALTR,uart-1.0", },
{},
};
MODULE_DEVICE_TABLE(of, altera_uart_match);
#else
#define altera_uart_match NULL
#endif /* CONFIG_OF */
static struct platform_driver altera_uart_platform_driver = {
.probe = altera_uart_probe,
.remove = __devexit_p(altera_uart_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = NULL,
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = altera_uart_match,
},
};

View file

@ -553,8 +553,7 @@ static struct uart_driver grlib_apbuart_driver = {
/* OF Platform Driver */
/* ======================================================================== */
static int __devinit apbuart_probe(struct platform_device *op,
const struct of_device_id *match)
static int __devinit apbuart_probe(struct platform_device *op)
{
int i = -1;
struct uart_port *port = NULL;
@ -587,7 +586,7 @@ static struct of_device_id __initdata apbuart_match[] = {
{},
};
static struct of_platform_driver grlib_apbuart_of_driver = {
static struct platform_driver grlib_apbuart_of_driver = {
.probe = apbuart_probe,
.driver = {
.owner = THIS_MODULE,
@ -676,10 +675,10 @@ static int __init grlib_apbuart_init(void)
return ret;
}
ret = of_register_platform_driver(&grlib_apbuart_of_driver);
ret = platform_driver_register(&grlib_apbuart_of_driver);
if (ret) {
printk(KERN_ERR
"%s: of_register_platform_driver failed (%i)\n",
"%s: platform_driver_register failed (%i)\n",
__FILE__, ret);
uart_unregister_driver(&grlib_apbuart_driver);
return ret;
@ -697,7 +696,7 @@ static void __exit grlib_apbuart_exit(void)
&grlib_apbuart_ports[i]);
uart_unregister_driver(&grlib_apbuart_driver);
of_unregister_platform_driver(&grlib_apbuart_of_driver);
platform_driver_unregister(&grlib_apbuart_of_driver);
}
module_init(grlib_apbuart_init);

View file

@ -1240,6 +1240,21 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
spin_unlock_irqrestore(&port->lock, flags);
}
static void atmel_set_ldisc(struct uart_port *port, int new)
{
int line = port->line;
if (line >= port->state->port.tty->driver->num)
return;
if (port->state->port.tty->ldisc->ops->num == N_PPS) {
port->flags |= UPF_HARDPPS_CD;
atmel_enable_ms(port);
} else {
port->flags &= ~UPF_HARDPPS_CD;
}
}
/*
* Return string describing the specified port
*/
@ -1380,6 +1395,7 @@ static struct uart_ops atmel_pops = {
.shutdown = atmel_shutdown,
.flush_buffer = atmel_flush_buffer,
.set_termios = atmel_set_termios,
.set_ldisc = atmel_set_ldisc,
.type = atmel_type,
.release_port = atmel_release_port,
.request_port = atmel_request_port,

View file

@ -788,7 +788,7 @@ static int __devinit sport_uart_probe(struct platform_device *pdev)
sport->port.mapbase = res->start;
sport->port.irq = platform_get_irq(pdev, 0);
if (sport->port.irq < 0) {
if ((int)sport->port.irq < 0) {
dev_err(&pdev->dev, "No sport RX/TX IRQ specified\n");
ret = -ENOENT;
goto out_error_unmap;

View file

@ -1359,8 +1359,7 @@ static struct uart_driver cpm_reg = {
static int probe_index;
static int __devinit cpm_uart_probe(struct platform_device *ofdev,
const struct of_device_id *match)
static int __devinit cpm_uart_probe(struct platform_device *ofdev)
{
int index = probe_index++;
struct uart_cpm_port *pinfo = &cpm_uart_ports[index];
@ -1405,7 +1404,7 @@ static struct of_device_id cpm_uart_match[] = {
{}
};
static struct of_platform_driver cpm_uart_driver = {
static struct platform_driver cpm_uart_driver = {
.driver = {
.name = "cpm_uart",
.owner = THIS_MODULE,
@ -1421,7 +1420,7 @@ static int __init cpm_uart_init(void)
if (ret)
return ret;
ret = of_register_platform_driver(&cpm_uart_driver);
ret = platform_driver_register(&cpm_uart_driver);
if (ret)
uart_unregister_driver(&cpm_reg);
@ -1430,7 +1429,7 @@ static int __init cpm_uart_init(void)
static void __exit cpm_uart_exit(void)
{
of_unregister_platform_driver(&cpm_uart_driver);
platform_driver_unregister(&cpm_uart_driver);
uart_unregister_driver(&cpm_reg);
}

View file

@ -3581,8 +3581,7 @@ rs_break(struct tty_struct *tty, int break_state)
}
static int
rs_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
rs_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned long flags;
@ -3614,7 +3613,7 @@ rs_tiocmset(struct tty_struct *tty, struct file *file,
}
static int
rs_tiocmget(struct tty_struct *tty, struct file *file)
rs_tiocmget(struct tty_struct *tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned int result;
@ -3648,7 +3647,7 @@ rs_tiocmget(struct tty_struct *tty, struct file *file)
static int
rs_ioctl(struct tty_struct *tty, struct file * file,
rs_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct e100_serial * info = (struct e100_serial *)tty->driver_data;

View file

@ -8,7 +8,7 @@
* Jan Dumon <j.dumon@option.com>
*
* Copyright (C) 2009, 2010 Intel Corp
* Russ Gorby <richardx.r.gorby@intel.com>
* Russ Gorby <russ.gorby@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -67,6 +67,7 @@
#define IFX_SPI_MORE_MASK 0x10
#define IFX_SPI_MORE_BIT 12 /* bit position in u16 */
#define IFX_SPI_CTS_BIT 13 /* bit position in u16 */
#define IFX_SPI_MODE SPI_MODE_1
#define IFX_SPI_TTY_ID 0
#define IFX_SPI_TIMEOUT_SEC 2
#define IFX_SPI_HEADER_0 (-1)
@ -76,7 +77,7 @@
static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev);
/* local variables */
static int spi_b16 = 1; /* 8 or 16 bit word length */
static int spi_bpw = 16; /* 8, 16 or 32 bit word length */
static struct tty_driver *tty_drv;
static struct ifx_spi_device *saved_ifx_dev;
static struct lock_class_key ifx_spi_key;
@ -244,7 +245,7 @@ static void ifx_spi_timeout(unsigned long arg)
* Map the signal state into Linux modem flags and report the value
* in Linux terms
*/
static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp)
static int ifx_spi_tiocmget(struct tty_struct *tty)
{
unsigned int value;
struct ifx_spi_device *ifx_dev = tty->driver_data;
@ -262,7 +263,6 @@ static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp)
/**
* ifx_spi_tiocmset - set modem bits
* @tty: the tty structure
* @filp: file handle issuing the request
* @set: bits to set
* @clear: bits to clear
*
@ -271,7 +271,7 @@ static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp)
*
* FIXME: do we need to kick the tranfers when we do this ?
*/
static int ifx_spi_tiocmset(struct tty_struct *tty, struct file *filp,
static int ifx_spi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct ifx_spi_device *ifx_dev = tty->driver_data;
@ -722,9 +722,9 @@ static void ifx_spi_io(unsigned long data)
/* note len is BYTES, not transfers */
ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE;
ifx_dev->spi_xfer.cs_change = 0;
ifx_dev->spi_xfer.speed_hz = 12500000;
ifx_dev->spi_xfer.speed_hz = ifx_dev->spi_dev->max_speed_hz;
/* ifx_dev->spi_xfer.speed_hz = 390625; */
ifx_dev->spi_xfer.bits_per_word = spi_b16 ? 16 : 8;
ifx_dev->spi_xfer.bits_per_word = spi_bpw;
ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer;
ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer;
@ -732,7 +732,7 @@ static void ifx_spi_io(unsigned long data)
/*
* setup dma pointers
*/
if (ifx_dev->is_6160) {
if (ifx_dev->use_dma) {
ifx_dev->spi_msg.is_dma_mapped = 1;
ifx_dev->tx_dma = ifx_dev->tx_bus;
ifx_dev->rx_dma = ifx_dev->rx_bus;
@ -798,8 +798,8 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
goto error_ret;
}
pport->ops = &ifx_tty_port_ops;
tty_port_init(pport);
pport->ops = &ifx_tty_port_ops;
ifx_dev->minor = IFX_SPI_TTY_ID;
ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
&ifx_dev->spi_dev->dev);
@ -960,7 +960,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
{
int ret;
int srdy;
struct ifx_modem_platform_data *pl_data = NULL;
struct ifx_modem_platform_data *pl_data;
struct ifx_spi_device *ifx_dev;
if (saved_ifx_dev) {
@ -968,6 +968,12 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
return -ENODEV;
}
pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data;
if (!pl_data) {
dev_err(&spi->dev, "missing platform data!");
return -ENODEV;
}
/* initialize structure to hold our device variables */
ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL);
if (!ifx_dev) {
@ -983,14 +989,25 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
init_timer(&ifx_dev->spi_timer);
ifx_dev->spi_timer.function = ifx_spi_timeout;
ifx_dev->spi_timer.data = (unsigned long)ifx_dev;
ifx_dev->is_6160 = pl_data->is_6160;
ifx_dev->modem = pl_data->modem_type;
ifx_dev->use_dma = pl_data->use_dma;
ifx_dev->max_hz = pl_data->max_hz;
/* initialize spi mode, etc */
spi->max_speed_hz = ifx_dev->max_hz;
spi->mode = IFX_SPI_MODE | (SPI_LOOP & spi->mode);
spi->bits_per_word = spi_bpw;
ret = spi_setup(spi);
if (ret) {
dev_err(&spi->dev, "SPI setup wasn't successful %d", ret);
return -ENODEV;
}
/* ensure SPI protocol flags are initialized to enable transfer */
ifx_dev->spi_more = 0;
ifx_dev->spi_slave_cts = 0;
/*initialize transfer and dma buffers */
ifx_dev->tx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
ifx_dev->tx_buffer = dma_alloc_coherent(ifx_dev->spi_dev->dev.parent,
IFX_SPI_TRANSFER_SIZE,
&ifx_dev->tx_bus,
GFP_KERNEL);
@ -999,7 +1016,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
ret = -ENOMEM;
goto error_ret;
}
ifx_dev->rx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
ifx_dev->rx_buffer = dma_alloc_coherent(ifx_dev->spi_dev->dev.parent,
IFX_SPI_TRANSFER_SIZE,
&ifx_dev->rx_bus,
GFP_KERNEL);
@ -1025,18 +1042,11 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
goto error_ret;
}
pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data;
if (pl_data) {
ifx_dev->gpio.reset = pl_data->rst_pmu;
ifx_dev->gpio.po = pl_data->pwr_on;
ifx_dev->gpio.mrdy = pl_data->mrdy;
ifx_dev->gpio.srdy = pl_data->srdy;
ifx_dev->gpio.reset_out = pl_data->rst_out;
} else {
dev_err(&spi->dev, "missing platform data!");
ret = -ENODEV;
goto error_ret;
}
ifx_dev->gpio.reset = pl_data->rst_pmu;
ifx_dev->gpio.po = pl_data->pwr_on;
ifx_dev->gpio.mrdy = pl_data->mrdy;
ifx_dev->gpio.srdy = pl_data->srdy;
ifx_dev->gpio.reset_out = pl_data->rst_out;
dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d",
ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy,
@ -1322,9 +1332,9 @@ static const struct spi_device_id ifx_id_table[] = {
MODULE_DEVICE_TABLE(spi, ifx_id_table);
/* spi operations */
static const struct spi_driver ifx_spi_driver_6160 = {
static const struct spi_driver ifx_spi_driver = {
.driver = {
.name = "ifx6160",
.name = DRVNAME,
.bus = &spi_bus_type,
.pm = &ifx_spi_pm,
.owner = THIS_MODULE},
@ -1346,7 +1356,7 @@ static void __exit ifx_spi_exit(void)
{
/* unregister */
tty_unregister_driver(tty_drv);
spi_unregister_driver((void *)&ifx_spi_driver_6160);
spi_unregister_driver((void *)&ifx_spi_driver);
}
/**
@ -1388,7 +1398,7 @@ static int __init ifx_spi_init(void)
return result;
}
result = spi_register_driver((void *)&ifx_spi_driver_6160);
result = spi_register_driver((void *)&ifx_spi_driver);
if (result) {
pr_err("%s: spi_register_driver failed(%d)",
DRVNAME, result);

View file

@ -29,8 +29,6 @@
#define DRVNAME "ifx6x60"
#define TTYNAME "ttyIFX"
/* #define IFX_THROTTLE_CODE */
#define IFX_SPI_MAX_MINORS 1
#define IFX_SPI_TRANSFER_SIZE 2048
#define IFX_SPI_FIFO_SIZE 4096
@ -88,7 +86,9 @@ struct ifx_spi_device {
dma_addr_t rx_dma;
dma_addr_t tx_dma;
int is_6160; /* Modem type */
int modem; /* Modem type */
int use_dma; /* provide dma-able addrs in SPI msg */
long max_hz; /* max SPI frequency */
spinlock_t write_lock;
int write_pending;

View file

@ -601,7 +601,7 @@ static int max3100_startup(struct uart_port *port)
s->rts = 0;
sprintf(b, "max3100-%d", s->minor);
s->workqueue = create_freezeable_workqueue(b);
s->workqueue = create_freezable_workqueue(b);
if (!s->workqueue) {
dev_warn(&s->spi->dev, "cannot create workqueue\n");
return -EBUSY;

View file

@ -833,7 +833,7 @@ static int max3107_startup(struct uart_port *port)
struct max3107_port *s = container_of(port, struct max3107_port, port);
/* Initialize work queue */
s->workqueue = create_freezeable_workqueue("max3107");
s->workqueue = create_freezable_workqueue("max3107");
if (!s->workqueue) {
dev_err(&s->spi->dev, "Workqueue creation failed\n");
return -EBUSY;

View file

@ -16,9 +16,7 @@
* 2/3 chan to port 1, 4/5 chan to port 3. Even number chans
* are used for RX, odd chans for TX
*
* 2. In A0 stepping, UART will not support TX half empty flag
*
* 3. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
* 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
* asserted, only when the HW is reset the DDCD and DDSR will
* be triggered
*/
@ -41,8 +39,6 @@
#include <linux/io.h>
#include <linux/debugfs.h>
#define MFD_HSU_A0_STEPPING 1
#define HSU_DMA_BUF_SIZE 2048
#define chan_readl(chan, offset) readl(chan->reg + offset)
@ -51,7 +47,10 @@
#define mfd_readl(obj, offset) readl(obj->reg + offset)
#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset)
#define HSU_DMA_TIMEOUT_CHECK_FREQ (HZ/10)
static int hsu_dma_enable;
module_param(hsu_dma_enable, int, 0);
MODULE_PARM_DESC(hsu_dma_enable, "It is a bitmap to set working mode, if \
bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode.");
struct hsu_dma_buffer {
u8 *buf;
@ -65,7 +64,6 @@ struct hsu_dma_chan {
enum dma_data_direction dirt;
struct uart_hsu_port *uport;
void __iomem *reg;
struct timer_list rx_timer; /* only needed by RX channel */
};
struct uart_hsu_port {
@ -355,8 +353,6 @@ void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf
| (0x1 << 24) /* timeout bit, see HSU Errata 1 */
);
chan_writel(rxc, HSU_CH_CR, 0x3);
mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
}
/* Protected by spin_lock_irqsave(port->lock) */
@ -420,7 +416,6 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
chan_writel(chan, HSU_CH_CR, 0x3);
return;
}
del_timer(&chan->rx_timer);
dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
dbuf->dma_size, DMA_FROM_DEVICE);
@ -448,8 +443,6 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
tty_flip_buffer_push(tty);
chan_writel(chan, HSU_CH_CR, 0x3);
chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ;
add_timer(&chan->rx_timer);
}
@ -551,16 +544,9 @@ static void transmit_chars(struct uart_hsu_port *up)
return;
}
#ifndef MFD_HSU_A0_STEPPING
/* The IRQ is for TX FIFO half-empty */
count = up->port.fifosize / 2;
#else
/*
* A0 only supports fully empty IRQ, and the first char written
* into it won't clear the EMPT bit, so we may need be cautious
* by useing a shorter buffer
*/
count = up->port.fifosize - 4;
#endif
do {
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@ -769,9 +755,8 @@ static void serial_hsu_break_ctl(struct uart_port *port, int break_state)
/*
* What special to do:
* 1. chose the 64B fifo mode
* 2. make sure not to select half empty mode for A0 stepping
* 3. start dma or pio depends on configuration
* 4. we only allocate dma memory when needed
* 2. start dma or pio depends on configuration
* 3. we only allocate dma memory when needed
*/
static int serial_hsu_startup(struct uart_port *port)
{
@ -870,8 +855,6 @@ static void serial_hsu_shutdown(struct uart_port *port)
container_of(port, struct uart_hsu_port, port);
unsigned long flags;
del_timer_sync(&up->rxc->rx_timer);
/* Disable interrupts from this port */
up->ier = 0;
serial_out(up, UART_IER, 0);
@ -977,10 +960,6 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B;
fcr |= UART_FCR_HSU_64B_FIFO;
#ifdef MFD_HSU_A0_STEPPING
/* A0 doesn't support half empty IRQ */
fcr |= UART_FCR_FULL_EMPT_TXI;
#endif
/*
* Ok, we're now changing the port state. Do it with
@ -1343,28 +1322,6 @@ err_disable:
return ret;
}
static void hsu_dma_rx_timeout(unsigned long data)
{
struct hsu_dma_chan *chan = (void *)data;
struct uart_hsu_port *up = chan->uport;
struct hsu_dma_buffer *dbuf = &up->rxbuf;
int count = 0;
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
if (!count) {
mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
goto exit;
}
hsu_dma_rx(up, 0);
exit:
spin_unlock_irqrestore(&up->port.lock, flags);
}
static void hsu_global_init(void)
{
struct hsu_port *hsu;
@ -1415,6 +1372,12 @@ static void hsu_global_init(void)
serial_hsu_ports[i] = uport;
uport->index = i;
if (hsu_dma_enable & (1<<i))
uport->use_dma = 1;
else
uport->use_dma = 0;
uport++;
}
@ -1427,12 +1390,6 @@ static void hsu_global_init(void)
dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET +
i * HSU_DMA_CHANS_REG_LENGTH;
/* Work around for RX */
if (dchan->dirt == DMA_FROM_DEVICE) {
init_timer(&dchan->rx_timer);
dchan->rx_timer.function = hsu_dma_rx_timeout;
dchan->rx_timer.data = (unsigned long)dchan;
}
dchan++;
}

View file

@ -1302,8 +1302,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
{},
};
static int __devinit
mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *match)
static int __devinit mpc52xx_uart_of_probe(struct platform_device *op)
{
int idx = -1;
unsigned int uartclk;
@ -1311,8 +1310,6 @@ mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *mat
struct resource res;
int ret;
dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match);
/* Check validity & presence */
for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
if (mpc52xx_uart_nodes[idx] == op->dev.of_node)
@ -1453,7 +1450,7 @@ mpc52xx_uart_of_enumerate(void)
MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
static struct of_platform_driver mpc52xx_uart_of_driver = {
static struct platform_driver mpc52xx_uart_of_driver = {
.probe = mpc52xx_uart_of_probe,
.remove = mpc52xx_uart_of_remove,
#ifdef CONFIG_PM
@ -1497,9 +1494,9 @@ mpc52xx_uart_init(void)
return ret;
}
ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
ret = platform_driver_register(&mpc52xx_uart_of_driver);
if (ret) {
printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
__FILE__, ret);
uart_unregister_driver(&mpc52xx_uart_driver);
return ret;
@ -1514,7 +1511,7 @@ mpc52xx_uart_exit(void)
if (psc_ops->fifoc_uninit)
psc_ops->fifoc_uninit();
of_unregister_platform_driver(&mpc52xx_uart_of_driver);
platform_driver_unregister(&mpc52xx_uart_of_driver);
uart_unregister_driver(&mpc52xx_uart_driver);
}

View file

@ -51,7 +51,7 @@
struct uart_max3110 {
struct uart_port port;
struct spi_device *spi;
char name[24];
char name[SPI_NAME_SIZE];
wait_queue_head_t wq;
struct task_struct *main_thread;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
/* drivers/tty/serial/msm_smd_tty.c
*
* Copyright (C) 2007 Google, Inc.
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <mach/msm_smd.h>
#define MAX_SMD_TTYS 32
struct smd_tty_info {
struct tty_port port;
smd_channel_t *ch;
};
struct smd_tty_channel_desc {
int id;
const char *name;
};
static struct smd_tty_info smd_tty[MAX_SMD_TTYS];
static const struct smd_tty_channel_desc smd_default_tty_channels[] = {
{ .id = 0, .name = "SMD_DS" },
{ .id = 27, .name = "SMD_GPSNMEA" },
};
static const struct smd_tty_channel_desc *smd_tty_channels =
smd_default_tty_channels;
static int smd_tty_channels_len = ARRAY_SIZE(smd_default_tty_channels);
static void smd_tty_notify(void *priv, unsigned event)
{
unsigned char *ptr;
int avail;
struct smd_tty_info *info = priv;
struct tty_struct *tty;
if (event != SMD_EVENT_DATA)
return;
tty = tty_port_tty_get(&info->port);
if (!tty)
return;
for (;;) {
if (test_bit(TTY_THROTTLED, &tty->flags))
break;
avail = smd_read_avail(info->ch);
if (avail == 0)
break;
avail = tty_prepare_flip_string(tty, &ptr, avail);
if (smd_read(info->ch, ptr, avail) != avail) {
/* shouldn't be possible since we're in interrupt
** context here and nobody else could 'steal' our
** characters.
*/
pr_err("OOPS - smd_tty_buffer mismatch?!");
}
tty_flip_buffer_push(tty);
}
/* XXX only when writable and necessary */
tty_wakeup(tty);
tty_kref_put(tty);
}
static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)
{
int i, res = 0;
int n = tty->index;
const char *name = NULL;
struct smd_tty_info *info = smd_tty + n;
for (i = 0; i < smd_tty_channels_len; i++) {
if (smd_tty_channels[i].id == n) {
name = smd_tty_channels[i].name;
break;
}
}
if (!name)
return -ENODEV;
if (info->ch)
smd_kick(info->ch);
else
res = smd_open(name, &info->ch, info, smd_tty_notify);
if (!res)
tty->driver_data = info;
return res;
}
static void smd_tty_port_shutdown(struct tty_port *tport)
{
struct smd_tty_info *info;
struct tty_struct *tty = tty_port_tty_get(tport);
info = tty->driver_data;
if (info->ch) {
smd_close(info->ch);
info->ch = 0;
}
tty->driver_data = 0;
tty_kref_put(tty);
}
static int smd_tty_open(struct tty_struct *tty, struct file *f)
{
struct smd_tty_info *info = smd_tty + tty->index;
return tty_port_open(&info->port, tty, f);
}
static void smd_tty_close(struct tty_struct *tty, struct file *f)
{
struct smd_tty_info *info = tty->driver_data;
tty_port_close(&info->port, tty, f);
}
static int smd_tty_write(struct tty_struct *tty,
const unsigned char *buf, int len)
{
struct smd_tty_info *info = tty->driver_data;
int avail;
/* if we're writing to a packet channel we will
** never be able to write more data than there
** is currently space for
*/
avail = smd_write_avail(info->ch);
if (len > avail)
len = avail;
return smd_write(info->ch, buf, len);
}
static int smd_tty_write_room(struct tty_struct *tty)
{
struct smd_tty_info *info = tty->driver_data;
return smd_write_avail(info->ch);
}
static int smd_tty_chars_in_buffer(struct tty_struct *tty)
{
struct smd_tty_info *info = tty->driver_data;
return smd_read_avail(info->ch);
}
static void smd_tty_unthrottle(struct tty_struct *tty)
{
struct smd_tty_info *info = tty->driver_data;
smd_kick(info->ch);
}
static const struct tty_port_operations smd_tty_port_ops = {
.shutdown = smd_tty_port_shutdown,
.activate = smd_tty_port_activate,
};
static const struct tty_operations smd_tty_ops = {
.open = smd_tty_open,
.close = smd_tty_close,
.write = smd_tty_write,
.write_room = smd_tty_write_room,
.chars_in_buffer = smd_tty_chars_in_buffer,
.unthrottle = smd_tty_unthrottle,
};
static struct tty_driver *smd_tty_driver;
static int __init smd_tty_init(void)
{
int ret, i;
smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
if (smd_tty_driver == 0)
return -ENOMEM;
smd_tty_driver->owner = THIS_MODULE;
smd_tty_driver->driver_name = "smd_tty_driver";
smd_tty_driver->name = "smd";
smd_tty_driver->major = 0;
smd_tty_driver->minor_start = 0;
smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
smd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
smd_tty_driver->init_termios = tty_std_termios;
smd_tty_driver->init_termios.c_iflag = 0;
smd_tty_driver->init_termios.c_oflag = 0;
smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
smd_tty_driver->init_termios.c_lflag = 0;
smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(smd_tty_driver, &smd_tty_ops);
ret = tty_register_driver(smd_tty_driver);
if (ret)
return ret;
for (i = 0; i < smd_tty_channels_len; i++) {
tty_port_init(&smd_tty[smd_tty_channels[i].id].port);
smd_tty[smd_tty_channels[i].id].port.ops = &smd_tty_port_ops;
tty_register_device(smd_tty_driver, smd_tty_channels[i].id, 0);
}
return 0;
}
module_init(smd_tty_init);

View file

@ -80,14 +80,16 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
/*
* Try to register a serial port
*/
static int __devinit of_platform_serial_probe(struct platform_device *ofdev,
const struct of_device_id *id)
static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
{
struct of_serial_info *info;
struct uart_port port;
int port_type;
int ret;
if (!ofdev->dev.of_match)
return -EINVAL;
if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
return -EBUSY;
@ -95,7 +97,7 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev,
if (info == NULL)
return -ENOMEM;
port_type = (unsigned long)id->data;
port_type = (unsigned long)ofdev->dev.of_match->data;
ret = of_platform_serial_setup(ofdev, port_type, &port);
if (ret)
goto out;
@ -160,21 +162,21 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
* A few common types, add more as needed.
*/
static struct of_device_id __devinitdata of_platform_serial_table[] = {
{ .type = "serial", .compatible = "ns8250", .data = (void *)PORT_8250, },
{ .type = "serial", .compatible = "ns16450", .data = (void *)PORT_16450, },
{ .type = "serial", .compatible = "ns16550a", .data = (void *)PORT_16550A, },
{ .type = "serial", .compatible = "ns16550", .data = (void *)PORT_16550, },
{ .type = "serial", .compatible = "ns16750", .data = (void *)PORT_16750, },
{ .type = "serial", .compatible = "ns16850", .data = (void *)PORT_16850, },
{ .compatible = "ns8250", .data = (void *)PORT_8250, },
{ .compatible = "ns16450", .data = (void *)PORT_16450, },
{ .compatible = "ns16550a", .data = (void *)PORT_16550A, },
{ .compatible = "ns16550", .data = (void *)PORT_16550, },
{ .compatible = "ns16750", .data = (void *)PORT_16750, },
{ .compatible = "ns16850", .data = (void *)PORT_16850, },
#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
{ .type = "serial", .compatible = "ibm,qpace-nwp-serial",
.data = (void *)PORT_NWPSERIAL, },
{ .compatible = "ibm,qpace-nwp-serial",
.data = (void *)PORT_NWPSERIAL, },
#endif
{ .type = "serial", .data = (void *)PORT_UNKNOWN, },
{ .type = "serial", .data = (void *)PORT_UNKNOWN, },
{ /* end of list */ },
};
static struct of_platform_driver of_platform_serial_driver = {
static struct platform_driver of_platform_serial_driver = {
.driver = {
.name = "of_serial",
.owner = THIS_MODULE,
@ -186,13 +188,13 @@ static struct of_platform_driver of_platform_serial_driver = {
static int __init of_platform_serial_init(void)
{
return of_register_platform_driver(&of_platform_serial_driver);
return platform_driver_register(&of_platform_serial_driver);
}
module_init(of_platform_serial_init);
static void __exit of_platform_serial_exit(void)
{
return of_unregister_platform_driver(&of_platform_serial_driver);
return platform_driver_unregister(&of_platform_serial_driver);
};
module_exit(of_platform_serial_exit);

View file

@ -20,6 +20,10 @@
* this driver as required for the omap-platform.
*/
#if defined(CONFIG_SERIAL_OMAP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/init.h>
#include <linux/console.h>
@ -190,7 +194,6 @@ static inline void receive_chars(struct uart_omap_port *up, int *status)
if (up->port.line == up->port.cons->index) {
/* Recover the break flag from console xmit */
lsr |= up->lsr_break_flag;
up->lsr_break_flag = 0;
}
#endif
if (lsr & UART_LSR_BI)
@ -517,6 +520,9 @@ static int serial_omap_startup(struct uart_port *port)
up->ier = UART_IER_RLSI | UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
/* Enable module level wake up */
serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP);
up->port_activity = jiffies;
return 0;
}
@ -824,9 +830,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, efr);
serial_out(up, UART_LCR, 0);
/* Enable module level wake up */
serial_out(up, UART_OMAP_WER,
(state != 0) ? OMAP_UART_WER_MOD_WKUP : 0);
}
static void serial_omap_release_port(struct uart_port *port)

View file

@ -21,6 +21,7 @@
#include <linux/serial_core.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/dmi.h>
#include <linux/dmaengine.h>
#include <linux/pch_dma.h>
@ -40,10 +41,11 @@ enum {
#define PCH_UART_DRIVER_DEVICE "ttyPCH"
#define PCH_UART_NR_GE_256FIFO 1
#define PCH_UART_NR_GE_64FIFO 3
#define PCH_UART_NR_GE (PCH_UART_NR_GE_256FIFO+PCH_UART_NR_GE_64FIFO)
#define PCH_UART_NR PCH_UART_NR_GE
/* Set the max number of UART port
* Intel EG20T PCH: 4 port
* OKI SEMICONDUCTOR ML7213 IOH: 3 port
*/
#define PCH_UART_NR 4
#define PCH_UART_HANDLED_RX_INT (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1))
#define PCH_UART_HANDLED_TX_INT (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1))
@ -192,6 +194,8 @@ enum {
#define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP)
#define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE)
#define PCI_VENDOR_ID_ROHM 0x10DB
struct pch_uart_buffer {
unsigned char *buf;
int size;
@ -215,6 +219,7 @@ struct eg20t_port {
struct pch_uart_buffer rxbuf;
unsigned int dmsr;
unsigned int fcr;
unsigned int mcr;
unsigned int use_dma;
unsigned int use_dma_flag;
struct dma_async_tx_descriptor *desc_tx;
@ -223,13 +228,44 @@ struct eg20t_port {
struct pch_dma_slave param_rx;
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
struct scatterlist sg_tx;
struct scatterlist *sg_tx_p;
int nent;
struct scatterlist sg_rx;
int tx_dma_use;
void *rx_buf_virt;
dma_addr_t rx_buf_dma;
};
/**
* struct pch_uart_driver_data - private data structure for UART-DMA
* @port_type: The number of DMA channel
* @line_no: UART port line number (0, 1, 2...)
*/
struct pch_uart_driver_data {
int port_type;
int line_no;
};
enum pch_uart_num_t {
pch_et20t_uart0 = 0,
pch_et20t_uart1,
pch_et20t_uart2,
pch_et20t_uart3,
pch_ml7213_uart0,
pch_ml7213_uart1,
pch_ml7213_uart2,
};
static struct pch_uart_driver_data drv_dat[] = {
[pch_et20t_uart0] = {PCH_UART_8LINE, 0},
[pch_et20t_uart1] = {PCH_UART_2LINE, 1},
[pch_et20t_uart2] = {PCH_UART_2LINE, 2},
[pch_et20t_uart3] = {PCH_UART_2LINE, 3},
[pch_ml7213_uart0] = {PCH_UART_8LINE, 0},
[pch_ml7213_uart1] = {PCH_UART_2LINE, 1},
[pch_ml7213_uart2] = {PCH_UART_2LINE, 2},
};
static unsigned int default_baud = 9600;
static const int trigger_level_256[4] = { 1, 64, 128, 224 };
static const int trigger_level_64[4] = { 1, 16, 32, 56 };
@ -278,7 +314,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
div = DIV_ROUND(priv->base_baud / 16, baud);
if (div < 0 || USHRT_MAX <= div) {
pr_err("Invalid Baud(div=0x%x)\n", div);
dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div);
return -EINVAL;
}
@ -286,17 +322,17 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
dlm = ((unsigned int)div >> 8) & 0x00FFU;
if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) {
pr_err("Invalid parity(0x%x)\n", parity);
dev_err(priv->port.dev, "Invalid parity(0x%x)\n", parity);
return -EINVAL;
}
if (bits & ~PCH_UART_LCR_WLS) {
pr_err("Invalid bits(0x%x)\n", bits);
dev_err(priv->port.dev, "Invalid bits(0x%x)\n", bits);
return -EINVAL;
}
if (stb & ~PCH_UART_LCR_STB) {
pr_err("Invalid STB(0x%x)\n", stb);
dev_err(priv->port.dev, "Invalid STB(0x%x)\n", stb);
return -EINVAL;
}
@ -304,7 +340,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
lcr |= bits;
lcr |= stb;
pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
dev_dbg(priv->port.dev, "%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
__func__, baud, div, lcr, jiffies);
iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
iowrite8(dll, priv->membase + PCH_UART_DLL);
@ -318,7 +354,8 @@ static int pch_uart_hal_fifo_reset(struct eg20t_port *priv,
unsigned int flag)
{
if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) {
pr_err("%s:Invalid flag(0x%x)\n", __func__, flag);
dev_err(priv->port.dev, "%s:Invalid flag(0x%x)\n",
__func__, flag);
return -EINVAL;
}
@ -337,17 +374,20 @@ static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
u8 fcr;
if (dmamode & ~PCH_UART_FCR_DMS) {
pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode);
dev_err(priv->port.dev, "%s:Invalid DMA Mode(0x%x)\n",
__func__, dmamode);
return -EINVAL;
}
if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) {
pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size);
dev_err(priv->port.dev, "%s:Invalid FIFO SIZE(0x%x)\n",
__func__, fifo_size);
return -EINVAL;
}
if (trigger & ~PCH_UART_FCR_RFTL) {
pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger);
dev_err(priv->port.dev, "%s:Invalid TRIGGER(0x%x)\n",
__func__, trigger);
return -EINVAL;
}
@ -386,7 +426,7 @@ static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
return get_msr(priv, priv->membase);
}
static int pch_uart_hal_write(struct eg20t_port *priv,
static void pch_uart_hal_write(struct eg20t_port *priv,
const unsigned char *buf, int tx_size)
{
int i;
@ -396,7 +436,6 @@ static int pch_uart_hal_write(struct eg20t_port *priv,
thr = buf[i++];
iowrite8(thr, priv->membase + PCH_UART_THR);
}
return i;
}
static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
@ -452,7 +491,7 @@ static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
port = &priv->port;
tty = tty_port_tty_get(&port->state->port);
if (!tty) {
pr_debug("%s:tty is busy now", __func__);
dev_dbg(priv->port.dev, "%s:tty is busy now", __func__);
return -EBUSY;
}
@ -469,8 +508,8 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
struct uart_port *port = &priv->port;
if (port->x_char) {
pr_debug("%s:X character send %02x (%lu)\n", __func__,
port->x_char, jiffies);
dev_dbg(priv->port.dev, "%s:X character send %02x (%lu)\n",
__func__, port->x_char, jiffies);
buf[0] = port->x_char;
port->x_char = 0;
ret = 1;
@ -490,7 +529,7 @@ static int dma_push_rx(struct eg20t_port *priv, int size)
port = &priv->port;
tty = tty_port_tty_get(&port->state->port);
if (!tty) {
pr_debug("%s:tty is busy now", __func__);
dev_dbg(priv->port.dev, "%s:tty is busy now", __func__);
return 0;
}
@ -560,11 +599,13 @@ static void pch_request_dma(struct uart_port *port)
/* Set Tx DMA */
param = &priv->param_tx;
param->dma_dev = &dma_dev->dev;
param->chan_id = priv->port.line;
param->chan_id = priv->port.line * 2; /* Tx = 0, 2, 4, ... */
param->tx_reg = port->mapbase + UART_TX;
chan = dma_request_channel(mask, filter, param);
if (!chan) {
pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__);
dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Tx)\n",
__func__);
return;
}
priv->chan_tx = chan;
@ -572,11 +613,13 @@ static void pch_request_dma(struct uart_port *port)
/* Set Rx DMA */
param = &priv->param_rx;
param->dma_dev = &dma_dev->dev;
param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */
param->chan_id = priv->port.line * 2 + 1; /* Rx = Tx + 1 */
param->rx_reg = port->mapbase + UART_RX;
chan = dma_request_channel(mask, filter, param);
if (!chan) {
pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__);
dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n",
__func__);
dma_release_channel(priv->chan_tx);
return;
}
@ -592,16 +635,20 @@ static void pch_dma_rx_complete(void *arg)
struct eg20t_port *priv = arg;
struct uart_port *port = &priv->port;
struct tty_struct *tty = tty_port_tty_get(&port->state->port);
int count;
if (!tty) {
pr_debug("%s:tty is busy now", __func__);
dev_dbg(priv->port.dev, "%s:tty is busy now", __func__);
return;
}
if (dma_push_rx(priv, priv->trigger_level))
dma_sync_sg_for_cpu(port->dev, &priv->sg_rx, 1, DMA_FROM_DEVICE);
count = dma_push_rx(priv, priv->trigger_level);
if (count)
tty_flip_buffer_push(tty);
tty_kref_put(tty);
async_tx_ack(priv->desc_rx);
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
}
static void pch_dma_tx_complete(void *arg)
@ -609,16 +656,23 @@ static void pch_dma_tx_complete(void *arg)
struct eg20t_port *priv = arg;
struct uart_port *port = &priv->port;
struct circ_buf *xmit = &port->state->xmit;
struct scatterlist *sg = priv->sg_tx_p;
int i;
xmit->tail += sg_dma_len(&priv->sg_tx);
for (i = 0; i < priv->nent; i++, sg++) {
xmit->tail += sg_dma_len(sg);
port->icount.tx += sg_dma_len(sg);
}
xmit->tail &= UART_XMIT_SIZE - 1;
port->icount.tx += sg_dma_len(&priv->sg_tx);
async_tx_ack(priv->desc_tx);
dma_unmap_sg(port->dev, sg, priv->nent, DMA_TO_DEVICE);
priv->tx_dma_use = 0;
priv->nent = 0;
kfree(priv->sg_tx_p);
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
}
static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
static int pop_tx(struct eg20t_port *priv, int size)
{
int count = 0;
struct uart_port *port = &priv->port;
@ -631,13 +685,13 @@ static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
int cnt_to_end =
CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
int sz = min(size - count, cnt_to_end);
memcpy(&buf[count], &xmit->buf[xmit->tail], sz);
pch_uart_hal_write(priv, &xmit->buf[xmit->tail], sz);
xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
count += sz;
} while (!uart_circ_empty(xmit) && count < size);
pop_tx_end:
pr_debug("%d characters. Remained %d characters. (%lu)\n",
dev_dbg(priv->port.dev, "%d characters. Remained %d characters.(%lu)\n",
count, size - count, jiffies);
return count;
@ -679,7 +733,7 @@ static int dma_handle_rx(struct eg20t_port *priv)
sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */
sg_dma_len(sg) = priv->fifo_size;
sg_dma_len(sg) = priv->trigger_level;
sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
@ -689,7 +743,8 @@ static int dma_handle_rx(struct eg20t_port *priv)
desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
sg, 1, DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT);
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
return 0;
@ -706,14 +761,14 @@ static unsigned int handle_tx(struct eg20t_port *priv)
{
struct uart_port *port = &priv->port;
struct circ_buf *xmit = &port->state->xmit;
int ret;
int fifo_size;
int tx_size;
int size;
int tx_empty;
if (!priv->start_tx) {
pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
__func__, jiffies);
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
priv->tx_empty = 1;
return 0;
@ -728,17 +783,21 @@ static unsigned int handle_tx(struct eg20t_port *priv)
fifo_size--;
}
size = min(xmit->head - xmit->tail, fifo_size);
tx_size = pop_tx(priv, xmit->buf, size);
if (size < 0)
size = fifo_size;
tx_size = pop_tx(priv, size);
if (tx_size > 0) {
ret = pch_uart_hal_write(priv, xmit->buf, tx_size);
port->icount.tx += ret;
port->icount.tx += tx_size;
tx_empty = 0;
}
priv->tx_empty = tx_empty;
if (tx_empty)
if (tx_empty) {
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
uart_write_wakeup(port);
}
return PCH_UART_HANDLED_TX_INT;
}
@ -747,14 +806,28 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
{
struct uart_port *port = &priv->port;
struct circ_buf *xmit = &port->state->xmit;
struct scatterlist *sg = &priv->sg_tx;
struct scatterlist *sg;
int nent;
int fifo_size;
int tx_empty;
struct dma_async_tx_descriptor *desc;
int num;
int i;
int bytes;
int size;
int rem;
if (!priv->start_tx) {
pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
__func__, jiffies);
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
priv->tx_empty = 1;
return 0;
}
if (priv->tx_dma_use) {
dev_dbg(priv->port.dev, "%s:Tx is not completed. (%lu)\n",
__func__, jiffies);
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
priv->tx_empty = 1;
return 0;
@ -769,37 +842,73 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
fifo_size--;
}
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
bytes = min((int)CIRC_CNT(xmit->head, xmit->tail,
UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
xmit->tail, UART_XMIT_SIZE));
if (!bytes) {
dev_dbg(priv->port.dev, "%s 0 bytes return\n", __func__);
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
uart_write_wakeup(port);
return 0;
}
if (bytes > fifo_size) {
num = bytes / fifo_size + 1;
size = fifo_size;
rem = bytes % fifo_size;
} else {
num = 1;
size = bytes;
rem = bytes;
}
dev_dbg(priv->port.dev, "%s num=%d size=%d rem=%d\n",
__func__, num, size, rem);
priv->tx_dma_use = 1;
sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */
priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf),
UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK);
sg_init_table(priv->sg_tx_p, num); /* Initialize SG table */
sg = priv->sg_tx_p;
nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE);
if (!nent) {
pr_err("%s:dma_map_sg Failed\n", __func__);
return 0;
for (i = 0; i < num; i++, sg++) {
if (i == (num - 1))
sg_set_page(sg, virt_to_page(xmit->buf),
rem, fifo_size * i);
else
sg_set_page(sg, virt_to_page(xmit->buf),
size, fifo_size * i);
}
sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
sg->offset;
sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail,
UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
xmit->tail, UART_XMIT_SIZE));
sg = priv->sg_tx_p;
nent = dma_map_sg(port->dev, sg, num, DMA_TO_DEVICE);
if (!nent) {
dev_err(priv->port.dev, "%s:dma_map_sg Failed\n", __func__);
return 0;
}
priv->nent = nent;
for (i = 0; i < nent; i++, sg++) {
sg->offset = (xmit->tail & (UART_XMIT_SIZE - 1)) +
fifo_size * i;
sg_dma_address(sg) = (sg_dma_address(sg) &
~(UART_XMIT_SIZE - 1)) + sg->offset;
if (i == (nent - 1))
sg_dma_len(sg) = rem;
else
sg_dma_len(sg) = size;
}
desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
priv->sg_tx_p, nent, DMA_TO_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
pr_err("%s:device_prep_slave_sg Failed\n", __func__);
dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n",
__func__);
return 0;
}
dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
dma_sync_sg_for_device(port->dev, priv->sg_tx_p, nent, DMA_TO_DEVICE);
priv->desc_tx = desc;
desc->callback = pch_dma_tx_complete;
desc->callback_param = priv;
@ -854,10 +963,16 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
}
break;
case PCH_UART_IID_RDR: /* Received Data Ready */
if (priv->use_dma)
if (priv->use_dma) {
pch_uart_hal_disable_interrupt(priv,
PCH_UART_HAL_RX_INT);
ret = dma_handle_rx(priv);
else
if (!ret)
pch_uart_hal_enable_interrupt(priv,
PCH_UART_HAL_RX_INT);
} else {
ret = handle_rx(priv);
}
break;
case PCH_UART_IID_RDR_TO: /* Received Data Ready
(FIFO Timeout) */
@ -874,7 +989,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
ret = PCH_UART_HANDLED_MS_INT;
break;
default: /* Never junp to this label */
pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies);
dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__,
iid, jiffies);
ret = -1;
break;
}
@ -932,7 +1048,6 @@ static unsigned int pch_uart_get_mctrl(struct uart_port *port)
static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
u32 mcr = 0;
unsigned int dat;
struct eg20t_port *priv = container_of(port, struct eg20t_port, port);
if (mctrl & TIOCM_DTR)
@ -942,11 +1057,11 @@ static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP;
if (mctrl) {
dat = pch_uart_get_mctrl(port);
dat |= mcr;
iowrite8(dat, priv->membase + UART_MCR);
}
if (priv->mcr & UART_MCR_AFE)
mcr |= UART_MCR_AFE;
if (mctrl)
iowrite8(mcr, priv->membase + UART_MCR);
}
static void pch_uart_stop_tx(struct uart_port *port)
@ -963,9 +1078,13 @@ static void pch_uart_start_tx(struct uart_port *port)
priv = container_of(port, struct eg20t_port, port);
if (priv->use_dma)
if (priv->tx_dma_use)
if (priv->use_dma) {
if (priv->tx_dma_use) {
dev_dbg(priv->port.dev, "%s : Tx DMA is NOT empty.\n",
__func__);
return;
}
}
priv->start_tx = 1;
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
@ -1010,7 +1129,12 @@ static int pch_uart_startup(struct uart_port *port)
priv = container_of(port, struct eg20t_port, port);
priv->tx_empty = 1;
port->uartclk = priv->base_baud;
if (port->uartclk)
priv->base_baud = port->uartclk;
else
port->uartclk = priv->base_baud;
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
ret = pch_uart_hal_set_line(priv, default_baud,
PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT,
@ -1081,7 +1205,8 @@ static void pch_uart_shutdown(struct uart_port *port)
ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1);
if (ret)
pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
dev_err(priv->port.dev,
"pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
if (priv->use_dma_flag)
pch_free_dma(port);
@ -1130,6 +1255,13 @@ static void pch_uart_set_termios(struct uart_port *port,
} else {
parity = PCH_UART_HAL_PARITY_NONE;
}
/* Only UART0 has auto hardware flow function */
if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256))
priv->mcr |= UART_MCR_AFE;
else
priv->mcr &= ~UART_MCR_AFE;
termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
@ -1202,17 +1334,19 @@ static int pch_uart_verify_port(struct uart_port *port,
priv = container_of(port, struct eg20t_port, port);
if (serinfo->flags & UPF_LOW_LATENCY) {
pr_info("PCH UART : Use PIO Mode (without DMA)\n");
dev_info(priv->port.dev,
"PCH UART : Use PIO Mode (without DMA)\n");
priv->use_dma = 0;
serinfo->flags &= ~UPF_LOW_LATENCY;
} else {
#ifndef CONFIG_PCH_DMA
pr_err("%s : PCH DMA is not Loaded.\n", __func__);
dev_err(priv->port.dev, "%s : PCH DMA is not Loaded.\n",
__func__);
return -EOPNOTSUPP;
#endif
priv->use_dma = 1;
priv->use_dma_flag = 1;
pr_info("PCH UART : Use DMA Mode\n");
dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
}
return 0;
@ -1249,7 +1383,7 @@ static struct uart_driver pch_uart_driver = {
};
static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
int port_type)
const struct pci_device_id *id)
{
struct eg20t_port *priv;
int ret;
@ -1257,7 +1391,11 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
unsigned int mapbase;
unsigned char *rxbuf;
int fifosize, base_baud;
static int num;
int port_type;
struct pch_uart_driver_data *board;
board = &drv_dat[id->driver_data];
port_type = board->port_type;
priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL);
if (priv == NULL)
@ -1267,14 +1405,18 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
if (!rxbuf)
goto init_port_free_txbuf;
base_baud = 1843200; /* 1.8432MHz */
/* quirk for CM-iTC board */
if (strstr(dmi_get_system_info(DMI_BOARD_NAME), "CM-iTC"))
base_baud = 192000000; /* 192.0MHz */
switch (port_type) {
case PORT_UNKNOWN:
fifosize = 256; /* UART0 */
base_baud = 1843200; /* 1.8432MHz */
fifosize = 256; /* EG20T/ML7213: UART0 */
break;
case PORT_8250:
fifosize = 64; /* UART1~3 */
base_baud = 1843200; /* 1.8432MHz */
fifosize = 64; /* EG20T:UART1~3 ML7213: UART1~2*/
break;
default:
dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type);
@ -1302,11 +1444,14 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
priv->port.ops = &pch_uart_ops;
priv->port.flags = UPF_BOOT_AUTOCONF;
priv->port.fifosize = fifosize;
priv->port.line = num++;
priv->port.line = board->line_no;
priv->trigger = PCH_UART_HAL_TRIGGER_M;
spin_lock_init(&priv->port.lock);
pci_set_drvdata(pdev, priv);
pch_uart_hal_request(pdev, fifosize, base_baud);
ret = uart_add_one_port(&pch_uart_driver, &priv->port);
if (ret < 0)
goto init_port_hal_free;
@ -1377,13 +1522,19 @@ static int pch_uart_pci_resume(struct pci_dev *pdev)
static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
.driver_data = PCH_UART_8LINE},
.driver_data = pch_et20t_uart0},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812),
.driver_data = PCH_UART_2LINE},
.driver_data = pch_et20t_uart1},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813),
.driver_data = PCH_UART_2LINE},
.driver_data = pch_et20t_uart2},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814),
.driver_data = PCH_UART_2LINE},
.driver_data = pch_et20t_uart3},
{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8027),
.driver_data = pch_ml7213_uart0},
{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8028),
.driver_data = pch_ml7213_uart1},
{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8029),
.driver_data = pch_ml7213_uart2},
{0,},
};
@ -1397,7 +1548,7 @@ static int __devinit pch_uart_pci_probe(struct pci_dev *pdev,
if (ret < 0)
goto probe_error;
priv = pch_uart_init_port(pdev, id->driver_data);
priv = pch_uart_init_port(pdev, id);
if (!priv) {
ret = -EBUSY;
goto probe_disable_device;

View file

@ -905,7 +905,7 @@ static int uart_get_lsr_info(struct tty_struct *tty,
return put_user(result, value);
}
static int uart_tiocmget(struct tty_struct *tty, struct file *file)
static int uart_tiocmget(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
@ -913,10 +913,8 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file)
int result = -EIO;
mutex_lock(&port->mutex);
if ((!file || !tty_hung_up_p(file)) &&
!(tty->flags & (1 << TTY_IO_ERROR))) {
if (!(tty->flags & (1 << TTY_IO_ERROR))) {
result = uport->mctrl;
spin_lock_irq(&uport->lock);
result |= uport->ops->get_mctrl(uport);
spin_unlock_irq(&uport->lock);
@ -927,8 +925,7 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file)
}
static int
uart_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
{
struct uart_state *state = tty->driver_data;
struct uart_port *uport = state->uart_port;
@ -936,8 +933,7 @@ uart_tiocmset(struct tty_struct *tty, struct file *file,
int ret = -EIO;
mutex_lock(&port->mutex);
if ((!file || !tty_hung_up_p(file)) &&
!(tty->flags & (1 << TTY_IO_ERROR))) {
if (!(tty->flags & (1 << TTY_IO_ERROR))) {
uart_update_mctrl(uport, set, clear);
ret = 0;
}
@ -1103,7 +1099,7 @@ static int uart_get_icount(struct tty_struct *tty,
* Called via sys_ioctl. We can use spin_lock_irq() here.
*/
static int
uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
uart_ioctl(struct tty_struct *tty, unsigned int cmd,
unsigned long arg)
{
struct uart_state *state = tty->driver_data;
@ -1156,7 +1152,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
mutex_lock(&port->mutex);
if (tty_hung_up_p(filp)) {
if (tty->flags & (1 << TTY_IO_ERROR)) {
ret = -EIO;
goto out_up;
}
@ -2064,7 +2060,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
/*
* Re-enable the console device after suspending.
*/
if (console_suspend_enabled && uart_console(uport)) {
if (uart_console(uport)) {
/*
* First try to use the console cflag setting.
*/
@ -2077,9 +2073,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
if (port->tty && port->tty->termios && termios.c_cflag == 0)
termios = *(port->tty->termios);
uart_change_pm(state, 0);
uport->ops->set_termios(uport, &termios, NULL);
console_start(uport->cons);
if (console_suspend_enabled)
console_start(uport->cons);
}
if (port->flags & ASYNC_SUSPENDED) {

View file

@ -712,6 +712,7 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0b05),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),

View file

@ -1,682 +0,0 @@
/* drivers/serial/serial_lh7a40x.c
*
* Copyright (C) 2004 Coastal Environmental Systems
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*/
/* Driver for Sharp LH7A40X embedded serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
* Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd.
*
* ---
*
* This driver supports the embedded UARTs of the Sharp LH7A40X series
* CPUs. While similar to the 16550 and other UART chips, there is
* nothing close to register compatibility. Moreover, some of the
* modem control lines are not available, either in the chip or they
* are lacking in the board-level implementation.
*
* - Use of SIRDIS
* For simplicity, we disable the IR functions of any UART whenever
* we enable it.
*
*/
#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#define DEV_MAJOR 204
#define DEV_MINOR 16
#define DEV_NR 3
#define ISR_LOOP_LIMIT 256
#define UR(p,o) _UR ((p)->membase, o)
#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
#define UART_REG_SIZE 32
#define UART_R_DATA (0x00)
#define UART_R_FCON (0x04)
#define UART_R_BRCON (0x08)
#define UART_R_CON (0x0c)
#define UART_R_STATUS (0x10)
#define UART_R_RAWISR (0x14)
#define UART_R_INTEN (0x18)
#define UART_R_ISR (0x1c)
#define UARTEN (0x01) /* UART enable */
#define SIRDIS (0x02) /* Serial IR disable (UART1 only) */
#define RxEmpty (0x10)
#define TxEmpty (0x80)
#define TxFull (0x20)
#define nRxRdy RxEmpty
#define nTxRdy TxFull
#define TxBusy (0x08)
#define RxBreak (0x0800)
#define RxOverrunError (0x0400)
#define RxParityError (0x0200)
#define RxFramingError (0x0100)
#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError)
#define DCD (0x04)
#define DSR (0x02)
#define CTS (0x01)
#define RxInt (0x01)
#define TxInt (0x02)
#define ModemInt (0x04)
#define RxTimeoutInt (0x08)
#define MSEOI (0x10)
#define WLEN_8 (0x60)
#define WLEN_7 (0x40)
#define WLEN_6 (0x20)
#define WLEN_5 (0x00)
#define WLEN (0x60) /* Mask for all word-length bits */
#define STP2 (0x08)
#define PEN (0x02) /* Parity Enable */
#define EPS (0x04) /* Even Parity Set */
#define FEN (0x10) /* FIFO Enable */
#define BRK (0x01) /* Send Break */
struct uart_port_lh7a40x {
struct uart_port port;
unsigned int statusPrev; /* Most recently read modem status */
};
static void lh7a40xuart_stop_tx (struct uart_port* port)
{
BIT_CLR (port, UART_R_INTEN, TxInt);
}
static void lh7a40xuart_start_tx (struct uart_port* port)
{
BIT_SET (port, UART_R_INTEN, TxInt);
/* *** FIXME: do I need to check for startup of the
transmitter? The old driver did, but AMBA
doesn't . */
}
static void lh7a40xuart_stop_rx (struct uart_port* port)
{
BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
}
static void lh7a40xuart_enable_ms (struct uart_port* port)
{
BIT_SET (port, UART_R_INTEN, ModemInt);
}
static void lh7a40xuart_rx_chars (struct uart_port* port)
{
struct tty_struct* tty = port->state->port.tty;
int cbRxMax = 256; /* (Gross) limit on receive */
unsigned int data; /* Received data and status */
unsigned int flag;
while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
data = UR (port, UART_R_DATA);
flag = TTY_NORMAL;
++port->icount.rx;
if (unlikely(data & RxError)) {
if (data & RxBreak) {
data &= ~(RxFramingError | RxParityError);
++port->icount.brk;
if (uart_handle_break (port))
continue;
}
else if (data & RxParityError)
++port->icount.parity;
else if (data & RxFramingError)
++port->icount.frame;
if (data & RxOverrunError)
++port->icount.overrun;
/* Mask by termios, leave Rx'd byte */
data &= port->read_status_mask | 0xff;
if (data & RxBreak)
flag = TTY_BREAK;
else if (data & RxParityError)
flag = TTY_PARITY;
else if (data & RxFramingError)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char (port, (unsigned char) data))
continue;
uart_insert_char(port, data, RxOverrunError, data, flag);
}
tty_flip_buffer_push (tty);
return;
}
static void lh7a40xuart_tx_chars (struct uart_port* port)
{
struct circ_buf* xmit = &port->state->xmit;
int cbTxMax = port->fifosize;
if (port->x_char) {
UR (port, UART_R_DATA) = port->x_char;
++port->icount.tx;
port->x_char = 0;
return;
}
if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
lh7a40xuart_stop_tx (port);
return;
}
/* Unlike the AMBA UART, the lh7a40x UART does not guarantee
that at least half of the FIFO is empty. Instead, we check
status for every character. Using the AMBA method causes
the transmitter to drop characters. */
do {
UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++port->icount.tx;
if (uart_circ_empty(xmit))
break;
} while (!(UR (port, UART_R_STATUS) & nTxRdy)
&& cbTxMax--);
if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
uart_write_wakeup (port);
if (uart_circ_empty (xmit))
lh7a40xuart_stop_tx (port);
}
static void lh7a40xuart_modem_status (struct uart_port* port)
{
unsigned int status = UR (port, UART_R_STATUS);
unsigned int delta
= status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
if (!delta) /* Only happens if we missed 2 transitions */
return;
((struct uart_port_lh7a40x*) port)->statusPrev = status;
if (delta & DCD)
uart_handle_dcd_change (port, status & DCD);
if (delta & DSR)
++port->icount.dsr;
if (delta & CTS)
uart_handle_cts_change (port, status & CTS);
wake_up_interruptible (&port->state->port.delta_msr_wait);
}
static irqreturn_t lh7a40xuart_int (int irq, void* dev_id)
{
struct uart_port* port = dev_id;
unsigned int cLoopLimit = ISR_LOOP_LIMIT;
unsigned int isr = UR (port, UART_R_ISR);
do {
if (isr & (RxInt | RxTimeoutInt))
lh7a40xuart_rx_chars(port);
if (isr & ModemInt)
lh7a40xuart_modem_status (port);
if (isr & TxInt)
lh7a40xuart_tx_chars (port);
if (--cLoopLimit == 0)
break;
isr = UR (port, UART_R_ISR);
} while (isr & (RxInt | TxInt | RxTimeoutInt));
return IRQ_HANDLED;
}
static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
{
return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
}
static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
{
unsigned int result = 0;
unsigned int status = UR (port, UART_R_STATUS);
if (status & DCD)
result |= TIOCM_CAR;
if (status & DSR)
result |= TIOCM_DSR;
if (status & CTS)
result |= TIOCM_CTS;
return result;
}
static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
{
/* None of the ports supports DTR. UART1 supports RTS through GPIO. */
/* Note, kernel appears to be setting DTR and RTS on console. */
/* *** FIXME: this deserves more work. There's some work in
tracing all of the IO pins. */
#if 0
if( port->mapbase == UART1_PHYS) {
gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
if (mctrl & TIOCM_RTS)
gpio->pbdr &= ~GPIOB_UART1_RTS;
else
gpio->pbdr |= GPIOB_UART1_RTS;
}
#endif
}
static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
{
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
if (break_state == -1)
BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
else
BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
spin_unlock_irqrestore(&port->lock, flags);
}
static int lh7a40xuart_startup (struct uart_port* port)
{
int retval;
retval = request_irq (port->irq, lh7a40xuart_int, 0,
"serial_lh7a40x", port);
if (retval)
return retval;
/* Initial modem control-line settings */
((struct uart_port_lh7a40x*) port)->statusPrev
= UR (port, UART_R_STATUS);
/* There is presently no configuration option to enable IR.
Thus, we always disable it. */
BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
return 0;
}
static void lh7a40xuart_shutdown (struct uart_port* port)
{
free_irq (port->irq, port);
BIT_CLR (port, UART_R_FCON, BRK | FEN);
BIT_CLR (port, UART_R_CON, UARTEN);
}
static void lh7a40xuart_set_termios (struct uart_port* port,
struct ktermios* termios,
struct ktermios* old)
{
unsigned int con;
unsigned int inten;
unsigned int fcon;
unsigned long flags;
unsigned int baud;
unsigned int quot;
baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
switch (termios->c_cflag & CSIZE) {
case CS5:
fcon = WLEN_5;
break;
case CS6:
fcon = WLEN_6;
break;
case CS7:
fcon = WLEN_7;
break;
case CS8:
default:
fcon = WLEN_8;
break;
}
if (termios->c_cflag & CSTOPB)
fcon |= STP2;
if (termios->c_cflag & PARENB) {
fcon |= PEN;
if (!(termios->c_cflag & PARODD))
fcon |= EPS;
}
if (port->fifosize > 1)
fcon |= FEN;
spin_lock_irqsave (&port->lock, flags);
uart_update_timeout (port, termios->c_cflag, baud);
port->read_status_mask = RxOverrunError;
if (termios->c_iflag & INPCK)
port->read_status_mask |= RxFramingError | RxParityError;
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= RxBreak;
/* Figure mask for status we ignore */
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= RxFramingError | RxParityError;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= RxBreak;
/* Ignore overrun when ignorning parity */
/* *** FIXME: is this in the right place? */
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= RxOverrunError;
}
/* Ignore all receive errors when receive disabled */
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= RxError;
con = UR (port, UART_R_CON);
inten = (UR (port, UART_R_INTEN) & ~ModemInt);
if (UART_ENABLE_MS (port, termios->c_cflag))
inten |= ModemInt;
BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */
UR (port, UART_R_INTEN) = 0; /* Disable interrupts */
UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */
UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */
UR (port, UART_R_INTEN) = inten; /* Enable interrupts */
UR (port, UART_R_CON) = con; /* Restore UART mode */
spin_unlock_irqrestore(&port->lock, flags);
}
static const char* lh7a40xuart_type (struct uart_port* port)
{
return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
}
static void lh7a40xuart_release_port (struct uart_port* port)
{
release_mem_region (port->mapbase, UART_REG_SIZE);
}
static int lh7a40xuart_request_port (struct uart_port* port)
{
return request_mem_region (port->mapbase, UART_REG_SIZE,
"serial_lh7a40x") != NULL
? 0 : -EBUSY;
}
static void lh7a40xuart_config_port (struct uart_port* port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_LH7A40X;
lh7a40xuart_request_port (port);
}
}
static int lh7a40xuart_verify_port (struct uart_port* port,
struct serial_struct* ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
ret = -EINVAL;
if (ser->irq < 0 || ser->irq >= nr_irqs)
ret = -EINVAL;
if (ser->baud_base < 9600) /* *** FIXME: is this true? */
ret = -EINVAL;
return ret;
}
static struct uart_ops lh7a40x_uart_ops = {
.tx_empty = lh7a40xuart_tx_empty,
.set_mctrl = lh7a40xuart_set_mctrl,
.get_mctrl = lh7a40xuart_get_mctrl,
.stop_tx = lh7a40xuart_stop_tx,
.start_tx = lh7a40xuart_start_tx,
.stop_rx = lh7a40xuart_stop_rx,
.enable_ms = lh7a40xuart_enable_ms,
.break_ctl = lh7a40xuart_break_ctl,
.startup = lh7a40xuart_startup,
.shutdown = lh7a40xuart_shutdown,
.set_termios = lh7a40xuart_set_termios,
.type = lh7a40xuart_type,
.release_port = lh7a40xuart_release_port,
.request_port = lh7a40xuart_request_port,
.config_port = lh7a40xuart_config_port,
.verify_port = lh7a40xuart_verify_port,
};
static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
{
.port = {
.membase = (void*) io_p2v (UART1_PHYS),
.mapbase = UART1_PHYS,
.iotype = UPIO_MEM,
.irq = IRQ_UART1INTR,
.uartclk = 14745600/2,
.fifosize = 16,
.ops = &lh7a40x_uart_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 0,
},
},
{
.port = {
.membase = (void*) io_p2v (UART2_PHYS),
.mapbase = UART2_PHYS,
.iotype = UPIO_MEM,
.irq = IRQ_UART2INTR,
.uartclk = 14745600/2,
.fifosize = 16,
.ops = &lh7a40x_uart_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 1,
},
},
{
.port = {
.membase = (void*) io_p2v (UART3_PHYS),
.mapbase = UART3_PHYS,
.iotype = UPIO_MEM,
.irq = IRQ_UART3INTR,
.uartclk = 14745600/2,
.fifosize = 16,
.ops = &lh7a40x_uart_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 2,
},
},
};
#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
# define LH7A40X_CONSOLE NULL
#else
# define LH7A40X_CONSOLE &lh7a40x_console
static void lh7a40xuart_console_putchar(struct uart_port *port, int ch)
{
while (UR(port, UART_R_STATUS) & nTxRdy)
;
UR(port, UART_R_DATA) = ch;
}
static void lh7a40xuart_console_write (struct console* co,
const char* s,
unsigned int count)
{
struct uart_port* port = &lh7a40x_ports[co->index].port;
unsigned int con = UR (port, UART_R_CON);
unsigned int inten = UR (port, UART_R_INTEN);
UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */
BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
uart_console_write(port, s, count, lh7a40xuart_console_putchar);
/* Wait until all characters are sent */
while (UR (port, UART_R_STATUS) & TxBusy)
;
/* Restore control and interrupt mask */
UR (port, UART_R_CON) = con;
UR (port, UART_R_INTEN) = inten;
}
static void __init lh7a40xuart_console_get_options (struct uart_port* port,
int* baud,
int* parity,
int* bits)
{
if (UR (port, UART_R_CON) & UARTEN) {
unsigned int fcon = UR (port, UART_R_FCON);
unsigned int quot = UR (port, UART_R_BRCON) + 1;
switch (fcon & (PEN | EPS)) {
default: *parity = 'n'; break;
case PEN: *parity = 'o'; break;
case PEN | EPS: *parity = 'e'; break;
}
switch (fcon & WLEN) {
default:
case WLEN_8: *bits = 8; break;
case WLEN_7: *bits = 7; break;
case WLEN_6: *bits = 6; break;
case WLEN_5: *bits = 5; break;
}
*baud = port->uartclk/(16*quot);
}
}
static int __init lh7a40xuart_console_setup (struct console* co, char* options)
{
struct uart_port* port;
int baud = 38400;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (co->index >= DEV_NR) /* Bounds check on device number */
co->index = 0;
port = &lh7a40x_ports[co->index].port;
if (options)
uart_parse_options (options, &baud, &parity, &bits, &flow);
else
lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
return uart_set_options (port, co, baud, parity, bits, flow);
}
static struct uart_driver lh7a40x_reg;
static struct console lh7a40x_console = {
.name = "ttyAM",
.write = lh7a40xuart_console_write,
.device = uart_console_device,
.setup = lh7a40xuart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &lh7a40x_reg,
};
static int __init lh7a40xuart_console_init(void)
{
register_console (&lh7a40x_console);
return 0;
}
console_initcall (lh7a40xuart_console_init);
#endif
static struct uart_driver lh7a40x_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyAM",
.dev_name = "ttyAM",
.major = DEV_MAJOR,
.minor = DEV_MINOR,
.nr = DEV_NR,
.cons = LH7A40X_CONSOLE,
};
static int __init lh7a40xuart_init(void)
{
int ret;
printk (KERN_INFO "serial: LH7A40X serial driver\n");
ret = uart_register_driver (&lh7a40x_reg);
if (ret == 0) {
int i;
for (i = 0; i < DEV_NR; i++) {
/* UART3, when used, requires GPIO pin reallocation */
if (lh7a40x_ports[i].port.mapbase == UART3_PHYS)
GPIO_PINMUX |= 1<<3;
uart_add_one_port (&lh7a40x_reg,
&lh7a40x_ports[i].port);
}
}
return ret;
}
static void __exit lh7a40xuart_exit(void)
{
int i;
for (i = 0; i < DEV_NR; i++)
uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
uart_unregister_driver (&lh7a40x_reg);
}
module_init (lh7a40xuart_init);
module_exit (lh7a40xuart_exit);
MODULE_AUTHOR ("Marc Singer");
MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
MODULE_LICENSE ("GPL");

View file

@ -519,7 +519,7 @@ static struct console sunhv_console = {
.data = &sunhv_reg,
};
static int __devinit hv_probe(struct platform_device *op, const struct of_device_id *match)
static int __devinit hv_probe(struct platform_device *op)
{
struct uart_port *port;
unsigned long minor;
@ -629,7 +629,7 @@ static const struct of_device_id hv_match[] = {
};
MODULE_DEVICE_TABLE(of, hv_match);
static struct of_platform_driver hv_driver = {
static struct platform_driver hv_driver = {
.driver = {
.name = "hv",
.owner = THIS_MODULE,
@ -644,12 +644,12 @@ static int __init sunhv_init(void)
if (tlb_type != hypervisor)
return -ENODEV;
return of_register_platform_driver(&hv_driver);
return platform_driver_register(&hv_driver);
}
static void __exit sunhv_exit(void)
{
of_unregister_platform_driver(&hv_driver);
platform_driver_unregister(&hv_driver);
}
module_init(sunhv_init);

View file

@ -1006,7 +1006,7 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
return 0;
}
static int __devinit sab_probe(struct platform_device *op, const struct of_device_id *match)
static int __devinit sab_probe(struct platform_device *op)
{
static int inst;
struct uart_sunsab_port *up;
@ -1092,7 +1092,7 @@ static const struct of_device_id sab_match[] = {
};
MODULE_DEVICE_TABLE(of, sab_match);
static struct of_platform_driver sab_driver = {
static struct platform_driver sab_driver = {
.driver = {
.name = "sab",
.owner = THIS_MODULE,
@ -1130,12 +1130,12 @@ static int __init sunsab_init(void)
}
}
return of_register_platform_driver(&sab_driver);
return platform_driver_register(&sab_driver);
}
static void __exit sunsab_exit(void)
{
of_unregister_platform_driver(&sab_driver);
platform_driver_unregister(&sab_driver);
if (sunsab_reg.nr) {
sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr);
}

View file

@ -1406,7 +1406,7 @@ static enum su_type __devinit su_get_type(struct device_node *dp)
return SU_PORT_PORT;
}
static int __devinit su_probe(struct platform_device *op, const struct of_device_id *match)
static int __devinit su_probe(struct platform_device *op)
{
static int inst;
struct device_node *dp = op->dev.of_node;
@ -1543,7 +1543,7 @@ static const struct of_device_id su_match[] = {
};
MODULE_DEVICE_TABLE(of, su_match);
static struct of_platform_driver su_driver = {
static struct platform_driver su_driver = {
.driver = {
.name = "su",
.owner = THIS_MODULE,
@ -1586,7 +1586,7 @@ static int __init sunsu_init(void)
return err;
}
err = of_register_platform_driver(&su_driver);
err = platform_driver_register(&su_driver);
if (err && num_uart)
sunserial_unregister_minors(&sunsu_reg, num_uart);

View file

@ -1399,7 +1399,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
static int zilog_irq = -1;
static int __devinit zs_probe(struct platform_device *op, const struct of_device_id *match)
static int __devinit zs_probe(struct platform_device *op)
{
static int kbm_inst, uart_inst;
int inst;
@ -1540,7 +1540,7 @@ static const struct of_device_id zs_match[] = {
};
MODULE_DEVICE_TABLE(of, zs_match);
static struct of_platform_driver zs_driver = {
static struct platform_driver zs_driver = {
.driver = {
.name = "zs",
.owner = THIS_MODULE,
@ -1576,7 +1576,7 @@ static int __init sunzilog_init(void)
goto out_free_tables;
}
err = of_register_platform_driver(&zs_driver);
err = platform_driver_register(&zs_driver);
if (err)
goto out_unregister_uart;
@ -1604,7 +1604,7 @@ out:
return err;
out_unregister_driver:
of_unregister_platform_driver(&zs_driver);
platform_driver_unregister(&zs_driver);
out_unregister_uart:
if (num_sunzilog) {
@ -1619,7 +1619,7 @@ out_free_tables:
static void __exit sunzilog_exit(void)
{
of_unregister_platform_driver(&zs_driver);
platform_driver_unregister(&zs_driver);
if (zilog_irq != -1) {
struct uart_sunzilog_port *up = sunzilog_irq_chain;

View file

@ -19,22 +19,11 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/io.h>
#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
/* Match table for of_platform binding */
static struct of_device_id ulite_of_match[] __devinitdata = {
{ .compatible = "xlnx,opb-uartlite-1.00.b", },
{ .compatible = "xlnx,xps-uartlite-1.00.a", },
{}
};
MODULE_DEVICE_TABLE(of, ulite_of_match);
#endif
#define ULITE_NAME "ttyUL"
#define ULITE_MAJOR 204
#define ULITE_MINOR 187
@ -571,9 +560,29 @@ static int __devexit ulite_release(struct device *dev)
* Platform bus binding
*/
#if defined(CONFIG_OF)
/* Match table for of_platform binding */
static struct of_device_id ulite_of_match[] __devinitdata = {
{ .compatible = "xlnx,opb-uartlite-1.00.b", },
{ .compatible = "xlnx,xps-uartlite-1.00.a", },
{}
};
MODULE_DEVICE_TABLE(of, ulite_of_match);
#else /* CONFIG_OF */
#define ulite_of_match NULL
#endif /* CONFIG_OF */
static int __devinit ulite_probe(struct platform_device *pdev)
{
struct resource *res, *res2;
int id = pdev->id;
#ifdef CONFIG_OF
const __be32 *prop;
prop = of_get_property(pdev->dev.of_node, "port-number", NULL);
if (prop)
id = be32_to_cpup(prop);
#endif
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@ -583,7 +592,7 @@ static int __devinit ulite_probe(struct platform_device *pdev)
if (!res2)
return -ENODEV;
return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start);
return ulite_assign(&pdev->dev, id, res->start, res2->start);
}
static int __devexit ulite_remove(struct platform_device *pdev)
@ -595,72 +604,15 @@ static int __devexit ulite_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:uartlite");
static struct platform_driver ulite_platform_driver = {
.probe = ulite_probe,
.remove = __devexit_p(ulite_remove),
.driver = {
.owner = THIS_MODULE,
.name = "uartlite",
},
};
/* ---------------------------------------------------------------------
* OF bus bindings
*/
#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
static int __devinit
ulite_of_probe(struct platform_device *op, const struct of_device_id *match)
{
struct resource res;
const unsigned int *id;
int irq, rc;
dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match);
rc = of_address_to_resource(op->dev.of_node, 0, &res);
if (rc) {
dev_err(&op->dev, "invalid address\n");
return rc;
}
irq = irq_of_parse_and_map(op->dev.of_node, 0);
id = of_get_property(op->dev.of_node, "port-number", NULL);
return ulite_assign(&op->dev, id ? *id : -1, res.start, irq);
}
static int __devexit ulite_of_remove(struct platform_device *op)
{
return ulite_release(&op->dev);
}
static struct of_platform_driver ulite_of_driver = {
.probe = ulite_of_probe,
.remove = __devexit_p(ulite_of_remove),
.probe = ulite_probe,
.remove = __devexit_p(ulite_remove),
.driver = {
.name = "uartlite",
.owner = THIS_MODULE,
.name = "uartlite",
.of_match_table = ulite_of_match,
},
};
/* Registration helpers to keep the number of #ifdefs to a minimum */
static inline int __init ulite_of_register(void)
{
pr_debug("uartlite: calling of_register_platform_driver()\n");
return of_register_platform_driver(&ulite_of_driver);
}
static inline void __exit ulite_of_unregister(void)
{
of_unregister_platform_driver(&ulite_of_driver);
}
#else /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
/* Appropriate config not enabled; do nothing helpers */
static inline int __init ulite_of_register(void) { return 0; }
static inline void __exit ulite_of_unregister(void) { }
#endif /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
/* ---------------------------------------------------------------------
* Module setup/teardown
*/
@ -674,10 +626,6 @@ int __init ulite_init(void)
if (ret)
goto err_uart;
ret = ulite_of_register();
if (ret)
goto err_of;
pr_debug("uartlite: calling platform_driver_register()\n");
ret = platform_driver_register(&ulite_platform_driver);
if (ret)
@ -686,8 +634,6 @@ int __init ulite_init(void)
return 0;
err_plat:
ulite_of_unregister();
err_of:
uart_unregister_driver(&ulite_uart_driver);
err_uart:
printk(KERN_ERR "registering uartlite driver failed: err=%i", ret);
@ -697,7 +643,6 @@ err_uart:
void __exit ulite_exit(void)
{
platform_driver_unregister(&ulite_platform_driver);
ulite_of_unregister();
uart_unregister_driver(&ulite_uart_driver);
}

View file

@ -1194,8 +1194,7 @@ static void uart_firmware_cont(const struct firmware *fw, void *context)
release_firmware(fw);
}
static int ucc_uart_probe(struct platform_device *ofdev,
const struct of_device_id *match)
static int ucc_uart_probe(struct platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_node;
const unsigned int *iprop; /* Integer OF properties */
@ -1485,7 +1484,7 @@ static struct of_device_id ucc_uart_match[] = {
};
MODULE_DEVICE_TABLE(of, ucc_uart_match);
static struct of_platform_driver ucc_uart_of_driver = {
static struct platform_driver ucc_uart_of_driver = {
.driver = {
.name = "ucc_uart",
.owner = THIS_MODULE,
@ -1510,7 +1509,7 @@ static int __init ucc_uart_init(void)
return ret;
}
ret = of_register_platform_driver(&ucc_uart_of_driver);
ret = platform_driver_register(&ucc_uart_of_driver);
if (ret)
printk(KERN_ERR
"ucc-uart: could not register platform driver\n");
@ -1523,7 +1522,7 @@ static void __exit ucc_uart_exit(void)
printk(KERN_INFO
"Freescale QUICC Engine UART device driver unloading\n");
of_unregister_platform_driver(&ucc_uart_of_driver);
platform_driver_unregister(&ucc_uart_of_driver);
uart_unregister_driver(&ucc_uart_driver);
}

8119
drivers/tty/synclink.c Normal file

File diff suppressed because it is too large Load diff

5161
drivers/tty/synclink_gt.c Normal file

File diff suppressed because it is too large Load diff

5600
drivers/tty/synclinkmp.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -571,6 +571,7 @@ struct sysrq_state {
unsigned int alt_use;
bool active;
bool need_reinject;
bool reinjecting;
};
static void sysrq_reinject_alt_sysrq(struct work_struct *work)
@ -581,6 +582,10 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work)
unsigned int alt_code = sysrq->alt_use;
if (sysrq->need_reinject) {
/* we do not want the assignment to be reordered */
sysrq->reinjecting = true;
mb();
/* Simulate press and release of Alt + SysRq */
input_inject_event(handle, EV_KEY, alt_code, 1);
input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1);
@ -589,6 +594,9 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work)
input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0);
input_inject_event(handle, EV_KEY, alt_code, 0);
input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
mb();
sysrq->reinjecting = false;
}
}
@ -599,6 +607,13 @@ static bool sysrq_filter(struct input_handle *handle,
bool was_active = sysrq->active;
bool suppress;
/*
* Do not filter anything if we are in the process of re-injecting
* Alt+SysRq combination.
*/
if (sysrq->reinjecting)
return false;
switch (type) {
case EV_SYN:
@ -629,7 +644,7 @@ static bool sysrq_filter(struct input_handle *handle,
sysrq->alt_use = sysrq->alt;
/*
* If nothing else will be pressed we'll need
* to * re-inject Alt-SysRq keysroke.
* to re-inject Alt-SysRq keysroke.
*/
sysrq->need_reinject = true;
}

View file

@ -95,8 +95,10 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
{
if (buf->valid == 0)
return;
if (audit_enabled == 0)
if (audit_enabled == 0) {
buf->valid = 0;
return;
}
tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
buf->data, buf->valid);
buf->valid = 0;

View file

@ -90,7 +90,6 @@
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/bitops.h>
@ -2465,12 +2464,12 @@ out:
* Locking: none (up to the driver)
*/
static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
static int tty_tiocmget(struct tty_struct *tty, int __user *p)
{
int retval = -EINVAL;
if (tty->ops->tiocmget) {
retval = tty->ops->tiocmget(tty, file);
retval = tty->ops->tiocmget(tty);
if (retval >= 0)
retval = put_user(retval, p);
@ -2481,7 +2480,6 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p
/**
* tty_tiocmset - set modem status
* @tty: tty device
* @file: user file pointer
* @cmd: command - clear bits, set bits or set all
* @p: pointer to desired bits
*
@ -2491,7 +2489,7 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p
* Locking: none (up to the driver)
*/
static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd,
unsigned __user *p)
{
int retval;
@ -2518,7 +2516,7 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
}
set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
return tty->ops->tiocmset(tty, file, set, clear);
return tty->ops->tiocmset(tty, set, clear);
}
static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
@ -2627,6 +2625,11 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return put_user(tty->ldisc->ops->num, (int __user *)p);
case TIOCSETD:
return tiocsetd(tty, p);
case TIOCVHANGUP:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
tty_vhangup(tty);
return 0;
case TIOCGDEV:
{
unsigned int ret = new_encode_dev(tty_devnum(real_tty));
@ -2655,11 +2658,11 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return send_break(tty, arg ? arg*100 : 250);
case TIOCMGET:
return tty_tiocmget(tty, file, p);
return tty_tiocmget(tty, p);
case TIOCMSET:
case TIOCMBIC:
case TIOCMBIS:
return tty_tiocmset(tty, file, cmd, p);
return tty_tiocmset(tty, cmd, p);
case TIOCGICOUNT:
retval = tty_tiocgicount(tty, p);
/* For the moment allow fall through to the old method */
@ -2677,7 +2680,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
if (tty->ops->ioctl) {
retval = (tty->ops->ioctl)(tty, file, cmd, arg);
retval = (tty->ops->ioctl)(tty, cmd, arg);
if (retval != -ENOIOCTLCMD)
return retval;
}
@ -2705,7 +2708,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
return -EINVAL;
if (tty->ops->compat_ioctl) {
retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
retval = (tty->ops->compat_ioctl)(tty, cmd, arg);
if (retval != -ENOIOCTLCMD)
return retval;
}

View file

@ -486,7 +486,7 @@ int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
EXPORT_SYMBOL(tty_termios_hw_change);
/**
* change_termios - update termios values
* tty_set_termios - update termios values
* @tty: tty to update
* @new_termios: desired new value
*
@ -497,7 +497,7 @@ EXPORT_SYMBOL(tty_termios_hw_change);
* Locking: termios_mutex
*/
static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
{
struct ktermios old_termios;
struct tty_ldisc *ld;
@ -553,7 +553,9 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
tty_ldisc_deref(ld);
}
mutex_unlock(&tty->termios_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(tty_set_termios);
/**
* set_termios - set termios values for a tty
@ -562,7 +564,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
* @opt: option information
*
* Helper function to prepare termios data and run necessary other
* functions before using change_termios to do the actual changes.
* functions before using tty_set_termios to do the actual changes.
*
* Locking:
* Called functions take ldisc and termios_mutex locks
@ -620,7 +622,7 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
return -EINTR;
}
change_termios(tty, &tmp_termios);
tty_set_termios(tty, &tmp_termios);
/* FIXME: Arguably if tmp_termios == tty->termios AND the
actual requested termios was not tmp_termios then we may
@ -797,7 +799,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
termios.c_ospeed);
#endif
mutex_unlock(&tty->termios_mutex);
change_termios(tty, &termios);
tty_set_termios(tty, &termios);
return 0;
}
#endif
@ -951,6 +953,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
int ret = 0;
struct ktermios kterm;
BUG_ON(file == NULL);
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
real_tty = tty->link;

View file

@ -34,8 +34,6 @@
#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>
@ -534,6 +532,19 @@ static int tty_ldisc_halt(struct tty_struct *tty)
return cancel_delayed_work_sync(&tty->buf.work);
}
/**
* tty_ldisc_flush_works - flush all works of a tty
* @tty: tty device to flush works for
*
* Sync flush all works belonging to @tty.
*/
static void tty_ldisc_flush_works(struct tty_struct *tty)
{
flush_work_sync(&tty->hangup_work);
flush_work_sync(&tty->SAK_work);
flush_delayed_work_sync(&tty->buf.work);
}
/**
* tty_ldisc_wait_idle - wait for the ldisc to become idle
* @tty: tty to wait for
@ -653,7 +664,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
mutex_unlock(&tty->ldisc_mutex);
flush_scheduled_work();
tty_ldisc_flush_works(tty);
retval = tty_ldisc_wait_idle(tty);
@ -905,7 +916,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
tty_unlock();
tty_ldisc_halt(tty);
flush_scheduled_work();
tty_ldisc_flush_works(tty);
tty_lock();
mutex_lock(&tty->ldisc_mutex);

View file

@ -654,7 +654,8 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
if (value >= ARRAY_SIZE(fn_handler))
return;
if ((kbd->kbdmode == VC_RAW ||
kbd->kbdmode == VC_MEDIUMRAW) &&
kbd->kbdmode == VC_MEDIUMRAW ||
kbd->kbdmode == VC_OFF) &&
value != KVAL(K_SAK))
return; /* SAK is allowed even in raw mode */
fn_handler[value](vc);
@ -1295,7 +1296,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if (rc == NOTIFY_STOP)
return;
if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
if ((raw_mode || kbd->kbdmode == VC_OFF) && type != KT_SPEC && type != KT_SHIFT)
return;
(*k_handler[type])(vc, keysym & 0xff, !down);

View file

@ -26,7 +26,6 @@
#include <linux/selection.h>
#include <linux/tiocl.h>
#include <linux/console.h>
#include <linux/smp_lock.h>
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
#define isspace(c) ((c) == ' ')

View file

@ -28,13 +28,11 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/kbd_kern.h>
#include <linux/console.h>
#include <linux/device.h>
#include <linux/smp_lock.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/poll.h>
@ -51,6 +49,8 @@
#undef addr
#define HEADER_SIZE 4
#define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
struct vcs_poll_data {
struct notifier_block notifier;
unsigned int cons_num;
@ -131,21 +131,45 @@ vcs_poll_data_get(struct file *file)
return poll;
}
/*
* Returns VC for inode.
* Must be called with console_lock.
*/
static struct vc_data*
vcs_vc(struct inode *inode, int *viewed)
{
unsigned int currcons = iminor(inode) & 127;
WARN_CONSOLE_UNLOCKED();
if (currcons == 0) {
currcons = fg_console;
if (viewed)
*viewed = 1;
} else {
currcons--;
if (viewed)
*viewed = 0;
}
return vc_cons[currcons].d;
}
/*
* Returns size for VC carried by inode.
* Must be called with console_lock.
*/
static int
vcs_size(struct inode *inode)
{
int size;
int minor = iminor(inode);
int currcons = minor & 127;
struct vc_data *vc;
if (currcons == 0)
currcons = fg_console;
else
currcons--;
if (!vc_cons_allocated(currcons))
WARN_CONSOLE_UNLOCKED();
vc = vcs_vc(inode, NULL);
if (!vc)
return -ENXIO;
vc = vc_cons[currcons].d;
size = vc->vc_rows * vc->vc_cols;
@ -158,11 +182,13 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
{
int size;
mutex_lock(&con_buf_mtx);
console_lock();
size = vcs_size(file->f_path.dentry->d_inode);
console_unlock();
if (size < 0)
return size;
switch (orig) {
default:
mutex_unlock(&con_buf_mtx);
return -EINVAL;
case 2:
offset += size;
@ -173,11 +199,9 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
break;
}
if (offset < 0 || offset > size) {
mutex_unlock(&con_buf_mtx);
return -EINVAL;
}
file->f_pos = offset;
mutex_unlock(&con_buf_mtx);
return file->f_pos;
}
@ -190,12 +214,15 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
struct vc_data *vc;
struct vcs_poll_data *poll;
long pos;
long viewed, attr, read;
int col, maxcol;
long attr, read;
int col, maxcol, viewed;
unsigned short *org = NULL;
ssize_t ret;
char *con_buf;
mutex_lock(&con_buf_mtx);
con_buf = (char *) __get_free_page(GFP_KERNEL);
if (!con_buf)
return -ENOMEM;
pos = *ppos;
@ -205,18 +232,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
console_lock();
attr = (currcons & 128);
currcons = (currcons & 127);
if (currcons == 0) {
currcons = fg_console;
viewed = 1;
} else {
currcons--;
viewed = 0;
}
ret = -ENXIO;
if (!vc_cons_allocated(currcons))
vc = vcs_vc(inode, &viewed);
if (!vc)
goto unlock_out;
vc = vc_cons[currcons].d;
ret = -EINVAL;
if (pos < 0)
@ -237,6 +256,12 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
* could sleep.
*/
size = vcs_size(inode);
if (size < 0) {
if (read)
break;
ret = size;
goto unlock_out;
}
if (pos >= size)
break;
if (count > size - pos)
@ -355,7 +380,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
ret = read;
unlock_out:
console_unlock();
mutex_unlock(&con_buf_mtx);
free_page((unsigned long) con_buf);
return ret;
}
@ -366,13 +391,16 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
unsigned int currcons = iminor(inode);
struct vc_data *vc;
long pos;
long viewed, attr, size, written;
long attr, size, written;
char *con_buf0;
int col, maxcol;
int col, maxcol, viewed;
u16 *org0 = NULL, *org = NULL;
size_t ret;
char *con_buf;
mutex_lock(&con_buf_mtx);
con_buf = (char *) __get_free_page(GFP_KERNEL);
if (!con_buf)
return -ENOMEM;
pos = *ppos;
@ -382,19 +410,10 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
console_lock();
attr = (currcons & 128);
currcons = (currcons & 127);
if (currcons == 0) {
currcons = fg_console;
viewed = 1;
} else {
currcons--;
viewed = 0;
}
ret = -ENXIO;
if (!vc_cons_allocated(currcons))
vc = vcs_vc(inode, &viewed);
if (!vc)
goto unlock_out;
vc = vc_cons[currcons].d;
size = vcs_size(inode);
ret = -EINVAL;
@ -436,6 +455,12 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
* Return data written up to now on failure.
*/
size = vcs_size(inode);
if (size < 0) {
if (written)
break;
ret = size;
goto unlock_out;
}
if (pos >= size)
break;
if (this_round > size - pos)
@ -543,9 +568,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
unlock_out:
console_unlock();
mutex_unlock(&con_buf_mtx);
free_page((unsigned long) con_buf);
return ret;
}

View file

@ -89,7 +89,6 @@
#include <linux/mutex.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/smp_lock.h>
#include <linux/tiocl.h>
#include <linux/kbd_kern.h>
#include <linux/consolemap.h>
@ -2068,18 +2067,6 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
}
}
/* This is a temporary buffer used to prepare a tty console write
* so that we can easily avoid touching user space while holding the
* console spinlock. It is allocated in con_init and is shared by
* this code and the vc_screen read/write tty calls.
*
* We have to allocate this statically in the kernel data section
* since console_init (and thus con_init) are called before any
* kernel memory allocation is available.
*/
char con_buf[CON_BUF_SIZE];
DEFINE_MUTEX(con_buf_mtx);
/* is_double_width() is based on the wcwidth() implementation by
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
@ -2157,10 +2144,10 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
currcons = vc->vc_num;
if (!vc_cons_allocated(currcons)) {
/* could this happen? */
printk_once("con_write: tty %d not allocated\n", currcons+1);
console_unlock();
return 0;
/* could this happen? */
pr_warn_once("con_write: tty %d not allocated\n", currcons+1);
console_unlock();
return 0;
}
himask = vc->vc_hi_font_mask;
@ -2940,7 +2927,7 @@ static int __init con_init(void)
gotoxy(vc, vc->vc_x, vc->vc_y);
csi_J(vc, 0);
update_screen(vc);
printk("Console: %s %s %dx%d",
pr_info("Console: %s %s %dx%d",
vc->vc_can_do_color ? "colour" : "mono",
display_desc, vc->vc_cols, vc->vc_rows);
printable = 1;
@ -3103,7 +3090,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
clear_buffer_attributes(vc);
}
printk("Console: switching ");
pr_info("Console: switching ");
if (!deflt)
printk("consoles %d-%d ", first+1, last+1);
if (j >= 0) {
@ -3809,7 +3796,8 @@ void do_unblank_screen(int leaving_gfx)
return;
if (!vc_cons_allocated(fg_console)) {
/* impossible */
printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
pr_warning("unblank_screen: tty %d not allocated ??\n",
fg_console+1);
return;
}
vc = vc_cons[fg_console].d;

View file

@ -27,7 +27,6 @@
#include <linux/console.h>
#include <linux/consolemap.h>
#include <linux/signal.h>
#include <linux/smp_lock.h>
#include <linux/timex.h>
#include <asm/io.h>
@ -495,7 +494,7 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
* We handle the console-specific ioctl's here. We allow the
* capability to modify any console, not just the fg_console.
*/
int vt_ioctl(struct tty_struct *tty, struct file * file,
int vt_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct vc_data *vc = tty->driver_data;
@ -688,6 +687,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
kbd->kbdmode = VC_UNICODE;
compute_shiftstate();
break;
case K_OFF:
kbd->kbdmode = VC_OFF;
break;
default:
ret = -EINVAL;
goto out;
@ -1007,8 +1009,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (ret)
break;
/* Commence switch and lock */
set_console(arg);
set_console(vsa.console);
}
break;
}
/*
@ -1491,7 +1494,7 @@ compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
return 0;
}
long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
long vt_compat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct vc_data *vc = tty->driver_data;
@ -1577,7 +1580,7 @@ out:
fallback:
tty_unlock();
return vt_ioctl(tty, file, cmd, arg);
return vt_ioctl(tty, cmd, arg);
}