tty and serial merge for 3.4-rc1
Here's the big serial and tty merge for the 3.4-rc1 tree. There's loads of fixes and reworks in here from Jiri for the tty layer, and a number of patches from Alan to help try to wrestle the vt layer into a sane model. Other than that, lots of driver updates and fixes, and other minor stuff, all detailed in the shortlog. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.18 (GNU/Linux) iEYEABECAAYFAk9nihQACgkQMUfUDdst+ylXTQCdFuwVuZgjCts+xDVa1jX2ac84 UogAn3Wr+P7NYFN6gvaGm52KbGbZs405 =2b/l -----END PGP SIGNATURE----- Merge tag 'tty-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull TTY/serial patches from Greg KH: "tty and serial merge for 3.4-rc1 Here's the big serial and tty merge for the 3.4-rc1 tree. There's loads of fixes and reworks in here from Jiri for the tty layer, and a number of patches from Alan to help try to wrestle the vt layer into a sane model. Other than that, lots of driver updates and fixes, and other minor stuff, all detailed in the shortlog." * tag 'tty-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (132 commits) serial: pxa: add clk_prepare/clk_unprepare calls TTY: Wrong unicode value copied in con_set_unimap() serial: PL011: clear pending interrupts serial: bfin-uart: Don't access tty circular buffer in TX DMA interrupt after it is reset. vt: NULL dereference in vt_do_kdsk_ioctl() tty: serial: vt8500: fix annotations for probe/remove serial: remove back and forth conversions in serial_out_sync serial: use serial_port_in/out vs serial_in/out in 8250 serial: introduce generic port in/out helpers serial: reduce number of indirections in 8250 code serial: delete useless void casts in 8250.c serial: make 8250's serial_in shareable to other drivers. serial: delete last unused traces of pausing I/O in 8250 pch_uart: Add module parameter descriptions pch_uart: Use existing default_baud in setup_console pch_uart: Add user_uartclk parameter pch_uart: Add Fish River Island II uart clock quirks pch_uart: Use uartclk instead of base_baud mpc5200b/uart: select more tolerant uart prescaler on low baudrates tty: moxa: fix bit test in moxa_start() ...
This commit is contained in:
commit
843ec558f9
|
@ -0,0 +1,14 @@
|
|||
* Energymicro efm32 UART
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "efm32,uart"
|
||||
- reg : Address and length of the register set
|
||||
- interrupts : Should contain uart interrupt
|
||||
|
||||
Example:
|
||||
|
||||
uart@0x4000c400 {
|
||||
compatible = "efm32,uart";
|
||||
reg = <0x4000c400 0x400>;
|
||||
interrupts = <15>;
|
||||
};
|
|
@ -6212,8 +6212,8 @@ L: sparclinux@vger.kernel.org
|
|||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
|
||||
S: Maintained
|
||||
F: include/linux/sunserialcore.h
|
||||
F: drivers/tty/serial/suncore.c
|
||||
F: drivers/tty/serial/suncore.h
|
||||
F: drivers/tty/serial/sunhv.c
|
||||
F: drivers/tty/serial/sunsab.c
|
||||
F: drivers/tty/serial/sunsab.h
|
||||
|
|
|
@ -30,10 +30,9 @@ static int srm_is_registered_console = 0;
|
|||
#define MAX_SRM_CONSOLE_DEVICES 1 /* only support 1 console device */
|
||||
|
||||
struct srmcons_private {
|
||||
struct tty_struct *tty;
|
||||
struct tty_port port;
|
||||
struct timer_list timer;
|
||||
spinlock_t lock;
|
||||
};
|
||||
} srmcons_singleton;
|
||||
|
||||
typedef union _srmcons_result {
|
||||
struct {
|
||||
|
@ -68,22 +67,21 @@ static void
|
|||
srmcons_receive_chars(unsigned long data)
|
||||
{
|
||||
struct srmcons_private *srmconsp = (struct srmcons_private *)data;
|
||||
struct tty_port *port = &srmconsp->port;
|
||||
unsigned long flags;
|
||||
int incr = 10;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (spin_trylock(&srmcons_callback_lock)) {
|
||||
if (!srmcons_do_receive_chars(srmconsp->tty))
|
||||
if (!srmcons_do_receive_chars(port->tty))
|
||||
incr = 100;
|
||||
spin_unlock(&srmcons_callback_lock);
|
||||
}
|
||||
|
||||
spin_lock(&srmconsp->lock);
|
||||
if (srmconsp->tty) {
|
||||
srmconsp->timer.expires = jiffies + incr;
|
||||
add_timer(&srmconsp->timer);
|
||||
}
|
||||
spin_unlock(&srmconsp->lock);
|
||||
spin_lock(&port->lock);
|
||||
if (port->tty)
|
||||
mod_timer(&srmconsp->timer, jiffies + incr);
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
@ -155,57 +153,23 @@ srmcons_chars_in_buffer(struct tty_struct *tty)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
srmcons_get_private_struct(struct srmcons_private **ps)
|
||||
{
|
||||
static struct srmcons_private *srmconsp = NULL;
|
||||
static DEFINE_SPINLOCK(srmconsp_lock);
|
||||
unsigned long flags;
|
||||
int retval = 0;
|
||||
|
||||
if (srmconsp == NULL) {
|
||||
srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
|
||||
spin_lock_irqsave(&srmconsp_lock, flags);
|
||||
|
||||
if (srmconsp == NULL)
|
||||
retval = -ENOMEM;
|
||||
else {
|
||||
srmconsp->tty = NULL;
|
||||
spin_lock_init(&srmconsp->lock);
|
||||
init_timer(&srmconsp->timer);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&srmconsp_lock, flags);
|
||||
}
|
||||
|
||||
*ps = srmconsp;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
srmcons_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct srmcons_private *srmconsp;
|
||||
struct srmcons_private *srmconsp = &srmcons_singleton;
|
||||
struct tty_port *port = &srmconsp->port;
|
||||
unsigned long flags;
|
||||
int retval;
|
||||
|
||||
retval = srmcons_get_private_struct(&srmconsp);
|
||||
if (retval)
|
||||
return retval;
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
spin_lock_irqsave(&srmconsp->lock, flags);
|
||||
|
||||
if (!srmconsp->tty) {
|
||||
if (!port->tty) {
|
||||
tty->driver_data = srmconsp;
|
||||
|
||||
srmconsp->tty = tty;
|
||||
srmconsp->timer.function = srmcons_receive_chars;
|
||||
srmconsp->timer.data = (unsigned long)srmconsp;
|
||||
srmconsp->timer.expires = jiffies + 10;
|
||||
add_timer(&srmconsp->timer);
|
||||
tty->port = port;
|
||||
port->tty = tty; /* XXX proper refcounting */
|
||||
mod_timer(&srmconsp->timer, jiffies + 10);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&srmconsp->lock, flags);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -214,16 +178,17 @@ static void
|
|||
srmcons_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct srmcons_private *srmconsp = tty->driver_data;
|
||||
struct tty_port *port = &srmconsp->port;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&srmconsp->lock, flags);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
if (tty->count == 1) {
|
||||
srmconsp->tty = NULL;
|
||||
port->tty = NULL;
|
||||
del_timer(&srmconsp->timer);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&srmconsp->lock, flags);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
|
||||
|
@ -240,6 +205,9 @@ static const struct tty_operations srmcons_ops = {
|
|||
static int __init
|
||||
srmcons_init(void)
|
||||
{
|
||||
tty_port_init(&srmcons_singleton.port);
|
||||
setup_timer(&srmcons_singleton.timer, srmcons_receive_chars,
|
||||
(unsigned long)&srmcons_singleton);
|
||||
if (srm_is_registered_console) {
|
||||
struct tty_driver *driver;
|
||||
int err;
|
||||
|
|
|
@ -160,28 +160,19 @@ sal_emulator (long index, unsigned long in1, unsigned long in2,
|
|||
*/
|
||||
status = 0;
|
||||
if (index == SAL_FREQ_BASE) {
|
||||
switch (in1) {
|
||||
case SAL_FREQ_BASE_PLATFORM:
|
||||
if (in1 == SAL_FREQ_BASE_PLATFORM)
|
||||
r9 = 200000000;
|
||||
break;
|
||||
|
||||
case SAL_FREQ_BASE_INTERVAL_TIMER:
|
||||
else if (in1 == SAL_FREQ_BASE_INTERVAL_TIMER) {
|
||||
/*
|
||||
* Is this supposed to be the cr.itc frequency
|
||||
* or something platform specific? The SAL
|
||||
* doc ain't exactly clear on this...
|
||||
*/
|
||||
r9 = 700000000;
|
||||
break;
|
||||
|
||||
case SAL_FREQ_BASE_REALTIME_CLOCK:
|
||||
} else if (in1 == SAL_FREQ_BASE_REALTIME_CLOCK)
|
||||
r9 = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
else
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
} else if (index == SAL_SET_VECTORS) {
|
||||
;
|
||||
} else if (index == SAL_GET_STATE_INFO) {
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include "hpsim_ssc.h"
|
||||
|
||||
static unsigned int
|
||||
hpsim_irq_startup(struct irq_data *data)
|
||||
{
|
||||
|
@ -37,15 +39,37 @@ static struct irq_chip irq_type_hp_sim = {
|
|||
.irq_set_affinity = hpsim_set_affinity_noop,
|
||||
};
|
||||
|
||||
static void hpsim_irq_set_chip(int irq)
|
||||
{
|
||||
struct irq_chip *chip = irq_get_chip(irq);
|
||||
|
||||
if (chip == &no_irq_chip)
|
||||
irq_set_chip(irq, &irq_type_hp_sim);
|
||||
}
|
||||
|
||||
static void hpsim_connect_irq(int intr, int irq)
|
||||
{
|
||||
ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
|
||||
}
|
||||
|
||||
int hpsim_get_irq(int intr)
|
||||
{
|
||||
int irq = assign_irq_vector(AUTO_ASSIGN);
|
||||
|
||||
if (irq >= 0) {
|
||||
hpsim_irq_set_chip(irq);
|
||||
irq_set_handler(irq, handle_simple_irq);
|
||||
hpsim_connect_irq(intr, irq);
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
void __init
|
||||
hpsim_irq_init (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for_each_active_irq(i) {
|
||||
struct irq_chip *chip = irq_get_chip(i);
|
||||
|
||||
if (chip == &no_irq_chip)
|
||||
irq_set_chip(i, &irq_type_hp_sim);
|
||||
}
|
||||
for_each_active_irq(i)
|
||||
hpsim_irq_set_chip(i);
|
||||
}
|
||||
|
|
|
@ -25,12 +25,6 @@
|
|||
|
||||
#include "hpsim_ssc.h"
|
||||
|
||||
void
|
||||
ia64_ssc_connect_irq (long intr, long irq)
|
||||
{
|
||||
ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
|
||||
}
|
||||
|
||||
void
|
||||
ia64_ctl_trace (long on)
|
||||
{
|
||||
|
|
|
@ -128,17 +128,6 @@ netdev_probe(char *name, unsigned char *ether)
|
|||
}
|
||||
|
||||
|
||||
static inline int
|
||||
netdev_connect(int irq)
|
||||
{
|
||||
/* XXX Fix me
|
||||
* this does not support multiple cards
|
||||
* also no return value
|
||||
*/
|
||||
ia64_ssc_connect_irq(NETWORK_INTR, irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
netdev_attach(int fd, int irq, unsigned int ipaddr)
|
||||
{
|
||||
|
@ -226,15 +215,13 @@ simeth_probe1(void)
|
|||
return err;
|
||||
}
|
||||
|
||||
if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)
|
||||
panic("%s: out of interrupt vectors!\n", __func__);
|
||||
dev->irq = rc;
|
||||
|
||||
/*
|
||||
* attach the interrupt in the simulator, this does enable interrupts
|
||||
* until a netdev_attach() is called
|
||||
*/
|
||||
netdev_connect(dev->irq);
|
||||
if ((rc = hpsim_get_irq(NETWORK_INTR)) < 0)
|
||||
panic("%s: out of interrupt vectors!\n", __func__);
|
||||
dev->irq = rc;
|
||||
|
||||
printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr",
|
||||
dev->name, simeth_device, local->simfd);
|
||||
|
|
|
@ -4,16 +4,11 @@
|
|||
* This driver is mostly used for bringup purposes and will go away.
|
||||
* It has a strong dependency on the system console. All outputs
|
||||
* are rerouted to the same facility as the one used by printk which, in our
|
||||
* case means sys_sim.c console (goes via the simulator). The code hereafter
|
||||
* is completely leveraged from the serial.c driver.
|
||||
* case means sys_sim.c console (goes via the simulator).
|
||||
*
|
||||
* Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co
|
||||
* Stephane Eranian <eranian@hpl.hp.com>
|
||||
* David Mosberger-Tang <davidm@hpl.hp.com>
|
||||
*
|
||||
* 02/04/00 D. Mosberger Merged in serial.c bug fixes in rs_close().
|
||||
* 02/25/00 D. Mosberger Synced up with 2.3.99pre-5 version of serial.c.
|
||||
* 07/30/02 D. Mosberger Replace sti()/cli() with explicit spinlocks & local irq masking
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
|
@ -27,15 +22,17 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serialP.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/hpsim.h>
|
||||
|
||||
#include "hpsim_ssc.h"
|
||||
|
||||
#undef SIMSERIAL_DEBUG /* define this to get some debug information */
|
||||
|
||||
|
@ -43,118 +40,44 @@
|
|||
|
||||
#define NR_PORTS 1 /* only one port for now */
|
||||
|
||||
#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED)
|
||||
|
||||
#define SSC_GETCHAR 21
|
||||
|
||||
extern long ia64_ssc (long, long, long, long, int);
|
||||
extern void ia64_ssc_connect_irq (long intr, long irq);
|
||||
|
||||
static char *serial_name = "SimSerial driver";
|
||||
static char *serial_version = "0.6";
|
||||
|
||||
/*
|
||||
* This has been extracted from asm/serial.h. We need one eventually but
|
||||
* I don't know exactly what we're going to put in it so just fake one
|
||||
* for now.
|
||||
*/
|
||||
#define BASE_BAUD ( 1843200 / 16 )
|
||||
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
|
||||
|
||||
/*
|
||||
* Most of the values here are meaningless to this particular driver.
|
||||
* However some values must be preserved for the code (leveraged from serial.c
|
||||
* to work correctly).
|
||||
* port must not be 0
|
||||
* type must not be UNKNOWN
|
||||
* So I picked arbitrary (guess from where?) values instead
|
||||
*/
|
||||
static struct serial_state rs_table[NR_PORTS]={
|
||||
/* UART CLK PORT IRQ FLAGS */
|
||||
{ 0, BASE_BAUD, 0x3F8, 0, STD_COM_FLAGS,0,PORT_16550 } /* ttyS0 */
|
||||
struct serial_state {
|
||||
struct tty_port port;
|
||||
struct circ_buf xmit;
|
||||
int irq;
|
||||
int x_char;
|
||||
};
|
||||
|
||||
/*
|
||||
* Just for the fun of it !
|
||||
*/
|
||||
static struct serial_uart_config uart_config[] = {
|
||||
{ "unknown", 1, 0 },
|
||||
{ "8250", 1, 0 },
|
||||
{ "16450", 1, 0 },
|
||||
{ "16550", 1, 0 },
|
||||
{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
|
||||
{ "cirrus", 1, 0 },
|
||||
{ "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
|
||||
{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
|
||||
UART_STARTECH },
|
||||
{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
|
||||
{ NULL, 0}
|
||||
};
|
||||
static struct serial_state rs_table[NR_PORTS];
|
||||
|
||||
struct tty_driver *hp_simserial_driver;
|
||||
|
||||
static struct async_struct *IRQ_ports[NR_IRQS];
|
||||
|
||||
static struct console *console;
|
||||
|
||||
static unsigned char *tmp_buf;
|
||||
|
||||
extern struct console *console_drivers; /* from kernel/printk.c */
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* rs_stop() and rs_start()
|
||||
*
|
||||
* This routines are called before setting or resetting tty->stopped.
|
||||
* They enable or disable transmitter interrupts, as necessary.
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
static void rs_stop(struct tty_struct *tty)
|
||||
{
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("rs_stop: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
|
||||
tty->stopped, tty->hw_stopped, tty->flow_stopped);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void rs_start(struct tty_struct *tty)
|
||||
{
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
|
||||
tty->stopped, tty->hw_stopped, tty->flow_stopped);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void receive_chars(struct tty_struct *tty)
|
||||
static void receive_chars(struct tty_struct *tty)
|
||||
{
|
||||
unsigned char ch;
|
||||
static unsigned char seen_esc = 0;
|
||||
|
||||
while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) {
|
||||
if ( ch == 27 && seen_esc == 0 ) {
|
||||
if (ch == 27 && seen_esc == 0) {
|
||||
seen_esc = 1;
|
||||
continue;
|
||||
} else {
|
||||
if ( seen_esc==1 && ch == 'O' ) {
|
||||
seen_esc = 2;
|
||||
continue;
|
||||
} else if ( seen_esc == 2 ) {
|
||||
if ( ch == 'P' ) /* F1 */
|
||||
show_state();
|
||||
} else if (seen_esc == 1 && ch == 'O') {
|
||||
seen_esc = 2;
|
||||
continue;
|
||||
} else if (seen_esc == 2) {
|
||||
if (ch == 'P') /* F1 */
|
||||
show_state();
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
if ( ch == 'S' ) { /* F4 */
|
||||
do
|
||||
ch = ia64_ssc(0, 0, 0, 0,
|
||||
SSC_GETCHAR);
|
||||
while (!ch);
|
||||
handle_sysrq(ch);
|
||||
}
|
||||
#endif
|
||||
seen_esc = 0;
|
||||
continue;
|
||||
if (ch == 'S') { /* F4 */
|
||||
do {
|
||||
ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR);
|
||||
} while (!ch);
|
||||
handle_sysrq(ch);
|
||||
}
|
||||
#endif
|
||||
seen_esc = 0;
|
||||
continue;
|
||||
}
|
||||
seen_esc = 0;
|
||||
|
||||
|
@ -169,22 +92,19 @@ static void receive_chars(struct tty_struct *tty)
|
|||
*/
|
||||
static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
|
||||
{
|
||||
struct async_struct * info;
|
||||
struct serial_state *info = dev_id;
|
||||
struct tty_struct *tty = tty_port_tty_get(&info->port);
|
||||
|
||||
/*
|
||||
* I don't know exactly why they don't use the dev_id opaque data
|
||||
* pointer instead of this extra lookup table
|
||||
*/
|
||||
info = IRQ_ports[irq];
|
||||
if (!info || !info->tty) {
|
||||
printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info);
|
||||
if (!tty) {
|
||||
printk(KERN_INFO "%s: tty=0 problem\n", __func__);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
/*
|
||||
* pretty simple in our case, because we only get interrupts
|
||||
* on inbound traffic
|
||||
*/
|
||||
receive_chars(info->tty);
|
||||
receive_chars(tty);
|
||||
tty_kref_put(tty);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -194,17 +114,12 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
|
|||
* -------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void do_softint(struct work_struct *private_)
|
||||
{
|
||||
printk(KERN_ERR "simserial: do_softint called\n");
|
||||
}
|
||||
|
||||
static int rs_put_char(struct tty_struct *tty, unsigned char ch)
|
||||
{
|
||||
struct async_struct *info = (struct async_struct *)tty->driver_data;
|
||||
struct serial_state *info = tty->driver_data;
|
||||
unsigned long flags;
|
||||
|
||||
if (!tty || !info->xmit.buf)
|
||||
if (!info->xmit.buf)
|
||||
return 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
@ -218,12 +133,12 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void transmit_chars(struct async_struct *info, int *intr_done)
|
||||
static void transmit_chars(struct tty_struct *tty, struct serial_state *info,
|
||||
int *intr_done)
|
||||
{
|
||||
int count;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (info->x_char) {
|
||||
|
@ -231,16 +146,16 @@ static void transmit_chars(struct async_struct *info, int *intr_done)
|
|||
|
||||
console->write(console, &c, 1);
|
||||
|
||||
info->state->icount.tx++;
|
||||
info->x_char = 0;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) {
|
||||
if (info->xmit.head == info->xmit.tail || tty->stopped ||
|
||||
tty->hw_stopped) {
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("transmit_chars: head=%d, tail=%d, stopped=%d\n",
|
||||
info->xmit.head, info->xmit.tail, info->tty->stopped);
|
||||
info->xmit.head, info->xmit.tail, tty->stopped);
|
||||
#endif
|
||||
goto out;
|
||||
}
|
||||
|
@ -272,24 +187,24 @@ out:
|
|||
|
||||
static void rs_flush_chars(struct tty_struct *tty)
|
||||
{
|
||||
struct async_struct *info = (struct async_struct *)tty->driver_data;
|
||||
struct serial_state *info = tty->driver_data;
|
||||
|
||||
if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped ||
|
||||
!info->xmit.buf)
|
||||
if (info->xmit.head == info->xmit.tail || tty->stopped ||
|
||||
tty->hw_stopped || !info->xmit.buf)
|
||||
return;
|
||||
|
||||
transmit_chars(info, NULL);
|
||||
transmit_chars(tty, info, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int rs_write(struct tty_struct * tty,
|
||||
const unsigned char *buf, int count)
|
||||
{
|
||||
struct serial_state *info = tty->driver_data;
|
||||
int c, ret = 0;
|
||||
struct async_struct *info = (struct async_struct *)tty->driver_data;
|
||||
unsigned long flags;
|
||||
|
||||
if (!tty || !info->xmit.buf || !tmp_buf) return 0;
|
||||
if (!info->xmit.buf)
|
||||
return 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
while (1) {
|
||||
|
@ -310,30 +225,30 @@ static int rs_write(struct tty_struct * tty,
|
|||
/*
|
||||
* Hey, we transmit directly from here in our case
|
||||
*/
|
||||
if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE)
|
||||
&& !tty->stopped && !tty->hw_stopped) {
|
||||
transmit_chars(info, NULL);
|
||||
}
|
||||
if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) &&
|
||||
!tty->stopped && !tty->hw_stopped)
|
||||
transmit_chars(tty, info, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rs_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct async_struct *info = (struct async_struct *)tty->driver_data;
|
||||
struct serial_state *info = tty->driver_data;
|
||||
|
||||
return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
|
||||
}
|
||||
|
||||
static int rs_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct async_struct *info = (struct async_struct *)tty->driver_data;
|
||||
struct serial_state *info = tty->driver_data;
|
||||
|
||||
return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
|
||||
}
|
||||
|
||||
static void rs_flush_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct async_struct *info = (struct async_struct *)tty->driver_data;
|
||||
struct serial_state *info = tty->driver_data;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
@ -349,7 +264,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
|
|||
*/
|
||||
static void rs_send_xchar(struct tty_struct *tty, char ch)
|
||||
{
|
||||
struct async_struct *info = (struct async_struct *)tty->driver_data;
|
||||
struct serial_state *info = tty->driver_data;
|
||||
|
||||
info->x_char = ch;
|
||||
if (ch) {
|
||||
|
@ -357,7 +272,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
|
|||
* I guess we could call console->write() directly but
|
||||
* let's do that for now.
|
||||
*/
|
||||
transmit_chars(info, NULL);
|
||||
transmit_chars(tty, info, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,14 +286,15 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
|
|||
*/
|
||||
static void rs_throttle(struct tty_struct * tty)
|
||||
{
|
||||
if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty));
|
||||
if (I_IXOFF(tty))
|
||||
rs_send_xchar(tty, STOP_CHAR(tty));
|
||||
|
||||
printk(KERN_INFO "simrs_throttle called\n");
|
||||
}
|
||||
|
||||
static void rs_unthrottle(struct tty_struct * tty)
|
||||
{
|
||||
struct async_struct *info = (struct async_struct *)tty->driver_data;
|
||||
struct serial_state *info = tty->driver_data;
|
||||
|
||||
if (I_IXOFF(tty)) {
|
||||
if (info->x_char)
|
||||
|
@ -389,7 +305,6 @@ static void rs_unthrottle(struct tty_struct * tty)
|
|||
printk(KERN_INFO "simrs_unthrottle called\n");
|
||||
}
|
||||
|
||||
|
||||
static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||
|
@ -400,48 +315,21 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
|||
}
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCGSERIAL:
|
||||
printk(KERN_INFO "simrs_ioctl TIOCGSERIAL called\n");
|
||||
return 0;
|
||||
case TIOCSSERIAL:
|
||||
printk(KERN_INFO "simrs_ioctl TIOCSSERIAL called\n");
|
||||
return 0;
|
||||
case TIOCSERCONFIG:
|
||||
printk(KERN_INFO "rs_ioctl: TIOCSERCONFIG called\n");
|
||||
return -EINVAL;
|
||||
|
||||
case TIOCSERGETLSR: /* Get line status register */
|
||||
printk(KERN_INFO "rs_ioctl: TIOCSERGETLSR called\n");
|
||||
return -EINVAL;
|
||||
|
||||
case TIOCSERGSTRUCT:
|
||||
printk(KERN_INFO "rs_ioctl: TIOCSERGSTRUCT called\n");
|
||||
#if 0
|
||||
if (copy_to_user((struct async_struct *) arg,
|
||||
info, sizeof(struct async_struct)))
|
||||
return -EFAULT;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
|
||||
* - mask passed in arg for lines of interest
|
||||
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
|
||||
* Caller should use TIOCGICOUNT to see which one it was
|
||||
*/
|
||||
case TIOCMIWAIT:
|
||||
printk(KERN_INFO "rs_ioctl: TIOCMIWAIT: called\n");
|
||||
return 0;
|
||||
case TIOCSERGWILD:
|
||||
case TIOCSERSWILD:
|
||||
/* "setserial -W" is called in Debian boot */
|
||||
printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n");
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
return 0;
|
||||
case TIOCGSERIAL:
|
||||
case TIOCSSERIAL:
|
||||
case TIOCSERGSTRUCT:
|
||||
case TIOCMIWAIT:
|
||||
return 0;
|
||||
case TIOCSERCONFIG:
|
||||
case TIOCSERGETLSR: /* Get line status register */
|
||||
return -EINVAL;
|
||||
case TIOCSERGWILD:
|
||||
case TIOCSERSWILD:
|
||||
/* "setserial -W" is called in Debian boot */
|
||||
printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n");
|
||||
return 0;
|
||||
}
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
|
||||
|
@ -452,220 +340,50 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
|||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios->c_cflag & CRTSCTS)) {
|
||||
tty->hw_stopped = 0;
|
||||
rs_start(tty);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This routine will shutdown a serial port; interrupts are disabled, and
|
||||
* DTR is dropped if the hangup on close termio flag is on.
|
||||
*/
|
||||
static void shutdown(struct async_struct * info)
|
||||
static void shutdown(struct tty_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct serial_state *state;
|
||||
int retval;
|
||||
|
||||
if (!(info->flags & ASYNC_INITIALIZED)) return;
|
||||
|
||||
state = info->state;
|
||||
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("Shutting down serial port %d (irq %d)....", info->line,
|
||||
state->irq);
|
||||
#endif
|
||||
struct serial_state *info = container_of(port, struct serial_state,
|
||||
port);
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
{
|
||||
/*
|
||||
* First unlink the serial port from the IRQ chain...
|
||||
*/
|
||||
if (info->next_port)
|
||||
info->next_port->prev_port = info->prev_port;
|
||||
if (info->prev_port)
|
||||
info->prev_port->next_port = info->next_port;
|
||||
else
|
||||
IRQ_ports[state->irq] = info->next_port;
|
||||
if (info->irq)
|
||||
free_irq(info->irq, info);
|
||||
|
||||
/*
|
||||
* Free the IRQ, if necessary
|
||||
*/
|
||||
if (state->irq && (!IRQ_ports[state->irq] ||
|
||||
!IRQ_ports[state->irq]->next_port)) {
|
||||
if (IRQ_ports[state->irq]) {
|
||||
free_irq(state->irq, NULL);
|
||||
retval = request_irq(state->irq, rs_interrupt_single,
|
||||
IRQ_T(info), "serial", NULL);
|
||||
|
||||
if (retval)
|
||||
printk(KERN_ERR "serial shutdown: request_irq: error %d"
|
||||
" Couldn't reacquire IRQ.\n", retval);
|
||||
} else
|
||||
free_irq(state->irq, NULL);
|
||||
}
|
||||
|
||||
if (info->xmit.buf) {
|
||||
free_page((unsigned long) info->xmit.buf);
|
||||
info->xmit.buf = NULL;
|
||||
}
|
||||
|
||||
if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
|
||||
|
||||
info->flags &= ~ASYNC_INITIALIZED;
|
||||
if (info->xmit.buf) {
|
||||
free_page((unsigned long) info->xmit.buf);
|
||||
info->xmit.buf = NULL;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* rs_close()
|
||||
*
|
||||
* This routine is called when the serial port gets closed. First, we
|
||||
* wait for the last remaining data to be sent. Then, we unlink its
|
||||
* async structure from the interrupt chain if necessary, and we free
|
||||
* that IRQ if nothing is left in the chain.
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
static void rs_close(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct async_struct * info = (struct async_struct *)tty->driver_data;
|
||||
struct serial_state *state;
|
||||
unsigned long flags;
|
||||
struct serial_state *info = tty->driver_data;
|
||||
|
||||
if (!info ) return;
|
||||
|
||||
state = info->state;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (tty_hung_up_p(filp)) {
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("rs_close: hung_up\n");
|
||||
#endif
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("rs_close ttys%d, count = %d\n", info->line, state->count);
|
||||
#endif
|
||||
if ((tty->count == 1) && (state->count != 1)) {
|
||||
/*
|
||||
* Uh, oh. tty->count is 1, which means that the tty
|
||||
* structure will be freed. state->count should always
|
||||
* be one in these conditions. If it's greater than
|
||||
* one, we've got real problems, since it means the
|
||||
* serial port won't be shutdown.
|
||||
*/
|
||||
printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, "
|
||||
"state->count is %d\n", state->count);
|
||||
state->count = 1;
|
||||
}
|
||||
if (--state->count < 0) {
|
||||
printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n",
|
||||
info->line, state->count);
|
||||
state->count = 0;
|
||||
}
|
||||
if (state->count) {
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
info->flags |= ASYNC_CLOSING;
|
||||
local_irq_restore(flags);
|
||||
|
||||
/*
|
||||
* Now we wait for the transmit buffer to clear; and we notify
|
||||
* the line discipline to only process XON/XOFF characters.
|
||||
*/
|
||||
shutdown(info);
|
||||
rs_flush_buffer(tty);
|
||||
tty_ldisc_flush(tty);
|
||||
info->event = 0;
|
||||
info->tty = NULL;
|
||||
if (info->blocked_open) {
|
||||
if (info->close_delay)
|
||||
schedule_timeout_interruptible(info->close_delay);
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
}
|
||||
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||
wake_up_interruptible(&info->close_wait);
|
||||
tty_port_close(&info->port, tty, filp);
|
||||
}
|
||||
|
||||
/*
|
||||
* rs_wait_until_sent() --- wait until the transmitter is empty
|
||||
*/
|
||||
static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* rs_hangup() --- called by tty_hangup() when a hangup is signaled.
|
||||
*/
|
||||
static void rs_hangup(struct tty_struct *tty)
|
||||
{
|
||||
struct async_struct * info = (struct async_struct *)tty->driver_data;
|
||||
struct serial_state *state = info->state;
|
||||
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("rs_hangup: called\n");
|
||||
#endif
|
||||
|
||||
state = info->state;
|
||||
struct serial_state *info = tty->driver_data;
|
||||
|
||||
rs_flush_buffer(tty);
|
||||
if (info->flags & ASYNC_CLOSING)
|
||||
return;
|
||||
shutdown(info);
|
||||
|
||||
info->event = 0;
|
||||
state->count = 0;
|
||||
info->flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
info->tty = NULL;
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
tty_port_hangup(&info->port);
|
||||
}
|
||||
|
||||
|
||||
static int get_async_struct(int line, struct async_struct **ret_info)
|
||||
static int activate(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
struct async_struct *info;
|
||||
struct serial_state *sstate;
|
||||
|
||||
sstate = rs_table + line;
|
||||
sstate->count++;
|
||||
if (sstate->info) {
|
||||
*ret_info = sstate->info;
|
||||
return 0;
|
||||
}
|
||||
info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
|
||||
if (!info) {
|
||||
sstate->count--;
|
||||
return -ENOMEM;
|
||||
}
|
||||
init_waitqueue_head(&info->open_wait);
|
||||
init_waitqueue_head(&info->close_wait);
|
||||
init_waitqueue_head(&info->delta_msr_wait);
|
||||
info->magic = SERIAL_MAGIC;
|
||||
info->port = sstate->port;
|
||||
info->flags = sstate->flags;
|
||||
info->xmit_fifo_size = sstate->xmit_fifo_size;
|
||||
info->line = line;
|
||||
INIT_WORK(&info->work, do_softint);
|
||||
info->state = sstate;
|
||||
if (sstate->info) {
|
||||
kfree(info);
|
||||
*ret_info = sstate->info;
|
||||
return 0;
|
||||
}
|
||||
*ret_info = sstate->info = info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
startup(struct async_struct *info)
|
||||
{
|
||||
unsigned long flags;
|
||||
int retval=0;
|
||||
irq_handler_t handler;
|
||||
struct serial_state *state= info->state;
|
||||
unsigned long page;
|
||||
struct serial_state *state = container_of(port, struct serial_state,
|
||||
port);
|
||||
unsigned long flags, page;
|
||||
int retval = 0;
|
||||
|
||||
page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!page)
|
||||
|
@ -673,86 +391,31 @@ startup(struct async_struct *info)
|
|||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (info->flags & ASYNC_INITIALIZED) {
|
||||
free_page(page);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (!state->port || !state->type) {
|
||||
if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
|
||||
free_page(page);
|
||||
goto errout;
|
||||
}
|
||||
if (info->xmit.buf)
|
||||
if (state->xmit.buf)
|
||||
free_page(page);
|
||||
else
|
||||
info->xmit.buf = (unsigned char *) page;
|
||||
state->xmit.buf = (unsigned char *) page;
|
||||
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("startup: ttys%d (irq %d)...", info->line, state->irq);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate the IRQ if necessary
|
||||
*/
|
||||
if (state->irq && (!IRQ_ports[state->irq] ||
|
||||
!IRQ_ports[state->irq]->next_port)) {
|
||||
if (IRQ_ports[state->irq]) {
|
||||
retval = -EBUSY;
|
||||
if (state->irq) {
|
||||
retval = request_irq(state->irq, rs_interrupt_single, 0,
|
||||
"simserial", state);
|
||||
if (retval)
|
||||
goto errout;
|
||||
} else
|
||||
handler = rs_interrupt_single;
|
||||
|
||||
retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL);
|
||||
if (retval) {
|
||||
if (capable(CAP_SYS_ADMIN)) {
|
||||
if (info->tty)
|
||||
set_bit(TTY_IO_ERROR,
|
||||
&info->tty->flags);
|
||||
retval = 0;
|
||||
}
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert serial port into IRQ chain.
|
||||
*/
|
||||
info->prev_port = NULL;
|
||||
info->next_port = IRQ_ports[state->irq];
|
||||
if (info->next_port)
|
||||
info->next_port->prev_port = info;
|
||||
IRQ_ports[state->irq] = info;
|
||||
|
||||
if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags);
|
||||
|
||||
info->xmit.head = info->xmit.tail = 0;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Set up serial timers...
|
||||
*/
|
||||
timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
|
||||
timer_active |= 1 << RS_TIMER;
|
||||
#endif
|
||||
state->xmit.head = state->xmit.tail = 0;
|
||||
|
||||
/*
|
||||
* Set up the tty->alt_speed kludge
|
||||
*/
|
||||
if (info->tty) {
|
||||
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
||||
info->tty->alt_speed = 57600;
|
||||
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
||||
info->tty->alt_speed = 115200;
|
||||
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
||||
info->tty->alt_speed = 230400;
|
||||
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
||||
info->tty->alt_speed = 460800;
|
||||
}
|
||||
|
||||
info->flags |= ASYNC_INITIALIZED;
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
||||
tty->alt_speed = 57600;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
||||
tty->alt_speed = 115200;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
||||
tty->alt_speed = 230400;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
||||
tty->alt_speed = 460800;
|
||||
|
||||
errout:
|
||||
local_irq_restore(flags);
|
||||
|
@ -768,56 +431,11 @@ errout:
|
|||
*/
|
||||
static int rs_open(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct async_struct *info;
|
||||
int retval, line;
|
||||
unsigned long page;
|
||||
struct serial_state *info = rs_table + tty->index;
|
||||
struct tty_port *port = &info->port;
|
||||
|
||||
line = tty->index;
|
||||
if ((line < 0) || (line >= NR_PORTS))
|
||||
return -ENODEV;
|
||||
retval = get_async_struct(line, &info);
|
||||
if (retval)
|
||||
return retval;
|
||||
tty->driver_data = info;
|
||||
info->tty = tty;
|
||||
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("rs_open %s, count = %d\n", tty->name, info->state->count);
|
||||
#endif
|
||||
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
if (!tmp_buf) {
|
||||
page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
if (tmp_buf)
|
||||
free_page(page);
|
||||
else
|
||||
tmp_buf = (unsigned char *) page;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the port is the middle of closing, bail out now
|
||||
*/
|
||||
if (tty_hung_up_p(filp) ||
|
||||
(info->flags & ASYNC_CLOSING)) {
|
||||
if (info->flags & ASYNC_CLOSING)
|
||||
interruptible_sleep_on(&info->close_wait);
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
return ((info->flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS);
|
||||
#else
|
||||
return -EAGAIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Start up serial port
|
||||
*/
|
||||
retval = startup(info);
|
||||
if (retval) {
|
||||
return retval;
|
||||
}
|
||||
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* figure out which console to use (should be one already)
|
||||
|
@ -828,30 +446,21 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
|
|||
console = console->next;
|
||||
}
|
||||
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("rs_open ttys%d successful\n", info->line);
|
||||
#endif
|
||||
return 0;
|
||||
return tty_port_open(port, tty, filp);
|
||||
}
|
||||
|
||||
/*
|
||||
* /proc fs routines....
|
||||
*/
|
||||
|
||||
static inline void line_info(struct seq_file *m, struct serial_state *state)
|
||||
{
|
||||
seq_printf(m, "%d: uart:%s port:%lX irq:%d\n",
|
||||
state->line, uart_config[state->type].name,
|
||||
state->port, state->irq);
|
||||
}
|
||||
|
||||
static int rs_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
int i;
|
||||
|
||||
seq_printf(m, "simserinfo:1.0 driver:%s\n", serial_version);
|
||||
seq_printf(m, "simserinfo:1.0\n");
|
||||
for (i = 0; i < NR_PORTS; i++)
|
||||
line_info(m, &rs_table[i]);
|
||||
seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n",
|
||||
i, rs_table[i].irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -868,25 +477,6 @@ static const struct file_operations rs_proc_fops = {
|
|||
.release = single_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------------
|
||||
* rs_init() and friends
|
||||
*
|
||||
* rs_init() is called at boot-time to initialize the serial driver.
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* This routine prints out the appropriate serial driver version
|
||||
* number, and identifies which options were configured into this
|
||||
* driver.
|
||||
*/
|
||||
static inline void show_serial_version(void)
|
||||
{
|
||||
printk(KERN_INFO "%s version %s with", serial_name, serial_version);
|
||||
printk(KERN_INFO " no serial options enabled\n");
|
||||
}
|
||||
|
||||
static const struct tty_operations hp_ops = {
|
||||
.open = rs_open,
|
||||
.close = rs_close,
|
||||
|
@ -901,34 +491,31 @@ static const struct tty_operations hp_ops = {
|
|||
.unthrottle = rs_unthrottle,
|
||||
.send_xchar = rs_send_xchar,
|
||||
.set_termios = rs_set_termios,
|
||||
.stop = rs_stop,
|
||||
.start = rs_start,
|
||||
.hangup = rs_hangup,
|
||||
.wait_until_sent = rs_wait_until_sent,
|
||||
.proc_fops = &rs_proc_fops,
|
||||
};
|
||||
|
||||
/*
|
||||
* The serial driver boot-time initialization code!
|
||||
*/
|
||||
static int __init
|
||||
simrs_init (void)
|
||||
static const struct tty_port_operations hp_port_ops = {
|
||||
.activate = activate,
|
||||
.shutdown = shutdown,
|
||||
};
|
||||
|
||||
static int __init simrs_init(void)
|
||||
{
|
||||
int i, rc;
|
||||
struct serial_state *state;
|
||||
struct serial_state *state;
|
||||
int retval;
|
||||
|
||||
if (!ia64_platform_is("hpsim"))
|
||||
return -ENODEV;
|
||||
|
||||
hp_simserial_driver = alloc_tty_driver(1);
|
||||
hp_simserial_driver = alloc_tty_driver(NR_PORTS);
|
||||
if (!hp_simserial_driver)
|
||||
return -ENOMEM;
|
||||
|
||||
show_serial_version();
|
||||
printk(KERN_INFO "SimSerial driver with no serial options enabled\n");
|
||||
|
||||
/* Initialize the tty_driver structure */
|
||||
|
||||
hp_simserial_driver->owner = THIS_MODULE;
|
||||
hp_simserial_driver->driver_name = "simserial";
|
||||
hp_simserial_driver->name = "ttyS";
|
||||
hp_simserial_driver->major = TTY_MAJOR;
|
||||
|
@ -941,31 +528,33 @@ simrs_init (void)
|
|||
hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW;
|
||||
tty_set_operations(hp_simserial_driver, &hp_ops);
|
||||
|
||||
/*
|
||||
* Let's have a little bit of fun !
|
||||
*/
|
||||
for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
|
||||
state = rs_table;
|
||||
tty_port_init(&state->port);
|
||||
state->port.ops = &hp_port_ops;
|
||||
state->port.close_delay = 0; /* XXX really 0? */
|
||||
|
||||
if (state->type == PORT_UNKNOWN) continue;
|
||||
|
||||
if (!state->irq) {
|
||||
if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)
|
||||
panic("%s: out of interrupt vectors!\n",
|
||||
__func__);
|
||||
state->irq = rc;
|
||||
ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq);
|
||||
}
|
||||
|
||||
printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n",
|
||||
state->line,
|
||||
state->port, state->irq,
|
||||
uart_config[state->type].name);
|
||||
retval = hpsim_get_irq(KEYBOARD_INTR);
|
||||
if (retval < 0) {
|
||||
printk(KERN_ERR "%s: out of interrupt vectors!\n",
|
||||
__func__);
|
||||
goto err_free_tty;
|
||||
}
|
||||
|
||||
if (tty_register_driver(hp_simserial_driver))
|
||||
panic("Couldn't register simserial driver\n");
|
||||
state->irq = retval;
|
||||
|
||||
/* the port is imaginary */
|
||||
printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq);
|
||||
|
||||
retval = tty_register_driver(hp_simserial_driver);
|
||||
if (retval) {
|
||||
printk(KERN_ERR "Couldn't register simserial driver\n");
|
||||
goto err_free_tty;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_free_tty:
|
||||
put_tty_driver(hp_simserial_driver);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifndef MODULE
|
||||
|
|
|
@ -10,7 +10,7 @@ int simcons_register(void);
|
|||
struct tty_driver;
|
||||
extern struct tty_driver *hp_simserial_driver;
|
||||
|
||||
void ia64_ssc_connect_irq(long intr, long irq);
|
||||
extern int hpsim_get_irq(int intr);
|
||||
void ia64_ctl_trace(long on);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -127,7 +127,6 @@ static int __init nfcon_init(void)
|
|||
if (!nfcon_tty_driver)
|
||||
return -ENOMEM;
|
||||
|
||||
nfcon_tty_driver->owner = THIS_MODULE;
|
||||
nfcon_tty_driver->driver_name = "nfcon";
|
||||
nfcon_tty_driver->name = "nfcon";
|
||||
nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
|
||||
|
|
|
@ -90,11 +90,13 @@ static int pdc_console_setup(struct console *co, char *options)
|
|||
|
||||
#define PDC_CONS_POLL_DELAY (30 * HZ / 1000)
|
||||
|
||||
static struct timer_list pdc_console_timer;
|
||||
static void pdc_console_poll(unsigned long unused);
|
||||
static DEFINE_TIMER(pdc_console_timer, pdc_console_poll, 0, 0);
|
||||
static struct tty_port tty_port;
|
||||
|
||||
static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
|
||||
tty_port_tty_set(&tty_port, tty);
|
||||
mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
|
||||
|
||||
return 0;
|
||||
|
@ -102,8 +104,10 @@ static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
if (!tty->count)
|
||||
del_timer(&pdc_console_timer);
|
||||
if (!tty->count) {
|
||||
del_timer_sync(&pdc_console_timer);
|
||||
tty_port_tty_set(&tty_port, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
|
@ -122,8 +126,6 @@ static int pdc_console_tty_chars_in_buffer(struct tty_struct *tty)
|
|||
return 0; /* no buffer */
|
||||
}
|
||||
|
||||
static struct tty_driver *pdc_console_tty_driver;
|
||||
|
||||
static const struct tty_operations pdc_console_tty_ops = {
|
||||
.open = pdc_console_tty_open,
|
||||
.close = pdc_console_tty_close,
|
||||
|
@ -134,10 +136,8 @@ static const struct tty_operations pdc_console_tty_ops = {
|
|||
|
||||
static void pdc_console_poll(unsigned long unused)
|
||||
{
|
||||
|
||||
int data, count = 0;
|
||||
|
||||
struct tty_struct *tty = pdc_console_tty_driver->ttys[0];
|
||||
struct tty_struct *tty = tty_port_tty_get(&tty_port);
|
||||
|
||||
if (!tty)
|
||||
return;
|
||||
|
@ -153,15 +153,17 @@ static void pdc_console_poll(unsigned long unused)
|
|||
if (count)
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
if (tty->count && (pdc_cons.flags & CON_ENABLED))
|
||||
tty_kref_put(tty);
|
||||
|
||||
if (pdc_cons.flags & CON_ENABLED)
|
||||
mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
|
||||
}
|
||||
|
||||
static struct tty_driver *pdc_console_tty_driver;
|
||||
|
||||
static int __init pdc_console_tty_driver_init(void)
|
||||
{
|
||||
|
||||
int err;
|
||||
struct tty_driver *drv;
|
||||
|
||||
/* Check if the console driver is still registered.
|
||||
* It is unregistered if the pdc console was not selected as the
|
||||
|
@ -183,32 +185,29 @@ static int __init pdc_console_tty_driver_init(void)
|
|||
printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n");
|
||||
pdc_cons.flags &= ~CON_BOOT;
|
||||
|
||||
drv = alloc_tty_driver(1);
|
||||
tty_port_init(&tty_port);
|
||||
|
||||
if (!drv)
|
||||
pdc_console_tty_driver = alloc_tty_driver(1);
|
||||
|
||||
if (!pdc_console_tty_driver)
|
||||
return -ENOMEM;
|
||||
|
||||
drv->driver_name = "pdc_cons";
|
||||
drv->name = "ttyB";
|
||||
drv->major = MUX_MAJOR;
|
||||
drv->minor_start = 0;
|
||||
drv->type = TTY_DRIVER_TYPE_SYSTEM;
|
||||
drv->init_termios = tty_std_termios;
|
||||
drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
|
||||
tty_set_operations(drv, &pdc_console_tty_ops);
|
||||
pdc_console_tty_driver->driver_name = "pdc_cons";
|
||||
pdc_console_tty_driver->name = "ttyB";
|
||||
pdc_console_tty_driver->major = MUX_MAJOR;
|
||||
pdc_console_tty_driver->minor_start = 0;
|
||||
pdc_console_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
|
||||
pdc_console_tty_driver->init_termios = tty_std_termios;
|
||||
pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW |
|
||||
TTY_DRIVER_RESET_TERMIOS;
|
||||
tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops);
|
||||
|
||||
err = tty_register_driver(drv);
|
||||
err = tty_register_driver(pdc_console_tty_driver);
|
||||
if (err) {
|
||||
printk(KERN_ERR "Unable to register the PDC console TTY driver\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
pdc_console_tty_driver = drv;
|
||||
|
||||
/* No need to initialize the pdc_console_timer if tty isn't allocated */
|
||||
init_timer(&pdc_console_timer);
|
||||
pdc_console_timer.function = pdc_console_poll;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <linux/param.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serialP.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/irq.h>
|
||||
|
@ -37,6 +36,7 @@
|
|||
#define SERIAL_TIMER_VALUE (20 * HZ)
|
||||
|
||||
static struct tty_driver *serial_driver;
|
||||
static struct tty_port serial_port;
|
||||
static struct timer_list serial_timer;
|
||||
|
||||
static DEFINE_SPINLOCK(timer_lock);
|
||||
|
@ -68,17 +68,10 @@ static void rs_poll(unsigned long);
|
|||
|
||||
static int rs_open(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
int line = tty->index;
|
||||
|
||||
if ((line < 0) || (line >= SERIAL_MAX_NUM_LINES))
|
||||
return -ENODEV;
|
||||
|
||||
tty->port = &serial_port;
|
||||
spin_lock(&timer_lock);
|
||||
|
||||
if (tty->count == 1) {
|
||||
init_timer(&serial_timer);
|
||||
serial_timer.data = (unsigned long) tty;
|
||||
serial_timer.function = rs_poll;
|
||||
setup_timer(&serial_timer, rs_poll, (unsigned long)tty);
|
||||
mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
|
||||
}
|
||||
spin_unlock(&timer_lock);
|
||||
|
@ -99,10 +92,10 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
|
|||
*/
|
||||
static void rs_close(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
spin_lock(&timer_lock);
|
||||
spin_lock_bh(&timer_lock);
|
||||
if (tty->count == 1)
|
||||
del_timer_sync(&serial_timer);
|
||||
spin_unlock(&timer_lock);
|
||||
spin_unlock_bh(&timer_lock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -210,13 +203,14 @@ static const struct tty_operations serial_ops = {
|
|||
|
||||
int __init rs_init(void)
|
||||
{
|
||||
serial_driver = alloc_tty_driver(1);
|
||||
tty_port_init(&serial_port);
|
||||
|
||||
serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES);
|
||||
|
||||
printk ("%s %s\n", serial_name, serial_version);
|
||||
|
||||
/* Initialize the tty_driver structure */
|
||||
|
||||
serial_driver->owner = THIS_MODULE;
|
||||
serial_driver->driver_name = "iss_serial";
|
||||
serial_driver->name = "ttyS";
|
||||
serial_driver->major = TTY_MAJOR;
|
||||
|
|
|
@ -244,16 +244,13 @@ static int keyboard_notifier_call(struct notifier_block *blk,
|
|||
|
||||
switch (val) {
|
||||
case KVAL(K_CAPS):
|
||||
on_off = vc_kbd_led(kbd_table + fg_console,
|
||||
VC_CAPSLOCK);
|
||||
on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
|
||||
break;
|
||||
case KVAL(K_NUM):
|
||||
on_off = vc_kbd_led(kbd_table + fg_console,
|
||||
VC_NUMLOCK);
|
||||
on_off = vt_get_leds(fg_console, VC_NUMLOCK);
|
||||
break;
|
||||
case KVAL(K_HOLD):
|
||||
on_off = vc_kbd_led(kbd_table + fg_console,
|
||||
VC_SCROLLOCK);
|
||||
on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
|
||||
break;
|
||||
}
|
||||
if (on_off == 1)
|
||||
|
|
|
@ -66,21 +66,6 @@ config TTY_PRINTK
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config BRIQ_PANEL
|
||||
tristate 'Total Impact briQ front panel driver'
|
||||
depends on PPC_CHRP
|
||||
---help---
|
||||
The briQ is a small footprint CHRP computer with a frontpanel VFD, a
|
||||
tristate led and two switches. It is the size of a CDROM drive.
|
||||
|
||||
If you have such one and want anything showing on the VFD then you
|
||||
must answer Y here.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called briq_panel.
|
||||
|
||||
It's safe to say N here.
|
||||
|
||||
config BFIN_OTP
|
||||
tristate "Blackfin On-Chip OTP Memory Support"
|
||||
depends on BLACKFIN && (BF51x || BF52x || BF54x)
|
||||
|
|
|
@ -16,7 +16,6 @@ obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
|
|||
obj-$(CONFIG_VIOTAPE) += viotape.o
|
||||
obj-$(CONFIG_IBM_BSR) += bsr.o
|
||||
obj-$(CONFIG_SGI_MBCS) += mbcs.o
|
||||
obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
|
||||
obj-$(CONFIG_BFIN_OTP) += bfin-otp.o
|
||||
|
||||
obj-$(CONFIG_PRINTER) += lp.o
|
||||
|
|
|
@ -1,266 +0,0 @@
|
|||
/*
|
||||
* Drivers for the Total Impact PPC based computer "BRIQ"
|
||||
* by Dr. Karsten Jeppesen
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/prom.h>
|
||||
|
||||
#define BRIQ_PANEL_MINOR 156
|
||||
#define BRIQ_PANEL_VFD_IOPORT 0x0390
|
||||
#define BRIQ_PANEL_LED_IOPORT 0x0398
|
||||
#define BRIQ_PANEL_VER "1.1 (04/20/2002)"
|
||||
#define BRIQ_PANEL_MSG0 "Loading Linux"
|
||||
|
||||
static int vfd_is_open;
|
||||
static unsigned char vfd[40];
|
||||
static int vfd_cursor;
|
||||
static unsigned char ledpb, led;
|
||||
|
||||
static void update_vfd(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* cursor home */
|
||||
outb(0x02, BRIQ_PANEL_VFD_IOPORT);
|
||||
for (i=0; i<20; i++)
|
||||
outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
|
||||
|
||||
/* cursor to next line */
|
||||
outb(0xc0, BRIQ_PANEL_VFD_IOPORT);
|
||||
for (i=20; i<40; i++)
|
||||
outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
|
||||
|
||||
}
|
||||
|
||||
static void set_led(char state)
|
||||
{
|
||||
if (state == 'R')
|
||||
led = 0x01;
|
||||
else if (state == 'G')
|
||||
led = 0x02;
|
||||
else if (state == 'Y')
|
||||
led = 0x03;
|
||||
else if (state == 'X')
|
||||
led = 0x00;
|
||||
outb(led, BRIQ_PANEL_LED_IOPORT);
|
||||
}
|
||||
|
||||
static int briq_panel_open(struct inode *ino, struct file *filep)
|
||||
{
|
||||
tty_lock();
|
||||
/* enforce single access, vfd_is_open is protected by BKL */
|
||||
if (vfd_is_open) {
|
||||
tty_unlock();
|
||||
return -EBUSY;
|
||||
}
|
||||
vfd_is_open = 1;
|
||||
|
||||
tty_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int briq_panel_release(struct inode *ino, struct file *filep)
|
||||
{
|
||||
if (!vfd_is_open)
|
||||
return -ENODEV;
|
||||
|
||||
vfd_is_open = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
unsigned short c;
|
||||
unsigned char cp;
|
||||
|
||||
if (!vfd_is_open)
|
||||
return -ENODEV;
|
||||
|
||||
c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003);
|
||||
set_led(' ');
|
||||
/* upper button released */
|
||||
if ((!(ledpb & 0x0004)) && (c & 0x0004)) {
|
||||
cp = ' ';
|
||||
ledpb = c;
|
||||
if (copy_to_user(buf, &cp, 1))
|
||||
return -EFAULT;
|
||||
return 1;
|
||||
}
|
||||
/* lower button released */
|
||||
else if ((!(ledpb & 0x0008)) && (c & 0x0008)) {
|
||||
cp = '\r';
|
||||
ledpb = c;
|
||||
if (copy_to_user(buf, &cp, 1))
|
||||
return -EFAULT;
|
||||
return 1;
|
||||
} else {
|
||||
ledpb = c;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void scroll_vfd( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<20; i++) {
|
||||
vfd[i] = vfd[i+20];
|
||||
vfd[i+20] = ' ';
|
||||
}
|
||||
vfd_cursor = 20;
|
||||
}
|
||||
|
||||
static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len,
|
||||
loff_t *ppos)
|
||||
{
|
||||
size_t indx = len;
|
||||
int i, esc = 0;
|
||||
|
||||
if (!vfd_is_open)
|
||||
return -EBUSY;
|
||||
|
||||
for (;;) {
|
||||
char c;
|
||||
if (!indx)
|
||||
break;
|
||||
if (get_user(c, buf))
|
||||
return -EFAULT;
|
||||
if (esc) {
|
||||
set_led(c);
|
||||
esc = 0;
|
||||
} else if (c == 27) {
|
||||
esc = 1;
|
||||
} else if (c == 12) {
|
||||
/* do a form feed */
|
||||
for (i=0; i<40; i++)
|
||||
vfd[i] = ' ';
|
||||
vfd_cursor = 0;
|
||||
} else if (c == 10) {
|
||||
if (vfd_cursor < 20)
|
||||
vfd_cursor = 20;
|
||||
else if (vfd_cursor < 40)
|
||||
vfd_cursor = 40;
|
||||
else if (vfd_cursor < 60)
|
||||
vfd_cursor = 60;
|
||||
if (vfd_cursor > 59)
|
||||
scroll_vfd();
|
||||
} else {
|
||||
/* just a character */
|
||||
if (vfd_cursor > 39)
|
||||
scroll_vfd();
|
||||
vfd[vfd_cursor++] = c;
|
||||
}
|
||||
indx--;
|
||||
buf++;
|
||||
}
|
||||
update_vfd();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations briq_panel_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = briq_panel_read,
|
||||
.write = briq_panel_write,
|
||||
.open = briq_panel_open,
|
||||
.release = briq_panel_release,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static struct miscdevice briq_panel_miscdev = {
|
||||
BRIQ_PANEL_MINOR,
|
||||
"briq_panel",
|
||||
&briq_panel_fops
|
||||
};
|
||||
|
||||
static int __init briq_panel_init(void)
|
||||
{
|
||||
struct device_node *root = of_find_node_by_path("/");
|
||||
const char *machine;
|
||||
int i;
|
||||
|
||||
machine = of_get_property(root, "model", NULL);
|
||||
if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
|
||||
of_node_put(root);
|
||||
return -ENODEV;
|
||||
}
|
||||
of_node_put(root);
|
||||
|
||||
printk(KERN_INFO
|
||||
"briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
|
||||
BRIQ_PANEL_VER);
|
||||
|
||||
if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel"))
|
||||
return -EBUSY;
|
||||
|
||||
if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) {
|
||||
release_region(BRIQ_PANEL_VFD_IOPORT, 4);
|
||||
return -EBUSY;
|
||||
}
|
||||
ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c;
|
||||
|
||||
if (misc_register(&briq_panel_miscdev) < 0) {
|
||||
release_region(BRIQ_PANEL_VFD_IOPORT, 4);
|
||||
release_region(BRIQ_PANEL_LED_IOPORT, 2);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
outb(0x38, BRIQ_PANEL_VFD_IOPORT); /* Function set */
|
||||
outb(0x01, BRIQ_PANEL_VFD_IOPORT); /* Clear display */
|
||||
outb(0x0c, BRIQ_PANEL_VFD_IOPORT); /* Display on */
|
||||
outb(0x06, BRIQ_PANEL_VFD_IOPORT); /* Entry normal */
|
||||
for (i=0; i<40; i++)
|
||||
vfd[i]=' ';
|
||||
#ifndef MODULE
|
||||
vfd[0] = 'L';
|
||||
vfd[1] = 'o';
|
||||
vfd[2] = 'a';
|
||||
vfd[3] = 'd';
|
||||
vfd[4] = 'i';
|
||||
vfd[5] = 'n';
|
||||
vfd[6] = 'g';
|
||||
vfd[7] = ' ';
|
||||
vfd[8] = '.';
|
||||
vfd[9] = '.';
|
||||
vfd[10] = '.';
|
||||
#endif /* !MODULE */
|
||||
|
||||
update_vfd();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit briq_panel_exit(void)
|
||||
{
|
||||
misc_deregister(&briq_panel_miscdev);
|
||||
release_region(BRIQ_PANEL_VFD_IOPORT, 4);
|
||||
release_region(BRIQ_PANEL_LED_IOPORT, 2);
|
||||
}
|
||||
|
||||
module_init(briq_panel_init);
|
||||
module_exit(briq_panel_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Karsten Jeppesen <karsten@jeppesens.com>");
|
||||
MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel");
|
|
@ -2484,7 +2484,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
|
|||
|
||||
/* verify range of specified line number */
|
||||
line = tty->index;
|
||||
if ((line < 0) || (line >= mgslpc_device_count)) {
|
||||
if (line >= mgslpc_device_count) {
|
||||
printk("%s(%d):mgslpc_open with invalid line #%d.\n",
|
||||
__FILE__,__LINE__,line);
|
||||
return -ENODEV;
|
||||
|
@ -2836,7 +2836,6 @@ static int __init synclink_cs_init(void)
|
|||
|
||||
/* Initialize the tty_driver structure */
|
||||
|
||||
serial_driver->owner = THIS_MODULE;
|
||||
serial_driver->driver_name = "synclink_cs";
|
||||
serial_driver->name = "ttySLP";
|
||||
serial_driver->major = ttymajor;
|
||||
|
|
|
@ -184,12 +184,10 @@ static int __init ttyprintk_init(void)
|
|||
if (!ttyprintk_driver)
|
||||
return ret;
|
||||
|
||||
ttyprintk_driver->owner = THIS_MODULE;
|
||||
ttyprintk_driver->driver_name = "ttyprintk";
|
||||
ttyprintk_driver->name = "ttyprintk";
|
||||
ttyprintk_driver->major = TTYAUX_MAJOR;
|
||||
ttyprintk_driver->minor_start = 3;
|
||||
ttyprintk_driver->num = 1;
|
||||
ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
|
||||
ttyprintk_driver->init_termios = tty_std_termios;
|
||||
ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
|
||||
|
|
|
@ -1013,16 +1013,12 @@ static const struct file_operations capi_fops =
|
|||
static int
|
||||
capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
int idx = tty->index;
|
||||
struct capiminor *mp = capiminor_get(idx);
|
||||
int ret = tty_init_termios(tty);
|
||||
struct capiminor *mp = capiminor_get(tty->index);
|
||||
int ret = tty_standard_install(driver, tty);
|
||||
|
||||
if (ret == 0) {
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
if (ret == 0)
|
||||
tty->driver_data = mp;
|
||||
driver->ttys[idx] = tty;
|
||||
} else
|
||||
else
|
||||
capiminor_put(mp);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1290,7 +1286,6 @@ static int __init capinc_tty_init(void)
|
|||
kfree(capiminors);
|
||||
return -ENOMEM;
|
||||
}
|
||||
drv->owner = THIS_MODULE;
|
||||
drv->driver_name = "capi_nc";
|
||||
drv->name = "capi";
|
||||
drv->major = 0;
|
||||
|
|
|
@ -720,12 +720,11 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
|
|||
|
||||
tasklet_init(&cs->event_tasklet, gigaset_handle_event,
|
||||
(unsigned long) cs);
|
||||
tty_port_init(&cs->port);
|
||||
cs->commands_pending = 0;
|
||||
cs->cur_at_seq = 0;
|
||||
cs->gotfwver = -1;
|
||||
cs->open_count = 0;
|
||||
cs->dev = NULL;
|
||||
cs->tty = NULL;
|
||||
cs->tty_dev = NULL;
|
||||
cs->cidmode = cidmode != 0;
|
||||
cs->tabnocid = gigaset_tab_nocid;
|
||||
|
@ -1051,8 +1050,6 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
|
|||
|
||||
struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
|
||||
{
|
||||
if (tty->index < 0 || tty->index >= tty->driver->num)
|
||||
return NULL;
|
||||
return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
|
||||
}
|
||||
|
||||
|
|
|
@ -433,8 +433,7 @@ struct cardstate {
|
|||
spinlock_t cmdlock;
|
||||
unsigned curlen, cmdbytes;
|
||||
|
||||
unsigned open_count;
|
||||
struct tty_struct *tty;
|
||||
struct tty_port port;
|
||||
struct tasklet_struct if_wake_tasklet;
|
||||
unsigned control_state;
|
||||
|
||||
|
|
|
@ -146,13 +146,10 @@ static const struct tty_operations if_ops = {
|
|||
static int if_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
unsigned long flags;
|
||||
|
||||
gig_dbg(DEBUG_IF, "%d+%d: %s()",
|
||||
tty->driver->minor_start, tty->index, __func__);
|
||||
|
||||
tty->driver_data = NULL;
|
||||
|
||||
cs = gigaset_get_cs_by_tty(tty);
|
||||
if (!cs || !try_module_get(cs->driver->owner))
|
||||
return -ENODEV;
|
||||
|
@ -163,12 +160,10 @@ static int if_open(struct tty_struct *tty, struct file *filp)
|
|||
}
|
||||
tty->driver_data = cs;
|
||||
|
||||
++cs->open_count;
|
||||
++cs->port.count;
|
||||
|
||||
if (cs->open_count == 1) {
|
||||
spin_lock_irqsave(&cs->lock, flags);
|
||||
cs->tty = tty;
|
||||
spin_unlock_irqrestore(&cs->lock, flags);
|
||||
if (cs->port.count == 1) {
|
||||
tty_port_tty_set(&cs->port, tty);
|
||||
tty->low_latency = 1;
|
||||
}
|
||||
|
||||
|
@ -178,12 +173,10 @@ static int if_open(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
static void if_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
unsigned long flags;
|
||||
struct cardstate *cs = tty->driver_data;
|
||||
|
||||
cs = (struct cardstate *) tty->driver_data;
|
||||
if (!cs) {
|
||||
pr_err("%s: no cardstate\n", __func__);
|
||||
if (!cs) { /* happens if we didn't find cs in open */
|
||||
printk(KERN_DEBUG "%s: no cardstate\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -193,15 +186,10 @@ static void if_close(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
if (!cs->connected)
|
||||
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
|
||||
else if (!cs->open_count)
|
||||
else if (!cs->port.count)
|
||||
dev_warn(cs->dev, "%s: device not opened\n", __func__);
|
||||
else {
|
||||
if (!--cs->open_count) {
|
||||
spin_lock_irqsave(&cs->lock, flags);
|
||||
cs->tty = NULL;
|
||||
spin_unlock_irqrestore(&cs->lock, flags);
|
||||
}
|
||||
}
|
||||
else if (!--cs->port.count)
|
||||
tty_port_tty_set(&cs->port, NULL);
|
||||
|
||||
mutex_unlock(&cs->mutex);
|
||||
|
||||
|
@ -211,18 +199,12 @@ static void if_close(struct tty_struct *tty, struct file *filp)
|
|||
static int if_ioctl(struct tty_struct *tty,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
struct cardstate *cs = tty->driver_data;
|
||||
int retval = -ENODEV;
|
||||
int int_arg;
|
||||
unsigned char buf[6];
|
||||
unsigned version[4];
|
||||
|
||||
cs = (struct cardstate *) tty->driver_data;
|
||||
if (!cs) {
|
||||
pr_err("%s: no cardstate\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
|
||||
|
||||
if (mutex_lock_interruptible(&cs->mutex))
|
||||
|
@ -231,9 +213,7 @@ static int if_ioctl(struct tty_struct *tty,
|
|||
if (!cs->connected) {
|
||||
gig_dbg(DEBUG_IF, "not connected");
|
||||
retval = -ENODEV;
|
||||
} else if (!cs->open_count)
|
||||
dev_warn(cs->dev, "%s: device not opened\n", __func__);
|
||||
else {
|
||||
} else {
|
||||
retval = 0;
|
||||
switch (cmd) {
|
||||
case GIGASET_REDIR:
|
||||
|
@ -285,15 +265,9 @@ static int if_ioctl(struct tty_struct *tty,
|
|||
|
||||
static int if_tiocmget(struct tty_struct *tty)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
struct cardstate *cs = tty->driver_data;
|
||||
int retval;
|
||||
|
||||
cs = (struct cardstate *) tty->driver_data;
|
||||
if (!cs) {
|
||||
pr_err("%s: no cardstate\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
|
||||
|
||||
if (mutex_lock_interruptible(&cs->mutex))
|
||||
|
@ -309,16 +283,10 @@ static int if_tiocmget(struct tty_struct *tty)
|
|||
static int if_tiocmset(struct tty_struct *tty,
|
||||
unsigned int set, unsigned int clear)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
struct cardstate *cs = tty->driver_data;
|
||||
int retval;
|
||||
unsigned mc;
|
||||
|
||||
cs = (struct cardstate *) tty->driver_data;
|
||||
if (!cs) {
|
||||
pr_err("%s: no cardstate\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
|
||||
cs->minor_index, __func__, set, clear);
|
||||
|
||||
|
@ -341,16 +309,10 @@ static int if_tiocmset(struct tty_struct *tty,
|
|||
|
||||
static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
struct cardstate *cs = tty->driver_data;
|
||||
struct cmdbuf_t *cb;
|
||||
int retval;
|
||||
|
||||
cs = (struct cardstate *) tty->driver_data;
|
||||
if (!cs) {
|
||||
pr_err("%s: no cardstate\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
|
||||
|
||||
if (mutex_lock_interruptible(&cs->mutex))
|
||||
|
@ -361,11 +323,6 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
|||
retval = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
if (!cs->open_count) {
|
||||
dev_warn(cs->dev, "%s: device not opened\n", __func__);
|
||||
retval = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
if (cs->mstate != MS_LOCKED) {
|
||||
dev_warn(cs->dev, "can't write to unlocked device\n");
|
||||
retval = -EBUSY;
|
||||
|
@ -397,15 +354,9 @@ done:
|
|||
|
||||
static int if_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
struct cardstate *cs = tty->driver_data;
|
||||
int retval = -ENODEV;
|
||||
|
||||
cs = (struct cardstate *) tty->driver_data;
|
||||
if (!cs) {
|
||||
pr_err("%s: no cardstate\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
|
||||
|
||||
if (mutex_lock_interruptible(&cs->mutex))
|
||||
|
@ -414,9 +365,7 @@ static int if_write_room(struct tty_struct *tty)
|
|||
if (!cs->connected) {
|
||||
gig_dbg(DEBUG_IF, "not connected");
|
||||
retval = -ENODEV;
|
||||
} else if (!cs->open_count)
|
||||
dev_warn(cs->dev, "%s: device not opened\n", __func__);
|
||||
else if (cs->mstate != MS_LOCKED) {
|
||||
} else if (cs->mstate != MS_LOCKED) {
|
||||
dev_warn(cs->dev, "can't write to unlocked device\n");
|
||||
retval = -EBUSY;
|
||||
} else
|
||||
|
@ -429,23 +378,15 @@ static int if_write_room(struct tty_struct *tty)
|
|||
|
||||
static int if_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
struct cardstate *cs = tty->driver_data;
|
||||
int retval = 0;
|
||||
|
||||
cs = (struct cardstate *) tty->driver_data;
|
||||
if (!cs) {
|
||||
pr_err("%s: no cardstate\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
|
||||
|
||||
mutex_lock(&cs->mutex);
|
||||
|
||||
if (!cs->connected)
|
||||
gig_dbg(DEBUG_IF, "not connected");
|
||||
else if (!cs->open_count)
|
||||
dev_warn(cs->dev, "%s: device not opened\n", __func__);
|
||||
else if (cs->mstate != MS_LOCKED)
|
||||
dev_warn(cs->dev, "can't write to unlocked device\n");
|
||||
else
|
||||
|
@ -458,13 +399,7 @@ static int if_chars_in_buffer(struct tty_struct *tty)
|
|||
|
||||
static void if_throttle(struct tty_struct *tty)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
|
||||
cs = (struct cardstate *) tty->driver_data;
|
||||
if (!cs) {
|
||||
pr_err("%s: no cardstate\n", __func__);
|
||||
return;
|
||||
}
|
||||
struct cardstate *cs = tty->driver_data;
|
||||
|
||||
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
|
||||
|
||||
|
@ -472,8 +407,6 @@ static void if_throttle(struct tty_struct *tty)
|
|||
|
||||
if (!cs->connected)
|
||||
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
|
||||
else if (!cs->open_count)
|
||||
dev_warn(cs->dev, "%s: device not opened\n", __func__);
|
||||
else
|
||||
gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
|
||||
|
||||
|
@ -482,13 +415,7 @@ static void if_throttle(struct tty_struct *tty)
|
|||
|
||||
static void if_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
|
||||
cs = (struct cardstate *) tty->driver_data;
|
||||
if (!cs) {
|
||||
pr_err("%s: no cardstate\n", __func__);
|
||||
return;
|
||||
}
|
||||
struct cardstate *cs = tty->driver_data;
|
||||
|
||||
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
|
||||
|
||||
|
@ -496,8 +423,6 @@ static void if_unthrottle(struct tty_struct *tty)
|
|||
|
||||
if (!cs->connected)
|
||||
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
|
||||
else if (!cs->open_count)
|
||||
dev_warn(cs->dev, "%s: device not opened\n", __func__);
|
||||
else
|
||||
gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
|
||||
|
||||
|
@ -506,18 +431,12 @@ static void if_unthrottle(struct tty_struct *tty)
|
|||
|
||||
static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
|
||||
{
|
||||
struct cardstate *cs;
|
||||
struct cardstate *cs = tty->driver_data;
|
||||
unsigned int iflag;
|
||||
unsigned int cflag;
|
||||
unsigned int old_cflag;
|
||||
unsigned int control_state, new_state;
|
||||
|
||||
cs = (struct cardstate *) tty->driver_data;
|
||||
if (!cs) {
|
||||
pr_err("%s: no cardstate\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
|
||||
|
||||
mutex_lock(&cs->mutex);
|
||||
|
@ -527,11 +446,6 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (!cs->open_count) {
|
||||
dev_warn(cs->dev, "%s: device not opened\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
iflag = tty->termios->c_iflag;
|
||||
cflag = tty->termios->c_cflag;
|
||||
old_cflag = old ? old->c_cflag : cflag;
|
||||
|
@ -588,10 +502,13 @@ out:
|
|||
/* wakeup tasklet for the write operation */
|
||||
static void if_wake(unsigned long data)
|
||||
{
|
||||
struct cardstate *cs = (struct cardstate *) data;
|
||||
struct cardstate *cs = (struct cardstate *)data;
|
||||
struct tty_struct *tty = tty_port_tty_get(&cs->port);
|
||||
|
||||
if (cs->tty)
|
||||
tty_wakeup(cs->tty);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
/*** interface to common ***/
|
||||
|
@ -644,18 +561,16 @@ void gigaset_if_free(struct cardstate *cs)
|
|||
void gigaset_if_receive(struct cardstate *cs,
|
||||
unsigned char *buffer, size_t len)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct tty_struct *tty;
|
||||
struct tty_struct *tty = tty_port_tty_get(&cs->port);
|
||||
|
||||
spin_lock_irqsave(&cs->lock, flags);
|
||||
tty = cs->tty;
|
||||
if (tty == NULL)
|
||||
if (tty == NULL) {
|
||||
gig_dbg(DEBUG_IF, "receive on closed device");
|
||||
else {
|
||||
tty_insert_flip_string(tty, buffer, len);
|
||||
tty_flip_buffer_push(tty);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(&cs->lock, flags);
|
||||
|
||||
tty_insert_flip_string(tty, buffer, len);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gigaset_if_receive);
|
||||
|
||||
|
@ -669,17 +584,15 @@ EXPORT_SYMBOL_GPL(gigaset_if_receive);
|
|||
void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
|
||||
const char *devname)
|
||||
{
|
||||
unsigned minors = drv->minors;
|
||||
int ret;
|
||||
struct tty_driver *tty;
|
||||
|
||||
drv->have_tty = 0;
|
||||
|
||||
drv->tty = tty = alloc_tty_driver(minors);
|
||||
drv->tty = tty = alloc_tty_driver(drv->minors);
|
||||
if (tty == NULL)
|
||||
goto enomem;
|
||||
|
||||
tty->magic = TTY_DRIVER_MAGIC,
|
||||
tty->type = TTY_DRIVER_TYPE_SERIAL,
|
||||
tty->subtype = SERIAL_TYPE_NORMAL,
|
||||
tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
|
||||
|
@ -687,9 +600,6 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
|
|||
tty->driver_name = procname;
|
||||
tty->name = devname;
|
||||
tty->minor_start = drv->minor;
|
||||
tty->num = drv->minors;
|
||||
|
||||
tty->owner = THIS_MODULE;
|
||||
|
||||
tty->init_termios = tty_std_termios;
|
||||
tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
|
||||
|
|
|
@ -1590,12 +1590,9 @@ static int
|
|||
isdn_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
modem_info *info;
|
||||
int retval, line;
|
||||
int retval;
|
||||
|
||||
line = tty->index;
|
||||
if (line < 0 || line >= ISDN_MAX_CHANNELS)
|
||||
return -ENODEV;
|
||||
info = &dev->mdm.info[line];
|
||||
info = &dev->mdm.info[tty->index];
|
||||
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
|
||||
return -ENODEV;
|
||||
if (!try_module_get(info->owner)) {
|
||||
|
|
|
@ -481,13 +481,9 @@ static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
{
|
||||
int idx = tty->index;
|
||||
struct pti_tty *pti_tty_data;
|
||||
int ret = tty_init_termios(tty);
|
||||
int ret = tty_standard_install(driver, tty);
|
||||
|
||||
if (ret == 0) {
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
driver->ttys[idx] = tty;
|
||||
|
||||
pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL);
|
||||
if (pti_tty_data == NULL)
|
||||
return -ENOMEM;
|
||||
|
@ -911,21 +907,17 @@ static int __init pti_init(void)
|
|||
|
||||
/* First register module as tty device */
|
||||
|
||||
pti_tty_driver = alloc_tty_driver(1);
|
||||
pti_tty_driver = alloc_tty_driver(PTITTY_MINOR_NUM);
|
||||
if (pti_tty_driver == NULL) {
|
||||
pr_err("%s(%d): Memory allocation failed for ptiTTY driver\n",
|
||||
__func__, __LINE__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pti_tty_driver->owner = THIS_MODULE;
|
||||
pti_tty_driver->magic = TTY_DRIVER_MAGIC;
|
||||
pti_tty_driver->driver_name = DRIVERNAME;
|
||||
pti_tty_driver->name = TTYNAME;
|
||||
pti_tty_driver->major = 0;
|
||||
pti_tty_driver->minor_start = PTITTY_MINOR_START;
|
||||
pti_tty_driver->minor_num = PTITTY_MINOR_NUM;
|
||||
pti_tty_driver->num = PTITTY_MINOR_NUM;
|
||||
pti_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
|
||||
pti_tty_driver->subtype = SYSTEM_TYPE_SYSCONS;
|
||||
pti_tty_driver->flags = TTY_DRIVER_REAL_RAW |
|
||||
|
|
|
@ -750,15 +750,12 @@ static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
{
|
||||
int idx = tty->index;
|
||||
struct sdio_uart_port *port = sdio_uart_port_get(idx);
|
||||
int ret = tty_init_termios(tty);
|
||||
int ret = tty_standard_install(driver, tty);
|
||||
|
||||
if (ret == 0) {
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
if (ret == 0)
|
||||
/* This is the ref sdio_uart_port get provided */
|
||||
tty->driver_data = port;
|
||||
driver->ttys[idx] = tty;
|
||||
} else
|
||||
else
|
||||
sdio_uart_port_put(port);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1178,7 +1175,6 @@ static int __init sdio_uart_init(void)
|
|||
if (!tty_drv)
|
||||
return -ENOMEM;
|
||||
|
||||
tty_drv->owner = THIS_MODULE;
|
||||
tty_drv->driver_name = "sdio_uart";
|
||||
tty_drv->name = "ttySDIO";
|
||||
tty_drv->major = 0; /* dynamically allocated */
|
||||
|
|
|
@ -3313,7 +3313,6 @@ static int __init hso_init(void)
|
|||
|
||||
/* fill in all needed values */
|
||||
tty_drv->magic = TTY_DRIVER_MAGIC;
|
||||
tty_drv->owner = THIS_MODULE;
|
||||
tty_drv->driver_name = driver_name;
|
||||
tty_drv->name = tty_filename;
|
||||
|
||||
|
@ -3322,7 +3321,6 @@ static int __init hso_init(void)
|
|||
tty_drv->major = tty_major;
|
||||
|
||||
tty_drv->minor_start = 0;
|
||||
tty_drv->num = HSO_SERIAL_TTY_MINORS;
|
||||
tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
|
||||
tty_drv->subtype = SERIAL_TYPE_NORMAL;
|
||||
tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
|
||||
|
|
|
@ -299,7 +299,6 @@ void cpc_tty_init(pc300dev_t * dev);
|
|||
void cpc_tty_unregister_service(pc300dev_t * pc300dev);
|
||||
void cpc_tty_receive(pc300dev_t * pc300dev);
|
||||
void cpc_tty_trigger_poll(pc300dev_t * pc300dev);
|
||||
void cpc_tty_reset_var(void);
|
||||
#endif
|
||||
|
||||
/************************/
|
||||
|
@ -3232,7 +3231,7 @@ static void plx_init(pc300_t * card)
|
|||
|
||||
}
|
||||
|
||||
static inline void show_version(void)
|
||||
static void show_version(void)
|
||||
{
|
||||
char *rcsvers, *rcsdate, *tmp;
|
||||
|
||||
|
@ -3413,19 +3412,10 @@ static void cpc_init_card(pc300_t * card)
|
|||
static int __devinit
|
||||
cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
static int first_time = 1;
|
||||
int err, eeprom_outdated = 0;
|
||||
u16 device_id;
|
||||
pc300_t *card;
|
||||
|
||||
if (first_time) {
|
||||
first_time = 0;
|
||||
show_version();
|
||||
#ifdef CONFIG_PC300_MLPPP
|
||||
cpc_tty_reset_var();
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((err = pci_enable_device(pdev)) < 0)
|
||||
return err;
|
||||
|
||||
|
@ -3661,6 +3651,7 @@ static struct pci_driver cpc_driver = {
|
|||
|
||||
static int __init cpc_init(void)
|
||||
{
|
||||
show_version();
|
||||
return pci_register_driver(&cpc_driver);
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,6 @@ void cpc_tty_init(pc300dev_t *dev);
|
|||
void cpc_tty_unregister_service(pc300dev_t *pc300dev);
|
||||
void cpc_tty_receive(pc300dev_t *pc300dev);
|
||||
void cpc_tty_trigger_poll(pc300dev_t *pc300dev);
|
||||
void cpc_tty_reset_var(void);
|
||||
|
||||
/*
|
||||
* PC300 TTY clear "signal"
|
||||
|
@ -1078,20 +1077,3 @@ void cpc_tty_trigger_poll(pc300dev_t *pc300dev)
|
|||
}
|
||||
schedule_work(&(cpc_tty->tty_tx_work));
|
||||
}
|
||||
|
||||
/*
|
||||
* PC300 TTY reset var routine
|
||||
* This routine is called by pc300driver to init the TTY area.
|
||||
*/
|
||||
|
||||
void cpc_tty_reset_var(void)
|
||||
{
|
||||
int i ;
|
||||
|
||||
CPC_TTY_DBG("hdlcX-tty: reset variables\n");
|
||||
/* reset the tty_driver structure - serial_drv */
|
||||
memset(&serial_drv, 0, sizeof(struct tty_driver));
|
||||
for (i=0; i < CPC_TTY_NPORTS; i++){
|
||||
memset(&cpc_tty_area[i],0, sizeof(st_cpc_tty_area));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -933,13 +933,9 @@ console_initcall(con3215_init);
|
|||
static int tty3215_open(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct raw3215_info *raw;
|
||||
int retval, line;
|
||||
int retval;
|
||||
|
||||
line = tty->index;
|
||||
if ((line < 0) || (line >= NR_3215))
|
||||
return -ENODEV;
|
||||
|
||||
raw = raw3215[line];
|
||||
raw = raw3215[tty->index];
|
||||
if (raw == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -1145,7 +1141,6 @@ static int __init tty3215_init(void)
|
|||
* proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
|
||||
*/
|
||||
|
||||
driver->owner = THIS_MODULE;
|
||||
driver->driver_name = "tty3215";
|
||||
driver->name = "ttyS";
|
||||
driver->major = TTY_MAJOR;
|
||||
|
|
|
@ -551,7 +551,6 @@ sclp_tty_init(void)
|
|||
return rc;
|
||||
}
|
||||
|
||||
driver->owner = THIS_MODULE;
|
||||
driver->driver_name = "sclp_line";
|
||||
driver->name = "sclp_line";
|
||||
driver->major = TTY_MAJOR;
|
||||
|
|
|
@ -685,7 +685,6 @@ static int __init sclp_vt220_tty_init(void)
|
|||
if (rc)
|
||||
goto out_driver;
|
||||
|
||||
driver->owner = THIS_MODULE;
|
||||
driver->driver_name = SCLP_VT220_DRIVER_NAME;
|
||||
driver->name = SCLP_VT220_DEVICE_NAME;
|
||||
driver->major = SCLP_VT220_MAJOR;
|
||||
|
|
|
@ -1784,7 +1784,6 @@ static int __init tty3270_init(void)
|
|||
* Entries in tty3270_driver that are NOT initialized:
|
||||
* proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
|
||||
*/
|
||||
driver->owner = THIS_MODULE;
|
||||
driver->driver_name = "ttyTUB";
|
||||
driver->name = "ttyTUB";
|
||||
driver->major = IBM_TTY3270_MAJOR;
|
||||
|
|
|
@ -1731,15 +1731,15 @@ static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
|
|||
switch (value) {
|
||||
case KVAL(K_CAPS):
|
||||
label = msg_get(MSG_KEYNAME_CAPSLOCK);
|
||||
on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK));
|
||||
on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
|
||||
break;
|
||||
case KVAL(K_NUM):
|
||||
label = msg_get(MSG_KEYNAME_NUMLOCK);
|
||||
on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK));
|
||||
on_off = vt_get_leds(fg_console, VC_NUMLOCK);
|
||||
break;
|
||||
case KVAL(K_HOLD):
|
||||
label = msg_get(MSG_KEYNAME_SCROLLLOCK);
|
||||
on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_SCROLLOCK));
|
||||
on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
|
||||
if (speakup_console[vc->vc_num])
|
||||
speakup_console[vc->vc_num]->tty_stopped = on_off;
|
||||
break;
|
||||
|
@ -2020,7 +2020,7 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
|
|||
if (type >= 0xf0)
|
||||
type -= 0xf0;
|
||||
if (type == KT_PAD
|
||||
&& (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) {
|
||||
&& (vt_get_leds(fg_console, VC_NUMLOCK))) {
|
||||
if (up_flag) {
|
||||
spk_keydown = 0;
|
||||
goto out;
|
||||
|
|
|
@ -8,21 +8,20 @@
|
|||
|
||||
static void start_serial_interrupt(int irq);
|
||||
|
||||
static struct serial_state rs_table[] = {
|
||||
static const struct old_serial_port rs_table[] = {
|
||||
SERIAL_PORT_DFNS
|
||||
};
|
||||
static struct serial_state *serstate;
|
||||
static const struct old_serial_port *serstate;
|
||||
static int timeouts;
|
||||
|
||||
struct serial_state *spk_serial_init(int index)
|
||||
const struct old_serial_port *spk_serial_init(int index)
|
||||
{
|
||||
int baud = 9600, quot = 0;
|
||||
unsigned int cval = 0;
|
||||
int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
|
||||
struct serial_state *ser = NULL;
|
||||
const struct old_serial_port *ser = rs_table + index;
|
||||
int err;
|
||||
|
||||
ser = rs_table + index;
|
||||
/* Divisor, bytesize and parity */
|
||||
quot = ser->baud_base / baud;
|
||||
cval = cflag & (CSIZE | CSTOPB);
|
||||
|
@ -41,7 +40,7 @@ struct serial_state *spk_serial_init(int index)
|
|||
__release_region(&ioport_resource, ser->port, 8);
|
||||
err = synth_request_region(ser->port, 8);
|
||||
if (err) {
|
||||
pr_warn("Unable to allocate port at %lx, errno %i",
|
||||
pr_warn("Unable to allocate port at %x, errno %i",
|
||||
ser->port, err);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -4,11 +4,22 @@
|
|||
#include <linux/serial.h> /* for rs_table, serial constants &
|
||||
serial_uart_config */
|
||||
#include <linux/serial_reg.h> /* for more serial constants */
|
||||
#include <linux/serialP.h> /* for struct serial_state */
|
||||
#ifndef __sparc__
|
||||
#include <asm/serial.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* this is cut&paste from 8250.h. Get rid of the structure, the definitions
|
||||
* and this whole broken driver.
|
||||
*/
|
||||
struct old_serial_port {
|
||||
unsigned int uart; /* unused */
|
||||
unsigned int baud_base;
|
||||
unsigned int port;
|
||||
unsigned int irq;
|
||||
unsigned int flags; /* unused */
|
||||
};
|
||||
|
||||
/* countdown values for serial timeouts in us */
|
||||
#define SPK_SERIAL_TIMEOUT 100000
|
||||
/* countdown values transmitter/dsr timeouts in us */
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
#define KT_SPKUP 15
|
||||
|
||||
extern struct serial_state *spk_serial_init(int index);
|
||||
extern const struct old_serial_port *spk_serial_init(int index);
|
||||
extern void stop_serial_interrupt(void);
|
||||
extern int wait_for_xmitr(void);
|
||||
extern unsigned char spk_serial_in(void);
|
||||
|
|
|
@ -34,7 +34,7 @@ static int do_synth_init(struct spk_synth *in_synth);
|
|||
|
||||
int serial_synth_probe(struct spk_synth *synth)
|
||||
{
|
||||
struct serial_state *ser;
|
||||
const struct old_serial_port *ser;
|
||||
int failed = 0;
|
||||
|
||||
if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -257,7 +257,6 @@ static int __init bfin_jc_init(void)
|
|||
if (!bfin_jc_driver)
|
||||
goto err_driver;
|
||||
|
||||
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;
|
||||
|
|
|
@ -1515,13 +1515,9 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
|
|||
static int cy_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct cyclades_port *info;
|
||||
unsigned int i, line;
|
||||
unsigned int i, line = tty->index;
|
||||
int retval;
|
||||
|
||||
line = tty->index;
|
||||
if (tty->index < 0 || NR_PORTS <= line)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < NR_CARDS; i++)
|
||||
if (line < cy_card[i].first_line + cy_card[i].nports &&
|
||||
line >= cy_card[i].first_line)
|
||||
|
@ -2413,7 +2409,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
|
|||
/* Not supported yet */
|
||||
return -EINVAL;
|
||||
}
|
||||
return put_user(result, (unsigned long __user *)value);
|
||||
return put_user(result, value);
|
||||
}
|
||||
|
||||
static int cy_tiocmget(struct tty_struct *tty)
|
||||
|
@ -4090,7 +4086,6 @@ static int __init cy_init(void)
|
|||
|
||||
/* Initialize the tty_driver structure */
|
||||
|
||||
cy_serial_driver->owner = THIS_MODULE;
|
||||
cy_serial_driver->driver_name = "cyclades";
|
||||
cy_serial_driver->name = "ttyC";
|
||||
cy_serial_driver->major = CYCLADES_MAJOR;
|
||||
|
|
|
@ -825,7 +825,6 @@ static int __init ehv_bc_init(void)
|
|||
goto error;
|
||||
}
|
||||
|
||||
ehv_bc_driver->owner = THIS_MODULE;
|
||||
ehv_bc_driver->driver_name = "ehv-bc";
|
||||
ehv_bc_driver->name = ehv_bc_console.name;
|
||||
ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE;
|
||||
|
|
|
@ -113,7 +113,7 @@ static int __init hvc_beat_init(void)
|
|||
if (!firmware_has_feature(FW_FEATURE_BEAT))
|
||||
return -ENODEV;
|
||||
|
||||
hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16);
|
||||
hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16);
|
||||
if (IS_ERR(hp))
|
||||
return PTR_ERR(hp);
|
||||
hvc_beat_dev = hp;
|
||||
|
|
|
@ -917,7 +917,6 @@ static int hvc_init(void)
|
|||
goto out;
|
||||
}
|
||||
|
||||
drv->owner = THIS_MODULE;
|
||||
drv->driver_name = "hvc";
|
||||
drv->name = "hvc";
|
||||
drv->major = HVC_MAJOR;
|
||||
|
|
|
@ -94,7 +94,7 @@ static int __init hvc_rtas_init(void)
|
|||
|
||||
/* Allocate an hvc_struct for the console device we instantiated
|
||||
* earlier. Save off hp so that we can return it on exit */
|
||||
hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16);
|
||||
hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16);
|
||||
if (IS_ERR(hp))
|
||||
return PTR_ERR(hp);
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ static int __init hvc_udbg_init(void)
|
|||
|
||||
BUG_ON(hvc_udbg_dev);
|
||||
|
||||
hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16);
|
||||
hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16);
|
||||
if (IS_ERR(hp))
|
||||
return PTR_ERR(hp);
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ static int __init xen_hvc_init(void)
|
|||
xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
|
||||
}
|
||||
if (xencons_irq < 0)
|
||||
xencons_irq = 0; /* NO_IRQ */
|
||||
xencons_irq = 0;
|
||||
else
|
||||
irq_set_noprobe(xencons_irq);
|
||||
|
||||
|
|
|
@ -1090,27 +1090,23 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
|
|||
*/
|
||||
static struct hvcs_struct *hvcs_get_by_index(int index)
|
||||
{
|
||||
struct hvcs_struct *hvcsd = NULL;
|
||||
struct hvcs_struct *hvcsd;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&hvcs_structs_lock);
|
||||
/* We can immediately discard OOB requests */
|
||||
if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) {
|
||||
list_for_each_entry(hvcsd, &hvcs_structs, next) {
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
if (hvcsd->index == index) {
|
||||
kref_get(&hvcsd->kref);
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
spin_unlock(&hvcs_structs_lock);
|
||||
return hvcsd;
|
||||
}
|
||||
list_for_each_entry(hvcsd, &hvcs_structs, next) {
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
if (hvcsd->index == index) {
|
||||
kref_get(&hvcsd->kref);
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
spin_unlock(&hvcs_structs_lock);
|
||||
return hvcsd;
|
||||
}
|
||||
hvcsd = NULL;
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
}
|
||||
|
||||
spin_unlock(&hvcs_structs_lock);
|
||||
return hvcsd;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1203,7 +1199,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
|||
{
|
||||
struct hvcs_struct *hvcsd;
|
||||
unsigned long flags;
|
||||
int irq = NO_IRQ;
|
||||
int irq;
|
||||
|
||||
/*
|
||||
* Is someone trying to close the file associated with this device after
|
||||
|
@ -1264,7 +1260,7 @@ static void hvcs_hangup(struct tty_struct * tty)
|
|||
struct hvcs_struct *hvcsd = tty->driver_data;
|
||||
unsigned long flags;
|
||||
int temp_open_count;
|
||||
int irq = NO_IRQ;
|
||||
int irq;
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
/* Preserve this so that we know how many kref refs to put */
|
||||
|
@ -1499,8 +1495,6 @@ static int __devinit hvcs_initialize(void)
|
|||
goto index_fail;
|
||||
}
|
||||
|
||||
hvcs_tty_driver->owner = THIS_MODULE;
|
||||
|
||||
hvcs_tty_driver->driver_name = hvcs_driver_name;
|
||||
hvcs_tty_driver->name = hvcs_device_node;
|
||||
|
||||
|
|
|
@ -737,14 +737,11 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
|
|||
{
|
||||
struct hvsi_struct *hp;
|
||||
unsigned long flags;
|
||||
int line = tty->index;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
if (line < 0 || line >= hvsi_count)
|
||||
return -ENODEV;
|
||||
hp = &hvsi_ports[line];
|
||||
hp = &hvsi_ports[tty->index];
|
||||
|
||||
tty->driver_data = hp;
|
||||
|
||||
|
@ -1088,7 +1085,6 @@ static int __init hvsi_init(void)
|
|||
if (!hvsi_driver)
|
||||
return -ENOMEM;
|
||||
|
||||
hvsi_driver->owner = THIS_MODULE;
|
||||
hvsi_driver->driver_name = "hvsi";
|
||||
hvsi_driver->name = "hvsi";
|
||||
hvsi_driver->major = HVSI_MAJOR;
|
||||
|
@ -1237,7 +1233,7 @@ static int __init hvsi_console_init(void)
|
|||
hp->state = HVSI_CLOSED;
|
||||
hp->vtermno = *vtermno;
|
||||
hp->virq = irq_create_mapping(NULL, irq[0]);
|
||||
if (hp->virq == NO_IRQ) {
|
||||
if (hp->virq == 0) {
|
||||
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
|
||||
__func__, irq[0]);
|
||||
continue;
|
||||
|
|
|
@ -90,33 +90,23 @@ static void report_deregistering(struct ipw_tty *tty)
|
|||
tty->index);
|
||||
}
|
||||
|
||||
static struct ipw_tty *get_tty(int minor)
|
||||
static struct ipw_tty *get_tty(int index)
|
||||
{
|
||||
if (minor < ipw_tty_driver->minor_start
|
||||
|| minor >= ipw_tty_driver->minor_start +
|
||||
IPWIRELESS_PCMCIA_MINORS)
|
||||
/*
|
||||
* The 'ras_raw' channel is only available when 'loopback' mode
|
||||
* is enabled.
|
||||
* Number of minor starts with 16 (_RANGE * _RAS_RAW).
|
||||
*/
|
||||
if (!ipwireless_loopback && index >=
|
||||
IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
|
||||
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];
|
||||
}
|
||||
return ttys[index];
|
||||
}
|
||||
|
||||
static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
|
||||
{
|
||||
int minor = linux_tty->index;
|
||||
struct ipw_tty *tty = get_tty(minor);
|
||||
struct ipw_tty *tty = get_tty(linux_tty->index);
|
||||
|
||||
if (!tty)
|
||||
return -ENODEV;
|
||||
|
@ -510,7 +500,7 @@ static int add_tty(int j,
|
|||
ipwireless_associate_network_tty(network,
|
||||
secondary_channel_idx,
|
||||
ttys[j]);
|
||||
if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j])
|
||||
if (get_tty(j) == ttys[j])
|
||||
report_registering(ttys[j]);
|
||||
return 0;
|
||||
}
|
||||
|
@ -570,7 +560,7 @@ void ipwireless_tty_free(struct ipw_tty *tty)
|
|||
|
||||
if (ttyj) {
|
||||
mutex_lock(&ttyj->ipw_tty_mutex);
|
||||
if (get_tty(j + ipw_tty_driver->minor_start) == ttyj)
|
||||
if (get_tty(j) == ttyj)
|
||||
report_deregistering(ttyj);
|
||||
ttyj->closing = 1;
|
||||
if (ttyj->linux_tty != NULL) {
|
||||
|
@ -614,7 +604,6 @@ int ipwireless_tty_init(void)
|
|||
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;
|
||||
|
|
|
@ -849,8 +849,6 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty)
|
|||
unsigned int board;
|
||||
int line = tty->index;
|
||||
|
||||
if (line < 0 || line > PORT_COUNT-1)
|
||||
return NULL;
|
||||
board = BOARD(line);
|
||||
card = &isi_card[board];
|
||||
|
||||
|
@ -1678,7 +1676,6 @@ static int __init isicom_init(void)
|
|||
goto error;
|
||||
}
|
||||
|
||||
isicom_normal->owner = THIS_MODULE;
|
||||
isicom_normal->name = "ttyM";
|
||||
isicom_normal->major = ISICOM_NMAJOR;
|
||||
isicom_normal->minor_start = 0;
|
||||
|
|
|
@ -1036,7 +1036,6 @@ static int __init moxa_init(void)
|
|||
if (!moxaDriver)
|
||||
return -ENOMEM;
|
||||
|
||||
moxaDriver->owner = THIS_MODULE;
|
||||
moxaDriver->name = "ttyMX";
|
||||
moxaDriver->major = ttymajor;
|
||||
moxaDriver->minor_start = 0;
|
||||
|
@ -1331,7 +1330,7 @@ static void moxa_start(struct tty_struct *tty)
|
|||
if (ch == NULL)
|
||||
return;
|
||||
|
||||
if (!(ch->statusflags & TXSTOPPED))
|
||||
if (!test_bit(TXSTOPPED, &ch->statusflags))
|
||||
return;
|
||||
|
||||
MoxaPortTxEnable(ch);
|
||||
|
|
|
@ -1010,8 +1010,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
|
|||
line = tty->index;
|
||||
if (line == MXSER_PORTS)
|
||||
return 0;
|
||||
if (line < 0 || line > MXSER_PORTS)
|
||||
return -ENODEV;
|
||||
info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
|
||||
if (!info->ioaddr)
|
||||
return -ENODEV;
|
||||
|
@ -2658,12 +2656,9 @@ static int __init mxser_module_init(void)
|
|||
MXSER_VERSION);
|
||||
|
||||
/* Initialize the tty_driver structure */
|
||||
mxvar_sdriver->owner = THIS_MODULE;
|
||||
mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
|
||||
mxvar_sdriver->name = "ttyMI";
|
||||
mxvar_sdriver->major = ttymajor;
|
||||
mxvar_sdriver->minor_start = 0;
|
||||
mxvar_sdriver->num = MXSER_PORTS + 1;
|
||||
mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
|
||||
mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
|
||||
mxvar_sdriver->init_termios = tty_std_termios;
|
||||
|
|
|
@ -3120,7 +3120,6 @@ static int __init gsm_init(void)
|
|||
pr_err("gsm_init: tty allocation failed.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
gsm_tty_driver->owner = THIS_MODULE;
|
||||
gsm_tty_driver->driver_name = "gsmtty";
|
||||
gsm_tty_driver->name = "gsmtty";
|
||||
gsm_tty_driver->major = 0; /* Dynamic */
|
||||
|
|
|
@ -1602,13 +1602,9 @@ static int ntty_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
int ret;
|
||||
if (!port || !dc || dc->state != NOZOMI_STATE_READY)
|
||||
return -ENODEV;
|
||||
ret = tty_init_termios(tty);
|
||||
if (ret == 0) {
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
ret = tty_standard_install(driver, tty);
|
||||
if (ret == 0)
|
||||
tty->driver_data = port;
|
||||
driver->ttys[tty->index] = tty;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1920,7 +1916,6 @@ static __init int nozomi_init(void)
|
|||
if (!ntty_driver)
|
||||
return -ENOMEM;
|
||||
|
||||
ntty_driver->owner = THIS_MODULE;
|
||||
ntty_driver->driver_name = NOZOMI_NAME_TTY;
|
||||
ntty_driver->name = "noz";
|
||||
ntty_driver->major = 0;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/major.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
|
@ -394,7 +393,6 @@ static void __init legacy_pty_init(void)
|
|||
if (!pty_slave_driver)
|
||||
panic("Couldn't allocate pty slave driver");
|
||||
|
||||
pty_driver->owner = THIS_MODULE;
|
||||
pty_driver->driver_name = "pty_master";
|
||||
pty_driver->name = "pty";
|
||||
pty_driver->major = PTY_MASTER_MAJOR;
|
||||
|
@ -412,7 +410,6 @@ static void __init legacy_pty_init(void)
|
|||
pty_driver->other = pty_slave_driver;
|
||||
tty_set_operations(pty_driver, &master_pty_ops_bsd);
|
||||
|
||||
pty_slave_driver->owner = THIS_MODULE;
|
||||
pty_slave_driver->driver_name = "pty_slave";
|
||||
pty_slave_driver->name = "ttyp";
|
||||
pty_slave_driver->major = PTY_SLAVE_MAJOR;
|
||||
|
@ -439,55 +436,9 @@ static inline void legacy_pty_init(void) { }
|
|||
|
||||
/* Unix98 devices */
|
||||
#ifdef CONFIG_UNIX98_PTYS
|
||||
/*
|
||||
* sysctl support for setting limits on the number of Unix98 ptys allocated.
|
||||
* Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
|
||||
*/
|
||||
int pty_limit = NR_UNIX98_PTY_DEFAULT;
|
||||
static int pty_limit_min;
|
||||
static int pty_limit_max = NR_UNIX98_PTY_MAX;
|
||||
static int pty_count;
|
||||
|
||||
static struct cdev ptmx_cdev;
|
||||
|
||||
static struct ctl_table pty_table[] = {
|
||||
{
|
||||
.procname = "max",
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.data = &pty_limit,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &pty_limit_min,
|
||||
.extra2 = &pty_limit_max,
|
||||
}, {
|
||||
.procname = "nr",
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0444,
|
||||
.data = &pty_count,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct ctl_table pty_kern_table[] = {
|
||||
{
|
||||
.procname = "pty",
|
||||
.mode = 0555,
|
||||
.child = pty_table,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct ctl_table pty_root_table[] = {
|
||||
{
|
||||
.procname = "kernel",
|
||||
.mode = 0555,
|
||||
.child = pty_kern_table,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
static int pty_unix98_ioctl(struct tty_struct *tty,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
|
@ -515,10 +466,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
|
|||
static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
|
||||
struct inode *ptm_inode, int idx)
|
||||
{
|
||||
struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
|
||||
if (tty)
|
||||
tty = tty->link;
|
||||
return tty;
|
||||
/* Master must be open via /dev/ptmx */
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -589,7 +538,6 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
*/
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
pty_count++;
|
||||
return 0;
|
||||
err_free_mem:
|
||||
deinitialize_tty_struct(o_tty);
|
||||
|
@ -603,7 +551,6 @@ err_free_tty:
|
|||
|
||||
static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
pty_count--;
|
||||
}
|
||||
|
||||
static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
||||
|
@ -677,7 +624,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
|||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock();
|
||||
tty = tty_init_dev(ptm_driver, index, 1);
|
||||
tty = tty_init_dev(ptm_driver, index);
|
||||
mutex_unlock(&tty_mutex);
|
||||
|
||||
if (IS_ERR(tty)) {
|
||||
|
@ -722,7 +669,6 @@ static void __init unix98_pty_init(void)
|
|||
if (!pts_driver)
|
||||
panic("Couldn't allocate Unix98 pts driver");
|
||||
|
||||
ptm_driver->owner = THIS_MODULE;
|
||||
ptm_driver->driver_name = "pty_master";
|
||||
ptm_driver->name = "ptm";
|
||||
ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
|
||||
|
@ -741,7 +687,6 @@ static void __init unix98_pty_init(void)
|
|||
ptm_driver->other = pts_driver;
|
||||
tty_set_operations(ptm_driver, &ptm_unix98_ops);
|
||||
|
||||
pts_driver->owner = THIS_MODULE;
|
||||
pts_driver->driver_name = "pty_slave";
|
||||
pts_driver->name = "pts";
|
||||
pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
|
||||
|
@ -762,8 +707,6 @@ static void __init unix98_pty_init(void)
|
|||
if (tty_register_driver(pts_driver))
|
||||
panic("Couldn't register Unix98 pts driver");
|
||||
|
||||
register_sysctl_table(pty_root_table);
|
||||
|
||||
/* Now create the /dev/ptmx special device */
|
||||
tty_default_fops(&ptmx_fops);
|
||||
ptmx_fops.open = ptmx_open;
|
||||
|
|
|
@ -892,12 +892,12 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
|
|||
{
|
||||
struct r_port *info;
|
||||
struct tty_port *port;
|
||||
int line = 0, retval;
|
||||
int retval;
|
||||
CHANNEL_t *cp;
|
||||
unsigned long page;
|
||||
|
||||
line = tty->index;
|
||||
if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL))
|
||||
info = rp_table[tty->index];
|
||||
if (info == NULL)
|
||||
return -ENXIO;
|
||||
port = &info->port;
|
||||
|
||||
|
@ -2277,7 +2277,6 @@ static int __init rp_init(void)
|
|||
* driver with the tty layer.
|
||||
*/
|
||||
|
||||
rocket_driver->owner = THIS_MODULE;
|
||||
rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
|
||||
rocket_driver->name = "ttyR";
|
||||
rocket_driver->driver_name = "Comtrol RocketPort";
|
||||
|
|
|
@ -331,7 +331,7 @@ static int serial21285_verify_port(struct uart_port *port, struct serial_struct
|
|||
int ret = 0;
|
||||
if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
|
||||
ret = -EINVAL;
|
||||
if (ser->irq != NO_IRQ)
|
||||
if (ser->irq <= 0)
|
||||
ret = -EINVAL;
|
||||
if (ser->baud_base != port->uartclk / 16)
|
||||
ret = -EINVAL;
|
||||
|
@ -360,7 +360,7 @@ static struct uart_ops serial21285_ops = {
|
|||
static struct uart_port serial21285_port = {
|
||||
.mapbase = 0x42000160,
|
||||
.iotype = UPIO_MEM,
|
||||
.irq = NO_IRQ,
|
||||
.irq = 0,
|
||||
.fifosize = 16,
|
||||
.ops = &serial21285_ops,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
|
|
|
@ -1190,14 +1190,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
int rs_open(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct m68k_serial *info;
|
||||
int retval, line;
|
||||
int retval;
|
||||
|
||||
line = tty->index;
|
||||
|
||||
if (line >= NR_PORTS || line < 0) /* we have exactly one */
|
||||
return -ENODEV;
|
||||
|
||||
info = &m68k_soft[line];
|
||||
info = &m68k_soft[tty->index];
|
||||
|
||||
if (serial_paranoia_check(info, tty->name, "rs_open"))
|
||||
return -ENODEV;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -86,6 +86,16 @@ struct serial8250_config {
|
|||
#define SERIAL8250_SHARE_IRQS 0
|
||||
#endif
|
||||
|
||||
static inline int serial_in(struct uart_8250_port *up, int offset)
|
||||
{
|
||||
return up->port.serial_in(&up->port, offset);
|
||||
}
|
||||
|
||||
static inline void serial_out(struct uart_8250_port *up, int offset, int value)
|
||||
{
|
||||
up->port.serial_out(&up->port, offset, value);
|
||||
}
|
||||
|
||||
#if defined(__alpha__) && !defined(CONFIG_PCI)
|
||||
/*
|
||||
* Digital did something really horribly wrong with the OUT1 and OUT2
|
||||
|
|
|
@ -1347,4 +1347,17 @@ config SERIAL_AR933X_NR_UARTS
|
|||
Set this to the number of serial ports you want the driver
|
||||
to support.
|
||||
|
||||
config SERIAL_EFM32_UART
|
||||
tristate "EFM32 UART/USART port."
|
||||
depends on ARCH_EFM32
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver support the USART and UART ports on
|
||||
Energy Micro's efm32 SoCs.
|
||||
|
||||
config SERIAL_EFM32_UART_CONSOLE
|
||||
bool "EFM32 UART/USART console support"
|
||||
depends on SERIAL_EFM32_UART=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -61,12 +61,12 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
|
|||
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
|
||||
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
|
||||
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
|
||||
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
|
||||
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
|
||||
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
|
||||
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
|
||||
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
|
||||
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
|
||||
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
|
||||
obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
|
||||
obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
|
||||
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
|
||||
|
@ -78,3 +78,4 @@ obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
|
|||
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
|
||||
obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
|
||||
obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o
|
||||
obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
|
||||
|
|
|
@ -377,6 +377,26 @@ static int altera_uart_verify_port(struct uart_port *port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int altera_uart_poll_get_char(struct uart_port *port)
|
||||
{
|
||||
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
|
||||
ALTERA_UART_STATUS_RRDY_MSK))
|
||||
cpu_relax();
|
||||
|
||||
return altera_uart_readl(port, ALTERA_UART_RXDATA_REG);
|
||||
}
|
||||
|
||||
static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
|
||||
ALTERA_UART_STATUS_TRDY_MSK))
|
||||
cpu_relax();
|
||||
|
||||
altera_uart_writel(port, c, ALTERA_UART_TXDATA_REG);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the basic serial functions we support.
|
||||
*/
|
||||
|
@ -397,35 +417,16 @@ static struct uart_ops altera_uart_ops = {
|
|||
.release_port = altera_uart_release_port,
|
||||
.config_port = altera_uart_config_port,
|
||||
.verify_port = altera_uart_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = altera_uart_poll_get_char,
|
||||
.poll_put_char = altera_uart_poll_put_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
|
||||
|
||||
#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
|
||||
|
||||
int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
|
||||
port = &altera_uart_ports[i].port;
|
||||
|
||||
port->line = i;
|
||||
port->type = PORT_ALTERA_UART;
|
||||
port->mapbase = platp[i].mapbase;
|
||||
port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
|
||||
port->iotype = SERIAL_IO_MEM;
|
||||
port->irq = platp[i].irq;
|
||||
port->uartclk = platp[i].uartclk;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->ops = &altera_uart_ops;
|
||||
port->private_data = platp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void altera_uart_console_putc(struct uart_port *port, const char c)
|
||||
{
|
||||
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
|
||||
|
|
|
@ -827,7 +827,12 @@ static void pl011_dma_rx_callback(void *data)
|
|||
{
|
||||
struct uart_amba_port *uap = data;
|
||||
struct pl011_dmarx_data *dmarx = &uap->dmarx;
|
||||
struct dma_chan *rxchan = dmarx->chan;
|
||||
bool lastbuf = dmarx->use_buf_b;
|
||||
struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ?
|
||||
&dmarx->sgbuf_b : &dmarx->sgbuf_a;
|
||||
size_t pending;
|
||||
struct dma_tx_state state;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
|
@ -838,11 +843,21 @@ static void pl011_dma_rx_callback(void *data)
|
|||
* we immediately trigger the next DMA job.
|
||||
*/
|
||||
spin_lock_irq(&uap->port.lock);
|
||||
/*
|
||||
* Rx data can be taken by the UART interrupts during
|
||||
* the DMA irq handler. So we check the residue here.
|
||||
*/
|
||||
rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
|
||||
pending = sgbuf->sg.length - state.residue;
|
||||
BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
|
||||
/* Then we terminate the transfer - we now know our residue */
|
||||
dmaengine_terminate_all(rxchan);
|
||||
|
||||
uap->dmarx.running = false;
|
||||
dmarx->use_buf_b = !lastbuf;
|
||||
ret = pl011_dma_rx_trigger_dma(uap);
|
||||
|
||||
pl011_dma_rx_chars(uap, PL011_DMA_BUFFER_SIZE, lastbuf, false);
|
||||
pl011_dma_rx_chars(uap, pending, lastbuf, false);
|
||||
spin_unlock_irq(&uap->port.lock);
|
||||
/*
|
||||
* Do this check after we picked the DMA chars so we don't
|
||||
|
@ -1381,6 +1396,10 @@ static int pl011_startup(struct uart_port *port)
|
|||
|
||||
uap->port.uartclk = clk_get_rate(uap->clk);
|
||||
|
||||
/* Clear pending error and receive interrupts */
|
||||
writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
|
||||
UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
|
||||
|
||||
/*
|
||||
* Allocate the IRQ
|
||||
*/
|
||||
|
@ -1417,10 +1436,6 @@ static int pl011_startup(struct uart_port *port)
|
|||
cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
|
||||
writew(cr, uap->port.membase + UART011_CR);
|
||||
|
||||
/* Clear pending error interrupts */
|
||||
writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
|
||||
uap->port.membase + UART011_ICR);
|
||||
|
||||
/*
|
||||
* initialise the old status of the modem signals
|
||||
*/
|
||||
|
@ -1435,6 +1450,9 @@ static int pl011_startup(struct uart_port *port)
|
|||
* as well.
|
||||
*/
|
||||
spin_lock_irq(&uap->port.lock);
|
||||
/* Clear out any spuriously appearing RX interrupts */
|
||||
writew(UART011_RTIS | UART011_RXIS,
|
||||
uap->port.membase + UART011_ICR);
|
||||
uap->im = UART011_RTIM;
|
||||
if (!pl011_dma_rx_running(uap))
|
||||
uap->im |= UART011_RXIM;
|
||||
|
@ -1927,6 +1945,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
goto unmap;
|
||||
}
|
||||
|
||||
/* Ensure interrupts from this UART are masked and cleared */
|
||||
writew(0, uap->port.membase + UART011_IMSC);
|
||||
writew(0xffff, uap->port.membase + UART011_ICR);
|
||||
|
||||
uap->vendor = vendor;
|
||||
uap->lcrh_rx = vendor->lcrh_rx;
|
||||
uap->lcrh_tx = vendor->lcrh_tx;
|
||||
|
|
|
@ -535,11 +535,13 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
|
|||
* when start a new tx.
|
||||
*/
|
||||
UART_CLEAR_IER(uart, ETBEI);
|
||||
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
|
||||
uart->port.icount.tx += uart->tx_count;
|
||||
if (!uart_circ_empty(xmit)) {
|
||||
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uart->port);
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uart->port);
|
||||
}
|
||||
|
||||
bfin_serial_dma_tx_chars(uart);
|
||||
}
|
||||
|
|
|
@ -4105,20 +4105,11 @@ static int
|
|||
rs_open(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct e100_serial *info;
|
||||
int retval, line;
|
||||
int retval;
|
||||
unsigned long page;
|
||||
int allocated_resources = 0;
|
||||
|
||||
/* find which port we want to open */
|
||||
line = tty->index;
|
||||
|
||||
if (line < 0 || line >= NR_PORTS)
|
||||
return -ENODEV;
|
||||
|
||||
/* find the corresponding e100_serial struct in the table */
|
||||
info = rs_table + line;
|
||||
|
||||
/* don't allow the opening of ports that are not enabled in the HW config */
|
||||
info = rs_table + tty->index;
|
||||
if (!info->enabled)
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -4131,7 +4122,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
|||
tty->driver_data = info;
|
||||
info->port.tty = tty;
|
||||
|
||||
info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
|
||||
|
||||
if (!tmp_buf) {
|
||||
page = get_zeroed_page(GFP_KERNEL);
|
||||
|
|
|
@ -0,0 +1,830 @@
|
|||
#if defined(CONFIG_SERIAL_EFM32_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/platform_data/efm32-uart.h>
|
||||
|
||||
#define DRIVER_NAME "efm32-uart"
|
||||
#define DEV_NAME "ttyefm"
|
||||
|
||||
#define UARTn_CTRL 0x00
|
||||
#define UARTn_CTRL_SYNC 0x0001
|
||||
#define UARTn_CTRL_TXBIL 0x1000
|
||||
|
||||
#define UARTn_FRAME 0x04
|
||||
#define UARTn_FRAME_DATABITS__MASK 0x000f
|
||||
#define UARTn_FRAME_DATABITS(n) ((n) - 3)
|
||||
#define UARTn_FRAME_PARITY_NONE 0x0000
|
||||
#define UARTn_FRAME_PARITY_EVEN 0x0200
|
||||
#define UARTn_FRAME_PARITY_ODD 0x0300
|
||||
#define UARTn_FRAME_STOPBITS_HALF 0x0000
|
||||
#define UARTn_FRAME_STOPBITS_ONE 0x1000
|
||||
#define UARTn_FRAME_STOPBITS_TWO 0x3000
|
||||
|
||||
#define UARTn_CMD 0x0c
|
||||
#define UARTn_CMD_RXEN 0x0001
|
||||
#define UARTn_CMD_RXDIS 0x0002
|
||||
#define UARTn_CMD_TXEN 0x0004
|
||||
#define UARTn_CMD_TXDIS 0x0008
|
||||
|
||||
#define UARTn_STATUS 0x10
|
||||
#define UARTn_STATUS_TXENS 0x0002
|
||||
#define UARTn_STATUS_TXC 0x0020
|
||||
#define UARTn_STATUS_TXBL 0x0040
|
||||
#define UARTn_STATUS_RXDATAV 0x0080
|
||||
|
||||
#define UARTn_CLKDIV 0x14
|
||||
|
||||
#define UARTn_RXDATAX 0x18
|
||||
#define UARTn_RXDATAX_RXDATA__MASK 0x01ff
|
||||
#define UARTn_RXDATAX_PERR 0x4000
|
||||
#define UARTn_RXDATAX_FERR 0x8000
|
||||
/*
|
||||
* This is a software only flag used for ignore_status_mask and
|
||||
* read_status_mask! It's used for breaks that the hardware doesn't report
|
||||
* explicitly.
|
||||
*/
|
||||
#define SW_UARTn_RXDATAX_BERR 0x2000
|
||||
|
||||
#define UARTn_TXDATA 0x34
|
||||
|
||||
#define UARTn_IF 0x40
|
||||
#define UARTn_IF_TXC 0x0001
|
||||
#define UARTn_IF_TXBL 0x0002
|
||||
#define UARTn_IF_RXDATAV 0x0004
|
||||
#define UARTn_IF_RXOF 0x0010
|
||||
|
||||
#define UARTn_IFS 0x44
|
||||
#define UARTn_IFC 0x48
|
||||
#define UARTn_IEN 0x4c
|
||||
|
||||
#define UARTn_ROUTE 0x54
|
||||
#define UARTn_ROUTE_LOCATION__MASK 0x0700
|
||||
#define UARTn_ROUTE_LOCATION(n) (((n) << 8) & UARTn_ROUTE_LOCATION__MASK)
|
||||
#define UARTn_ROUTE_RXPEN 0x0001
|
||||
#define UARTn_ROUTE_TXPEN 0x0002
|
||||
|
||||
struct efm32_uart_port {
|
||||
struct uart_port port;
|
||||
unsigned int txirq;
|
||||
struct clk *clk;
|
||||
};
|
||||
#define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port)
|
||||
#define efm_debug(efm_port, format, arg...) \
|
||||
dev_dbg(efm_port->port.dev, format, ##arg)
|
||||
|
||||
static void efm32_uart_write32(struct efm32_uart_port *efm_port,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel_relaxed(value, efm_port->port.membase + offset);
|
||||
}
|
||||
|
||||
static u32 efm32_uart_read32(struct efm32_uart_port *efm_port,
|
||||
unsigned offset)
|
||||
{
|
||||
return readl_relaxed(efm_port->port.membase + offset);
|
||||
}
|
||||
|
||||
static unsigned int efm32_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
|
||||
if (status & UARTn_STATUS_TXC)
|
||||
return TIOCSER_TEMT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void efm32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
/* sorry, neither handshaking lines nor loop functionallity */
|
||||
}
|
||||
|
||||
static unsigned int efm32_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
/* sorry, no handshaking lines available */
|
||||
return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
|
||||
}
|
||||
|
||||
static void efm32_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 ien = efm32_uart_read32(efm_port, UARTn_IEN);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
|
||||
ien &= ~(UARTn_IF_TXC | UARTn_IF_TXBL);
|
||||
efm32_uart_write32(efm_port, ien, UARTn_IEN);
|
||||
}
|
||||
|
||||
static void efm32_uart_tx_chars(struct efm32_uart_port *efm_port)
|
||||
{
|
||||
struct uart_port *port = &efm_port->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
|
||||
while (efm32_uart_read32(efm_port, UARTn_STATUS) &
|
||||
UARTn_STATUS_TXBL) {
|
||||
if (port->x_char) {
|
||||
port->icount.tx++;
|
||||
efm32_uart_write32(efm_port, port->x_char,
|
||||
UARTn_TXDATA);
|
||||
port->x_char = 0;
|
||||
continue;
|
||||
}
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
|
||||
port->icount.tx++;
|
||||
efm32_uart_write32(efm_port, xmit->buf[xmit->tail],
|
||||
UARTn_TXDATA);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (!port->x_char && uart_circ_empty(xmit) &&
|
||||
efm32_uart_read32(efm_port, UARTn_STATUS) &
|
||||
UARTn_STATUS_TXC)
|
||||
efm32_uart_stop_tx(port);
|
||||
}
|
||||
|
||||
static void efm32_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 ien;
|
||||
|
||||
efm32_uart_write32(efm_port,
|
||||
UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IFC);
|
||||
ien = efm32_uart_read32(efm_port, UARTn_IEN);
|
||||
efm32_uart_write32(efm_port,
|
||||
ien | UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IEN);
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
|
||||
|
||||
efm32_uart_tx_chars(efm_port);
|
||||
}
|
||||
|
||||
static void efm32_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD);
|
||||
}
|
||||
|
||||
static void efm32_uart_enable_ms(struct uart_port *port)
|
||||
{
|
||||
/* no handshake lines, no modem status interrupts */
|
||||
}
|
||||
|
||||
static void efm32_uart_break_ctl(struct uart_port *port, int ctl)
|
||||
{
|
||||
/* not possible without fiddling with gpios */
|
||||
}
|
||||
|
||||
static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port,
|
||||
struct tty_struct *tty)
|
||||
{
|
||||
struct uart_port *port = &efm_port->port;
|
||||
|
||||
while (efm32_uart_read32(efm_port, UARTn_STATUS) &
|
||||
UARTn_STATUS_RXDATAV) {
|
||||
u32 rxdata = efm32_uart_read32(efm_port, UARTn_RXDATAX);
|
||||
int flag = 0;
|
||||
|
||||
/*
|
||||
* This is a reserved bit and I only saw it read as 0. But to be
|
||||
* sure not to be confused too much by new devices adhere to the
|
||||
* warning in the reference manual that reserverd bits might
|
||||
* read as 1 in the future.
|
||||
*/
|
||||
rxdata &= ~SW_UARTn_RXDATAX_BERR;
|
||||
|
||||
port->icount.rx++;
|
||||
|
||||
if ((rxdata & UARTn_RXDATAX_FERR) &&
|
||||
!(rxdata & UARTn_RXDATAX_RXDATA__MASK)) {
|
||||
rxdata |= SW_UARTn_RXDATAX_BERR;
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
} else if (rxdata & UARTn_RXDATAX_PERR)
|
||||
port->icount.parity++;
|
||||
else if (rxdata & UARTn_RXDATAX_FERR)
|
||||
port->icount.frame++;
|
||||
|
||||
rxdata &= port->read_status_mask;
|
||||
|
||||
if (rxdata & SW_UARTn_RXDATAX_BERR)
|
||||
flag = TTY_BREAK;
|
||||
else if (rxdata & UARTn_RXDATAX_PERR)
|
||||
flag = TTY_PARITY;
|
||||
else if (rxdata & UARTn_RXDATAX_FERR)
|
||||
flag = TTY_FRAME;
|
||||
else if (uart_handle_sysrq_char(port,
|
||||
rxdata & UARTn_RXDATAX_RXDATA__MASK))
|
||||
continue;
|
||||
|
||||
if (tty && (rxdata & port->ignore_status_mask) == 0)
|
||||
tty_insert_flip_char(tty,
|
||||
rxdata & UARTn_RXDATAX_RXDATA__MASK, flag);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t efm32_uart_rxirq(int irq, void *data)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = data;
|
||||
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
|
||||
int handled = IRQ_NONE;
|
||||
struct uart_port *port = &efm_port->port;
|
||||
struct tty_struct *tty;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
tty = tty_kref_get(port->state->port.tty);
|
||||
|
||||
if (irqflag & UARTn_IF_RXDATAV) {
|
||||
efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC);
|
||||
efm32_uart_rx_chars(efm_port, tty);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (irqflag & UARTn_IF_RXOF) {
|
||||
efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC);
|
||||
port->icount.overrun++;
|
||||
if (tty)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (tty) {
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
static irqreturn_t efm32_uart_txirq(int irq, void *data)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = data;
|
||||
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
|
||||
|
||||
/* TXBL doesn't need to be cleared */
|
||||
if (irqflag & UARTn_IF_TXC)
|
||||
efm32_uart_write32(efm_port, UARTn_IF_TXC, UARTn_IFC);
|
||||
|
||||
if (irqflag & (UARTn_IF_TXC | UARTn_IF_TXBL)) {
|
||||
efm32_uart_tx_chars(efm_port);
|
||||
return IRQ_HANDLED;
|
||||
} else
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int efm32_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 location = 0;
|
||||
struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev);
|
||||
int ret;
|
||||
|
||||
if (pdata)
|
||||
location = UARTn_ROUTE_LOCATION(pdata->location);
|
||||
|
||||
ret = clk_enable(efm_port->clk);
|
||||
if (ret) {
|
||||
efm_debug(efm_port, "failed to enable clk\n");
|
||||
goto err_clk_enable;
|
||||
}
|
||||
port->uartclk = clk_get_rate(efm_port->clk);
|
||||
|
||||
/* Enable pins at configured location */
|
||||
efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN,
|
||||
UARTn_ROUTE);
|
||||
|
||||
ret = request_irq(port->irq, efm32_uart_rxirq, 0,
|
||||
DRIVER_NAME, efm_port);
|
||||
if (ret) {
|
||||
efm_debug(efm_port, "failed to register rxirq\n");
|
||||
goto err_request_irq_rx;
|
||||
}
|
||||
|
||||
/* disable all irqs */
|
||||
efm32_uart_write32(efm_port, 0, UARTn_IEN);
|
||||
|
||||
ret = request_irq(efm_port->txirq, efm32_uart_txirq, 0,
|
||||
DRIVER_NAME, efm_port);
|
||||
if (ret) {
|
||||
efm_debug(efm_port, "failed to register txirq\n");
|
||||
free_irq(port->irq, efm_port);
|
||||
err_request_irq_rx:
|
||||
|
||||
clk_disable(efm_port->clk);
|
||||
} else {
|
||||
efm32_uart_write32(efm_port,
|
||||
UARTn_IF_RXDATAV | UARTn_IF_RXOF, UARTn_IEN);
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_RXEN, UARTn_CMD);
|
||||
}
|
||||
|
||||
err_clk_enable:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void efm32_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
|
||||
efm32_uart_write32(efm_port, 0, UARTn_IEN);
|
||||
free_irq(port->irq, efm_port);
|
||||
|
||||
clk_disable(efm_port->clk);
|
||||
}
|
||||
|
||||
static void efm32_uart_set_termios(struct uart_port *port,
|
||||
struct ktermios *new, struct ktermios *old)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
unsigned long flags;
|
||||
unsigned baud;
|
||||
u32 clkdiv;
|
||||
u32 frame = 0;
|
||||
|
||||
/* no modem control lines */
|
||||
new->c_cflag &= ~(CRTSCTS | CMSPAR);
|
||||
|
||||
baud = uart_get_baud_rate(port, new, old,
|
||||
DIV_ROUND_CLOSEST(port->uartclk, 16 * 8192),
|
||||
DIV_ROUND_CLOSEST(port->uartclk, 16));
|
||||
|
||||
switch (new->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
frame |= UARTn_FRAME_DATABITS(5);
|
||||
break;
|
||||
case CS6:
|
||||
frame |= UARTn_FRAME_DATABITS(6);
|
||||
break;
|
||||
case CS7:
|
||||
frame |= UARTn_FRAME_DATABITS(7);
|
||||
break;
|
||||
case CS8:
|
||||
frame |= UARTn_FRAME_DATABITS(8);
|
||||
break;
|
||||
}
|
||||
|
||||
if (new->c_cflag & CSTOPB)
|
||||
/* the receiver only verifies the first stop bit */
|
||||
frame |= UARTn_FRAME_STOPBITS_TWO;
|
||||
else
|
||||
frame |= UARTn_FRAME_STOPBITS_ONE;
|
||||
|
||||
if (new->c_cflag & PARENB) {
|
||||
if (new->c_cflag & PARODD)
|
||||
frame |= UARTn_FRAME_PARITY_ODD;
|
||||
else
|
||||
frame |= UARTn_FRAME_PARITY_EVEN;
|
||||
} else
|
||||
frame |= UARTn_FRAME_PARITY_NONE;
|
||||
|
||||
/*
|
||||
* the 6 lowest bits of CLKDIV are dc, bit 6 has value 0.25.
|
||||
* port->uartclk <= 14e6, so 4 * port->uartclk doesn't overflow.
|
||||
*/
|
||||
clkdiv = (DIV_ROUND_CLOSEST(4 * port->uartclk, 16 * baud) - 4) << 6;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
efm32_uart_write32(efm_port,
|
||||
UARTn_CMD_TXDIS | UARTn_CMD_RXDIS, UARTn_CMD);
|
||||
|
||||
port->read_status_mask = UARTn_RXDATAX_RXDATA__MASK;
|
||||
if (new->c_iflag & INPCK)
|
||||
port->read_status_mask |=
|
||||
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
|
||||
if (new->c_iflag & (BRKINT | PARMRK))
|
||||
port->read_status_mask |= SW_UARTn_RXDATAX_BERR;
|
||||
|
||||
port->ignore_status_mask = 0;
|
||||
if (new->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |=
|
||||
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
|
||||
if (new->c_iflag & IGNBRK)
|
||||
port->ignore_status_mask |= SW_UARTn_RXDATAX_BERR;
|
||||
|
||||
uart_update_timeout(port, new->c_cflag, baud);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CTRL_TXBIL, UARTn_CTRL);
|
||||
efm32_uart_write32(efm_port, frame, UARTn_FRAME);
|
||||
efm32_uart_write32(efm_port, clkdiv, UARTn_CLKDIV);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXEN | UARTn_CMD_RXEN,
|
||||
UARTn_CMD);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static const char *efm32_uart_type(struct uart_port *port)
|
||||
{
|
||||
return port->type == PORT_EFMUART ? "efm32-uart" : NULL;
|
||||
}
|
||||
|
||||
static void efm32_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
|
||||
clk_unprepare(efm_port->clk);
|
||||
clk_put(efm_port->clk);
|
||||
iounmap(port->membase);
|
||||
}
|
||||
|
||||
static int efm32_uart_request_port(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
int ret;
|
||||
|
||||
port->membase = ioremap(port->mapbase, 60);
|
||||
if (!efm_port->port.membase) {
|
||||
ret = -ENOMEM;
|
||||
efm_debug(efm_port, "failed to remap\n");
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
efm_port->clk = clk_get(port->dev, NULL);
|
||||
if (IS_ERR(efm_port->clk)) {
|
||||
ret = PTR_ERR(efm_port->clk);
|
||||
efm_debug(efm_port, "failed to get clock\n");
|
||||
goto err_clk_get;
|
||||
}
|
||||
|
||||
ret = clk_prepare(efm_port->clk);
|
||||
if (ret) {
|
||||
clk_put(efm_port->clk);
|
||||
err_clk_get:
|
||||
|
||||
iounmap(port->membase);
|
||||
err_ioremap:
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void efm32_uart_config_port(struct uart_port *port, int type)
|
||||
{
|
||||
if (type & UART_CONFIG_TYPE &&
|
||||
!efm32_uart_request_port(port))
|
||||
port->type = PORT_EFMUART;
|
||||
}
|
||||
|
||||
static int efm32_uart_verify_port(struct uart_port *port,
|
||||
struct serial_struct *serinfo)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (serinfo->type != PORT_UNKNOWN && serinfo->type != PORT_EFMUART)
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct uart_ops efm32_uart_pops = {
|
||||
.tx_empty = efm32_uart_tx_empty,
|
||||
.set_mctrl = efm32_uart_set_mctrl,
|
||||
.get_mctrl = efm32_uart_get_mctrl,
|
||||
.stop_tx = efm32_uart_stop_tx,
|
||||
.start_tx = efm32_uart_start_tx,
|
||||
.stop_rx = efm32_uart_stop_rx,
|
||||
.enable_ms = efm32_uart_enable_ms,
|
||||
.break_ctl = efm32_uart_break_ctl,
|
||||
.startup = efm32_uart_startup,
|
||||
.shutdown = efm32_uart_shutdown,
|
||||
.set_termios = efm32_uart_set_termios,
|
||||
.type = efm32_uart_type,
|
||||
.release_port = efm32_uart_release_port,
|
||||
.request_port = efm32_uart_request_port,
|
||||
.config_port = efm32_uart_config_port,
|
||||
.verify_port = efm32_uart_verify_port,
|
||||
};
|
||||
|
||||
static struct efm32_uart_port *efm32_uart_ports[5];
|
||||
|
||||
#ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE
|
||||
static void efm32_uart_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
unsigned int timeout = 0x400;
|
||||
u32 status;
|
||||
|
||||
while (1) {
|
||||
status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
|
||||
if (status & UARTn_STATUS_TXBL)
|
||||
break;
|
||||
if (!timeout--)
|
||||
return;
|
||||
}
|
||||
efm32_uart_write32(efm_port, ch, UARTn_TXDATA);
|
||||
}
|
||||
|
||||
static void efm32_uart_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = efm32_uart_ports[co->index];
|
||||
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
unsigned int timeout = 0x400;
|
||||
|
||||
if (!(status & UARTn_STATUS_TXENS))
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
|
||||
|
||||
uart_console_write(&efm_port->port, s, count,
|
||||
efm32_uart_console_putchar);
|
||||
|
||||
/* Wait for the transmitter to become empty */
|
||||
while (1) {
|
||||
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
if (status & UARTn_STATUS_TXC)
|
||||
break;
|
||||
if (!timeout--)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(status & UARTn_STATUS_TXENS))
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
|
||||
}
|
||||
|
||||
static void efm32_uart_console_get_options(struct efm32_uart_port *efm_port,
|
||||
int *baud, int *parity, int *bits)
|
||||
{
|
||||
u32 ctrl = efm32_uart_read32(efm_port, UARTn_CTRL);
|
||||
u32 route, clkdiv, frame;
|
||||
|
||||
if (ctrl & UARTn_CTRL_SYNC)
|
||||
/* not operating in async mode */
|
||||
return;
|
||||
|
||||
route = efm32_uart_read32(efm_port, UARTn_ROUTE);
|
||||
if (!(route & UARTn_ROUTE_TXPEN))
|
||||
/* tx pin not routed */
|
||||
return;
|
||||
|
||||
clkdiv = efm32_uart_read32(efm_port, UARTn_CLKDIV);
|
||||
|
||||
*baud = DIV_ROUND_CLOSEST(4 * efm_port->port.uartclk,
|
||||
16 * (4 + (clkdiv >> 6)));
|
||||
|
||||
frame = efm32_uart_read32(efm_port, UARTn_FRAME);
|
||||
if (frame & UARTn_FRAME_PARITY_ODD)
|
||||
*parity = 'o';
|
||||
else if (frame & UARTn_FRAME_PARITY_EVEN)
|
||||
*parity = 'e';
|
||||
else
|
||||
*parity = 'n';
|
||||
|
||||
*bits = (frame & UARTn_FRAME_DATABITS__MASK) -
|
||||
UARTn_FRAME_DATABITS(4) + 4;
|
||||
|
||||
efm_debug(efm_port, "get_opts: options=%d%c%d\n",
|
||||
*baud, *parity, *bits);
|
||||
}
|
||||
|
||||
static int efm32_uart_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct efm32_uart_port *efm_port;
|
||||
int baud = 115200;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
int ret;
|
||||
|
||||
if (co->index < 0 || co->index >= ARRAY_SIZE(efm32_uart_ports)) {
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE(efm32_uart_ports); ++i) {
|
||||
if (efm32_uart_ports[i]) {
|
||||
pr_warn("efm32-console: fall back to console index %u (from %hhi)\n",
|
||||
i, co->index);
|
||||
co->index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
efm_port = efm32_uart_ports[co->index];
|
||||
if (!efm_port) {
|
||||
pr_warn("efm32-console: No port at %d\n", co->index);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = clk_prepare(efm_port->clk);
|
||||
if (ret) {
|
||||
dev_warn(efm_port->port.dev,
|
||||
"console: clk_prepare failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
efm_port->port.uartclk = clk_get_rate(efm_port->clk);
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
else
|
||||
efm32_uart_console_get_options(efm_port,
|
||||
&baud, &parity, &bits);
|
||||
|
||||
return uart_set_options(&efm_port->port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static struct uart_driver efm32_uart_reg;
|
||||
|
||||
static struct console efm32_uart_console = {
|
||||
.name = DEV_NAME,
|
||||
.write = efm32_uart_console_write,
|
||||
.device = uart_console_device,
|
||||
.setup = efm32_uart_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &efm32_uart_reg,
|
||||
};
|
||||
|
||||
#else
|
||||
#define efm32_uart_console (*(struct console *)NULL)
|
||||
#endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */
|
||||
|
||||
static struct uart_driver efm32_uart_reg = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = DRIVER_NAME,
|
||||
.dev_name = DEV_NAME,
|
||||
.nr = ARRAY_SIZE(efm32_uart_ports),
|
||||
.cons = &efm32_uart_console,
|
||||
};
|
||||
|
||||
static int efm32_uart_probe_dt(struct platform_device *pdev,
|
||||
struct efm32_uart_port *efm_port)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
if (!np)
|
||||
return 1;
|
||||
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
|
||||
return ret;
|
||||
} else {
|
||||
efm_port->port.line = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int __devinit efm32_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct efm32_uart_port *efm_port;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL);
|
||||
if (!efm_port) {
|
||||
dev_dbg(&pdev->dev, "failed to allocate private data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
dev_dbg(&pdev->dev, "failed to determine base address\n");
|
||||
goto err_get_base;
|
||||
}
|
||||
|
||||
if (resource_size(res) < 60) {
|
||||
ret = -EINVAL;
|
||||
dev_dbg(&pdev->dev, "memory resource too small\n");
|
||||
goto err_too_small;
|
||||
}
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_dbg(&pdev->dev, "failed to get rx irq\n");
|
||||
goto err_get_rxirq;
|
||||
}
|
||||
|
||||
efm_port->port.irq = ret;
|
||||
|
||||
ret = platform_get_irq(pdev, 1);
|
||||
if (ret <= 0)
|
||||
ret = efm_port->port.irq + 1;
|
||||
|
||||
efm_port->txirq = ret;
|
||||
|
||||
efm_port->port.dev = &pdev->dev;
|
||||
efm_port->port.mapbase = res->start;
|
||||
efm_port->port.type = PORT_EFMUART;
|
||||
efm_port->port.iotype = UPIO_MEM32;
|
||||
efm_port->port.fifosize = 2;
|
||||
efm_port->port.ops = &efm32_uart_pops;
|
||||
efm_port->port.flags = UPF_BOOT_AUTOCONF;
|
||||
|
||||
ret = efm32_uart_probe_dt(pdev, efm_port);
|
||||
if (ret > 0)
|
||||
/* not created by device tree */
|
||||
efm_port->port.line = pdev->id;
|
||||
|
||||
if (efm_port->port.line >= 0 &&
|
||||
efm_port->port.line < ARRAY_SIZE(efm32_uart_ports))
|
||||
efm32_uart_ports[efm_port->port.line] = efm_port;
|
||||
|
||||
ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port);
|
||||
if (ret) {
|
||||
dev_dbg(&pdev->dev, "failed to add port: %d\n", ret);
|
||||
|
||||
if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
|
||||
efm32_uart_ports[pdev->id] = NULL;
|
||||
err_get_rxirq:
|
||||
err_too_small:
|
||||
err_get_base:
|
||||
kfree(efm_port);
|
||||
} else {
|
||||
platform_set_drvdata(pdev, efm_port);
|
||||
dev_dbg(&pdev->dev, "\\o/\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit efm32_uart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
uart_remove_one_port(&efm32_uart_reg, &efm_port->port);
|
||||
|
||||
if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
|
||||
efm32_uart_ports[pdev->id] = NULL;
|
||||
|
||||
kfree(efm_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id efm32_uart_dt_ids[] = {
|
||||
{
|
||||
.compatible = "efm32,uart",
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids);
|
||||
|
||||
static struct platform_driver efm32_uart_driver = {
|
||||
.probe = efm32_uart_probe,
|
||||
.remove = __devexit_p(efm32_uart_remove),
|
||||
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = efm32_uart_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init efm32_uart_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uart_register_driver(&efm32_uart_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&efm32_uart_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&efm32_uart_reg);
|
||||
|
||||
pr_info("EFM32 UART/USART driver\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(efm32_uart_init);
|
||||
|
||||
static void __exit efm32_uart_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&efm32_uart_driver);
|
||||
uart_unregister_driver(&efm32_uart_reg);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("EFM32 UART/USART driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
|
@ -1375,12 +1375,9 @@ static int __init ifx_spi_init(void)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tty_drv->magic = TTY_DRIVER_MAGIC;
|
||||
tty_drv->owner = THIS_MODULE;
|
||||
tty_drv->driver_name = DRVNAME;
|
||||
tty_drv->name = TTYNAME;
|
||||
tty_drv->minor_start = IFX_SPI_TTY_ID;
|
||||
tty_drv->num = 1;
|
||||
tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
|
||||
tty_drv->subtype = SERIAL_TYPE_NORMAL;
|
||||
tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serialP.h>
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -975,7 +974,7 @@ intr_connect(struct ioc4_soft *soft, int type,
|
|||
BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
|
||||
|| (type == IOC4_OTHER_INTR_TYPE)));
|
||||
|
||||
i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1;
|
||||
i = atomic_inc_return(&soft-> is_intr_type[type].is_num_intrs) - 1;
|
||||
BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
|
||||
|
||||
/* Save off the lower level interrupt handler */
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include <linux/console.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serialP.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/m32r.h>
|
||||
|
@ -70,13 +69,6 @@
|
|||
|
||||
#define PASS_LIMIT 256
|
||||
|
||||
/*
|
||||
* We default to IRQ0 for the "no irq" hack. Some
|
||||
* machine types want others as well - they're free
|
||||
* to redefine this in their header file.
|
||||
*/
|
||||
#define is_real_interrupt(irq) ((irq) != 0)
|
||||
|
||||
#define BASE_BAUD 115200
|
||||
|
||||
/* Standard COM flags */
|
||||
|
@ -640,7 +632,7 @@ static int m32r_sio_startup(struct uart_port *port)
|
|||
* hardware interrupt, we use a timer-based system. The original
|
||||
* driver used to do this with IRQ0.
|
||||
*/
|
||||
if (!is_real_interrupt(up->port.irq)) {
|
||||
if (!up->port.irq) {
|
||||
unsigned int timeout = up->port.timeout;
|
||||
|
||||
timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
|
||||
|
@ -687,7 +679,7 @@ static void m32r_sio_shutdown(struct uart_port *port)
|
|||
|
||||
sio_init();
|
||||
|
||||
if (!is_real_interrupt(up->port.irq))
|
||||
if (!up->port.irq)
|
||||
del_timer_sync(&up->timer);
|
||||
else
|
||||
serial_unlink_irq_chain(up);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
struct m32r_sio_probe {
|
||||
struct module *owner;
|
||||
|
|
|
@ -262,8 +262,9 @@ static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
|
|||
port->uartclk / 4);
|
||||
divisor = (port->uartclk + 2 * baud) / (4 * baud);
|
||||
|
||||
/* select the proper prescaler and set the divisor */
|
||||
if (divisor > 0xffff) {
|
||||
/* select the proper prescaler and set the divisor
|
||||
* prefer high prescaler for more tolerance on low baudrates */
|
||||
if (divisor > 0xffff || baud <= 115200) {
|
||||
divisor = (divisor + 4) / 8;
|
||||
prescaler = 0xdd00; /* /32 */
|
||||
} else
|
||||
|
@ -507,7 +508,7 @@ static int __init mpc512x_psc_fifoc_init(void)
|
|||
|
||||
psc_fifoc_irq = irq_of_parse_and_map(np, 0);
|
||||
of_node_put(np);
|
||||
if (psc_fifoc_irq == NO_IRQ) {
|
||||
if (psc_fifoc_irq == 0) {
|
||||
pr_err("%s: Can't get FIFOC irq\n", __func__);
|
||||
iounmap(psc_fifoc);
|
||||
return -ENODEV;
|
||||
|
@ -1354,7 +1355,7 @@ static int __devinit mpc52xx_uart_of_probe(struct platform_device *op)
|
|||
}
|
||||
|
||||
psc_ops->get_irq(port, op->dev.of_node);
|
||||
if (port->irq == NO_IRQ) {
|
||||
if (port->irq == 0) {
|
||||
dev_dbg(&op->dev, "Could not get irq\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -203,7 +203,6 @@ static int __init smd_tty_init(void)
|
|||
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;
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial.h>
|
||||
|
@ -499,7 +498,7 @@ static int __init mux_probe(struct parisc_device *dev)
|
|||
port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
|
||||
port->iotype = UPIO_MEM;
|
||||
port->type = PORT_MUX;
|
||||
port->irq = NO_IRQ;
|
||||
port->irq = 0;
|
||||
port->uartclk = 0;
|
||||
port->fifosize = MUX_FIFO_SIZE;
|
||||
port->ops = &mux_pops;
|
||||
|
|
|
@ -159,7 +159,7 @@ static void serial_omap_stop_tx(struct uart_port *port)
|
|||
serial_out(up, UART_IER, up->ier);
|
||||
}
|
||||
|
||||
if (!up->use_dma && pdata->set_forceidle)
|
||||
if (!up->use_dma && pdata && pdata->set_forceidle)
|
||||
pdata->set_forceidle(up->pdev);
|
||||
|
||||
pm_runtime_mark_last_busy(&up->pdev->dev);
|
||||
|
@ -298,7 +298,7 @@ static void serial_omap_start_tx(struct uart_port *port)
|
|||
if (!up->use_dma) {
|
||||
pm_runtime_get_sync(&up->pdev->dev);
|
||||
serial_omap_enable_ier_thri(up);
|
||||
if (pdata->set_noidle)
|
||||
if (pdata && pdata->set_noidle)
|
||||
pdata->set_noidle(up->pdev);
|
||||
pm_runtime_mark_last_busy(&up->pdev->dev);
|
||||
pm_runtime_put_autosuspend(&up->pdev->dev);
|
||||
|
@ -1613,7 +1613,7 @@ static int serial_omap_runtime_resume(struct device *dev)
|
|||
struct uart_omap_port *up = dev_get_drvdata(dev);
|
||||
struct omap_uart_port_info *pdata = dev->platform_data;
|
||||
|
||||
if (up) {
|
||||
if (up && pdata) {
|
||||
if (pdata->get_context_loss_count) {
|
||||
u32 loss_cnt = pdata->get_context_loss_count(dev);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/nmi.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/pch_dma.h>
|
||||
|
||||
|
@ -144,6 +145,8 @@ enum {
|
|||
#define PCH_UART_DLL 0x00
|
||||
#define PCH_UART_DLM 0x01
|
||||
|
||||
#define PCH_UART_BRCSR 0x0E
|
||||
|
||||
#define PCH_UART_IID_RLS (PCH_UART_IIR_REI)
|
||||
#define PCH_UART_IID_RDR (PCH_UART_IIR_RRI)
|
||||
#define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
|
||||
|
@ -203,7 +206,10 @@ enum {
|
|||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
#define DEFAULT_BAUD_RATE 1843200 /* 1.8432MHz */
|
||||
#define DEFAULT_UARTCLK 1843200 /* 1.8432 MHz */
|
||||
#define CMITC_UARTCLK 192000000 /* 192.0000 MHz */
|
||||
#define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */
|
||||
#define FRI2_48_UARTCLK 48000000 /* 48.0000 MHz */
|
||||
|
||||
struct pch_uart_buffer {
|
||||
unsigned char *buf;
|
||||
|
@ -218,7 +224,7 @@ struct eg20t_port {
|
|||
unsigned int iobase;
|
||||
struct pci_dev *pdev;
|
||||
int fifo_size;
|
||||
int base_baud;
|
||||
int uartclk;
|
||||
int start_tx;
|
||||
int start_rx;
|
||||
int tx_empty;
|
||||
|
@ -243,6 +249,8 @@ struct eg20t_port {
|
|||
int tx_dma_use;
|
||||
void *rx_buf_virt;
|
||||
dma_addr_t rx_buf_dma;
|
||||
|
||||
struct dentry *debugfs;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -287,26 +295,100 @@ static struct pch_uart_driver_data drv_dat[] = {
|
|||
static struct eg20t_port *pch_uart_ports[PCH_UART_NR];
|
||||
#endif
|
||||
static unsigned int default_baud = 9600;
|
||||
static unsigned int user_uartclk = 0;
|
||||
static const int trigger_level_256[4] = { 1, 64, 128, 224 };
|
||||
static const int trigger_level_64[4] = { 1, 16, 32, 56 };
|
||||
static const int trigger_level_16[4] = { 1, 4, 8, 14 };
|
||||
static const int trigger_level_1[4] = { 1, 1, 1, 1 };
|
||||
|
||||
static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize,
|
||||
int base_baud)
|
||||
{
|
||||
struct eg20t_port *priv = pci_get_drvdata(pdev);
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
priv->trigger_level = 1;
|
||||
priv->fcr = 0;
|
||||
#define PCH_REGS_BUFSIZE 1024
|
||||
static int pch_show_regs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base)
|
||||
static ssize_t port_show_regs(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
unsigned int msr = ioread8(base + UART_MSR);
|
||||
priv->dmsr |= msr & PCH_UART_MSR_DELTA;
|
||||
struct eg20t_port *priv = file->private_data;
|
||||
char *buf;
|
||||
u32 len = 0;
|
||||
ssize_t ret;
|
||||
unsigned char lcr;
|
||||
|
||||
return msr;
|
||||
buf = kzalloc(PCH_REGS_BUFSIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"PCH EG20T port[%d] regs:\n", priv->port.line);
|
||||
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"=================================\n");
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"IER: \t0x%02x\n", ioread8(priv->membase + UART_IER));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"BRCSR: \t0x%02x\n",
|
||||
ioread8(priv->membase + PCH_UART_BRCSR));
|
||||
|
||||
lcr = ioread8(priv->membase + UART_LCR);
|
||||
iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM));
|
||||
iowrite8(lcr, priv->membase + UART_LCR);
|
||||
|
||||
if (len > PCH_REGS_BUFSIZE)
|
||||
len = PCH_REGS_BUFSIZE;
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations port_regs_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = pch_show_regs_open,
|
||||
.read = port_show_regs,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
/* Return UART clock, checking for board specific clocks. */
|
||||
static int pch_uart_get_uartclk(void)
|
||||
{
|
||||
const char *cmp;
|
||||
|
||||
if (user_uartclk)
|
||||
return user_uartclk;
|
||||
|
||||
cmp = dmi_get_system_info(DMI_BOARD_NAME);
|
||||
if (cmp && strstr(cmp, "CM-iTC"))
|
||||
return CMITC_UARTCLK;
|
||||
|
||||
cmp = dmi_get_system_info(DMI_BIOS_VERSION);
|
||||
if (cmp && strnstr(cmp, "FRI2", 4))
|
||||
return FRI2_64_UARTCLK;
|
||||
|
||||
cmp = dmi_get_system_info(DMI_PRODUCT_NAME);
|
||||
if (cmp && strstr(cmp, "Fish River Island II"))
|
||||
return FRI2_48_UARTCLK;
|
||||
|
||||
return DEFAULT_UARTCLK;
|
||||
}
|
||||
|
||||
static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
|
||||
|
@ -332,7 +414,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
|
|||
unsigned int dll, dlm, lcr;
|
||||
int div;
|
||||
|
||||
div = DIV_ROUND_CLOSEST(priv->base_baud / 16, baud);
|
||||
div = DIV_ROUND_CLOSEST(priv->uartclk / 16, baud);
|
||||
if (div < 0 || USHRT_MAX <= div) {
|
||||
dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div);
|
||||
return -EINVAL;
|
||||
|
@ -442,8 +524,9 @@ static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
|
|||
|
||||
static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
|
||||
{
|
||||
priv->dmsr = 0;
|
||||
return get_msr(priv, priv->membase);
|
||||
unsigned int msr = ioread8(priv->membase + UART_MSR);
|
||||
priv->dmsr = msr & PCH_UART_MSR_DELTA;
|
||||
return (u8)msr;
|
||||
}
|
||||
|
||||
static void pch_uart_hal_write(struct eg20t_port *priv,
|
||||
|
@ -524,7 +607,7 @@ static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
|
|||
|
||||
static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct uart_port *port = &priv->port;
|
||||
|
||||
if (port->x_char) {
|
||||
|
@ -533,8 +616,6 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
|
|||
buf[0] = port->x_char;
|
||||
port->x_char = 0;
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1032,14 +1113,12 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
|
|||
static unsigned int pch_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct eg20t_port *priv;
|
||||
int ret;
|
||||
|
||||
priv = container_of(port, struct eg20t_port, port);
|
||||
if (priv->tx_empty)
|
||||
ret = TIOCSER_TEMT;
|
||||
return TIOCSER_TEMT;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns the current state of modem control inputs. */
|
||||
|
@ -1153,9 +1232,9 @@ static int pch_uart_startup(struct uart_port *port)
|
|||
priv->tx_empty = 1;
|
||||
|
||||
if (port->uartclk)
|
||||
priv->base_baud = port->uartclk;
|
||||
priv->uartclk = port->uartclk;
|
||||
else
|
||||
port->uartclk = priv->base_baud;
|
||||
port->uartclk = priv->uartclk;
|
||||
|
||||
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
|
||||
ret = pch_uart_hal_set_line(priv, default_baud,
|
||||
|
@ -1273,9 +1352,8 @@ static void pch_uart_set_termios(struct uart_port *port,
|
|||
else
|
||||
parity = PCH_UART_HAL_PARITY_EVEN;
|
||||
|
||||
} else {
|
||||
} else
|
||||
parity = PCH_UART_HAL_PARITY_NONE;
|
||||
}
|
||||
|
||||
/* Only UART0 has auto hardware flow function */
|
||||
if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256))
|
||||
|
@ -1447,7 +1525,6 @@ static void
|
|||
pch_console_write(struct console *co, const char *s, unsigned int count)
|
||||
{
|
||||
struct eg20t_port *priv;
|
||||
|
||||
unsigned long flags;
|
||||
u8 ier;
|
||||
int locked = 1;
|
||||
|
@ -1489,7 +1566,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
|
|||
static int __init pch_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int baud = 9600;
|
||||
int baud = default_baud;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
|
@ -1506,8 +1583,7 @@ static int __init pch_console_setup(struct console *co, char *options)
|
|||
if (!port || (!port->iobase && !port->membase))
|
||||
return -ENODEV;
|
||||
|
||||
/* setup uartclock */
|
||||
port->uartclk = DEFAULT_BAUD_RATE;
|
||||
port->uartclk = pch_uart_get_uartclk();
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
@ -1550,10 +1626,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
unsigned int iobase;
|
||||
unsigned int mapbase;
|
||||
unsigned char *rxbuf;
|
||||
int fifosize, base_baud;
|
||||
int fifosize;
|
||||
int port_type;
|
||||
struct pch_uart_driver_data *board;
|
||||
const char *board_name;
|
||||
char name[32]; /* for debugfs file name */
|
||||
|
||||
board = &drv_dat[id->driver_data];
|
||||
port_type = board->port_type;
|
||||
|
@ -1566,13 +1642,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
if (!rxbuf)
|
||||
goto init_port_free_txbuf;
|
||||
|
||||
base_baud = DEFAULT_BAUD_RATE;
|
||||
|
||||
/* quirk for CM-iTC board */
|
||||
board_name = dmi_get_system_info(DMI_BOARD_NAME);
|
||||
if (board_name && strstr(board_name, "CM-iTC"))
|
||||
base_baud = 192000000; /* 192.0MHz */
|
||||
|
||||
switch (port_type) {
|
||||
case PORT_UNKNOWN:
|
||||
fifosize = 256; /* EG20T/ML7213: UART0 */
|
||||
|
@ -1597,7 +1666,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
priv->rxbuf.size = PAGE_SIZE;
|
||||
|
||||
priv->fifo_size = fifosize;
|
||||
priv->base_baud = base_baud;
|
||||
priv->uartclk = pch_uart_get_uartclk();
|
||||
priv->port_type = PORT_MAX_8250 + port_type + 1;
|
||||
priv->port.dev = &pdev->dev;
|
||||
priv->port.iobase = iobase;
|
||||
|
@ -1614,7 +1683,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
spin_lock_init(&priv->port.lock);
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
pch_uart_hal_request(pdev, fifosize, base_baud);
|
||||
priv->trigger_level = 1;
|
||||
priv->fcr = 0;
|
||||
|
||||
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
|
||||
pch_uart_ports[board->line_no] = priv;
|
||||
|
@ -1623,6 +1693,12 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
if (ret < 0)
|
||||
goto init_port_hal_free;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
snprintf(name, sizeof(name), "uart%d_regs", board->line_no);
|
||||
priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO,
|
||||
NULL, priv, &port_regs_ops);
|
||||
#endif
|
||||
|
||||
return priv;
|
||||
|
||||
init_port_hal_free:
|
||||
|
@ -1639,6 +1715,11 @@ init_port_alloc_err:
|
|||
|
||||
static void pch_uart_exit_port(struct eg20t_port *priv)
|
||||
{
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
if (priv->debugfs)
|
||||
debugfs_remove(priv->debugfs);
|
||||
#endif
|
||||
uart_remove_one_port(&pch_uart_driver, &priv->port);
|
||||
pci_set_drvdata(priv->pdev, NULL);
|
||||
free_page((unsigned long)priv->rxbuf.buf);
|
||||
|
@ -1646,9 +1727,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
|
|||
|
||||
static void pch_uart_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct eg20t_port *priv;
|
||||
|
||||
priv = (struct eg20t_port *)pci_get_drvdata(pdev);
|
||||
struct eg20t_port *priv = pci_get_drvdata(pdev);
|
||||
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
|
@ -1785,3 +1864,8 @@ module_exit(pch_uart_module_exit);
|
|||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver");
|
||||
module_param(default_baud, uint, S_IRUGO);
|
||||
MODULE_PARM_DESC(default_baud,
|
||||
"Default BAUD for initial driver state and console (default 9600)");
|
||||
module_param(user_uartclk, uint, S_IRUGO);
|
||||
MODULE_PARM_DESC(user_uartclk,
|
||||
"Override UART default or board specific UART clock");
|
||||
|
|
|
@ -1506,7 +1506,7 @@ no_dma:
|
|||
* fixed up interrupt info, but we use the device-tree directly
|
||||
* here due to early probing so we need the fixup too.
|
||||
*/
|
||||
if (uap->port.irq == NO_IRQ &&
|
||||
if (uap->port.irq == 0 &&
|
||||
np->parent && np->parent->parent &&
|
||||
of_device_is_compatible(np->parent->parent, "gatwick")) {
|
||||
/* IRQs on gatwick are offset by 64 */
|
||||
|
|
|
@ -579,9 +579,9 @@ serial_pxa_pm(struct uart_port *port, unsigned int state,
|
|||
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
|
||||
|
||||
if (!state)
|
||||
clk_enable(up->clk);
|
||||
clk_prepare_enable(up->clk);
|
||||
else
|
||||
clk_disable(up->clk);
|
||||
clk_disable_unprepare(up->clk);
|
||||
}
|
||||
|
||||
static void serial_pxa_release_port(struct uart_port *port)
|
||||
|
@ -668,7 +668,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
|
|||
struct uart_pxa_port *up = serial_pxa_ports[co->index];
|
||||
unsigned int ier;
|
||||
|
||||
clk_enable(up->clk);
|
||||
clk_prepare_enable(up->clk);
|
||||
|
||||
/*
|
||||
* First save the IER then disable the interrupts
|
||||
|
@ -685,7 +685,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
|
|||
wait_for_xmitr(up);
|
||||
serial_out(up, UART_IER, ier);
|
||||
|
||||
clk_disable(up->clk);
|
||||
clk_disable_unprepare(up->clk);
|
||||
}
|
||||
|
||||
static int __init
|
||||
|
|
|
@ -1507,7 +1507,7 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = {
|
|||
#endif
|
||||
|
||||
#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \
|
||||
defined(CONFIG_CPU_S3C2443)
|
||||
defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2442)
|
||||
static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
|
||||
.info = &(struct s3c24xx_uart_info) {
|
||||
.name = "Samsung S3C2440 UART",
|
||||
|
|
|
@ -2230,7 +2230,6 @@ int uart_register_driver(struct uart_driver *drv)
|
|||
|
||||
drv->tty_driver = normal;
|
||||
|
||||
normal->owner = drv->owner;
|
||||
normal->driver_name = drv->driver_name;
|
||||
normal->name = drv->dev_name;
|
||||
normal->major = drv->major;
|
||||
|
|
|
@ -461,12 +461,12 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
|
|||
struct tty_struct *tty;
|
||||
|
||||
if (!port) {
|
||||
printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n");
|
||||
printk(KERN_ERR "sn_receive_chars - port NULL so can't receive\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!port->sc_ops) {
|
||||
printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receieve\n");
|
||||
printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receive\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/sunserialcore.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/prom.h>
|
||||
|
||||
#include "suncore.h"
|
||||
|
||||
static int sunserial_current_minor = 64;
|
||||
|
||||
|
|
|
@ -29,8 +29,7 @@
|
|||
#endif
|
||||
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#include "suncore.h"
|
||||
#include <linux/sunserialcore.h>
|
||||
|
||||
#define CON_BREAK ((long)-1)
|
||||
#define CON_HUP ((long)-2)
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
#endif
|
||||
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/sunserialcore.h>
|
||||
|
||||
#include "suncore.h"
|
||||
#include "sunsab.h"
|
||||
|
||||
struct uart_sunsab_port {
|
||||
|
|
|
@ -47,8 +47,7 @@
|
|||
#endif
|
||||
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#include "suncore.h"
|
||||
#include <linux/sunserialcore.h>
|
||||
|
||||
/* We are on a NS PC87303 clocked with 24.0 MHz, which results
|
||||
* in a UART clock of 1.8462 MHz.
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
#endif
|
||||
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/sunserialcore.h>
|
||||
|
||||
#include "suncore.h"
|
||||
#include "sunzilog.h"
|
||||
|
||||
/* On 32-bit sparcs we need to delay after register accesses
|
||||
|
@ -1397,7 +1397,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
|
|||
#endif
|
||||
}
|
||||
|
||||
static int zilog_irq = -1;
|
||||
static int zilog_irq;
|
||||
|
||||
static int __devinit zs_probe(struct platform_device *op)
|
||||
{
|
||||
|
@ -1425,7 +1425,7 @@ static int __devinit zs_probe(struct platform_device *op)
|
|||
|
||||
rp = sunzilog_chip_regs[inst];
|
||||
|
||||
if (zilog_irq == -1)
|
||||
if (!zilog_irq)
|
||||
zilog_irq = op->archdata.irqs[0];
|
||||
|
||||
up = &sunzilog_port_table[inst * 2];
|
||||
|
@ -1580,7 +1580,7 @@ static int __init sunzilog_init(void)
|
|||
if (err)
|
||||
goto out_unregister_uart;
|
||||
|
||||
if (zilog_irq != -1) {
|
||||
if (!zilog_irq) {
|
||||
struct uart_sunzilog_port *up = sunzilog_irq_chain;
|
||||
err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
|
||||
"zs", sunzilog_irq_chain);
|
||||
|
@ -1621,7 +1621,7 @@ static void __exit sunzilog_exit(void)
|
|||
{
|
||||
platform_driver_unregister(&zs_driver);
|
||||
|
||||
if (zilog_irq != -1) {
|
||||
if (!zilog_irq) {
|
||||
struct uart_sunzilog_port *up = sunzilog_irq_chain;
|
||||
|
||||
/* Disable Interrupts */
|
||||
|
@ -1637,7 +1637,7 @@ static void __exit sunzilog_exit(void)
|
|||
}
|
||||
|
||||
free_irq(zilog_irq, sunzilog_irq_chain);
|
||||
zilog_irq = -1;
|
||||
zilog_irq = 0;
|
||||
}
|
||||
|
||||
if (sunzilog_reg.nr) {
|
||||
|
|
|
@ -1360,7 +1360,7 @@ static int ucc_uart_probe(struct platform_device *ofdev)
|
|||
}
|
||||
|
||||
qe_port->port.irq = irq_of_parse_and_map(np, 0);
|
||||
if (qe_port->port.irq == NO_IRQ) {
|
||||
if (qe_port->port.irq == 0) {
|
||||
dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
|
||||
qe_port->ucc_num + 1);
|
||||
ret = -EINVAL;
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
|
||||
[0 ... SIU_PORTS_MAX-1] = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
|
||||
.irq = -1,
|
||||
.irq = 0,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -171,7 +171,7 @@ static inline unsigned int siu_check_type(struct uart_port *port)
|
|||
{
|
||||
if (port->line == 0)
|
||||
return PORT_VR41XX_SIU;
|
||||
if (port->line == 1 && port->irq != -1)
|
||||
if (port->line == 1 && port->irq)
|
||||
return PORT_VR41XX_DSIU;
|
||||
|
||||
return PORT_UNKNOWN;
|
||||
|
|
|
@ -544,7 +544,7 @@ static struct uart_driver vt8500_uart_driver = {
|
|||
.cons = VT8500_CONSOLE,
|
||||
};
|
||||
|
||||
static int __init vt8500_serial_probe(struct platform_device *pdev)
|
||||
static int __devinit vt8500_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct vt8500_port *vt8500_port;
|
||||
struct resource *mmres, *irqres;
|
||||
|
@ -605,7 +605,7 @@ static int __devexit vt8500_serial_remove(struct platform_device *pdev)
|
|||
|
||||
static struct platform_driver vt8500_platform_driver = {
|
||||
.probe = vt8500_serial_probe,
|
||||
.remove = vt8500_serial_remove,
|
||||
.remove = __devexit_p(vt8500_serial_remove),
|
||||
.driver = {
|
||||
.name = "vt8500_serial",
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -3381,7 +3381,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
|
|||
|
||||
/* verify range of specified line number */
|
||||
line = tty->index;
|
||||
if ((line < 0) || (line >= mgsl_device_count)) {
|
||||
if (line >= mgsl_device_count) {
|
||||
printk("%s(%d):mgsl_open with invalid line #%d.\n",
|
||||
__FILE__,__LINE__,line);
|
||||
return -ENODEV;
|
||||
|
@ -4333,7 +4333,6 @@ static int mgsl_init_tty(void)
|
|||
if (!serial_driver)
|
||||
return -ENOMEM;
|
||||
|
||||
serial_driver->owner = THIS_MODULE;
|
||||
serial_driver->driver_name = "synclink";
|
||||
serial_driver->name = "ttySL";
|
||||
serial_driver->major = ttymajor;
|
||||
|
|
|
@ -654,7 +654,7 @@ static int open(struct tty_struct *tty, struct file *filp)
|
|||
unsigned long flags;
|
||||
|
||||
line = tty->index;
|
||||
if ((line < 0) || (line >= slgt_device_count)) {
|
||||
if (line >= slgt_device_count) {
|
||||
DBGERR(("%s: open with invalid line #%d.\n", driver_name, line));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -3795,7 +3795,6 @@ static int __init slgt_init(void)
|
|||
|
||||
/* Initialize the tty_driver structure */
|
||||
|
||||
serial_driver->owner = THIS_MODULE;
|
||||
serial_driver->driver_name = tty_driver_name;
|
||||
serial_driver->name = tty_dev_prefix;
|
||||
serial_driver->major = ttymajor;
|
||||
|
|
|
@ -721,7 +721,7 @@ static int open(struct tty_struct *tty, struct file *filp)
|
|||
unsigned long flags;
|
||||
|
||||
line = tty->index;
|
||||
if ((line < 0) || (line >= synclinkmp_device_count)) {
|
||||
if (line >= synclinkmp_device_count) {
|
||||
printk("%s(%d): open with invalid line #%d.\n",
|
||||
__FILE__,__LINE__,line);
|
||||
return -ENODEV;
|
||||
|
@ -3977,7 +3977,6 @@ static int __init synclinkmp_init(void)
|
|||
|
||||
/* Initialize the tty_driver structure */
|
||||
|
||||
serial_driver->owner = THIS_MODULE;
|
||||
serial_driver->driver_name = "synclinkmp";
|
||||
serial_driver->name = "ttySLM";
|
||||
serial_driver->major = ttymajor;
|
||||
|
|
|
@ -110,11 +110,9 @@ static struct sysrq_key_op sysrq_SAK_op = {
|
|||
#ifdef CONFIG_VT
|
||||
static void sysrq_handle_unraw(int key)
|
||||
{
|
||||
struct kbd_struct *kbd = &kbd_table[fg_console];
|
||||
|
||||
if (kbd)
|
||||
kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
|
||||
vt_reset_unicode(fg_console);
|
||||
}
|
||||
|
||||
static struct sysrq_key_op sysrq_unraw_op = {
|
||||
.handler = sysrq_handle_unraw,
|
||||
.help_msg = "unRaw",
|
||||
|
@ -322,11 +320,16 @@ static void send_sig_all(int sig)
|
|||
{
|
||||
struct task_struct *p;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process(p) {
|
||||
if (p->mm && !is_global_init(p))
|
||||
/* Not swapper, init nor kernel thread */
|
||||
force_sig(sig, p);
|
||||
if (p->flags & PF_KTHREAD)
|
||||
continue;
|
||||
if (is_global_init(p))
|
||||
continue;
|
||||
|
||||
force_sig(sig, p);
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
}
|
||||
|
||||
static void sysrq_handle_term(int key)
|
||||
|
|
|
@ -1230,13 +1230,10 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
|
|||
static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
|
||||
struct inode *inode, int idx)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (driver->ops->lookup)
|
||||
return driver->ops->lookup(driver, inode, idx);
|
||||
|
||||
tty = driver->ttys[idx];
|
||||
return tty;
|
||||
return driver->ttys[idx];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1271,6 +1268,19 @@ int tty_init_termios(struct tty_struct *tty)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(tty_init_termios);
|
||||
|
||||
int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
int ret = tty_init_termios(tty);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
driver->ttys[tty->index] = tty;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_standard_install);
|
||||
|
||||
/**
|
||||
* tty_driver_install_tty() - install a tty entry in the driver
|
||||
* @driver: the driver for the tty
|
||||
|
@ -1286,21 +1296,8 @@ EXPORT_SYMBOL_GPL(tty_init_termios);
|
|||
static int tty_driver_install_tty(struct tty_driver *driver,
|
||||
struct tty_struct *tty)
|
||||
{
|
||||
int idx = tty->index;
|
||||
int ret;
|
||||
|
||||
if (driver->ops->install) {
|
||||
ret = driver->ops->install(driver, tty);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tty_init_termios(tty) == 0) {
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
driver->ttys[idx] = tty;
|
||||
return 0;
|
||||
}
|
||||
return -ENOMEM;
|
||||
return driver->ops->install ? driver->ops->install(driver, tty) :
|
||||
tty_standard_install(driver, tty);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1351,7 +1348,6 @@ static int tty_reopen(struct tty_struct *tty)
|
|||
tty->link->count++;
|
||||
}
|
||||
tty->count++;
|
||||
tty->driver = driver; /* N.B. why do this every time?? */
|
||||
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
|
||||
|
@ -1365,7 +1361,6 @@ static int tty_reopen(struct tty_struct *tty)
|
|||
* @driver: tty driver we are opening a device on
|
||||
* @idx: device index
|
||||
* @ret_tty: returned tty structure
|
||||
* @first_ok: ok to open a new device (used by ptmx)
|
||||
*
|
||||
* Prepare a tty device. This may not be a "new" clean device but
|
||||
* could also be an active device. The pty drivers require special
|
||||
|
@ -1385,18 +1380,11 @@ static int tty_reopen(struct tty_struct *tty)
|
|||
* relaxed for the (most common) case of reopening a tty.
|
||||
*/
|
||||
|
||||
struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
||||
int first_ok)
|
||||
struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
int retval;
|
||||
|
||||
/* Check if pty master is being opened multiple times */
|
||||
if (driver->subtype == PTY_TYPE_MASTER &&
|
||||
(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* First time open is complex, especially for PTY devices.
|
||||
* This code guarantees that either everything succeeds and the
|
||||
|
@ -1950,7 +1938,7 @@ retry_open:
|
|||
if (retval)
|
||||
tty = ERR_PTR(retval);
|
||||
} else
|
||||
tty = tty_init_dev(driver, index, 0);
|
||||
tty = tty_init_dev(driver, index);
|
||||
|
||||
mutex_unlock(&tty_mutex);
|
||||
if (driver)
|
||||
|
@ -2941,7 +2929,6 @@ void initialize_tty_struct(struct tty_struct *tty,
|
|||
tty->session = NULL;
|
||||
tty->pgrp = NULL;
|
||||
tty->overrun_time = jiffies;
|
||||
tty->buf.head = tty->buf.tail = NULL;
|
||||
tty_buffer_init(tty);
|
||||
mutex_init(&tty->termios_mutex);
|
||||
mutex_init(&tty->ldisc_mutex);
|
||||
|
@ -3058,7 +3045,7 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
|
|||
}
|
||||
EXPORT_SYMBOL(tty_unregister_device);
|
||||
|
||||
struct tty_driver *alloc_tty_driver(int lines)
|
||||
struct tty_driver *__alloc_tty_driver(int lines, struct module *owner)
|
||||
{
|
||||
struct tty_driver *driver;
|
||||
|
||||
|
@ -3067,11 +3054,12 @@ struct tty_driver *alloc_tty_driver(int lines)
|
|||
kref_init(&driver->kref);
|
||||
driver->magic = TTY_DRIVER_MAGIC;
|
||||
driver->num = lines;
|
||||
driver->owner = owner;
|
||||
/* later we'll move allocation of tables here */
|
||||
}
|
||||
return driver;
|
||||
}
|
||||
EXPORT_SYMBOL(alloc_tty_driver);
|
||||
EXPORT_SYMBOL(__alloc_tty_driver);
|
||||
|
||||
static void destruct_tty_driver(struct kref *kref)
|
||||
{
|
||||
|
|
|
@ -516,6 +516,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
|||
int err = 0, err1, i;
|
||||
struct uni_pagedir *p, *q;
|
||||
|
||||
/* Save original vc_unipagdir_loc in case we allocate a new one */
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
if (p->readonly) return -EIO;
|
||||
|
||||
|
@ -528,26 +529,57 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
|||
err1 = con_clear_unimap(vc, NULL);
|
||||
if (err1) return err1;
|
||||
|
||||
/*
|
||||
* Since refcount was > 1, con_clear_unimap() allocated a
|
||||
* a new uni_pagedir for this vc. Re: p != q
|
||||
*/
|
||||
q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
for (i = 0, l = 0; i < 32; i++)
|
||||
|
||||
/*
|
||||
* uni_pgdir is a 32*32*64 table with rows allocated
|
||||
* when its first entry is added. The unicode value must
|
||||
* still be incremented for empty rows. We are copying
|
||||
* entries from "p" (old) to "q" (new).
|
||||
*/
|
||||
l = 0; /* unicode value */
|
||||
for (i = 0; i < 32; i++)
|
||||
if ((p1 = p->uni_pgdir[i]))
|
||||
for (j = 0; j < 32; j++)
|
||||
if ((p2 = p1[j]))
|
||||
if ((p2 = p1[j])) {
|
||||
for (k = 0; k < 64; k++, l++)
|
||||
if (p2[k] != 0xffff) {
|
||||
/*
|
||||
* Found one, copy entry for unicode
|
||||
* l with fontpos value p2[k].
|
||||
*/
|
||||
err1 = con_insert_unipair(q, l, p2[k]);
|
||||
if (err1) {
|
||||
p->refcount++;
|
||||
*vc->vc_uni_pagedir_loc = (unsigned long)p;
|
||||
con_release_unimap(q);
|
||||
kfree(q);
|
||||
return err1;
|
||||
return err1;
|
||||
}
|
||||
}
|
||||
p = q;
|
||||
} else if (p == dflt)
|
||||
}
|
||||
} else {
|
||||
/* Account for row of 64 empty entries */
|
||||
l += 64;
|
||||
}
|
||||
else
|
||||
/* Account for empty table */
|
||||
l += 32 * 64;
|
||||
|
||||
/*
|
||||
* Finished copying font table, set vc_uni_pagedir to new table
|
||||
*/
|
||||
p = q;
|
||||
} else if (p == dflt) {
|
||||
dflt = NULL;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert user specified unicode pairs into new table.
|
||||
*/
|
||||
while (ct--) {
|
||||
unsigned short unicode, fontpos;
|
||||
__get_user(unicode, &list->unicode);
|
||||
|
@ -557,11 +589,14 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
|||
list++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge with fontmaps of any other virtual consoles.
|
||||
*/
|
||||
if (con_unify_unimap(vc, p))
|
||||
return err;
|
||||
|
||||
for (i = 0; i <= 3; i++)
|
||||
set_inverse_transl(vc, p, i); /* Update all inverse translations */
|
||||
set_inverse_transl(vc, p, i); /* Update inverse translations */
|
||||
set_inverse_trans_unicode(vc, p);
|
||||
|
||||
return err;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <linux/reboot.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/irq_regs.h>
|
||||
|
||||
|
@ -55,8 +56,8 @@ extern void ctrl_alt_del(void);
|
|||
/*
|
||||
* Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
|
||||
* This seems a good reason to start with NumLock off. On HIL keyboards
|
||||
* of PARISC machines however there is no NumLock key and everyone expects the keypad
|
||||
* to be used for numbers.
|
||||
* of PARISC machines however there is no NumLock key and everyone expects the
|
||||
* keypad to be used for numbers.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
|
||||
|
@ -67,8 +68,6 @@ extern void ctrl_alt_del(void);
|
|||
|
||||
#define KBD_DEFLOCK 0
|
||||
|
||||
void compute_shiftstate(void);
|
||||
|
||||
/*
|
||||
* Handler Tables.
|
||||
*/
|
||||
|
@ -99,35 +98,29 @@ static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
|
|||
* Variables exported for vt_ioctl.c
|
||||
*/
|
||||
|
||||
/* maximum values each key_handler can handle */
|
||||
const int max_vals[] = {
|
||||
255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
|
||||
NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
|
||||
255, NR_LOCK - 1, 255, NR_BRL - 1
|
||||
};
|
||||
|
||||
const int NR_TYPES = ARRAY_SIZE(max_vals);
|
||||
|
||||
struct kbd_struct kbd_table[MAX_NR_CONSOLES];
|
||||
EXPORT_SYMBOL_GPL(kbd_table);
|
||||
static struct kbd_struct *kbd = kbd_table;
|
||||
|
||||
struct vt_spawn_console vt_spawn_con = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
|
||||
.pid = NULL,
|
||||
.sig = 0,
|
||||
};
|
||||
|
||||
/*
|
||||
* Variables exported for vt.c
|
||||
*/
|
||||
|
||||
int shift_state = 0;
|
||||
|
||||
/*
|
||||
* Internal Data.
|
||||
*/
|
||||
|
||||
static struct kbd_struct kbd_table[MAX_NR_CONSOLES];
|
||||
static struct kbd_struct *kbd = kbd_table;
|
||||
|
||||
/* maximum values each key_handler can handle */
|
||||
static const int max_vals[] = {
|
||||
255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
|
||||
NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
|
||||
255, NR_LOCK - 1, 255, NR_BRL - 1
|
||||
};
|
||||
|
||||
static const int NR_TYPES = ARRAY_SIZE(max_vals);
|
||||
|
||||
static struct input_handler kbd_handler;
|
||||
static DEFINE_SPINLOCK(kbd_event_lock);
|
||||
static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
|
||||
|
@ -137,6 +130,8 @@ static int npadch = -1; /* -1 or number assembled on pad */
|
|||
static unsigned int diacr;
|
||||
static char rep; /* flag telling character repeat */
|
||||
|
||||
static int shift_state = 0;
|
||||
|
||||
static unsigned char ledstate = 0xff; /* undefined */
|
||||
static unsigned char ledioctl;
|
||||
|
||||
|
@ -187,7 +182,7 @@ static int getkeycode_helper(struct input_handle *handle, void *data)
|
|||
return d->error == 0; /* stop as soon as we successfully get one */
|
||||
}
|
||||
|
||||
int getkeycode(unsigned int scancode)
|
||||
static int getkeycode(unsigned int scancode)
|
||||
{
|
||||
struct getset_keycode_data d = {
|
||||
.ke = {
|
||||
|
@ -214,7 +209,7 @@ static int setkeycode_helper(struct input_handle *handle, void *data)
|
|||
return d->error == 0; /* stop as soon as we successfully set one */
|
||||
}
|
||||
|
||||
int setkeycode(unsigned int scancode, unsigned int keycode)
|
||||
static int setkeycode(unsigned int scancode, unsigned int keycode)
|
||||
{
|
||||
struct getset_keycode_data d = {
|
||||
.ke = {
|
||||
|
@ -382,9 +377,11 @@ static void to_utf8(struct vc_data *vc, uint c)
|
|||
/*
|
||||
* Called after returning from RAW mode or when changing consoles - recompute
|
||||
* shift_down[] and shift_state from key_down[] maybe called when keymap is
|
||||
* undefined, so that shiftkey release is seen
|
||||
* undefined, so that shiftkey release is seen. The caller must hold the
|
||||
* kbd_event_lock.
|
||||
*/
|
||||
void compute_shiftstate(void)
|
||||
|
||||
static void do_compute_shiftstate(void)
|
||||
{
|
||||
unsigned int i, j, k, sym, val;
|
||||
|
||||
|
@ -417,6 +414,15 @@ void compute_shiftstate(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* We still have to export this method to vt.c */
|
||||
void compute_shiftstate(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
do_compute_shiftstate();
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a combining character DIACR here, followed by the character CH.
|
||||
* If the combination occurs in the table, return the corresponding value.
|
||||
|
@ -636,7 +642,7 @@ static void fn_SAK(struct vc_data *vc)
|
|||
|
||||
static void fn_null(struct vc_data *vc)
|
||||
{
|
||||
compute_shiftstate();
|
||||
do_compute_shiftstate();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -989,6 +995,8 @@ unsigned char getledstate(void)
|
|||
|
||||
void setledstate(struct kbd_struct *kbd, unsigned int led)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
if (!(led & ~7)) {
|
||||
ledioctl = led;
|
||||
kbd->ledmode = LED_SHOW_IOCTL;
|
||||
|
@ -996,6 +1004,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led)
|
|||
kbd->ledmode = LED_SHOW_FLAGS;
|
||||
|
||||
set_leds();
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
}
|
||||
|
||||
static inline unsigned char getleds(void)
|
||||
|
@ -1035,6 +1044,75 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_get_leds - helper for braille console
|
||||
* @console: console to read
|
||||
* @flag: flag we want to check
|
||||
*
|
||||
* Check the status of a keyboard led flag and report it back
|
||||
*/
|
||||
int vt_get_leds(int console, int flag)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
ret = vc_kbd_led(kbd, flag);
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vt_get_leds);
|
||||
|
||||
/**
|
||||
* vt_set_led_state - set LED state of a console
|
||||
* @console: console to set
|
||||
* @leds: LED bits
|
||||
*
|
||||
* Set the LEDs on a console. This is a wrapper for the VT layer
|
||||
* so that we can keep kbd knowledge internal
|
||||
*/
|
||||
void vt_set_led_state(int console, int leds)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
setledstate(kbd, leds);
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_kbd_con_start - Keyboard side of console start
|
||||
* @console: console
|
||||
*
|
||||
* Handle console start. This is a wrapper for the VT layer
|
||||
* so that we can keep kbd knowledge internal
|
||||
*/
|
||||
void vt_kbd_con_start(int console)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
clr_vc_kbd_led(kbd, VC_SCROLLOCK);
|
||||
set_leds();
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_kbd_con_stop - Keyboard side of console stop
|
||||
* @console: console
|
||||
*
|
||||
* Handle console stop. This is a wrapper for the VT layer
|
||||
* so that we can keep kbd knowledge internal
|
||||
*/
|
||||
void vt_kbd_con_stop(int console)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
set_vc_kbd_led(kbd, VC_SCROLLOCK);
|
||||
set_leds();
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the tasklet that updates LED state on all keyboards
|
||||
* attached to the box. The reason we use tasklet is that we
|
||||
|
@ -1254,7 +1332,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
|
|||
if (rc == NOTIFY_STOP || !key_map) {
|
||||
atomic_notifier_call_chain(&keyboard_notifier_list,
|
||||
KBD_UNBOUND_KEYCODE, ¶m);
|
||||
compute_shiftstate();
|
||||
do_compute_shiftstate();
|
||||
kbd->slockstate = 0;
|
||||
return;
|
||||
}
|
||||
|
@ -1404,14 +1482,14 @@ static void kbd_start(struct input_handle *handle)
|
|||
|
||||
static const struct input_device_id kbd_ids[] = {
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
|
||||
.evbit = { BIT_MASK(EV_KEY) },
|
||||
},
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
|
||||
.evbit = { BIT_MASK(EV_KEY) },
|
||||
},
|
||||
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
|
||||
.evbit = { BIT_MASK(EV_SND) },
|
||||
},
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
|
||||
.evbit = { BIT_MASK(EV_SND) },
|
||||
},
|
||||
|
||||
{ }, /* Terminating entry */
|
||||
};
|
||||
|
@ -1433,7 +1511,7 @@ int __init kbd_init(void)
|
|||
int i;
|
||||
int error;
|
||||
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
kbd_table[i].ledflagstate = KBD_DEFLEDS;
|
||||
kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
|
||||
kbd_table[i].ledmode = LED_SHOW_FLAGS;
|
||||
|
@ -1452,3 +1530,658 @@ int __init kbd_init(void)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ioctl support code */
|
||||
|
||||
/**
|
||||
* vt_do_diacrit - diacritical table updates
|
||||
* @cmd: ioctl request
|
||||
* @up: pointer to user data for ioctl
|
||||
* @perm: permissions check computed by caller
|
||||
*
|
||||
* Update the diacritical tables atomically and safely. Lock them
|
||||
* against simultaneous keypresses
|
||||
*/
|
||||
int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
|
||||
{
|
||||
struct kbdiacrs __user *a = up;
|
||||
unsigned long flags;
|
||||
int asize;
|
||||
int ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case KDGKBDIACR:
|
||||
{
|
||||
struct kbdiacr *diacr;
|
||||
int i;
|
||||
|
||||
diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr),
|
||||
GFP_KERNEL);
|
||||
if (diacr == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Lock the diacriticals table, make a copy and then
|
||||
copy it after we unlock */
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
|
||||
asize = accent_table_size;
|
||||
for (i = 0; i < asize; i++) {
|
||||
diacr[i].diacr = conv_uni_to_8bit(
|
||||
accent_table[i].diacr);
|
||||
diacr[i].base = conv_uni_to_8bit(
|
||||
accent_table[i].base);
|
||||
diacr[i].result = conv_uni_to_8bit(
|
||||
accent_table[i].result);
|
||||
}
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
|
||||
if (put_user(asize, &a->kb_cnt))
|
||||
ret = -EFAULT;
|
||||
else if (copy_to_user(a->kbdiacr, diacr,
|
||||
asize * sizeof(struct kbdiacr)))
|
||||
ret = -EFAULT;
|
||||
kfree(diacr);
|
||||
return ret;
|
||||
}
|
||||
case KDGKBDIACRUC:
|
||||
{
|
||||
struct kbdiacrsuc __user *a = up;
|
||||
void *buf;
|
||||
|
||||
buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc),
|
||||
GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Lock the diacriticals table, make a copy and then
|
||||
copy it after we unlock */
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
|
||||
asize = accent_table_size;
|
||||
memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
|
||||
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
|
||||
if (put_user(asize, &a->kb_cnt))
|
||||
ret = -EFAULT;
|
||||
else if (copy_to_user(a->kbdiacruc, buf,
|
||||
asize*sizeof(struct kbdiacruc)))
|
||||
ret = -EFAULT;
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
case KDSKBDIACR:
|
||||
{
|
||||
struct kbdiacrs __user *a = up;
|
||||
struct kbdiacr *diacr = NULL;
|
||||
unsigned int ct;
|
||||
int i;
|
||||
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
if (get_user(ct, &a->kb_cnt))
|
||||
return -EFAULT;
|
||||
if (ct >= MAX_DIACR)
|
||||
return -EINVAL;
|
||||
|
||||
if (ct) {
|
||||
diacr = kmalloc(sizeof(struct kbdiacr) * ct,
|
||||
GFP_KERNEL);
|
||||
if (diacr == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(diacr, a->kbdiacr,
|
||||
sizeof(struct kbdiacr) * ct)) {
|
||||
kfree(diacr);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
accent_table_size = ct;
|
||||
for (i = 0; i < ct; i++) {
|
||||
accent_table[i].diacr =
|
||||
conv_8bit_to_uni(diacr[i].diacr);
|
||||
accent_table[i].base =
|
||||
conv_8bit_to_uni(diacr[i].base);
|
||||
accent_table[i].result =
|
||||
conv_8bit_to_uni(diacr[i].result);
|
||||
}
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
kfree(diacr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case KDSKBDIACRUC:
|
||||
{
|
||||
struct kbdiacrsuc __user *a = up;
|
||||
unsigned int ct;
|
||||
void *buf = NULL;
|
||||
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
|
||||
if (get_user(ct, &a->kb_cnt))
|
||||
return -EFAULT;
|
||||
|
||||
if (ct >= MAX_DIACR)
|
||||
return -EINVAL;
|
||||
|
||||
if (ct) {
|
||||
buf = kmalloc(ct * sizeof(struct kbdiacruc),
|
||||
GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(buf, a->kbdiacruc,
|
||||
ct * sizeof(struct kbdiacruc))) {
|
||||
kfree(buf);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
if (ct)
|
||||
memcpy(accent_table, buf,
|
||||
ct * sizeof(struct kbdiacruc));
|
||||
accent_table_size = ct;
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
kfree(buf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_do_kdskbmode - set keyboard mode ioctl
|
||||
* @console: the console to use
|
||||
* @arg: the requested mode
|
||||
*
|
||||
* Update the keyboard mode bits while holding the correct locks.
|
||||
* Return 0 for success or an error code.
|
||||
*/
|
||||
int vt_do_kdskbmode(int console, unsigned int arg)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
switch(arg) {
|
||||
case K_RAW:
|
||||
kbd->kbdmode = VC_RAW;
|
||||
break;
|
||||
case K_MEDIUMRAW:
|
||||
kbd->kbdmode = VC_MEDIUMRAW;
|
||||
break;
|
||||
case K_XLATE:
|
||||
kbd->kbdmode = VC_XLATE;
|
||||
do_compute_shiftstate();
|
||||
break;
|
||||
case K_UNICODE:
|
||||
kbd->kbdmode = VC_UNICODE;
|
||||
do_compute_shiftstate();
|
||||
break;
|
||||
case K_OFF:
|
||||
kbd->kbdmode = VC_OFF;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_do_kdskbmeta - set keyboard meta state
|
||||
* @console: the console to use
|
||||
* @arg: the requested meta state
|
||||
*
|
||||
* Update the keyboard meta bits while holding the correct locks.
|
||||
* Return 0 for success or an error code.
|
||||
*/
|
||||
int vt_do_kdskbmeta(int console, unsigned int arg)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
switch(arg) {
|
||||
case K_METABIT:
|
||||
clr_vc_kbd_mode(kbd, VC_META);
|
||||
break;
|
||||
case K_ESCPREFIX:
|
||||
set_vc_kbd_mode(kbd, VC_META);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
|
||||
int perm)
|
||||
{
|
||||
struct kbkeycode tmp;
|
||||
int kc = 0;
|
||||
|
||||
if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
|
||||
return -EFAULT;
|
||||
switch (cmd) {
|
||||
case KDGETKEYCODE:
|
||||
kc = getkeycode(tmp.scancode);
|
||||
if (kc >= 0)
|
||||
kc = put_user(kc, &user_kbkc->keycode);
|
||||
break;
|
||||
case KDSETKEYCODE:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
kc = setkeycode(tmp.scancode, tmp.keycode);
|
||||
break;
|
||||
}
|
||||
return kc;
|
||||
}
|
||||
|
||||
#define i (tmp.kb_index)
|
||||
#define s (tmp.kb_table)
|
||||
#define v (tmp.kb_value)
|
||||
|
||||
int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
|
||||
int console)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
struct kbentry tmp;
|
||||
ushort *key_map, *new_map, val, ov;
|
||||
unsigned long flags;
|
||||
|
||||
if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!capable(CAP_SYS_TTY_CONFIG))
|
||||
perm = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case KDGKBENT:
|
||||
/* Ensure another thread doesn't free it under us */
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
key_map = key_maps[s];
|
||||
if (key_map) {
|
||||
val = U(key_map[i]);
|
||||
if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
|
||||
val = K_HOLE;
|
||||
} else
|
||||
val = (i ? K_HOLE : K_NOSUCHMAP);
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
return put_user(val, &user_kbe->kb_value);
|
||||
case KDSKBENT:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
if (!i && v == K_NOSUCHMAP) {
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
/* deallocate map */
|
||||
key_map = key_maps[s];
|
||||
if (s && key_map) {
|
||||
key_maps[s] = NULL;
|
||||
if (key_map[0] == U(K_ALLOCATED)) {
|
||||
kfree(key_map);
|
||||
keymap_count--;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
if (KTYP(v) < NR_TYPES) {
|
||||
if (KVAL(v) > max_vals[KTYP(v)])
|
||||
return -EINVAL;
|
||||
} else
|
||||
if (kbd->kbdmode != VC_UNICODE)
|
||||
return -EINVAL;
|
||||
|
||||
/* ++Geert: non-PC keyboards may generate keycode zero */
|
||||
#if !defined(__mc68000__) && !defined(__powerpc__)
|
||||
/* assignment to entry 0 only tests validity of args */
|
||||
if (!i)
|
||||
break;
|
||||
#endif
|
||||
|
||||
new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
|
||||
if (!new_map)
|
||||
return -ENOMEM;
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
key_map = key_maps[s];
|
||||
if (key_map == NULL) {
|
||||
int j;
|
||||
|
||||
if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
|
||||
!capable(CAP_SYS_RESOURCE)) {
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
kfree(new_map);
|
||||
return -EPERM;
|
||||
}
|
||||
key_maps[s] = new_map;
|
||||
key_map = new_map;
|
||||
key_map[0] = U(K_ALLOCATED);
|
||||
for (j = 1; j < NR_KEYS; j++)
|
||||
key_map[j] = U(K_HOLE);
|
||||
keymap_count++;
|
||||
} else
|
||||
kfree(new_map);
|
||||
|
||||
ov = U(key_map[i]);
|
||||
if (v == ov)
|
||||
goto out;
|
||||
/*
|
||||
* Attention Key.
|
||||
*/
|
||||
if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) {
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
return -EPERM;
|
||||
}
|
||||
key_map[i] = U(v);
|
||||
if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
|
||||
do_compute_shiftstate();
|
||||
out:
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#undef i
|
||||
#undef s
|
||||
#undef v
|
||||
|
||||
/* FIXME: This one needs untangling and locking */
|
||||
int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
||||
{
|
||||
struct kbsentry *kbs;
|
||||
char *p;
|
||||
u_char *q;
|
||||
u_char __user *up;
|
||||
int sz;
|
||||
int delta;
|
||||
char *first_free, *fj, *fnw;
|
||||
int i, j, k;
|
||||
int ret;
|
||||
|
||||
if (!capable(CAP_SYS_TTY_CONFIG))
|
||||
perm = 0;
|
||||
|
||||
kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
|
||||
if (!kbs) {
|
||||
ret = -ENOMEM;
|
||||
goto reterr;
|
||||
}
|
||||
|
||||
/* we mostly copy too much here (512bytes), but who cares ;) */
|
||||
if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
|
||||
ret = -EFAULT;
|
||||
goto reterr;
|
||||
}
|
||||
kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
|
||||
i = kbs->kb_func;
|
||||
|
||||
switch (cmd) {
|
||||
case KDGKBSENT:
|
||||
sz = sizeof(kbs->kb_string) - 1; /* sz should have been
|
||||
a struct member */
|
||||
up = user_kdgkb->kb_string;
|
||||
p = func_table[i];
|
||||
if(p)
|
||||
for ( ; *p && sz; p++, sz--)
|
||||
if (put_user(*p, up++)) {
|
||||
ret = -EFAULT;
|
||||
goto reterr;
|
||||
}
|
||||
if (put_user('\0', up)) {
|
||||
ret = -EFAULT;
|
||||
goto reterr;
|
||||
}
|
||||
kfree(kbs);
|
||||
return ((p && *p) ? -EOVERFLOW : 0);
|
||||
case KDSKBSENT:
|
||||
if (!perm) {
|
||||
ret = -EPERM;
|
||||
goto reterr;
|
||||
}
|
||||
|
||||
q = func_table[i];
|
||||
first_free = funcbufptr + (funcbufsize - funcbufleft);
|
||||
for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
|
||||
;
|
||||
if (j < MAX_NR_FUNC)
|
||||
fj = func_table[j];
|
||||
else
|
||||
fj = first_free;
|
||||
|
||||
delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
|
||||
if (delta <= funcbufleft) { /* it fits in current buf */
|
||||
if (j < MAX_NR_FUNC) {
|
||||
memmove(fj + delta, fj, first_free - fj);
|
||||
for (k = j; k < MAX_NR_FUNC; k++)
|
||||
if (func_table[k])
|
||||
func_table[k] += delta;
|
||||
}
|
||||
if (!q)
|
||||
func_table[i] = fj;
|
||||
funcbufleft -= delta;
|
||||
} else { /* allocate a larger buffer */
|
||||
sz = 256;
|
||||
while (sz < funcbufsize - funcbufleft + delta)
|
||||
sz <<= 1;
|
||||
fnw = kmalloc(sz, GFP_KERNEL);
|
||||
if(!fnw) {
|
||||
ret = -ENOMEM;
|
||||
goto reterr;
|
||||
}
|
||||
|
||||
if (!q)
|
||||
func_table[i] = fj;
|
||||
if (fj > funcbufptr)
|
||||
memmove(fnw, funcbufptr, fj - funcbufptr);
|
||||
for (k = 0; k < j; k++)
|
||||
if (func_table[k])
|
||||
func_table[k] = fnw + (func_table[k] - funcbufptr);
|
||||
|
||||
if (first_free > fj) {
|
||||
memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
|
||||
for (k = j; k < MAX_NR_FUNC; k++)
|
||||
if (func_table[k])
|
||||
func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
|
||||
}
|
||||
if (funcbufptr != func_buf)
|
||||
kfree(funcbufptr);
|
||||
funcbufptr = fnw;
|
||||
funcbufleft = funcbufleft - delta + sz - funcbufsize;
|
||||
funcbufsize = sz;
|
||||
}
|
||||
strcpy(func_table[i], kbs->kb_string);
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
reterr:
|
||||
kfree(kbs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
unsigned long flags;
|
||||
unsigned char ucval;
|
||||
|
||||
switch(cmd) {
|
||||
/* the ioctls below read/set the flags usually shown in the leds */
|
||||
/* don't use them - they will go away without warning */
|
||||
case KDGKBLED:
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
return put_user(ucval, (char __user *)arg);
|
||||
|
||||
case KDSKBLED:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
if (arg & ~0x77)
|
||||
return -EINVAL;
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
kbd->ledflagstate = (arg & 7);
|
||||
kbd->default_ledflagstate = ((arg >> 4) & 7);
|
||||
set_leds();
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
break;
|
||||
|
||||
/* the ioctls below only set the lights, not the functions */
|
||||
/* for those, see KDGKBLED and KDSKBLED above */
|
||||
case KDGETLED:
|
||||
ucval = getledstate();
|
||||
return put_user(ucval, (char __user *)arg);
|
||||
|
||||
case KDSETLED:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
setledstate(kbd, arg);
|
||||
return 0;
|
||||
}
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
int vt_do_kdgkbmode(int console)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
/* This is a spot read so needs no locking */
|
||||
switch (kbd->kbdmode) {
|
||||
case VC_RAW:
|
||||
return K_RAW;
|
||||
case VC_MEDIUMRAW:
|
||||
return K_MEDIUMRAW;
|
||||
case VC_UNICODE:
|
||||
return K_UNICODE;
|
||||
case VC_OFF:
|
||||
return K_OFF;
|
||||
default:
|
||||
return K_XLATE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_do_kdgkbmeta - report meta status
|
||||
* @console: console to report
|
||||
*
|
||||
* Report the meta flag status of this console
|
||||
*/
|
||||
int vt_do_kdgkbmeta(int console)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
/* Again a spot read so no locking */
|
||||
return vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_reset_unicode - reset the unicode status
|
||||
* @console: console being reset
|
||||
*
|
||||
* Restore the unicode console state to its default
|
||||
*/
|
||||
void vt_reset_unicode(int console)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_get_shiftstate - shift bit state
|
||||
*
|
||||
* Report the shift bits from the keyboard state. We have to export
|
||||
* this to support some oddities in the vt layer.
|
||||
*/
|
||||
int vt_get_shift_state(void)
|
||||
{
|
||||
/* Don't lock as this is a transient report */
|
||||
return shift_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_reset_keyboard - reset keyboard state
|
||||
* @console: console to reset
|
||||
*
|
||||
* Reset the keyboard bits for a console as part of a general console
|
||||
* reset event
|
||||
*/
|
||||
void vt_reset_keyboard(int console)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
set_vc_kbd_mode(kbd, VC_REPEAT);
|
||||
clr_vc_kbd_mode(kbd, VC_CKMODE);
|
||||
clr_vc_kbd_mode(kbd, VC_APPLIC);
|
||||
clr_vc_kbd_mode(kbd, VC_CRLF);
|
||||
kbd->lockstate = 0;
|
||||
kbd->slockstate = 0;
|
||||
kbd->ledmode = LED_SHOW_FLAGS;
|
||||
kbd->ledflagstate = kbd->default_ledflagstate;
|
||||
/* do not do set_leds here because this causes an endless tasklet loop
|
||||
when the keyboard hasn't been initialized yet */
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_get_kbd_mode_bit - read keyboard status bits
|
||||
* @console: console to read from
|
||||
* @bit: mode bit to read
|
||||
*
|
||||
* Report back a vt mode bit. We do this without locking so the
|
||||
* caller must be sure that there are no synchronization needs
|
||||
*/
|
||||
|
||||
int vt_get_kbd_mode_bit(int console, int bit)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
return vc_kbd_mode(kbd, bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_set_kbd_mode_bit - read keyboard status bits
|
||||
* @console: console to read from
|
||||
* @bit: mode bit to read
|
||||
*
|
||||
* Set a vt mode bit. We do this without locking so the
|
||||
* caller must be sure that there are no synchronization needs
|
||||
*/
|
||||
|
||||
void vt_set_kbd_mode_bit(int console, int bit)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
set_vc_kbd_mode(kbd, bit);
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_clr_kbd_mode_bit - read keyboard status bits
|
||||
* @console: console to read from
|
||||
* @bit: mode bit to read
|
||||
*
|
||||
* Report back a vt mode bit. We do this without locking so the
|
||||
* caller must be sure that there are no synchronization needs
|
||||
*/
|
||||
|
||||
void vt_clr_kbd_mode_bit(int console, int bit)
|
||||
{
|
||||
struct kbd_struct * kbd = kbd_table + console;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
clr_vc_kbd_mode(kbd, bit);
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
extern void poke_blanked_console(void);
|
||||
|
||||
/* FIXME: all this needs locking */
|
||||
/* Variables for selection control. */
|
||||
/* Use a dynamic buffer, instead of static (Dec 1994) */
|
||||
struct vc_data *sel_cons; /* must not be deallocated */
|
||||
|
@ -61,10 +62,14 @@ sel_pos(int n)
|
|||
use_unicode);
|
||||
}
|
||||
|
||||
/* remove the current selection highlight, if any,
|
||||
from the console holding the selection. */
|
||||
void
|
||||
clear_selection(void) {
|
||||
/**
|
||||
* clear_selection - remove current selection
|
||||
*
|
||||
* Remove the current selection highlight, if any from the console
|
||||
* holding the selection. The caller must hold the console lock.
|
||||
*/
|
||||
void clear_selection(void)
|
||||
{
|
||||
highlight_pointer(-1); /* hide the pointer */
|
||||
if (sel_start != -1) {
|
||||
highlight(sel_start, sel_end);
|
||||
|
@ -74,7 +79,7 @@ clear_selection(void) {
|
|||
|
||||
/*
|
||||
* User settable table: what characters are to be considered alphabetic?
|
||||
* 256 bits
|
||||
* 256 bits. Locked by the console lock.
|
||||
*/
|
||||
static u32 inwordLut[8]={
|
||||
0x00000000, /* control chars */
|
||||
|
@ -91,10 +96,20 @@ static inline int inword(const u16 c) {
|
|||
return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
|
||||
}
|
||||
|
||||
/* set inwordLut contents. Invoked by ioctl(). */
|
||||
/**
|
||||
* set loadlut - load the LUT table
|
||||
* @p: user table
|
||||
*
|
||||
* Load the LUT table from user space. The caller must hold the console
|
||||
* lock. Make a temporary copy so a partial update doesn't make a mess.
|
||||
*/
|
||||
int sel_loadlut(char __user *p)
|
||||
{
|
||||
return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
|
||||
u32 tmplut[8];
|
||||
if (copy_from_user(tmplut, (u32 __user *)(p+4), 32))
|
||||
return -EFAULT;
|
||||
memcpy(inwordLut, tmplut, 32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* does screen address p correspond to character at LH/RH edge of screen? */
|
||||
|
@ -130,7 +145,16 @@ static int store_utf8(u16 c, char *p)
|
|||
}
|
||||
}
|
||||
|
||||
/* set the current selection. Invoked by ioctl() or by kernel code. */
|
||||
/**
|
||||
* set_selection - set the current selection.
|
||||
* @sel: user selection info
|
||||
* @tty: the console tty
|
||||
*
|
||||
* Invoked by the ioctl handle for the vt layer.
|
||||
*
|
||||
* The entire selection process is managed under the console_lock. It's
|
||||
* a lot under the lock but its hardly a performance path
|
||||
*/
|
||||
int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
|
||||
{
|
||||
struct vc_data *vc = vc_cons[fg_console].d;
|
||||
|
@ -138,7 +162,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
|
|||
char *bp, *obp;
|
||||
int i, ps, pe, multiplier;
|
||||
u16 c;
|
||||
struct kbd_struct *kbd = kbd_table + fg_console;
|
||||
int mode;
|
||||
|
||||
poke_blanked_console();
|
||||
|
||||
|
@ -182,7 +206,11 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
|
|||
clear_selection();
|
||||
sel_cons = vc_cons[fg_console].d;
|
||||
}
|
||||
use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
|
||||
mode = vt_do_kdgkbmode(fg_console);
|
||||
if (mode == K_UNICODE)
|
||||
use_unicode = 1;
|
||||
else
|
||||
use_unicode = 0;
|
||||
|
||||
switch (sel_mode)
|
||||
{
|
||||
|
@ -302,7 +330,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
|
|||
* queue of the tty associated with the current console.
|
||||
* Invoked by ioctl().
|
||||
*
|
||||
* Locking: always called with BTM from vt_ioctl
|
||||
* Locking: called without locks. Calls the ldisc wrongly with
|
||||
* unsafe methods,
|
||||
*/
|
||||
int paste_selection(struct tty_struct *tty)
|
||||
{
|
||||
|
@ -317,13 +346,12 @@ int paste_selection(struct tty_struct *tty)
|
|||
poke_blanked_console();
|
||||
console_unlock();
|
||||
|
||||
/* FIXME: wtf is this supposed to achieve ? */
|
||||
ld = tty_ldisc_ref(tty);
|
||||
if (!ld) {
|
||||
tty_unlock();
|
||||
if (!ld)
|
||||
ld = tty_ldisc_ref_wait(tty);
|
||||
tty_lock();
|
||||
}
|
||||
|
||||
/* FIXME: this is completely unsafe */
|
||||
add_wait_queue(&vc->paste_wait, &wait);
|
||||
while (sel_buffer && sel_buffer_lth > pasted) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
|
|
@ -608,10 +608,10 @@ vcs_open(struct inode *inode, struct file *filp)
|
|||
unsigned int currcons = iminor(inode) & 127;
|
||||
int ret = 0;
|
||||
|
||||
tty_lock();
|
||||
console_lock();
|
||||
if(currcons && !vc_cons_allocated(currcons-1))
|
||||
ret = -ENXIO;
|
||||
tty_unlock();
|
||||
console_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1028,9 +1028,9 @@ void vc_deallocate(unsigned int currcons)
|
|||
* VT102 emulator
|
||||
*/
|
||||
|
||||
#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
|
||||
#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
|
||||
#define is_kbd(vc, x) vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
|
||||
#define set_kbd(vc, x) vt_set_kbd_mode_bit((vc)->vc_num, (x))
|
||||
#define clr_kbd(vc, x) vt_clr_kbd_mode_bit((vc)->vc_num, (x))
|
||||
#define is_kbd(vc, x) vt_get_kbd_mode_bit((vc)->vc_num, (x))
|
||||
|
||||
#define decarm VC_REPEAT
|
||||
#define decckm VC_CKMODE
|
||||
|
@ -1652,16 +1652,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
|
|||
vc->vc_deccm = global_cursor_default;
|
||||
vc->vc_decim = 0;
|
||||
|
||||
set_kbd(vc, decarm);
|
||||
clr_kbd(vc, decckm);
|
||||
clr_kbd(vc, kbdapplic);
|
||||
clr_kbd(vc, lnm);
|
||||
kbd_table[vc->vc_num].lockstate = 0;
|
||||
kbd_table[vc->vc_num].slockstate = 0;
|
||||
kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
|
||||
kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
|
||||
/* do not do set_leds here because this causes an endless tasklet loop
|
||||
when the keyboard hasn't been initialized yet */
|
||||
vt_reset_keyboard(vc->vc_num);
|
||||
|
||||
vc->vc_cursor_type = cur_default;
|
||||
vc->vc_complement_mask = vc->vc_s_complement_mask;
|
||||
|
@ -1979,7 +1970,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
|
|||
case 'q': /* DECLL - but only 3 leds */
|
||||
/* map 0,1,2,3 to 0,1,2,4 */
|
||||
if (vc->vc_par[0] < 4)
|
||||
setledstate(kbd_table + vc->vc_num,
|
||||
vt_set_led_state(vc->vc_num,
|
||||
(vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
|
||||
return;
|
||||
case 'r':
|
||||
|
@ -2632,7 +2623,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
|
|||
console_unlock();
|
||||
break;
|
||||
case TIOCL_SELLOADLUT:
|
||||
console_lock();
|
||||
ret = sel_loadlut(p);
|
||||
console_unlock();
|
||||
break;
|
||||
case TIOCL_GETSHIFTSTATE:
|
||||
|
||||
|
@ -2642,15 +2635,19 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
|
|||
* kernel-internal variable; programs not closely
|
||||
* related to the kernel should not use this.
|
||||
*/
|
||||
data = shift_state;
|
||||
data = vt_get_shift_state();
|
||||
ret = __put_user(data, p);
|
||||
break;
|
||||
case TIOCL_GETMOUSEREPORTING:
|
||||
console_lock(); /* May be overkill */
|
||||
data = mouse_reporting();
|
||||
console_unlock();
|
||||
ret = __put_user(data, p);
|
||||
break;
|
||||
case TIOCL_SETVESABLANK:
|
||||
console_lock();
|
||||
ret = set_vesa_blanking(p);
|
||||
console_unlock();
|
||||
break;
|
||||
case TIOCL_GETKMSGREDIRECT:
|
||||
data = vt_get_kmsg_redirect();
|
||||
|
@ -2667,13 +2664,21 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
|
|||
}
|
||||
break;
|
||||
case TIOCL_GETFGCONSOLE:
|
||||
/* No locking needed as this is a transiently
|
||||
correct return anyway if the caller hasn't
|
||||
disabled switching */
|
||||
ret = fg_console;
|
||||
break;
|
||||
case TIOCL_SCROLLCONSOLE:
|
||||
if (get_user(lines, (s32 __user *)(p+4))) {
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
/* Need the console lock here. Note that lots
|
||||
of other calls need fixing before the lock
|
||||
is actually useful ! */
|
||||
console_lock();
|
||||
scrollfront(vc_cons[fg_console].d, lines);
|
||||
console_unlock();
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
@ -2753,8 +2758,7 @@ static void con_stop(struct tty_struct *tty)
|
|||
console_num = tty->index;
|
||||
if (!vc_cons_allocated(console_num))
|
||||
return;
|
||||
set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
|
||||
set_leds();
|
||||
vt_kbd_con_stop(console_num);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2768,8 +2772,7 @@ static void con_start(struct tty_struct *tty)
|
|||
console_num = tty->index;
|
||||
if (!vc_cons_allocated(console_num))
|
||||
return;
|
||||
clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
|
||||
set_leds();
|
||||
vt_kbd_con_start(console_num);
|
||||
}
|
||||
|
||||
static void con_flush_chars(struct tty_struct *tty)
|
||||
|
@ -2991,7 +2994,7 @@ int __init vty_init(const struct file_operations *console_fops)
|
|||
console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
|
||||
if (!console_driver)
|
||||
panic("Couldn't allocate console driver\n");
|
||||
console_driver->owner = THIS_MODULE;
|
||||
|
||||
console_driver->name = "tty";
|
||||
console_driver->name_base = 1;
|
||||
console_driver->major = TTY_MAJOR;
|
||||
|
@ -3980,9 +3983,6 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
|
|||
int rc = -EINVAL;
|
||||
int c;
|
||||
|
||||
if (vc->vc_mode != KD_TEXT)
|
||||
return -EINVAL;
|
||||
|
||||
if (op->data) {
|
||||
font.data = kmalloc(max_font_size, GFP_KERNEL);
|
||||
if (!font.data)
|
||||
|
@ -3991,7 +3991,9 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
|
|||
font.data = NULL;
|
||||
|
||||
console_lock();
|
||||
if (vc->vc_sw->con_font_get)
|
||||
if (vc->vc_mode != KD_TEXT)
|
||||
rc = -EINVAL;
|
||||
else if (vc->vc_sw->con_font_get)
|
||||
rc = vc->vc_sw->con_font_get(vc, &font);
|
||||
else
|
||||
rc = -ENOSYS;
|
||||
|
@ -4073,7 +4075,9 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
|
|||
if (IS_ERR(font.data))
|
||||
return PTR_ERR(font.data);
|
||||
console_lock();
|
||||
if (vc->vc_sw->con_font_set)
|
||||
if (vc->vc_mode != KD_TEXT)
|
||||
rc = -EINVAL;
|
||||
else if (vc->vc_sw->con_font_set)
|
||||
rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
|
||||
else
|
||||
rc = -ENOSYS;
|
||||
|
@ -4089,8 +4093,6 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
|
|||
char *s = name;
|
||||
int rc;
|
||||
|
||||
if (vc->vc_mode != KD_TEXT)
|
||||
return -EINVAL;
|
||||
|
||||
if (!op->data)
|
||||
s = NULL;
|
||||
|
@ -4100,6 +4102,10 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
|
|||
name[MAX_FONT_NAME - 1] = 0;
|
||||
|
||||
console_lock();
|
||||
if (vc->vc_mode != KD_TEXT) {
|
||||
console_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
if (vc->vc_sw->con_font_default)
|
||||
rc = vc->vc_sw->con_font_default(vc, &font, s);
|
||||
else
|
||||
|
@ -4117,11 +4123,11 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
|
|||
int con = op->height;
|
||||
int rc;
|
||||
|
||||
if (vc->vc_mode != KD_TEXT)
|
||||
return -EINVAL;
|
||||
|
||||
console_lock();
|
||||
if (!vc->vc_sw->con_font_copy)
|
||||
if (vc->vc_mode != KD_TEXT)
|
||||
rc = -EINVAL;
|
||||
else if (!vc->vc_sw->con_font_copy)
|
||||
rc = -ENOSYS;
|
||||
else if (con < 0 || !vc_cons_allocated(con))
|
||||
rc = -ENOTTY;
|
||||
|
|
|
@ -130,7 +130,7 @@ static void vt_event_wait(struct vt_event_wait *vw)
|
|||
list_add(&vw->list, &vt_events);
|
||||
spin_unlock_irqrestore(&vt_event_lock, flags);
|
||||
/* Wait for it to pass */
|
||||
wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
|
||||
wait_event_interruptible(vt_event_waitqueue, vw->done);
|
||||
/* Dequeue it */
|
||||
spin_lock_irqsave(&vt_event_lock, flags);
|
||||
list_del(&vw->list);
|
||||
|
@ -195,232 +195,7 @@ int vt_waitactive(int n)
|
|||
#define GPLAST 0x3df
|
||||
#define GPNUM (GPLAST - GPFIRST + 1)
|
||||
|
||||
#define i (tmp.kb_index)
|
||||
#define s (tmp.kb_table)
|
||||
#define v (tmp.kb_value)
|
||||
static inline int
|
||||
do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
|
||||
{
|
||||
struct kbentry tmp;
|
||||
ushort *key_map, val, ov;
|
||||
|
||||
if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!capable(CAP_SYS_TTY_CONFIG))
|
||||
perm = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case KDGKBENT:
|
||||
key_map = key_maps[s];
|
||||
if (key_map) {
|
||||
val = U(key_map[i]);
|
||||
if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
|
||||
val = K_HOLE;
|
||||
} else
|
||||
val = (i ? K_HOLE : K_NOSUCHMAP);
|
||||
return put_user(val, &user_kbe->kb_value);
|
||||
case KDSKBENT:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
if (!i && v == K_NOSUCHMAP) {
|
||||
/* deallocate map */
|
||||
key_map = key_maps[s];
|
||||
if (s && key_map) {
|
||||
key_maps[s] = NULL;
|
||||
if (key_map[0] == U(K_ALLOCATED)) {
|
||||
kfree(key_map);
|
||||
keymap_count--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (KTYP(v) < NR_TYPES) {
|
||||
if (KVAL(v) > max_vals[KTYP(v)])
|
||||
return -EINVAL;
|
||||
} else
|
||||
if (kbd->kbdmode != VC_UNICODE)
|
||||
return -EINVAL;
|
||||
|
||||
/* ++Geert: non-PC keyboards may generate keycode zero */
|
||||
#if !defined(__mc68000__) && !defined(__powerpc__)
|
||||
/* assignment to entry 0 only tests validity of args */
|
||||
if (!i)
|
||||
break;
|
||||
#endif
|
||||
|
||||
if (!(key_map = key_maps[s])) {
|
||||
int j;
|
||||
|
||||
if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
|
||||
!capable(CAP_SYS_RESOURCE))
|
||||
return -EPERM;
|
||||
|
||||
key_map = kmalloc(sizeof(plain_map),
|
||||
GFP_KERNEL);
|
||||
if (!key_map)
|
||||
return -ENOMEM;
|
||||
key_maps[s] = key_map;
|
||||
key_map[0] = U(K_ALLOCATED);
|
||||
for (j = 1; j < NR_KEYS; j++)
|
||||
key_map[j] = U(K_HOLE);
|
||||
keymap_count++;
|
||||
}
|
||||
ov = U(key_map[i]);
|
||||
if (v == ov)
|
||||
break; /* nothing to do */
|
||||
/*
|
||||
* Attention Key.
|
||||
*/
|
||||
if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
key_map[i] = U(v);
|
||||
if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
|
||||
compute_shiftstate();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#undef i
|
||||
#undef s
|
||||
#undef v
|
||||
|
||||
static inline int
|
||||
do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
|
||||
{
|
||||
struct kbkeycode tmp;
|
||||
int kc = 0;
|
||||
|
||||
if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
|
||||
return -EFAULT;
|
||||
switch (cmd) {
|
||||
case KDGETKEYCODE:
|
||||
kc = getkeycode(tmp.scancode);
|
||||
if (kc >= 0)
|
||||
kc = put_user(kc, &user_kbkc->keycode);
|
||||
break;
|
||||
case KDSETKEYCODE:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
kc = setkeycode(tmp.scancode, tmp.keycode);
|
||||
break;
|
||||
}
|
||||
return kc;
|
||||
}
|
||||
|
||||
static inline int
|
||||
do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
||||
{
|
||||
struct kbsentry *kbs;
|
||||
char *p;
|
||||
u_char *q;
|
||||
u_char __user *up;
|
||||
int sz;
|
||||
int delta;
|
||||
char *first_free, *fj, *fnw;
|
||||
int i, j, k;
|
||||
int ret;
|
||||
|
||||
if (!capable(CAP_SYS_TTY_CONFIG))
|
||||
perm = 0;
|
||||
|
||||
kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
|
||||
if (!kbs) {
|
||||
ret = -ENOMEM;
|
||||
goto reterr;
|
||||
}
|
||||
|
||||
/* we mostly copy too much here (512bytes), but who cares ;) */
|
||||
if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
|
||||
ret = -EFAULT;
|
||||
goto reterr;
|
||||
}
|
||||
kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
|
||||
i = kbs->kb_func;
|
||||
|
||||
switch (cmd) {
|
||||
case KDGKBSENT:
|
||||
sz = sizeof(kbs->kb_string) - 1; /* sz should have been
|
||||
a struct member */
|
||||
up = user_kdgkb->kb_string;
|
||||
p = func_table[i];
|
||||
if(p)
|
||||
for ( ; *p && sz; p++, sz--)
|
||||
if (put_user(*p, up++)) {
|
||||
ret = -EFAULT;
|
||||
goto reterr;
|
||||
}
|
||||
if (put_user('\0', up)) {
|
||||
ret = -EFAULT;
|
||||
goto reterr;
|
||||
}
|
||||
kfree(kbs);
|
||||
return ((p && *p) ? -EOVERFLOW : 0);
|
||||
case KDSKBSENT:
|
||||
if (!perm) {
|
||||
ret = -EPERM;
|
||||
goto reterr;
|
||||
}
|
||||
|
||||
q = func_table[i];
|
||||
first_free = funcbufptr + (funcbufsize - funcbufleft);
|
||||
for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
|
||||
;
|
||||
if (j < MAX_NR_FUNC)
|
||||
fj = func_table[j];
|
||||
else
|
||||
fj = first_free;
|
||||
|
||||
delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
|
||||
if (delta <= funcbufleft) { /* it fits in current buf */
|
||||
if (j < MAX_NR_FUNC) {
|
||||
memmove(fj + delta, fj, first_free - fj);
|
||||
for (k = j; k < MAX_NR_FUNC; k++)
|
||||
if (func_table[k])
|
||||
func_table[k] += delta;
|
||||
}
|
||||
if (!q)
|
||||
func_table[i] = fj;
|
||||
funcbufleft -= delta;
|
||||
} else { /* allocate a larger buffer */
|
||||
sz = 256;
|
||||
while (sz < funcbufsize - funcbufleft + delta)
|
||||
sz <<= 1;
|
||||
fnw = kmalloc(sz, GFP_KERNEL);
|
||||
if(!fnw) {
|
||||
ret = -ENOMEM;
|
||||
goto reterr;
|
||||
}
|
||||
|
||||
if (!q)
|
||||
func_table[i] = fj;
|
||||
if (fj > funcbufptr)
|
||||
memmove(fnw, funcbufptr, fj - funcbufptr);
|
||||
for (k = 0; k < j; k++)
|
||||
if (func_table[k])
|
||||
func_table[k] = fnw + (func_table[k] - funcbufptr);
|
||||
|
||||
if (first_free > fj) {
|
||||
memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
|
||||
for (k = j; k < MAX_NR_FUNC; k++)
|
||||
if (func_table[k])
|
||||
func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
|
||||
}
|
||||
if (funcbufptr != func_buf)
|
||||
kfree(funcbufptr);
|
||||
funcbufptr = fnw;
|
||||
funcbufleft = funcbufleft - delta + sz - funcbufsize;
|
||||
funcbufsize = sz;
|
||||
}
|
||||
strcpy(func_table[i], kbs->kb_string);
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
reterr:
|
||||
kfree(kbs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
|
||||
|
@ -497,7 +272,6 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
{
|
||||
struct vc_data *vc = tty->driver_data;
|
||||
struct console_font_op op; /* used in multiple places here */
|
||||
struct kbd_struct * kbd;
|
||||
unsigned int console;
|
||||
unsigned char ucval;
|
||||
unsigned int uival;
|
||||
|
@ -507,7 +281,6 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
|
||||
console = vc->vc_num;
|
||||
|
||||
tty_lock();
|
||||
|
||||
if (!vc_cons_allocated(console)) { /* impossible? */
|
||||
ret = -ENOIOCTLCMD;
|
||||
|
@ -523,19 +296,18 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
|
||||
perm = 1;
|
||||
|
||||
kbd = kbd_table + console;
|
||||
switch (cmd) {
|
||||
case TIOCLINUX:
|
||||
ret = tioclinux(tty, arg);
|
||||
break;
|
||||
case KIOCSOUND:
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
/*
|
||||
* The use of PIT_TICK_RATE is historic, it used to be
|
||||
* the platform-dependent CLOCK_TICK_RATE between 2.6.12
|
||||
* and 2.6.36, which was a minor but unfortunate ABI
|
||||
* change.
|
||||
* change. kd_mksound is locked by the input layer.
|
||||
*/
|
||||
if (arg)
|
||||
arg = PIT_TICK_RATE / arg;
|
||||
|
@ -544,7 +316,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
|
||||
case KDMKTONE:
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
{
|
||||
unsigned int ticks, count;
|
||||
|
||||
|
@ -562,10 +334,11 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
|
||||
case KDGKBTYPE:
|
||||
/*
|
||||
* this is naive.
|
||||
* this is naïve.
|
||||
*/
|
||||
ucval = KB_101;
|
||||
goto setchar;
|
||||
ret = put_user(ucval, (char __user *)arg);
|
||||
break;
|
||||
|
||||
/*
|
||||
* These cannot be implemented on any machine that implements
|
||||
|
@ -579,6 +352,8 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
/*
|
||||
* KDADDIO and KDDELIO may be able to add ports beyond what
|
||||
* we reject here, but to be safe...
|
||||
*
|
||||
* These are locked internally via sys_ioperm
|
||||
*/
|
||||
if (arg < GPFIRST || arg > GPLAST) {
|
||||
ret = -EINVAL;
|
||||
|
@ -601,7 +376,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
struct kbd_repeat kbrep;
|
||||
|
||||
if (!capable(CAP_SYS_TTY_CONFIG))
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
|
||||
ret = -EFAULT;
|
||||
|
@ -625,7 +400,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
* need to restore their engine state. --BenH
|
||||
*/
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
switch (arg) {
|
||||
case KD_GRAPHICS:
|
||||
break;
|
||||
|
@ -638,6 +413,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/* FIXME: this needs the console lock extending */
|
||||
if (vc->vc_mode == (unsigned char) arg)
|
||||
break;
|
||||
vc->vc_mode = (unsigned char) arg;
|
||||
|
@ -669,69 +445,26 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
|
||||
case KDSKBMODE:
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
switch(arg) {
|
||||
case K_RAW:
|
||||
kbd->kbdmode = VC_RAW;
|
||||
break;
|
||||
case K_MEDIUMRAW:
|
||||
kbd->kbdmode = VC_MEDIUMRAW;
|
||||
break;
|
||||
case K_XLATE:
|
||||
kbd->kbdmode = VC_XLATE;
|
||||
compute_shiftstate();
|
||||
break;
|
||||
case K_UNICODE:
|
||||
kbd->kbdmode = VC_UNICODE;
|
||||
compute_shiftstate();
|
||||
break;
|
||||
case K_OFF:
|
||||
kbd->kbdmode = VC_OFF;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
tty_ldisc_flush(tty);
|
||||
return -EPERM;
|
||||
ret = vt_do_kdskbmode(console, arg);
|
||||
if (ret == 0)
|
||||
tty_ldisc_flush(tty);
|
||||
break;
|
||||
|
||||
case KDGKBMODE:
|
||||
switch (kbd->kbdmode) {
|
||||
case VC_RAW:
|
||||
uival = K_RAW;
|
||||
break;
|
||||
case VC_MEDIUMRAW:
|
||||
uival = K_MEDIUMRAW;
|
||||
break;
|
||||
case VC_UNICODE:
|
||||
uival = K_UNICODE;
|
||||
break;
|
||||
case VC_OFF:
|
||||
uival = K_OFF;
|
||||
break;
|
||||
default:
|
||||
uival = K_XLATE;
|
||||
break;
|
||||
}
|
||||
goto setint;
|
||||
uival = vt_do_kdgkbmode(console);
|
||||
ret = put_user(uival, (int __user *)arg);
|
||||
break;
|
||||
|
||||
/* this could be folded into KDSKBMODE, but for compatibility
|
||||
reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
|
||||
case KDSKBMETA:
|
||||
switch(arg) {
|
||||
case K_METABIT:
|
||||
clr_vc_kbd_mode(kbd, VC_META);
|
||||
break;
|
||||
case K_ESCPREFIX:
|
||||
set_vc_kbd_mode(kbd, VC_META);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
ret = vt_do_kdskbmeta(console, arg);
|
||||
break;
|
||||
|
||||
case KDGKBMETA:
|
||||
uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
|
||||
/* FIXME: should review whether this is worth locking */
|
||||
uival = vt_do_kdgkbmeta(console);
|
||||
setint:
|
||||
ret = put_user(uival, (int __user *)arg);
|
||||
break;
|
||||
|
@ -740,133 +473,35 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
case KDSETKEYCODE:
|
||||
if(!capable(CAP_SYS_TTY_CONFIG))
|
||||
perm = 0;
|
||||
ret = do_kbkeycode_ioctl(cmd, up, perm);
|
||||
ret = vt_do_kbkeycode_ioctl(cmd, up, perm);
|
||||
break;
|
||||
|
||||
case KDGKBENT:
|
||||
case KDSKBENT:
|
||||
ret = do_kdsk_ioctl(cmd, up, perm, kbd);
|
||||
ret = vt_do_kdsk_ioctl(cmd, up, perm, console);
|
||||
break;
|
||||
|
||||
case KDGKBSENT:
|
||||
case KDSKBSENT:
|
||||
ret = do_kdgkb_ioctl(cmd, up, perm);
|
||||
ret = vt_do_kdgkb_ioctl(cmd, up, perm);
|
||||
break;
|
||||
|
||||
/* Diacritical processing. Handled in keyboard.c as it has
|
||||
to operate on the keyboard locks and structures */
|
||||
case KDGKBDIACR:
|
||||
{
|
||||
struct kbdiacrs __user *a = up;
|
||||
struct kbdiacr diacr;
|
||||
int i;
|
||||
|
||||
if (put_user(accent_table_size, &a->kb_cnt)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < accent_table_size; i++) {
|
||||
diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
|
||||
diacr.base = conv_uni_to_8bit(accent_table[i].base);
|
||||
diacr.result = conv_uni_to_8bit(accent_table[i].result);
|
||||
if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KDGKBDIACRUC:
|
||||
{
|
||||
struct kbdiacrsuc __user *a = up;
|
||||
|
||||
if (put_user(accent_table_size, &a->kb_cnt))
|
||||
ret = -EFAULT;
|
||||
else if (copy_to_user(a->kbdiacruc, accent_table,
|
||||
accent_table_size*sizeof(struct kbdiacruc)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
case KDSKBDIACR:
|
||||
{
|
||||
struct kbdiacrs __user *a = up;
|
||||
struct kbdiacr diacr;
|
||||
unsigned int ct;
|
||||
int i;
|
||||
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
if (get_user(ct,&a->kb_cnt)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (ct >= MAX_DIACR) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
accent_table_size = ct;
|
||||
for (i = 0; i < ct; i++) {
|
||||
if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
|
||||
accent_table[i].base = conv_8bit_to_uni(diacr.base);
|
||||
accent_table[i].result = conv_8bit_to_uni(diacr.result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KDSKBDIACRUC:
|
||||
{
|
||||
struct kbdiacrsuc __user *a = up;
|
||||
unsigned int ct;
|
||||
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
if (get_user(ct,&a->kb_cnt)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (ct >= MAX_DIACR) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
accent_table_size = ct;
|
||||
if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
|
||||
ret = -EFAULT;
|
||||
ret = vt_do_diacrit(cmd, up, perm);
|
||||
break;
|
||||
}
|
||||
|
||||
/* the ioctls below read/set the flags usually shown in the leds */
|
||||
/* don't use them - they will go away without warning */
|
||||
case KDGKBLED:
|
||||
ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
|
||||
goto setchar;
|
||||
|
||||
case KDSKBLED:
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
if (arg & ~0x77) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
kbd->ledflagstate = (arg & 7);
|
||||
kbd->default_ledflagstate = ((arg >> 4) & 7);
|
||||
set_leds();
|
||||
break;
|
||||
|
||||
/* the ioctls below only set the lights, not the functions */
|
||||
/* for those, see KDGKBLED and KDSKBLED above */
|
||||
case KDGETLED:
|
||||
ucval = getledstate();
|
||||
setchar:
|
||||
ret = put_user(ucval, (char __user *)arg);
|
||||
break;
|
||||
|
||||
case KDSETLED:
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
setledstate(kbd, arg);
|
||||
ret = vt_do_kdskled(console, cmd, arg, perm);
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -879,7 +514,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
case KDSIGACCEPT:
|
||||
{
|
||||
if (!perm || !capable(CAP_KILL))
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
|
||||
ret = -EINVAL;
|
||||
else {
|
||||
|
@ -897,7 +532,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
struct vt_mode tmp;
|
||||
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
|
@ -943,6 +578,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
struct vt_stat __user *vtstat = up;
|
||||
unsigned short state, mask;
|
||||
|
||||
/* Review: FIXME: Console lock ? */
|
||||
if (put_user(fg_console + 1, &vtstat->v_active))
|
||||
ret = -EFAULT;
|
||||
else {
|
||||
|
@ -960,6 +596,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
* Returns the first available (non-opened) console.
|
||||
*/
|
||||
case VT_OPENQRY:
|
||||
/* FIXME: locking ? - but then this is a stupid API */
|
||||
for (i = 0; i < MAX_NR_CONSOLES; ++i)
|
||||
if (! VT_IS_IN_USE(i))
|
||||
break;
|
||||
|
@ -973,7 +610,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
*/
|
||||
case VT_ACTIVATE:
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
if (arg == 0 || arg > MAX_NR_CONSOLES)
|
||||
ret = -ENXIO;
|
||||
else {
|
||||
|
@ -992,7 +629,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
struct vt_setactivate vsa;
|
||||
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
|
||||
sizeof(struct vt_setactivate))) {
|
||||
|
@ -1020,6 +657,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
if (ret)
|
||||
break;
|
||||
/* Commence switch and lock */
|
||||
/* Review set_console locks */
|
||||
set_console(vsa.console);
|
||||
}
|
||||
break;
|
||||
|
@ -1030,7 +668,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
*/
|
||||
case VT_WAITACTIVE:
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
if (arg == 0 || arg > MAX_NR_CONSOLES)
|
||||
ret = -ENXIO;
|
||||
else
|
||||
|
@ -1049,16 +687,17 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
*/
|
||||
case VT_RELDISP:
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
|
||||
console_lock();
|
||||
if (vc->vt_mode.mode != VT_PROCESS) {
|
||||
console_unlock();
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Switching-from response
|
||||
*/
|
||||
console_lock();
|
||||
if (vc->vt_newvt >= 0) {
|
||||
if (arg == 0)
|
||||
/*
|
||||
|
@ -1135,7 +774,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
|
||||
ushort ll,cc;
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
if (get_user(ll, &vtsizes->v_rows) ||
|
||||
get_user(cc, &vtsizes->v_cols))
|
||||
ret = -EFAULT;
|
||||
|
@ -1146,6 +785,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
|
||||
if (vc) {
|
||||
vc->vc_resize_user = 1;
|
||||
/* FIXME: review v tty lock */
|
||||
vc_resize(vc_cons[i].d, cc, ll);
|
||||
}
|
||||
}
|
||||
|
@ -1159,7 +799,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
struct vt_consize __user *vtconsize = up;
|
||||
ushort ll,cc,vlin,clin,vcol,ccol;
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
if (!access_ok(VERIFY_READ, vtconsize,
|
||||
sizeof(struct vt_consize))) {
|
||||
ret = -EFAULT;
|
||||
|
@ -1215,7 +855,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
|
||||
case PIO_FONT: {
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
op.op = KD_FONT_OP_SET;
|
||||
op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
|
||||
op.width = 8;
|
||||
|
@ -1256,7 +896,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
case PIO_FONTRESET:
|
||||
{
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
|
||||
#ifdef BROKEN_GRAPHICS_PROGRAMS
|
||||
/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
|
||||
|
@ -1282,7 +922,7 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
break;
|
||||
}
|
||||
if (!perm && op.op != KD_FONT_OP_GET)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
ret = con_font_op(vc, &op);
|
||||
if (ret)
|
||||
break;
|
||||
|
@ -1294,50 +934,65 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
case PIO_SCRNMAP:
|
||||
if (!perm)
|
||||
ret = -EPERM;
|
||||
else
|
||||
else {
|
||||
tty_lock();
|
||||
ret = con_set_trans_old(up);
|
||||
tty_unlock();
|
||||
}
|
||||
break;
|
||||
|
||||
case GIO_SCRNMAP:
|
||||
tty_lock();
|
||||
ret = con_get_trans_old(up);
|
||||
tty_unlock();
|
||||
break;
|
||||
|
||||
case PIO_UNISCRNMAP:
|
||||
if (!perm)
|
||||
ret = -EPERM;
|
||||
else
|
||||
else {
|
||||
tty_lock();
|
||||
ret = con_set_trans_new(up);
|
||||
tty_unlock();
|
||||
}
|
||||
break;
|
||||
|
||||
case GIO_UNISCRNMAP:
|
||||
tty_lock();
|
||||
ret = con_get_trans_new(up);
|
||||
tty_unlock();
|
||||
break;
|
||||
|
||||
case PIO_UNIMAPCLR:
|
||||
{ struct unimapinit ui;
|
||||
if (!perm)
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
else
|
||||
else {
|
||||
tty_lock();
|
||||
con_clear_unimap(vc, &ui);
|
||||
tty_unlock();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PIO_UNIMAP:
|
||||
case GIO_UNIMAP:
|
||||
tty_lock();
|
||||
ret = do_unimap_ioctl(cmd, up, perm, vc);
|
||||
tty_unlock();
|
||||
break;
|
||||
|
||||
case VT_LOCKSWITCH:
|
||||
if (!capable(CAP_SYS_TTY_CONFIG))
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
vt_dont_switch = 1;
|
||||
break;
|
||||
case VT_UNLOCKSWITCH:
|
||||
if (!capable(CAP_SYS_TTY_CONFIG))
|
||||
goto eperm;
|
||||
return -EPERM;
|
||||
vt_dont_switch = 0;
|
||||
break;
|
||||
case VT_GETHIFONTMASK:
|
||||
|
@ -1351,17 +1006,13 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
ret = -ENOIOCTLCMD;
|
||||
}
|
||||
out:
|
||||
tty_unlock();
|
||||
return ret;
|
||||
eperm:
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
void reset_vc(struct vc_data *vc)
|
||||
{
|
||||
vc->vc_mode = KD_TEXT;
|
||||
kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
|
||||
vt_reset_unicode(vc->vc_num);
|
||||
vc->vt_mode.mode = VT_AUTO;
|
||||
vc->vt_mode.waitv = 0;
|
||||
vc->vt_mode.relsig = 0;
|
||||
|
@ -1384,6 +1035,7 @@ void vc_SAK(struct work_struct *work)
|
|||
console_lock();
|
||||
vc = vc_con->d;
|
||||
if (vc) {
|
||||
/* FIXME: review tty ref counting */
|
||||
tty = vc->port.tty;
|
||||
/*
|
||||
* SAK should also work in all raw modes and reset
|
||||
|
@ -1516,8 +1168,6 @@ long vt_compat_ioctl(struct tty_struct *tty,
|
|||
|
||||
console = vc->vc_num;
|
||||
|
||||
tty_lock();
|
||||
|
||||
if (!vc_cons_allocated(console)) { /* impossible? */
|
||||
ret = -ENOIOCTLCMD;
|
||||
goto out;
|
||||
|
@ -1546,7 +1196,9 @@ long vt_compat_ioctl(struct tty_struct *tty,
|
|||
|
||||
case PIO_UNIMAP:
|
||||
case GIO_UNIMAP:
|
||||
tty_lock();
|
||||
ret = compat_unimap_ioctl(cmd, up, perm, vc);
|
||||
tty_unlock();
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -1583,11 +1235,9 @@ long vt_compat_ioctl(struct tty_struct *tty,
|
|||
goto fallback;
|
||||
}
|
||||
out:
|
||||
tty_unlock();
|
||||
return ret;
|
||||
|
||||
fallback:
|
||||
tty_unlock();
|
||||
return vt_ioctl(tty, cmd, arg);
|
||||
}
|
||||
|
||||
|
@ -1773,13 +1423,10 @@ int vt_move_to_console(unsigned int vt, int alloc)
|
|||
return -EIO;
|
||||
}
|
||||
console_unlock();
|
||||
tty_lock();
|
||||
if (vt_waitactive(vt + 1)) {
|
||||
pr_debug("Suspend: Can't switch VCs.");
|
||||
tty_unlock();
|
||||
return -EINTR;
|
||||
}
|
||||
tty_unlock();
|
||||
return prev;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue