mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
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:
commit
1d2a1959fe
4568 changed files with 286714 additions and 174809 deletions
321
drivers/tty/Kconfig
Normal file
321
drivers/tty/Kconfig
Normal 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.
|
||||
|
||||
|
|
@ -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
2178
drivers/tty/amiserial.c
Normal file
File diff suppressed because it is too large
Load diff
366
drivers/tty/bfin_jtag_comm.c
Normal file
366
drivers/tty/bfin_jtag_comm.c
Normal 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
4200
drivers/tty/cyclades.c
Normal file
File diff suppressed because it is too large
Load diff
105
drivers/tty/hvc/Kconfig
Normal file
105
drivers/tty/hvc/Kconfig
Normal 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.
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
105
drivers/tty/hvc/hvc_bfin_jtag.c
Normal file
105
drivers/tty/hvc/hvc_bfin_jtag.c
Normal 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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
10
drivers/tty/ipwireless/Makefile
Normal file
10
drivers/tty/ipwireless/Makefile
Normal 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
|
||||
|
||||
1764
drivers/tty/ipwireless/hardware.c
Normal file
1764
drivers/tty/ipwireless/hardware.c
Normal file
File diff suppressed because it is too large
Load diff
62
drivers/tty/ipwireless/hardware.h
Normal file
62
drivers/tty/ipwireless/hardware.h
Normal 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
|
||||
347
drivers/tty/ipwireless/main.c
Normal file
347
drivers/tty/ipwireless/main.c
Normal 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");
|
||||
68
drivers/tty/ipwireless/main.h
Normal file
68
drivers/tty/ipwireless/main.h
Normal 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
|
||||
508
drivers/tty/ipwireless/network.c
Normal file
508
drivers/tty/ipwireless/network.c
Normal 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;
|
||||
}
|
||||
53
drivers/tty/ipwireless/network.h
Normal file
53
drivers/tty/ipwireless/network.h
Normal 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
|
||||
108
drivers/tty/ipwireless/setup_protocol.h
Normal file
108
drivers/tty/ipwireless/setup_protocol.h
Normal 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_ */
|
||||
679
drivers/tty/ipwireless/tty.c
Normal file
679
drivers/tty/ipwireless/tty.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
45
drivers/tty/ipwireless/tty.h
Normal file
45
drivers/tty/ipwireless/tty.h
Normal 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
1736
drivers/tty/isicom.c
Normal file
File diff suppressed because it is too large
Load diff
2092
drivers/tty/moxa.c
Normal file
2092
drivers/tty/moxa.c
Normal file
File diff suppressed because it is too large
Load diff
304
drivers/tty/moxa.h
Normal file
304
drivers/tty/moxa.h
Normal 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
2757
drivers/tty/mxser.c
Normal file
File diff suppressed because it is too large
Load diff
150
drivers/tty/mxser.h
Normal file
150
drivers/tty/mxser.h
Normal 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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
1991
drivers/tty/nozomi.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
3199
drivers/tty/rocket.c
Normal file
File diff suppressed because it is too large
Load diff
111
drivers/tty/rocket.h
Normal file
111
drivers/tty/rocket.h
Normal 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
1214
drivers/tty/rocket_int.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
1880
drivers/tty/serial/msm_serial_hs.c
Normal file
1880
drivers/tty/serial/msm_serial_hs.c
Normal file
File diff suppressed because it is too large
Load diff
236
drivers/tty/serial/msm_smd_tty.c
Normal file
236
drivers/tty/serial/msm_smd_tty.c
Normal 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);
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
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
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
5600
drivers/tty/synclinkmp.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) == ' ')
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue