summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-23 12:23:20 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-23 12:23:20 -0700
commit99dff5856220a02b8711f2e8746413ea6e53ccf6 (patch)
treed8bae7ccdf8f7ad5221b053bb74a6220df996b3a /drivers
parentbb74e8ca352eecefdc5c1a9ebab01f18aa2f6f3c (diff)
parentd9a0fbfd7bc5d2c42f0fa9bcbdab62c4942d0388 (diff)
Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6: (48 commits) serial: 8250_pci: add support for Cronyx Omega PCI multiserial board. tty/serial: Fix break handling for PORT_TEGRA tty/serial: Add explicit PORT_TEGRA type n_tracerouter and n_tracesink ldisc additions. Intel PTI implementaiton of MIPI 1149.7. Kernel documentation for the PTI feature. export kernel call get_task_comm(). tty: Remove to support serial for S5P6442 pch_phub: Support new device ML7223 8250_pci: Add support for the Digi/IBM PCIe 2-port Adapter ASoC: Update cx20442 for TTY API change pch_uart: Support new device ML7223 IOH parport: Use request_muxed_region for IT87 probe and lock tty/serial: add support for Xilinx PS UART n_gsm: Use print_hex_dump_bytes drivers/tty/moxa.c: Put correct tty value TTY: tty_io, annotate locking functions TTY: serial_core, remove superfluous set_task_state TTY: serial_core, remove invalid test Char: moxa, fix locking in moxa_write ... Fix up trivial conflicts in drivers/bluetooth/hci_ldisc.c and drivers/tty/serial/Makefile. I did the hci_ldisc thing as an evil merge, cleaning things up.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/hci_ldisc.c19
-rw-r--r--drivers/input/serio/serport.c10
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c8
-rw-r--r--drivers/misc/Kconfig25
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/pch_phub.c153
-rw-r--r--drivers/misc/pti.c980
-rw-r--r--drivers/misc/ti-st/st_core.c6
-rw-r--r--drivers/net/caif/caif_serial.c6
-rw-r--r--drivers/net/can/slcan.c9
-rw-r--r--drivers/net/hamradio/6pack.c8
-rw-r--r--drivers/net/hamradio/mkiss.c11
-rw-r--r--drivers/net/irda/irtty-sir.c16
-rw-r--r--drivers/net/ppp_async.c6
-rw-r--r--drivers/net/ppp_synctty.c6
-rw-r--r--drivers/net/slip.c11
-rw-r--r--drivers/net/wan/x25_asy.c7
-rw-r--r--drivers/parport/parport_pc.c2
-rw-r--r--drivers/tty/Kconfig31
-rw-r--r--drivers/tty/Makefile2
-rw-r--r--drivers/tty/amiserial.c2
-rw-r--r--drivers/tty/cyclades.c5
-rw-r--r--drivers/tty/ipwireless/Makefile2
-rw-r--r--drivers/tty/moxa.c18
-rw-r--r--drivers/tty/n_gsm.c41
-rw-r--r--drivers/tty/n_hdlc.c18
-rw-r--r--drivers/tty/n_r3964.c10
-rw-r--r--drivers/tty/n_tracerouter.c243
-rw-r--r--drivers/tty/n_tracesink.c238
-rw-r--r--drivers/tty/n_tracesink.h36
-rw-r--r--drivers/tty/n_tty.c61
-rw-r--r--drivers/tty/nozomi.c29
-rw-r--r--drivers/tty/pty.c35
-rw-r--r--drivers/tty/rocket.c47
-rw-r--r--drivers/tty/serial/21285.c2
-rw-r--r--drivers/tty/serial/8250.c44
-rw-r--r--drivers/tty/serial/8250.h3
-rw-r--r--drivers/tty/serial/8250_accent.c2
-rw-r--r--drivers/tty/serial/8250_boca.c2
-rw-r--r--drivers/tty/serial/8250_exar_st16c554.c2
-rw-r--r--drivers/tty/serial/8250_fourport.c2
-rw-r--r--drivers/tty/serial/8250_hub6.c2
-rw-r--r--drivers/tty/serial/8250_mca.c2
-rw-r--r--drivers/tty/serial/8250_pci.c53
-rw-r--r--drivers/tty/serial/8250_pnp.c2
-rw-r--r--drivers/tty/serial/Kconfig27
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/altera_uart.c26
-rw-r--r--drivers/tty/serial/amba-pl010.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c2
-rw-r--r--drivers/tty/serial/atmel_serial.c2
-rw-r--r--drivers/tty/serial/clps711x.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart.h2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h2
-rw-r--r--drivers/tty/serial/ifx6x60.c2
-rw-r--r--drivers/tty/serial/imx.c2
-rw-r--r--drivers/tty/serial/msm_serial.c2
-rw-r--r--drivers/tty/serial/msm_serial.h2
-rw-r--r--drivers/tty/serial/msm_smd_tty.c3
-rw-r--r--drivers/tty/serial/netx-serial.c2
-rw-r--r--drivers/tty/serial/pch_uart.c8
-rw-r--r--drivers/tty/serial/pmac_zilog.c2
-rw-r--r--drivers/tty/serial/pxa.c2
-rw-r--r--drivers/tty/serial/s3c2400.c3
-rw-r--r--drivers/tty/serial/s3c2410.c3
-rw-r--r--drivers/tty/serial/s3c2412.c3
-rw-r--r--drivers/tty/serial/s3c2440.c3
-rw-r--r--drivers/tty/serial/s3c24a0.c3
-rw-r--r--drivers/tty/serial/s3c6400.c3
-rw-r--r--drivers/tty/serial/s5pv210.c3
-rw-r--r--drivers/tty/serial/sa1100.c2
-rw-r--r--drivers/tty/serial/samsung.c3
-rw-r--r--drivers/tty/serial/samsung.h3
-rw-r--r--drivers/tty/serial/sb1250-duart.c2
-rw-r--r--drivers/tty/serial/serial_core.c90
-rw-r--r--drivers/tty/serial/serial_ks8695.c2
-rw-r--r--drivers/tty/serial/serial_txx9.c2
-rw-r--r--drivers/tty/serial/sh-sci.c2
-rw-r--r--drivers/tty/serial/vt8500_serial.c2
-rw-r--r--drivers/tty/serial/xilinx_uartps.c1113
-rw-r--r--drivers/tty/synclink.c2
-rw-r--r--drivers/tty/tty_buffer.c15
-rw-r--r--drivers/tty/tty_io.c53
-rw-r--r--drivers/tty/tty_ioctl.c2
-rw-r--r--drivers/tty/tty_ldisc.c13
-rw-r--r--drivers/tty/tty_mutex.c3
-rw-r--r--drivers/tty/vt/keyboard.c2
-rw-r--r--drivers/tty/vt/selection.c5
-rw-r--r--drivers/tty/vt/vc_screen.c2
-rw-r--r--drivers/tty/vt/vt.c13
-rw-r--r--drivers/tty/vt/vt_ioctl.c25
95 files changed, 3185 insertions, 509 deletions
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 320f71803a2..b3f01996318 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -355,26 +355,29 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
* flags pointer to flags for data
* count count of received data in bytes
*
- * Return Value: None
+ * Return Value: Number of bytes received
*/
-static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
+static unsigned int hci_uart_tty_receive(struct tty_struct *tty,
+ const u8 *data, char *flags, int count)
{
- int ret;
struct hci_uart *hu = (void *)tty->disc_data;
+ int received;
if (!hu || tty != hu->tty)
- return;
+ return -ENODEV;
if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
- return;
+ return -EINVAL;
spin_lock(&hu->rx_lock);
- ret = hu->proto->recv(hu, (void *) data, count);
- if (ret > 0)
- hu->hdev->stat.byte_rx += count;
+ received = hu->proto->recv(hu, (void *) data, count);
+ if (received > 0)
+ hu->hdev->stat.byte_rx += received;
spin_unlock(&hu->rx_lock);
tty_unthrottle(tty);
+
+ return received;
}
static int hci_uart_register_dev(struct hci_uart *hu)
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 8755f5f3ad3..f3698967edf 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -120,17 +120,21 @@ static void serport_ldisc_close(struct tty_struct *tty)
* 'interrupt' routine.
*/
-static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+static unsigned int serport_ldisc_receive(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct serport *serport = (struct serport*) tty->disc_data;
unsigned long flags;
unsigned int ch_flags;
+ int ret = 0;
int i;
spin_lock_irqsave(&serport->lock, flags);
- if (!test_bit(SERPORT_ACTIVE, &serport->flags))
+ if (!test_bit(SERPORT_ACTIVE, &serport->flags)) {
+ ret = -EINVAL;
goto out;
+ }
for (i = 0; i < count; i++) {
switch (fp[i]) {
@@ -152,6 +156,8 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
out:
spin_unlock_irqrestore(&serport->lock, flags);
+
+ return ret == 0 ? count : ret;
}
/*
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index 86a5c4f7775..1d44d470897 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -674,7 +674,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
* cflags buffer containing error flags for received characters (ignored)
* count number of received characters
*/
-static void
+static unsigned int
gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
char *cflags, int count)
{
@@ -683,12 +683,12 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
struct inbuf_t *inbuf;
if (!cs)
- return;
+ return -ENODEV;
inbuf = cs->inbuf;
if (!inbuf) {
dev_err(cs->dev, "%s: no inbuf\n", __func__);
cs_put(cs);
- return;
+ return -EINVAL;
}
tail = inbuf->tail;
@@ -725,6 +725,8 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
gigaset_schedule_event(cs);
cs_put(cs);
+
+ return count;
}
/*
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index d80dcdee88f..4e349cd98bc 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -144,6 +144,19 @@ config PHANTOM
If you choose to build module, its name will be phantom. If unsure,
say N here.
+config INTEL_MID_PTI
+ tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard"
+ default n
+ help
+ The PTI (Parallel Trace Interface) driver directs
+ trace data routed from various parts in the system out
+ through an Intel Penwell PTI port and out of the mobile
+ device for analysis with a debugging tool (Lauterbach or Fido).
+
+ You should select this driver if the target kernel is meant for
+ an Intel Atom (non-netbook) mobile device containing a MIPI
+ P1149.7 standard implementation.
+
config SGI_IOC4
tristate "SGI IOC4 Base IO support"
depends on PCI
@@ -459,7 +472,7 @@ config BMP085
module will be called bmp085.
config PCH_PHUB
- tristate "PCH Packet Hub of Intel Topcliff / OKI SEMICONDUCTOR ML7213"
+ tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) PHUB"
depends on PCI
help
This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of
@@ -467,10 +480,12 @@ config PCH_PHUB
processor. The Topcliff has MAC address and Option ROM data in SROM.
This driver can access MAC address and Option ROM data in SROM.
- This driver also can be used for OKI SEMICONDUCTOR's ML7213 which is
- for IVI(In-Vehicle Infotainment) use.
- ML7213 is companion chip for Intel Atom E6xx series.
- ML7213 is completely compatible for Intel EG20T PCH.
+ This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+ Output Hub), ML7213 and ML7223.
+ ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
+ for MP(Media Phone) use.
+ ML7213/ML7223 is companion chip for Intel Atom E6xx series.
+ ML7213/ML7223 is completely compatible for Intel EG20T PCH.
To compile this driver as a module, choose M here: the module will
be called pch_phub.
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 848e8464faa..5f03172cc0b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o
obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o
obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o
+0bj-$(CONFIG_INTEL_MID_PTI) += pti.o
obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index a19cb710a24..5fe79df4483 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -34,12 +34,18 @@
#define PHUB_TIMEOUT 0x05 /* Time out value for Status Register */
#define PCH_PHUB_ROM_WRITE_ENABLE 0x01 /* Enabling for writing ROM */
#define PCH_PHUB_ROM_WRITE_DISABLE 0x00 /* Disabling for writing ROM */
-#define PCH_PHUB_MAC_START_ADDR 0x20C /* MAC data area start address offset */
-#define PCH_PHUB_ROM_START_ADDR_EG20T 0x14 /* ROM data area start address offset
+#define PCH_PHUB_MAC_START_ADDR_EG20T 0x14 /* MAC data area start address
+ offset */
+#define PCH_PHUB_MAC_START_ADDR_ML7223 0x20C /* MAC data area start address
+ offset */
+#define PCH_PHUB_ROM_START_ADDR_EG20T 0x80 /* ROM data area start address offset
(Intel EG20T PCH)*/
#define PCH_PHUB_ROM_START_ADDR_ML7213 0x400 /* ROM data area start address
offset(OKI SEMICONDUCTOR ML7213)
*/
+#define PCH_PHUB_ROM_START_ADDR_ML7223 0x400 /* ROM data area start address
+ offset(OKI SEMICONDUCTOR ML7223)
+ */
/* MAX number of INT_REDUCE_CONTROL registers */
#define MAX_NUM_INT_REDUCE_CONTROL_REG 128
@@ -63,6 +69,10 @@
#define PCI_VENDOR_ID_ROHM 0x10db
#define PCI_DEVICE_ID_ROHM_ML7213_PHUB 0x801A
+/* Macros for ML7223 */
+#define PCI_DEVICE_ID_ROHM_ML7223_mPHUB 0x8012 /* for Bus-m */
+#define PCI_DEVICE_ID_ROHM_ML7223_nPHUB 0x8002 /* for Bus-n */
+
/* SROM ACCESS Macro */
#define PCH_WORD_ADDR_MASK (~((1 << 2) - 1))
@@ -100,6 +110,9 @@
* @clkcfg_reg: CLK CFG register val
* @pch_phub_base_address: Register base address
* @pch_phub_extrom_base_address: external rom base address
+ * @pch_mac_start_address: MAC address area start address
+ * @pch_opt_rom_start_address: Option ROM start address
+ * @ioh_type: Save IOH type
*/
struct pch_phub_reg {
u32 phub_id_reg;
@@ -117,6 +130,9 @@ struct pch_phub_reg {
u32 clkcfg_reg;
void __iomem *pch_phub_base_address;
void __iomem *pch_phub_extrom_base_address;
+ u32 pch_mac_start_address;
+ u32 pch_opt_rom_start_address;
+ int ioh_type;
};
/* SROM SPEC for MAC address assignment offset */
@@ -319,7 +335,7 @@ static void pch_phub_read_serial_rom_val(struct pch_phub_reg *chip,
{
unsigned int mem_addr;
- mem_addr = PCH_PHUB_ROM_START_ADDR_EG20T +
+ mem_addr = chip->pch_mac_start_address +
pch_phub_mac_offset[offset_address];
pch_phub_read_serial_rom(chip, mem_addr, data);
@@ -336,7 +352,7 @@ static int pch_phub_write_serial_rom_val(struct pch_phub_reg *chip,
int retval;
unsigned int mem_addr;
- mem_addr = PCH_PHUB_ROM_START_ADDR_EG20T +
+ mem_addr = chip->pch_mac_start_address +
pch_phub_mac_offset[offset_address];
retval = pch_phub_write_serial_rom(chip, mem_addr, data);
@@ -384,6 +400,48 @@ static int pch_phub_gbe_serial_rom_conf(struct pch_phub_reg *chip)
return retval;
}
+/* pch_phub_gbe_serial_rom_conf_mp - makes SerialROM header format configuration
+ * for Gigabit Ethernet MAC address
+ */
+static int pch_phub_gbe_serial_rom_conf_mp(struct pch_phub_reg *chip)
+{
+ int retval;
+ u32 offset_addr;
+
+ offset_addr = 0x200;
+ retval = pch_phub_write_serial_rom(chip, 0x03 + offset_addr, 0xbc);
+ retval |= pch_phub_write_serial_rom(chip, 0x02 + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x01 + offset_addr, 0x40);
+ retval |= pch_phub_write_serial_rom(chip, 0x00 + offset_addr, 0x02);
+
+ retval |= pch_phub_write_serial_rom(chip, 0x07 + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x06 + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x05 + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x04 + offset_addr, 0x80);
+
+ retval |= pch_phub_write_serial_rom(chip, 0x0b + offset_addr, 0xbc);
+ retval |= pch_phub_write_serial_rom(chip, 0x0a + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x09 + offset_addr, 0x40);
+ retval |= pch_phub_write_serial_rom(chip, 0x08 + offset_addr, 0x18);
+
+ retval |= pch_phub_write_serial_rom(chip, 0x13 + offset_addr, 0xbc);
+ retval |= pch_phub_write_serial_rom(chip, 0x12 + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x11 + offset_addr, 0x40);
+ retval |= pch_phub_write_serial_rom(chip, 0x10 + offset_addr, 0x19);
+
+ retval |= pch_phub_write_serial_rom(chip, 0x1b + offset_addr, 0xbc);
+ retval |= pch_phub_write_serial_rom(chip, 0x1a + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x19 + offset_addr, 0x40);
+ retval |= pch_phub_write_serial_rom(chip, 0x18 + offset_addr, 0x3a);
+
+ retval |= pch_phub_write_serial_rom(chip, 0x1f + offset_addr, 0x01);
+ retval |= pch_phub_write_serial_rom(chip, 0x1e + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x1d + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x1c + offset_addr, 0x00);
+
+ return retval;
+}
+
/**
* pch_phub_read_gbe_mac_addr() - Read Gigabit Ethernet MAC address
* @offset_address: Gigabit Ethernet MAC address offset value.
@@ -406,7 +464,10 @@ static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data)
int retval;
int i;
- retval = pch_phub_gbe_serial_rom_conf(chip);
+ if (chip->ioh_type == 1) /* EG20T */
+ retval = pch_phub_gbe_serial_rom_conf(chip);
+ else /* ML7223 */
+ retval = pch_phub_gbe_serial_rom_conf_mp(chip);
if (retval)
return retval;
@@ -441,12 +502,16 @@ static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj,
}
/* Get Rom signature */
- pch_phub_read_serial_rom(chip, 0x80, (unsigned char *)&rom_signature);
+ pch_phub_read_serial_rom(chip, chip->pch_opt_rom_start_address,
+ (unsigned char *)&rom_signature);
rom_signature &= 0xff;
- pch_phub_read_serial_rom(chip, 0x81, (unsigned char *)&tmp);
+ pch_phub_read_serial_rom(chip, chip->pch_opt_rom_start_address + 1,
+ (unsigned char *)&tmp);
rom_signature |= (tmp & 0xff) << 8;
if (rom_signature == 0xAA55) {
- pch_phub_read_serial_rom(chip, 0x82, &rom_length);
+ pch_phub_read_serial_rom(chip,
+ chip->pch_opt_rom_start_address + 2,
+ &rom_length);
orom_size = rom_length * 512;
if (orom_size < off) {
addr_offset = 0;
@@ -458,8 +523,9 @@ static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj,
}
for (addr_offset = 0; addr_offset < count; addr_offset++) {
- pch_phub_read_serial_rom(chip, 0x80 + addr_offset + off,
- &buf[addr_offset]);
+ pch_phub_read_serial_rom(chip,
+ chip->pch_opt_rom_start_address + addr_offset + off,
+ &buf[addr_offset]);
}
} else {
err = -ENODATA;
@@ -502,8 +568,9 @@ static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj,
if (PCH_PHUB_OROM_SIZE < off + addr_offset)
goto return_ok;
- ret = pch_phub_write_serial_rom(chip, 0x80 + addr_offset + off,
- buf[addr_offset]);
+ ret = pch_phub_write_serial_rom(chip,
+ chip->pch_opt_rom_start_address + addr_offset + off,
+ buf[addr_offset]);
if (ret) {
err = ret;
goto return_err;
@@ -603,19 +670,22 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,
dev_dbg(&pdev->dev, "%s : pci_iomap SUCCESS and value "
"in pch_phub_base_address variable is %p\n", __func__,
chip->pch_phub_base_address);
- chip->pch_phub_extrom_base_address = pci_map_rom(pdev, &rom_size);
- if (chip->pch_phub_extrom_base_address == 0) {
- dev_err(&pdev->dev, "%s : pci_map_rom FAILED", __func__);
- ret = -ENOMEM;
- goto err_pci_map;
+ if (id->driver_data != 3) {
+ chip->pch_phub_extrom_base_address =\
+ pci_map_rom(pdev, &rom_size);
+ if (chip->pch_phub_extrom_base_address == 0) {
+ dev_err(&pdev->dev, "%s: pci_map_rom FAILED", __func__);
+ ret = -ENOMEM;
+ goto err_pci_map;
+ }
+ dev_dbg(&pdev->dev, "%s : "
+ "pci_map_rom SUCCESS and value in "
+ "pch_phub_extrom_base_address variable is %p\n",
+ __func__, chip->pch_phub_extrom_base_address);
}
- dev_dbg(&pdev->dev, "%s : "
- "pci_map_rom SUCCESS and value in "
- "pch_phub_extrom_base_address variable is %p\n", __func__,
- chip->pch_phub_extrom_base_address);
- if (id->driver_data == 1) {
+ if (id->driver_data == 1) { /* EG20T PCH */
retval = sysfs_create_file(&pdev->dev.kobj,
&dev_attr_pch_mac.attr);
if (retval)
@@ -642,7 +712,9 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,
iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14);
/* set the interrupt delay value */
iowrite32(0x25, chip->pch_phub_base_address + 0x44);
- } else if (id->driver_data == 2) {
+ chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T;
+ chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T;
+ } else if (id->driver_data == 2) { /* ML7213 IOH */
retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr);
if (retval)
goto err_sysfs_create;
@@ -653,7 +725,38 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,
* Device8(USB OHCI #0/ USB EHCI #0):a
*/
iowrite32(0x000affa0, chip->pch_phub_base_address + 0x14);
+ chip->pch_opt_rom_start_address =\
+ PCH_PHUB_ROM_START_ADDR_ML7213;
+ } else if (id->driver_data == 3) { /* ML7223 IOH Bus-m*/
+ /* set the prefech value
+ * Device8(GbE)
+ */
+ iowrite32(0x000a0000, chip->pch_phub_base_address + 0x14);
+ chip->pch_opt_rom_start_address =\
+ PCH_PHUB_ROM_START_ADDR_ML7223;
+ chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223;
+ } else if (id->driver_data == 4) { /* ML7223 IOH Bus-n*/
+ retval = sysfs_create_file(&pdev->dev.kobj,
+ &dev_attr_pch_mac.attr);
+ if (retval)
+ goto err_sysfs_create;
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr);
+ if (retval)
+ goto exit_bin_attr;
+ /* set the prefech value
+ * Device2(USB OHCI #0,1,2,3/ USB EHCI #0):a
+ * Device4(SDIO #0,1):f
+ * Device6(SATA 2):f
+ */
+ iowrite32(0x0000ffa0, chip->pch_phub_base_address + 0x14);
+ /* set the interrupt delay value */
+ iowrite32(0x25, chip->pch_phub_base_address + 0x140);
+ chip->pch_opt_rom_start_address =\
+ PCH_PHUB_ROM_START_ADDR_ML7223;
+ chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223;
}
+
+ chip->ioh_type = id->driver_data;
pci_set_drvdata(pdev, chip);
return 0;
@@ -733,6 +836,8 @@ static int pch_phub_resume(struct pci_dev *pdev)
static struct pci_device_id pch_phub_pcidev_id[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH1_PHUB), 1, },
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_mPHUB), 3, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_nPHUB), 4, },
{ }
};
MODULE_DEVICE_TABLE(pci, pch_phub_pcidev_id);
@@ -759,5 +864,5 @@ static void __exit pch_phub_pci_exit(void)
module_init(pch_phub_pci_init);
module_exit(pch_phub_pci_exit);
-MODULE_DESCRIPTION("PCH Packet Hub PCI Driver");
+MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR IOH(ML7213/ML7223) PHUB");
MODULE_LICENSE("GPL");
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
new file mode 100644
index 00000000000..bb6f9255c17
--- /dev/null
+++ b/drivers/misc/pti.c
@@ -0,0 +1,980 @@
+/*
+ * pti.c - PTI driver for cJTAG data extration
+ *
+ * Copyright (C) Intel 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * The PTI (Parallel Trace Interface) driver directs trace data routed from
+ * various parts in the system out through the Intel Penwell PTI port and
+ * out of the mobile device for analysis with a debugging tool
+ * (Lauterbach, Fido). This is part of a solution for the MIPI P1149.7,
+ * compact JTAG, standard.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/pti.h>
+
+#define DRIVERNAME "pti"
+#define PCINAME "pciPTI"
+#define TTYNAME "ttyPTI"
+#define CHARNAME "pti"
+#define PTITTY_MINOR_START 0
+#define PTITTY_MINOR_NUM 2
+#define MAX_APP_IDS 16 /* 128 channel ids / u8 bit size */
+#define MAX_OS_IDS 16 /* 128 channel ids / u8 bit size */
+#define MAX_MODEM_IDS 16 /* 128 channel ids / u8 bit size */
+#define MODEM_BASE_ID 71 /* modem master ID address */
+#define CONTROL_ID 72 /* control master ID address */
+#define CONSOLE_ID 73 /* console master ID address */
+#define OS_BASE_ID 74 /* base OS master ID address */
+#define APP_BASE_ID 80 /* base App master ID address */
+#define CONTROL_FRAME_LEN 32 /* PTI control frame maximum size */
+#define USER_COPY_SIZE 8192 /* 8Kb buffer for user space copy */
+#define APERTURE_14 0x3800000 /* offset to first OS write addr */
+#define APERTURE_LEN 0x400000 /* address length */
+
+struct pti_tty {
+ struct pti_masterchannel *mc;
+};
+
+struct pti_dev {
+ struct tty_port port;
+ unsigned long pti_addr;
+ unsigned long aperture_base;
+ void __iomem *pti_ioaddr;
+ u8 ia_app[MAX_APP_IDS];
+ u8 ia_os[MAX_OS_IDS];
+ u8 ia_modem[MAX_MODEM_IDS];
+};
+
+/*
+ * This protects access to ia_app, ia_os, and ia_modem,
+ * which keeps track of channels allocated in
+ * an aperture write id.
+ */
+static DEFINE_MUTEX(alloclock);
+
+static struct pci_device_id pci_ids[] __devinitconst = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)},
+ {0}
+};
+
+static struct tty_driver *pti_tty_driver;
+static struct pti_dev *drv_data;
+
+static unsigned int pti_console_channel;
+static unsigned int pti_control_channel;
+
+/**
+ * pti_write_to_aperture()- The private write function to PTI HW.
+ *
+ * @mc: The 'aperture'. It's part of a write address that holds
+ * a master and channel ID.
+ * @buf: Data being written to the HW that will ultimately be seen
+ * in a debugging tool (Fido, Lauterbach).
+ * @len: Size of buffer.
+ *
+ * Since each aperture is specified by a unique
+ * master/channel ID, no two processes will be writing
+ * to the same aperture at the same time so no lock is required. The
+ * PTI-Output agent will send these out in the order that they arrived, and
+ * thus, it will intermix these messages. The debug tool can then later
+ * regroup the appropriate message segments together reconstituting each
+ * message.
+ */
+static void pti_write_to_aperture(struct pti_masterchannel *mc,
+ u8 *buf,
+ int len)
+{
+ int dwordcnt;
+ int final;
+ int i;
+ u32 ptiword;
+ u32 __iomem *aperture;
+ u8 *p = buf;
+
+ /*
+ * calculate the aperture offset from the base using the master and
+ * channel id's.
+ */
+ aperture = drv_data->pti_ioaddr + (mc->master << 15)
+ + (mc->channel << 8);
+
+ dwordcnt = len >> 2;
+ final = len - (dwordcnt << 2); /* final = trailing bytes */
+ if (final == 0 && dwordcnt != 0) { /* always need a final dword */
+ final += 4;
+ dwordcnt--;
+ }
+
+ for (i = 0; i < dwordcnt; i++) {
+ ptiword = be32_to_cpu(*(u32 *)p);
+ p += 4;
+ iowrite32(ptiword, aperture);
+ }
+
+ aperture += PTI_LASTDWORD_DTS; /* adding DTS signals that is EOM */
+
+ ptiword = 0;
+ for (i = 0; i < final; i++)
+ ptiword |= *p++ << (24-(8*i));
+
+ iowrite32(ptiword, aperture);
+ return;
+}
+
+/**
+ * pti_control_frame_built_and_sent()- control frame build and send function.
+ *
+ * @mc: The master / channel structure on which the function
+ * built a control frame.
+ *
+ * To be able to post process the PTI contents on host side, a control frame
+ * is added before sending any PTI content. So the host side knows on
+ * each PTI frame the name of the thread using a dedicated master / channel.
+ * The thread name is retrieved from the 'current' global variable.
+ * This function builds this frame and sends it to a master ID CONTROL_ID.
+ * The overhead is only 32 bytes since the driver only writes to HW
+ * in 32 byte chunks.
+ */
+
+static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc)
+{
+ struct pti_masterchannel mccontrol = {.master = CONTROL_ID,
+ .channel = 0};
+ const char *control_format = "%3d %3d %s";
+ u8 control_frame[CONTROL_FRAME_LEN];
+
+ /*
+ * Since we access the comm member in current's task_struct,
+ * we only need to be as large as what 'comm' in that
+ * structure is.
+ */
+ char comm[TASK_COMM_LEN];
+
+ if (!in_interrupt())
+ get_task_comm(comm, current);
+ else
+ strncpy(comm, "Interrupt", TASK_COMM_LEN);
+
+ /* Absolutely ensure our buffer is zero terminated. */
+ comm[TASK_COMM_LEN-1] = 0;
+
+ mccontrol.channel = pti_control_channel;
+ pti_control_channel = (pti_control_channel + 1) & 0x7f;
+
+ snprintf(control_frame, CONTROL_FRAME_LEN, control_format, mc->master,
+ mc->channel, comm);
+ pti_write_to_aperture(&mccontrol, control_frame, strlen(control_frame));
+}
+
+/**
+ * pti_write_full_frame_to_aperture()- high level function to
+ * write to PTI.
+ *
+ * @mc: The 'aperture'. It's part of a write address that holds
+ * a master and channel ID.
+ * @buf: Data being written to the HW that will ultimately be seen
+ * in a debugging tool (Fido, Lauterbach).
+ * @len: Size of buffer.
+ *
+ * All threads sending data (either console, user space application, ...)
+ * are calling the high level function to write to PTI meaning that it is
+ * possible to add a control frame before sending the content.
+ */
+static void pti_write_full_frame_to_aperture(struct pti_masterchannel *mc,
+ const unsigned char *buf,
+ int len)
+{
+ pti_control_frame_built_and_sent(mc);
+ pti_write_to_aperture(mc, (u8 *)buf, len);
+}
+
+/**
+ * get_id()- Allocate a master and channel ID.
+ *
+ * @id_array: an array of bits representing what channel
+ * id's are allocated for writing.
+ * @max_ids: The max amount of available write IDs to use.
+ * @base_id: The starting SW channel ID, based on the Intel
+ * PTI arch.
+ *
+ * Returns:
+ * pti_masterchannel struct with master, channel ID address
+ * 0 for error
+ *
+ * Each bit in the arrays ia_app and ia_os correspond to a master and
+ * channel id. The bit is one if the id is taken and 0 if free. For
+ * every master there are 128 channel id's.
+ */
+static struct pti_masterchannel *get_id(u8 *id_array, int max_ids, int base_id)
+{
+ struct pti_masterchannel *mc;
+ int i, j, mask;
+
+ mc = kmalloc(sizeof(struct pti_masterchannel), GFP_KERNEL);
+ if (mc == NULL)
+ return NULL;
+
+ /* look for a byte with a free bit */
+ for (i = 0; i < max_ids; i++)
+ if (id_array[i] != 0xff)
+ break;
+ if (i == max_ids) {
+ kfree(mc);
+ return NULL;
+ }
+ /* find the bit in the 128 possible channel opportunities */
+ mask = 0x80;
+ for (j = 0; j < 8; j++) {
+ if ((id_array[i] & mask) == 0)
+ break;
+ mask >>= 1;
+ }
+
+ /* grab it */
+ id_array[i] |= mask;
+ mc->master = base_id;
+ mc->channel = ((i & 0xf)<<3) + j;
+ /* write new master Id / channel Id allocation to channel control */
+ pti_control_frame_built_and_sent(mc);
+ return mc;
+}
+
+/*
+ * The following three functions:
+ * pti_request_mastercahannel(), mipi_release_masterchannel()
+ * and pti_writedata() are an API for other kernel drivers to
+ * access PTI.
+ */
+
+/**
+ * pti_request_masterchannel()- Kernel API function used to allocate
+ * a master, channel ID address
+ * to write to PTI HW.
+ *
+ * @type: 0- request Application master, channel aperture ID write address.
+ * 1- request OS master, channel aperture ID write
+ * address.
+ * 2- request Modem master, channel aperture ID
+ * write address.
+ * Other values, error.
+ *
+ * Returns:
+ * pti_masterchannel struct
+ * 0 for error
+ */
+struct pti_masterchannel *pti_request_masterchannel(u8 type)
+{
+ struct pti_masterchannel *mc;
+
+ mutex_lock(&alloclock);
+
+ switch (type) {
+
+ case 0:
+ mc = get_id(drv_data->ia_app, MAX_APP_IDS, APP_BASE_ID);
+ break;
+
+ case 1:
+ mc = get_id(drv_data->ia_os, MAX_OS_IDS, OS_BASE_ID);
+ break;
+
+ case 2:
+ mc = get_id(drv_data->ia_modem, MAX_MODEM_IDS, MODEM_BASE_ID);
+ break;
+ default:
+ mc = NULL;
+ }
+
+ mutex_unlock(&alloclock);
+ return mc;
+}
+EXPORT_SYMBOL_GPL(pti_request_masterchannel);
+
+/**
+ * pti_release_masterchannel()- Kernel API function used to release
+ * a master, channel ID address
+ * used to write to PTI HW.
+ *
+ * @mc: master, channel apeture ID address to be released.
+ */
+void pti_release_masterchannel(struct pti_masterchannel *mc)
+{
+ u8 master, channel, i;
+
+ mutex_lock(&alloclock);
+
+ if (mc) {
+ master = mc->master;
+ channel = mc->channel;
+
+ if (master == APP_BASE_ID) {
+ i = channel >> 3;
+ drv_data->ia_app[i] &= ~(0x80>>(channel & 0x7));
+ } else if (master == OS_BASE_ID) {
+ i = channel >> 3;
+ drv_data->ia_os[i] &= ~(0x80>>(channel & 0x7));
+ } else {
+ i = channel >> 3;
+ drv_data->ia_modem[i] &= ~(0x80>>(channel & 0x7));
+ }
+
+ kfree(mc);
+ }
+
+ mutex_unlock(&alloclock);
+}
+EXPORT_SYMBOL_GPL(pti_release_masterchannel);
+
+/**
+ * pti_writedata()- Kernel API function used to write trace
+ * debugging data to PTI HW.
+ *
+ * @mc: Master, channel aperture ID address to write to.
+ * Null value will return with no write occurring.
+ * @buf: Trace debuging data to write to the PTI HW.
+ * Null value will return with no write occurring.
+ * @count: Size of buf. Value of 0 or a negative number will
+ * return with no write occuring.
+ */
+void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count)
+{
+ /*
+ * since this function is exported, this is treated like an
+ * API function, thus, all parameters should
+ * be checked for validity.
+ */
+ if ((mc != NULL) && (buf != NULL) && (count > 0))
+ pti_write_to_aperture(mc, buf, count);
+ return;
+}
+EXPORT_SYMBOL_GPL(pti_writedata);
+
+/**
+ * pti_pci_remove()- Driver exit method to remove PTI from
+ * PCI bus.
+ * @pdev: variable containing pci info of PTI.
+ */
+static void __devexit pti_pci_remove(struct pci_dev *pdev)
+{
+ struct pti_dev *drv_data;
+
+ drv_data = pci_get_drvdata(pdev);
+ if (drv_data != NULL) {
+ pci_iounmap(pdev, drv_data->pti_ioaddr);
+ pci_set_drvdata(pdev, NULL);
+ kfree(drv_data);
+ pci_release_region(pdev, 1);
+ pci_disable_device(pdev);
+ }
+}
+
+/*
+ * for the tty_driver_*() basic function descriptions, see tty_driver.h.
+ * Specific header comments made for PTI-related specifics.
+ */
+
+/**
+ * pti_tty_driver_open()- Open an Application master, channel aperture
+ * ID to the PTI device via tty device.
+ *
+ * @tty: tty interface.
+ * @filp: filp interface pased to tty_port_open() call.
+ *
+ * Returns:
+ * int, 0 for success
+ * otherwise, fail value
+ *
+ * The main purpose of using the tty device interface is for
+ * each tty port to have a unique PTI write aperture. In an
+ * example use case, ttyPTI0 gets syslogd and an APP aperture
+ * ID and ttyPTI1 is where the n_tracesink ldisc hooks to route
+ * modem messages into PTI. Modem trace data does not have to
+ * go to ttyPTI1, but ttyPTI0 and ttyPTI1 do need to be distinct
+ * master IDs. These messages go through the PTI HW and out of
+ * the handheld platform and to the Fido/Lauterbach device.
+ */
+static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
+{
+ /*
+ * we actually want to allocate a new channel per open, per
+ * system arch. HW gives more than plenty channels for a single
+ * system task to have its own channel to write trace data. This
+ * also removes a locking requirement for the actual write
+ * procedure.
+ */
+ return tty_port_open(&drv_data->port, tty, filp);
+}
+
+/**
+ * pti_tty_driver_close()- close tty device and release Application
+ * master, channel aperture ID to the PTI device via tty device.
+ *
+ * @tty: tty interface.
+ * @filp: filp interface pased to tty_port_close() call.
+ *
+ * The main purpose of using the tty device interface is to route
+ * syslog daemon messages to the PTI HW and out of the handheld platform
+ * and to the Fido/Lauterbach device.
+ */
+static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp)
+{
+ tty_port_close(&drv_data->port, tty, filp);
+}
+
+/**
+ * pti_tty_intstall()- Used to set up specific master-channels
+ * to tty ports for organizational purposes when
+ * tracing viewed from debuging tools.
+ *
+ * @driver: tty driver information.
+ * @tty: tty struct containing pti information.
+ *
+ * Returns:
+ * 0 for success
+ * otherwise, error
+ */
+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);
+
+ 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;
+
+ if (idx == PTITTY_MINOR_START)
+ pti_tty_data->mc = pti_request_masterchannel(0);
+ else
+ pti_tty_data->mc = pti_request_masterchannel(2);
+
+ if (pti_tty_data->mc == NULL)
+ return -ENXIO;
+ tty->driver_data = pti_tty_data;
+ }
+
+ return ret;
+}
+
+/**
+ * pti_tty_cleanup()- Used to de-allocate master-channel resources
+ * tied to tty's of this driver.
+ *
+ * @tty: tty struct containing pti information.
+ */
+static void pti_tty_cleanup(struct tty_struct *tty)
+{
+ struct pti_tty *pti_tty_data = tty->driver_data;
+ if (pti_tty_data == NULL)
+ return;
+ pti_release_masterchannel(pti_tty_data->mc);
+ kfree(tty->driver_data);
+ tty->driver_data = NULL;
+}
+
+/**
+ * pti_tty_driver_write()- Write trace debugging data through the char
+ * interface to the PTI HW. Part of the misc device implementation.
+ *
+ * @filp: Contains private data which is used to obtain
+ * master, channel write ID.
+ * @data: trace data to be written.
+ * @len: # of byte to write.
+ *
+ * Returns:
+ * int, # of bytes written
+ * otherwise, error
+ */
+static int pti_tty_driver_write(struct tty_struct *tty,
+ const unsigned char *buf, int len)
+{
+ struct pti_tty *pti_tty_data = tty->driver_data;
+ if ((pti_tty_data != NULL) && (pti_tty_data->mc != NULL)) {
+ pti_write_to_aperture(pti_tty_data->mc, (u8 *)buf, len);
+ return len;
+ }
+ /*
+ * we can't write to the pti hardware if the private driver_data
+ * and the mc address is not there.
+ */
+ else
+ return -EFAULT;
+}
+
+/**
+ * pti_tty_write_room()- Always returns 2048.
+ *
+ * @tty: contains tty info of the pti driver.
+ */
+static int pti_tty_write_room(struct tty_struct *tty)
+{
+ return 2048;
+}
+
+/**
+ * pti_char_open()- Open an Application master, channel aperture
+ * ID to the PTI device. Part of the misc device implementation.
+ *
+ * @inode: not used.
+ * @filp: Output- will have a masterchannel struct set containing
+ * the allocated application PTI aperture write address.
+ *
+ * Returns:
+ * int, 0 for success
+ * otherwise, a fail value
+ */
+static int pti_char_open(struct inode *inode, struct file *filp)
+{
+ struct pti_masterchannel *mc;
+
+ /*
+ * We really do want to fail immediately if
+ * pti_request_masterchannel() fails,
+ * before assigning the value to filp->private_data.
+ * Slightly easier to debug if this driver needs debugging.
+ */
+ mc = pti_request_masterchannel(0);
+ if (mc == NULL)
+ return -ENOMEM;
+ filp->private_data = mc;
+ return 0;
+}
+
+/**
+ * pti_char_release()- Close a char channel to the PTI device. Part
+ * of the misc device implementation.
+ *
+ * @inode: Not used in this implementaiton.
+ * @filp: Contains private_data that contains the master, channel
+ * ID to be released by the PTI device.
+ *
+ * Returns:
+ * always 0
+ */
+static int pti_char_release(struct inode *inode, struct file *filp)
+{
+ pti_release_masterchannel(filp->private_data);
+ kfree(filp->private_data);
+ return 0;
+}
+
+/**
+ * pti_char_write()- Write trace debugging data through the char
+ * interface to the PTI HW. Part of the misc device implementation.
+ *
+ * @filp: Contains private data which is used to obtain
+ * master, channel write ID.
+ * @data: trace data to be written.
+ * @len: # of byte to write.
+ * @ppose: Not used in this function implementation.
+ *
+ * Returns:
+ * int, # of bytes written
+ * otherwise, error value
+ *
+ * Notes: From side discussions with Alan Cox and experimenting
+ * with PTI debug HW like Nokia's Fido box and Lauterbach
+ * devices, 8192 byte write buffer used by USER_COPY_SIZE was
+ * deemed an appropriate size for this type of usage with
+ * debugging HW.
+ */
+static ssize_t pti_char_write(struct file *filp, const char __user *data,
+ size_t len, loff_t *ppose)
+{
+ struct pti_masterchannel *mc;
+ void *kbuf;
+ const char __user *tmp;
+ size_t size = USER_COPY_SIZE;
+ size_t n = 0;
+
+ tmp = data;
+ mc = filp->private_data;
+
+ kbuf = kmalloc(size, GFP_KERNEL);
+ if (kbuf == NULL) {
+ pr_err("%s(%d): buf allocation failed\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ do {
+ if (len - n > USER_COPY_SIZE)
+ size = USER_COPY_SIZE;
+ else
+ size = len - n;
+
+ if (copy_from_user(kbuf, tmp, size)) {
+ kfree(kbuf);
+ return n ? n : -EFAULT;
+ }
+
+ pti_write_to_aperture(mc, kbuf, size);
+ n += size;
+ tmp += size;
+
+ } while (len > n);
+
+ kfree(kbuf);
+ return len;
+}
+
+static const struct tty_operations pti_tty_driver_ops = {
+ .open = pti_tty_driver_open,
+ .close = pti_tty_driver_close,
+ .write = pti_tty_driver_write,
+ .write_room = pti_tty_write_room,
+ .install = pti_tty_install,
+ .cleanup = pti_tty_cleanup
+};
+
+static const struct file_operations pti_char_driver_ops = {
+ .owner = THIS_MODULE,
+ .write = pti_char_write,
+ .open = pti_char_open,
+ .release = pti_char_release,
+};
+
+static struct miscdevice pti_char_driver = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = CHARNAME,
+ .fops = &pti_char_driver_ops
+};
+
+/**
+ * pti_console_write()- Write to the console that has been acquired.
+ *
+ * @c: Not used in this implementaiton.
+ * @buf: Data to be written.
+ * @len: Length of buf.
+ */
+static void pti_console_write(struct console *c, const char *buf, unsigned len)
+{
+ static struct pti_masterchannel mc = {.master = CONSOLE_ID,
+ .channel = 0};
+
+ mc.channel = pti_console_channel;
+ pti_console_channel = (pti_console_channel + 1) & 0x7f;
+
+ pti_write_full_frame_to_aperture(&mc, buf, len);
+}
+
+/**
+ * pti_console_device()- Return the driver tty structure and set the
+ * associated index implementation.
+ *
+ * @c: Console device of the driver.
+ * @index: index associated with c.
+ *
+ * Returns:
+ * always value of pti_tty_driver structure when this function
+ * is called.
+ */
+static struct tty_driver *pti_console_device(struct console *c, int *index)
+{
+ *index = c->index;
+ return pti_tty_driver;
+}
+
+/**
+ * pti_console_setup()- Initialize console variables used by the driver.
+ *
+ * @c: Not used.
+ * @opts: Not used.
+ *
+ * Returns:
+ * always 0.
+ */
+static int pti_console_setup(struct console *c, char *opts)
+{
+ pti_console_channel = 0;
+ pti_control_channel = 0;
+ return 0;
+}
+
+/*
+ * pti_console struct, used to capture OS printk()'s and shift
+ * out to the PTI device for debugging. This cannot be
+ * enabled upon boot because of the possibility of eating
+ * any serial console printk's (race condition discovered).
+ * The console should be enabled upon when the tty port is
+ * used for the first time. Since the primary purpose for
+ * the tty port is to hook up syslog to it, the tty port
+ * will be open for a really long time.
+ */
+static struct console pti_console = {
+ .name = TTYNAME,
+ .write = pti_console_write,
+ .device = pti_console_device,
+ .setup = pti_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = 0,
+};
+
+/**
+ * pti_port_activate()- Used to start/initialize any items upon
+ * first opening of tty_port().
+ *
+ * @port- The tty port number of the PTI device.
+ * @tty- The tty struct associated with this device.
+ *
+ * Returns:
+ * always returns 0
+ *
+ * Notes: The primary purpose of the PTI tty port 0 is to hook
+ * the syslog daemon to it; thus this port will be open for a
+ * very long time.
+ */
+static int pti_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+ if (port->tty->index == PTITTY_MINOR_START)
+ console_start(&pti_console);
+ return 0;
+}
+
+/**
+ * pti_port_shutdown()- Used to stop/shutdown any items upon the
+ * last tty port close.
+ *
+ * @port- The tty port number of the PTI device.
+ *
+ * Notes: The primary purpose of the PTI tty port 0 is to hook
+ * the syslog daemon to it; thus this port will be open for a
+ * very long time.
+ */
+static void pti_port_shutdown(struct tty_port *port)
+{
+ if (port->tty->index == PTITTY_MINOR_START)
+ console_stop(&pti_console);
+}
+
+static const struct tty_port_operations tty_port_ops = {
+ .activate = pti_port_activate,
+ .shutdown = pti_port_shutdown,
+};
+
+/*
+ * Note the _probe() call sets everything up and ties the char and tty
+ * to successfully detecting the PTI device on the pci bus.
+ */
+
+/**
+ * pti_pci_probe()- Used to detect pti on the pci bus and set
+ * things up in the driver.
+ *
+ * @pdev- pci_dev struct values for pti.
+ * @ent- pci_device_id struct for pti driver.
+ *
+ * Returns:
+ * 0 for success
+ * otherwise, error
+ */
+static int __devinit pti_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int retval = -EINVAL;
+ int pci_bar = 1;
+
+ dev_dbg(&pdev->dev, "%s %s(%d): PTI PCI ID %04x:%04x\n", __FILE__,
+ __func__, __LINE__, pdev->vendor, pdev->device);
+
+ retval = misc_register(&pti_char_driver);
+ if (retval) {
+ pr_err("%s(%d): CHAR registration failed of pti driver\n",
+ __func__, __LINE__);
+ pr_err("%s(%d): Error value returned: %d\n",
+ __func__, __LINE__, retval);
+ return retval;
+ }
+
+ retval = pci_enable_device(pdev);
+ if (retval != 0) {
+ dev_err(&pdev->dev,
+ "%s: pci_enable_device() returned error %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
+
+ if (drv_data == NULL) {
+ retval = -ENOMEM;
+ dev_err(&pdev->dev,
+ "%s(%d): kmalloc() returned NULL memory.\n",
+ __func__, __LINE__);
+ return retval;
+ }
+ drv_data->pti_addr = pci_resource_start(pdev, pci_bar);
+
+ retval = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev));
+ if (retval != 0) {
+ dev_err(&pdev->dev,
+ "%s(%d): pci_request_region() returned error %d\n",
+ __func__, __LINE__, retval);
+ kfree(drv_data);
+ return retval;
+ }
+ drv_data->aperture_base = drv_data->pti_addr+APERTURE_14;
+ drv_data->pti_ioaddr =
+ ioremap_nocache((u32)drv_data->aperture_base,
+ APERTURE_LEN);
+ if (!drv_data->pti_ioaddr) {
+ pci_release_region(pdev, pci_bar);
+ retval = -ENOMEM;
+ kfree(drv_data);
+ return retval;
+ }
+
+ pci_set_drvdata(pdev, drv_data);
+
+ tty_port_init(&drv_data->port);
+ drv_data->port.ops = &tty_port_ops;
+
+ tty_register_device(pti_tty_driver, 0, &pdev->dev);
+ tty_register_device(pti_tty_driver, 1, &pdev->dev);
+
+ register_console(&pti_console);
+
+ return retval;
+}
+
+static struct pci_driver pti_pci_driver = {
+ .name = PCINAME,
+ .id_table = pci_ids,
+ .probe = pti_pci_probe,
+ .remove = pti_pci_remove,
+};
+
+/**
+ *
+ * pti_init()- Overall entry/init call to the pti driver.
+ * It starts the registration process with the kernel.
+ *
+ * Returns:
+ * int __init, 0 for success
+ * otherwise value is an error
+ *
+ */
+static int __init pti_init(void)
+{
+ int retval = -EINVAL;
+
+ /* First register module as tty device */
+
+ pti_tty_driver = alloc_tty_driver(1);
+ 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 |
+ TTY_DRIVER_DYNAMIC_DEV;
+ pti_tty_driver->init_termios = tty_std_termios;
+
+ tty_set_operations(pti_tty_driver, &pti_tty_driver_ops);
+
+ retval = tty_register_driver(pti_tty_driver);
+ if (retval) {
+ pr_err("%s(%d): TTY registration failed of pti driver\n",
+ __func__, __LINE__);
+ pr_err("%s(%d): Error value returned: %d\n",
+ __func__, __LINE__, retval);
+
+ pti_tty_driver = NULL;
+ return retval;
+ }
+
+ retval = pci_register_driver(&pti_pci_driver);
+
+ if (retval) {
+ pr_err("%s(%d): PCI registration failed of pti driver\n",
+ __func__, __LINE__);
+ pr_err("%s(%d): Error value returned: %d\n",
+ __func__, __LINE__, retval);
+
+ tty_unregister_driver(pti_tty_driver);
+ pr_err("%s(%d): Unregistering TTY part of pti driver\n",
+ __func__, __LINE__);
+ pti_tty_driver = NULL;
+ return retval;
+ }
+
+ return retval;
+}
+
+/**
+ * pti_exit()- Unregisters this module as a tty and pci driver.
+ */
+static void __exit pti_exit(void)
+{
+ int retval;
+
+ tty_unregister_device(pti_tty_driver, 0);
+ tty_unregister_device(pti_tty_driver, 1);
+
+ retval = tty_unregister_driver(pti_tty_driver);
+ if (retval) {
+ pr_err("%s(%d): TTY unregistration failed of pti driver\n",
+ __func__, __LINE__);
+ pr_err("%s(%d): Error value returned: %d\n",
+ __func__, __LINE__, retval);
+ }
+
+ pci_unregister_driver(&pti_pci_driver);
+
+ retval = misc_deregister(&pti_char_driver);
+ if (retval) {
+ pr_err("%s(%d): CHAR unregistration failed of pti driver\n",
+ __func__, __LINE__);
+ pr_err("%s(%d): Error value returned: %d\n",
+ __func__, __LINE__, retval);
+ }
+
+ unregister_console(&pti_console);
+ return;
+}
+
+module_init(pti_init);
+module_exit(pti_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ken Mills, Jay Freyensee");
+MODULE_DESCRIPTION("PTI Driver");
+
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index f91f82eabda..1a05fe08e2c 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -747,8 +747,8 @@ static void st_tty_close(struct tty_struct *tty)
pr_debug("%s: done ", __func__);
}
-static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
- char *tty_flags, int count)
+static unsigned int st_tty_receive(struct tty_struct *tty,
+ const unsigned char *data, char *tty_flags, int count)
{
#ifdef VERBOSE
print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
@@ -761,6 +761,8 @@ static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
*/
st_recv(tty->disc_data, data, count);
pr_debug("done %s", __func__);
+
+ return count;
}
/* wake-up function called in from the TTY layer
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 3df0c0f8b8b..73c7e03617e 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -167,8 +167,8 @@ static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)
#endif
-static void ldisc_receive(struct tty_struct *tty, const u8 *data,
- char *flags, int count)
+static unsigned int ldisc_receive(struct tty_struct *tty,
+ const u8 *data, char *flags, int count)
{
struct sk_buff *skb = NULL;
struct ser_device *ser;
@@ -215,6 +215,8 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data,
} else
++ser->dev->stats.rx_dropped;
update_tty_status(ser);
+
+ return count;
}
static int handle_tx(struct ser_device *ser)
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index 1b49df6b247..75622d54581 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -425,16 +425,17 @@ static void slc_setup(struct net_device *dev)
* in parallel
*/
-static void slcan_receive_buf(struct tty_struct *tty,
+static unsigned int slcan_receive_buf(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct slcan *sl = (struct slcan *) tty->disc_data;
+ int bytes = count;
if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
- return;
+ return -ENODEV;
/* Read the characters out of the buffer */
- while (count--) {
+ while (bytes--) {
if (fp && *fp++) {
if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->dev->stats.rx_errors++;
@@ -443,6 +444,8 @@ static void slcan_receive_buf(struct tty_struct *tty,
}
slcan_unesc(sl, *cp++);
}
+
+ return count;
}
/************************************
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 3e5d0b6b651..992089639ea 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -456,7 +456,7 @@ out:
* a block of 6pack data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing.
*/
-static void sixpack_receive_buf(struct tty_struct *tty,
+static unsigned int sixpack_receive_buf(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct sixpack *sp;
@@ -464,11 +464,11 @@ static void sixpack_receive_buf(struct tty_struct *tty,
int count1;
if (!count)
- return;
+ return 0;
sp = sp_get(tty);
if (!sp)
- return;
+ return -ENODEV;
memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf));
@@ -487,6 +487,8 @@ static void sixpack_receive_buf(struct tty_struct *tty,
sp_put(sp);
tty_unthrottle(tty);
+
+ return count1;
}
/*
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 4c628393c8b..0e4f2353114 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -923,13 +923,14 @@ static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file,
* a block of data has been received, which can now be decapsulated
* and sent on to the AX.25 layer for further processing.
*/
-static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static unsigned int mkiss_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct mkiss *ax = mkiss_get(tty);
+ int bytes = count;
if (!ax)
- return;
+ return -ENODEV;
/*
* Argh! mtu change time! - costs us the packet part received
@@ -939,7 +940,7 @@ static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
ax_changedmtu(ax);
/* Read the characters out of the buffer */
- while (count--) {
+ while (bytes--) {
if (fp != NULL && *fp++) {
if (!test_and_set_bit(AXF_ERROR, &ax->flags))
ax->dev->stats.rx_errors++;
@@ -952,6 +953,8 @@ static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
mkiss_put(ax);
tty_unthrottle(tty);
+
+ return count;
}
/*
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 3352b2443e5..035861d8acb 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -216,23 +216,23 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
* usbserial: urb-complete-interrupt / softint
*/
-static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static unsigned int irtty_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct sir_dev *dev;
struct sirtty_cb *priv = tty->disc_data;
int i;
- IRDA_ASSERT(priv != NULL, return;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
+ IRDA_ASSERT(priv != NULL, return -ENODEV;);
+ IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EINVAL;);
if (unlikely(count==0)) /* yes, this happens */
- return;
+ return 0;
dev = priv->dev;
if (!dev) {
IRDA_WARNING("%s(), not ready yet!\n", __func__);
- return;
+ return -ENODEV;
}
for (i = 0; i < count; i++) {
@@ -242,11 +242,13 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
if (fp && *fp++) {
IRDA_DEBUG(0, "Framing or parity error!\n");
sirdev_receive(dev, NULL, 0); /* notify sir_dev (updating stats) */
- return;
+ return -EINVAL;
}
}
sirdev_receive(dev, cp, count);
+
+ return count;
}
/*
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index a1b82c9c67d..53872d7d738 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -340,7 +340,7 @@ ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
}
/* May sleep, don't call from interrupt level or with interrupts disabled */
-static void
+static unsigned int
ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
char *cflags, int count)
{
@@ -348,7 +348,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
unsigned long flags;
if (!ap)
- return;
+ return -ENODEV;
spin_lock_irqsave(&ap->recv_lock, flags);
ppp_async_input(ap, buf, cflags, count);
spin_unlock_irqrestore(&ap->recv_lock, flags);
@@ -356,6 +356,8 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
tasklet_schedule(&ap->tsk);
ap_put(ap);
tty_unthrottle(tty);
+
+ return count;
}
static void
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 2573f525f11..0815790a5cf 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -381,7 +381,7 @@ ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
}
/* May sleep, don't call from interrupt level or with interrupts disabled */
-static void
+static unsigned int
ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
char *cflags, int count)
{
@@ -389,7 +389,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
unsigned long flags;
if (!ap)
- return;
+ return -ENODEV;
spin_lock_irqsave(&ap->recv_lock, flags);
ppp_sync_input(ap, buf, cflags, count);
spin_unlock_irqrestore(&ap->recv_lock, flags);
@@ -397,6 +397,8 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
tasklet_schedule(&ap->tsk);
sp_put(ap);
tty_unthrottle(tty);
+
+ return count;
}
static void
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 8ec1a9a0bb9..584809c656d 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -670,16 +670,17 @@ static void sl_setup(struct net_device *dev)
* in parallel
*/
-static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static unsigned int slip_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct slip *sl = tty->disc_data;
+ int bytes = count;
if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
- return;
+ return -ENODEV;
/* Read the characters out of the buffer */
- while (count--) {
+ while (bytes--) {
if (fp && *fp++) {
if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->dev->stats.rx_errors++;
@@ -693,6 +694,8 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
#endif
slip_unesc(sl, *cp++);
}
+
+ return count;
}
/************************************
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 24297b274cd..40398bf7d03 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -517,17 +517,18 @@ static int x25_asy_close(struct net_device *dev)
* and sent on to some IP layer for further processing.
*/
-static void x25_asy_receive_buf(struct tty_struct *tty,
+static unsigned int x25_asy_receive_buf(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct x25_asy *sl = tty->disc_data;
+ int bytes = count;
if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
return;
/* Read the characters out of the buffer */
- while (count--) {
+ while (bytes--) {
if (fp && *fp++) {
if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->dev->stats.rx_errors++;
@@ -536,6 +537,8 @@ static void x25_asy_receive_buf(struct tty_struct *tty,
}
x25_asy_unesc(sl, *cp++);
}
+
+ return count;
}
/*
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index bc8ce48f077..f330338c2f2 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1621,7 +1621,7 @@ static void __devinit detect_and_report_it87(void)
u8 origval, r;
if (verbose_probing)
printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n");
- if (!request_region(0x2e, 2, __func__))
+ if (!request_muxed_region(0x2e, 2, __func__))
return;
origval = inb(0x2e); /* Save original value */
outb(0x87, 0x2e);
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 3fd7199301b..bd7cc052799 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -319,3 +319,34 @@ config N_GSM
This line discipline provides support for the GSM MUX protocol and
presents the mux as a set of 61 individual tty devices.
+config TRACE_ROUTER
+ tristate "Trace data router for MIPI P1149.7 cJTAG standard"
+ depends on TRACE_SINK
+ default n
+ help
+ The trace router uses the Linux tty line discipline framework to
+ route trace data coming from a tty port (say UART for example) to
+ the trace sink line discipline driver and to another tty port (say
+ USB). This is part of a solution for the MIPI P1149.7, compact JTAG,
+ standard, which is for debugging mobile devices. The PTI driver in
+ drivers/misc/pti.c defines the majority of this MIPI solution.
+
+ You should select this driver if the target kernel is meant for
+ a mobile device containing a modem. Then you will need to select
+ "Trace data sink for MIPI P1149.7 cJTAG standard" line discipline
+ driver.
+
+config TRACE_SINK
+ tristate "Trace data sink for MIPI P1149.7 cJTAG standard"
+ default n
+ help
+ The trace sink uses the Linux line discipline framework to receive
+ trace data coming from the trace router line discipline driver
+ to a user-defined tty port target, like USB.
+ This is to provide a way to extract modem trace data on
+ devices that do not have a PTI HW module, or just need modem
+ trace data to come out of a different HW output port.
+ This is part of a solution for the P1149.7, compact JTAG, standard.
+
+ If you select this option, you need to select
+ "Trace data router for MIPI P1149.7 cJTAG standard".
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 690522fcb33..ea89b0bd15f 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -6,6 +6,8 @@ obj-$(CONFIG_AUDIT) += tty_audit.o
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_N_GSM) += n_gsm.o
+obj-$(CONFIG_TRACE_ROUTER) += n_tracerouter.o
+obj-$(CONFIG_TRACE_SINK) += n_tracesink.o
obj-$(CONFIG_R3964) += n_r3964.o
obj-y += vt/
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index f214e502247..220579592c2 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/amiserial.c
- *
* Serial driver for the amiga builtin port.
*
* This code was created by taking serial.c version 4.30 from kernel
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index c99728f0cd9..bfa05e80182 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -3,8 +3,6 @@
#undef Z_EXT_CHARS_IN_BUFFER
/*
- * linux/drivers/char/cyclades.c
- *
* This file contains the driver for the Cyclades async multiport
* serial boards.
*
@@ -1445,13 +1443,11 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
{
struct cyclades_card *card;
unsigned long flags;
- int channel;
if (!(info->port.flags & ASYNC_INITIALIZED))
return;
card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
@@ -1476,6 +1472,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
#ifdef CY_DEBUG_OPEN
+ int channel = info->line - card->first_line;
printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
"base_addr %p\n", card, channel, card->base_addr);
#endif
diff --git a/drivers/tty/ipwireless/Makefile b/drivers/tty/ipwireless/Makefile
index db80873d7f2..fe2e1730986 100644
--- a/drivers/tty/ipwireless/Makefile
+++ b/drivers/tty/ipwireless/Makefile
@@ -1,6 +1,4 @@
#
-# drivers/char/pcmcia/ipwireless/Makefile
-#
# Makefile for the IPWireless driver
#
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 35b0c38590e..ba679ce0a77 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -371,7 +371,7 @@ static int moxa_ioctl(struct tty_struct *tty,
tmp.cflag = p->cflag;
else
tmp.cflag = ttyp->termios->c_cflag;
- tty_kref_put(tty);
+ tty_kref_put(ttyp);
copy:
if (copy_to_user(argm, &tmp, sizeof(tmp)))
return -EFAULT;
@@ -1129,7 +1129,6 @@ static void moxa_shutdown(struct tty_port *port)
struct moxa_port *ch = container_of(port, struct moxa_port, port);
MoxaPortDisable(ch);
MoxaPortFlushData(ch, 2);
- clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
}
static int moxa_carrier_raised(struct tty_port *port)
@@ -1155,7 +1154,6 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
struct moxa_board_conf *brd;
struct moxa_port *ch;
int port;
- int retval;
port = tty->index;
if (port == MAX_PORTS) {
@@ -1190,10 +1188,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
mutex_unlock(&ch->port.mutex);
mutex_unlock(&moxa_openlock);
- retval = tty_port_block_til_ready(&ch->port, tty, filp);
- if (retval == 0)
- set_bit(ASYNCB_NORMAL_ACTIVE, &ch->port.flags);
- return retval;
+ return tty_port_block_til_ready(&ch->port, tty, filp);
}
static void moxa_close(struct tty_struct *tty, struct file *filp)
@@ -1207,14 +1202,15 @@ static int moxa_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
struct moxa_port *ch = tty->driver_data;
+ unsigned long flags;
int len;
if (ch == NULL)
return 0;
- spin_lock_bh(&moxa_lock);
+ spin_lock_irqsave(&moxa_lock, flags);
len = MoxaPortWriteData(tty, buf, count);
- spin_unlock_bh(&moxa_lock);
+ spin_unlock_irqrestore(&moxa_lock, flags);
set_bit(LOWWAIT, &ch->statusflags);
return len;
@@ -1281,10 +1277,8 @@ static int moxa_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct moxa_port *ch;
- int port;
int dtr, rts;
- port = tty->index;
mutex_lock(&moxa_openlock);
ch = tty->driver_data;
if (!ch) {
@@ -1756,11 +1750,9 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
speed_t baud)
{
void __iomem *ofsAddr;
- tcflag_t cflag;
tcflag_t mode = 0;
ofsAddr = port->tableAddr;
- cflag = termio->c_cflag; /* termio->c_cflag */
mode = termio->c_cflag & CSIZE;
if (mode == CS5)
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 77623b93653..a4c42a75a3b 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -526,19 +526,6 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
return olen;
}
-static void hex_packet(const unsigned char *p, int len)
-{
- int i;
- for (i = 0; i < len; i++) {
- if (i && (i % 16) == 0) {
- pr_cont("\n");
- pr_debug("");
- }
- pr_cont("%02X ", *p++);
- }
- pr_cont("\n");
-}
-
/**
* gsm_send - send a control frame
* @gsm: our GSM mux
@@ -685,10 +672,10 @@ static void gsm_data_kick(struct gsm_mux *gsm)
len = msg->len + 2;
}
- if (debug & 4) {
- pr_debug("gsm_data_kick:\n");
- hex_packet(gsm->txframe, len);
- }
+ if (debug & 4)
+ print_hex_dump_bytes("gsm_data_kick: ",
+ DUMP_PREFIX_OFFSET,
+ gsm->txframe, len);
if (gsm->output(gsm, gsm->txframe + skip_sof,
len - skip_sof) < 0)
@@ -2095,10 +2082,9 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
set_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags);
return -ENOSPC;
}
- if (debug & 4) {
- pr_debug("-->%d bytes out\n", len);
- hex_packet(data, len);
- }
+ if (debug & 4)
+ print_hex_dump_bytes("gsmld_output: ", DUMP_PREFIX_OFFSET,
+ data, len);
gsm->tty->ops->write(gsm->tty, data, len);
return len;
}
@@ -2142,8 +2128,8 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
gsm->tty = NULL;
}
-static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static unsigned int gsmld_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct gsm_mux *gsm = tty->disc_data;
const unsigned char *dp;
@@ -2152,10 +2138,9 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char buf[64];
char flags;
- if (debug & 4) {
- pr_debug("Inbytes %dd\n", count);
- hex_packet(cp, count);
- }
+ if (debug & 4)
+ print_hex_dump_bytes("gsmld_receive: ", DUMP_PREFIX_OFFSET,
+ cp, count);
for (i = count, dp = cp, f = fp; i; i--, dp++) {
flags = *f++;
@@ -2177,6 +2162,8 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
/* FASYNC if needed ? */
/* If clogged call tty_throttle(tty); */
+
+ return count;
}
/**
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index cea56033b34..cac666314ae 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -188,8 +188,8 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
poll_table *wait);
static int n_hdlc_tty_open(struct tty_struct *tty);
static void n_hdlc_tty_close(struct tty_struct *tty);
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
- char *fp, int count);
+static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
+ const __u8 *cp, char *fp, int count);
static void n_hdlc_tty_wakeup(struct tty_struct *tty);
#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
@@ -509,8 +509,8 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
* Called by tty low level driver when receive data is available. Data is
* interpreted as one HDLC frame.
*/
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
- char *flags, int count)
+static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
+ const __u8 *data, char *flags, int count)
{
register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
register struct n_hdlc_buf *buf;
@@ -521,20 +521,20 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
/* This can happen if stuff comes in on the backup tty */
if (!n_hdlc || tty != n_hdlc->tty)
- return;
+ return -ENODEV;
/* verify line is using HDLC discipline */
if (n_hdlc->magic != HDLC_MAGIC) {
printk("%s(%d) line not using HDLC discipline\n",
__FILE__,__LINE__);
- return;
+ return -EINVAL;
}
if ( count>maxframe ) {
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d) rx count>maxframesize, data discarded\n",
__FILE__,__LINE__);
- return;
+ return -EINVAL;
}
/* get a free HDLC buffer */
@@ -550,7 +550,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d) no more rx buffers, data discarded\n",
__FILE__,__LINE__);
- return;
+ return -EINVAL;
}
/* copy received data to HDLC buffer */
@@ -565,6 +565,8 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
if (n_hdlc->tty->fasync != NULL)
kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
+ return count;
+
} /* end of n_hdlc_tty_receive() */
/**
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
index 5c6c31459a2..a4bc39c21a4 100644
--- a/drivers/tty/n_r3964.c
+++ b/drivers/tty/n_r3964.c
@@ -139,8 +139,8 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file,
static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
struct poll_table_struct *wait);
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count);
+static unsigned int r3964_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count);
static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
.owner = THIS_MODULE,
@@ -1239,8 +1239,8 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
return result;
}
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static unsigned int r3964_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct r3964_info *pInfo = tty->disc_data;
const unsigned char *p;
@@ -1257,6 +1257,8 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
}
+
+ return count;
}
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/n_tracerouter.c b/drivers/tty/n_tracerouter.c
new file mode 100644
index 00000000000..1f063d3aa32
--- /dev/null
+++ b/drivers/tty/n_tracerouter.c
@@ -0,0 +1,243 @@
+/*
+ * n_tracerouter.c - Trace data router through tty space
+ *
+ * Copyright (C) Intel 2011
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This trace router uses the Linux line discipline framework to route
+ * trace data coming from a HW Modem to a PTI (Parallel Trace Module) port.
+ * The solution is not specific to a HW modem and this line disciple can
+ * be used to route any stream of data in kernel space.
+ * This is part of a solution for the P1149.7, compact JTAG, standard.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/tty.h>
+#include <linux/tty_ldisc.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <asm-generic/bug.h>
+#include "n_tracesink.h"
+
+/*
+ * Other ldisc drivers use 65536 which basically means,
+ * 'I can always accept 64k' and flow control is off.
+ * This number is deemed appropriate for this driver.
+ */
+#define RECEIVE_ROOM 65536
+#define DRIVERNAME "n_tracerouter"
+
+/*
+ * struct to hold private configuration data for this ldisc.
+ * opencalled is used to hold if this ldisc has been opened.
+ * kref_tty holds the tty reference the ldisc sits on top of.
+ */
+struct tracerouter_data {
+ u8 opencalled;
+ struct tty_struct *kref_tty;
+};
+static struct tracerouter_data *tr_data;
+
+/* lock for when tty reference is being used */
+static DEFINE_MUTEX(routelock);
+
+/**
+ * n_tracerouter_open() - Called when a tty is opened by a SW entity.
+ * @tty: terminal device to the ldisc.
+ *
+ * Return:
+ * 0 for success.
+ *
+ * Caveats: This should only be opened one time per SW entity.
+ */
+static int n_tracerouter_open(struct tty_struct *tty)
+{
+ int retval = -EEXIST;
+
+ mutex_lock(&routelock);
+ if (tr_data->opencalled == 0) {
+
+ tr_data->kref_tty = tty_kref_get(tty);
+ if (tr_data->kref_tty == NULL) {
+ retval = -EFAULT;
+ } else {
+ tr_data->opencalled = 1;
+ tty->disc_data = tr_data;
+ tty->receive_room = RECEIVE_ROOM;
+ tty_driver_flush_buffer(tty);
+ retval = 0;
+ }
+ }
+ mutex_unlock(&routelock);
+ return retval;
+}
+
+/**
+ * n_tracerouter_close() - close connection
+ * @tty: terminal device to the ldisc.
+ *
+ * Called when a software entity wants to close a connection.
+ */
+static void n_tracerouter_close(struct tty_struct *tty)
+{
+ struct tracerouter_data *tptr = tty->disc_data;
+
+ mutex_lock(&routelock);
+ WARN_ON(tptr->kref_tty != tr_data->kref_tty);
+ tty_driver_flush_buffer(tty);
+ tty_kref_put(tr_data->kref_tty);
+ tr_data->kref_tty = NULL;
+ tr_data->opencalled = 0;
+ tty->disc_data = NULL;
+ mutex_unlock(&routelock);
+}
+
+/**
+ * n_tracerouter_read() - read request from user space
+ * @tty: terminal device passed into the ldisc.
+ * @file: pointer to open file object.
+ * @buf: pointer to the data buffer that gets eventually returned.
+ * @nr: number of bytes of the data buffer that is returned.
+ *
+ * function that allows read() functionality in userspace. By default if this
+ * is not implemented it returns -EIO. This module is functioning like a
+ * router via n_tracerouter_receivebuf(), and there is no real requirement
+ * to implement this function. However, an error return value other than
+ * -EIO should be used just to show that there was an intent not to have
+ * this function implemented. Return value based on read() man pages.
+ *
+ * Return:
+ * -EINVAL
+ */
+static ssize_t n_tracerouter_read(struct tty_struct *tty, struct file *file,
+ unsigned char __user *buf, size_t nr) {
+ return -EINVAL;
+}
+
+/**
+ * n_tracerouter_write() - Function that allows write() in userspace.
+ * @tty: terminal device passed into the ldisc.
+ * @file: pointer to open file object.
+ * @buf: pointer to the data buffer that gets eventually returned.
+ * @nr: number of bytes of the data buffer that is returned.
+ *
+ * By default if this is not implemented, it returns -EIO.
+ * This should not be implemented, ever, because
+ * 1. this driver is functioning like a router via
+ * n_tracerouter_receivebuf()
+ * 2. No writes to HW will ever go through this line discpline driver.
+ * However, an error return value other than -EIO should be used
+ * just to show that there was an intent not to have this function
+ * implemented. Return value based on write() man pages.
+ *
+ * Return:
+ * -EINVAL
+ */
+static ssize_t n_tracerouter_write(struct tty_struct *tty, struct file *file,
+ const unsigned char *buf, size_t nr) {
+ return -EINVAL;
+}
+
+/**
+ * n_tracerouter_receivebuf() - Routing function for driver.
+ * @tty: terminal device passed into the ldisc. It's assumed
+ * tty will never be NULL.
+ * @cp: buffer, block of characters to be eventually read by
+ * someone, somewhere (user read() call or some kernel function).
+ * @fp: flag buffer.
+ * @count: number of characters (aka, bytes) in cp.
+ *
+ * This function takes the input buffer, cp, and passes it to
+ * an external API function for processing.
+ */
+static void n_tracerouter_receivebuf(struct tty_struct *tty,
+ const unsigned char *cp,
+ char *fp, int count)
+{
+ mutex_lock(&routelock);
+ n_tracesink_datadrain((u8 *) cp, count);
+ mutex_unlock(&routelock);
+}
+
+/*
+ * Flush buffer is not impelemented as the ldisc has no internal buffering
+ * so the tty_driver_flush_buffer() is sufficient for this driver's needs.
+ */
+
+static struct tty_ldisc_ops tty_ptirouter_ldisc = {
+ .owner = THIS_MODULE,
+ .magic = TTY_LDISC_MAGIC,
+ .name = DRIVERNAME,
+ .open = n_tracerouter_open,
+ .close = n_tracerouter_close,
+ .read = n_tracerouter_read,
+ .write = n_tracerouter_write,
+ .receive_buf = n_tracerouter_receivebuf
+};
+
+/**
+ * n_tracerouter_init - module initialisation
+ *
+ * Registers this module as a line discipline driver.
+ *
+ * Return:
+ * 0 for success, any other value error.
+ */
+static int __init n_tracerouter_init(void)
+{
+ int retval;
+
+ tr_data = kzalloc(sizeof(struct tracerouter_data), GFP_KERNEL);
+ if (tr_data == NULL)
+ return -ENOMEM;
+
+
+ /* Note N_TRACEROUTER is defined in linux/tty.h */
+ retval = tty_register_ldisc(N_TRACEROUTER, &tty_ptirouter_ldisc);
+ if (retval < 0) {
+ pr_err("%s: Registration failed: %d\n", __func__, retval);
+ kfree(tr_data);
+ }
+ return retval;
+}
+
+/**
+ * n_tracerouter_exit - module unload
+ *
+ * Removes this module as a line discipline driver.
+ */
+static void __exit n_tracerouter_exit(void)
+{
+ int retval = tty_unregister_ldisc(N_TRACEROUTER);
+
+ if (retval < 0)
+ pr_err("%s: Unregistration failed: %d\n", __func__, retval);
+ else
+ kfree(tr_data);
+}
+
+module_init(n_tracerouter_init);
+module_exit(n_tracerouter_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jay Freyensee");
+MODULE_ALIAS_LDISC(N_TRACEROUTER);
+MODULE_DESCRIPTION("Trace router ldisc driver");
diff --git a/drivers/tty/n_tracesink.c b/drivers/tty/n_tracesink.c
new file mode 100644
index 00000000000..ddce58b973d
--- /dev/null
+++ b/drivers/tty/n_tracesink.c
@@ -0,0 +1,238 @@
+/*
+ * n_tracesink.c - Trace data router and sink path through tty space.
+ *
+ * Copyright (C) Intel 2011
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * The trace sink uses the Linux line discipline framework to receive
+ * trace data coming from the PTI source line discipline driver
+ * to a user-desired tty port, like USB.
+ * This is to provide a way to extract modem trace data on
+ * devices that do not have a PTI HW module, or just need modem
+ * trace data to come out of a different HW output port.
+ * This is part of a solution for the P1149.7, compact JTAG, standard.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/tty.h>
+#include <linux/tty_ldisc.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <asm-generic/bug.h>
+#include "n_tracesink.h"
+
+/*
+ * Other ldisc drivers use 65536 which basically means,
+ * 'I can always accept 64k' and flow control is off.
+ * This number is deemed appropriate for this driver.
+ */
+#define RECEIVE_ROOM 65536
+#define DRIVERNAME "n_tracesink"
+
+/*
+ * there is a quirk with this ldisc is he can write data
+ * to a tty from anyone calling his kernel API, which
+ * meets customer requirements in the drivers/misc/pti.c
+ * project. So he needs to know when he can and cannot write when
+ * the API is called. In theory, the API can be called
+ * after an init() but before a successful open() which
+ * would crash the system if tty is not checked.
+ */
+static struct tty_struct *this_tty;
+static DEFINE_MUTEX(writelock);
+
+/**
+ * n_tracesink_open() - Called when a tty is opened by a SW entity.
+ * @tty: terminal device to the ldisc.
+ *
+ * Return:
+ * 0 for success,
+ * -EFAULT = couldn't get a tty kref n_tracesink will sit
+ * on top of
+ * -EEXIST = open() called successfully once and it cannot
+ * be called again.
+ *
+ * Caveats: open() should only be successful the first time a
+ * SW entity calls it.
+ */
+static int n_tracesink_open(struct tty_struct *tty)
+{
+ int retval = -EEXIST;
+
+ mutex_lock(&writelock);
+ if (this_tty == NULL) {
+ this_tty = tty_kref_get(tty);
+ if (this_tty == NULL) {
+ retval = -EFAULT;
+ } else {
+ tty->disc_data = this_tty;
+ tty_driver_flush_buffer(tty);
+ retval = 0;
+ }
+ }
+ mutex_unlock(&writelock);
+
+ return retval;
+}
+
+/**
+ * n_tracesink_close() - close connection
+ * @tty: terminal device to the ldisc.
+ *
+ * Called when a software entity wants to close a connection.
+ */
+static void n_tracesink_close(struct tty_struct *tty)
+{
+ mutex_lock(&writelock);
+ tty_driver_flush_buffer(tty);
+ tty_kref_put(this_tty);
+ this_tty = NULL;
+ tty->disc_data = NULL;
+ mutex_unlock(&writelock);
+}
+
+/**
+ * n_tracesink_read() - read request from user space
+ * @tty: terminal device passed into the ldisc.
+ * @file: pointer to open file object.
+ * @buf: pointer to the data buffer that gets eventually returned.
+ * @nr: number of bytes of the data buffer that is returned.
+ *
+ * function that allows read() functionality in userspace. By default if this
+ * is not implemented it returns -EIO. This module is functioning like a
+ * router via n_tracesink_receivebuf(), and there is no real requirement
+ * to implement this function. However, an error return value other than
+ * -EIO should be used just to show that there was an intent not to have
+ * this function implemented. Return value based on read() man pages.
+ *
+ * Return:
+ * -EINVAL
+ */
+static ssize_t n_tracesink_read(struct tty_struct *tty, struct file *file,
+ unsigned char __user *buf, size_t nr) {
+ return -EINVAL;
+}
+
+/**
+ * n_tracesink_write() - Function that allows write() in userspace.
+ * @tty: terminal device passed into the ldisc.
+ * @file: pointer to open file object.
+ * @buf: pointer to the data buffer that gets eventually returned.
+ * @nr: number of bytes of the data buffer that is returned.
+ *
+ * By default if this is not implemented, it returns -EIO.
+ * This should not be implemented, ever, because
+ * 1. this driver is functioning like a router via
+ * n_tracesink_receivebuf()
+ * 2. No writes to HW will ever go through this line discpline driver.
+ * However, an error return value other than -EIO should be used
+ * just to show that there was an intent not to have this function
+ * implemented. Return value based on write() man pages.
+ *
+ * Return:
+ * -EINVAL
+ */
+static ssize_t n_tracesink_write(struct tty_struct *tty, struct file *file,
+ const unsigned char *buf, size_t nr) {
+ return -EINVAL;
+}
+
+/**
+ * n_tracesink_datadrain() - Kernel API function used to route
+ * trace debugging data to user-defined
+ * port like USB.
+ *
+ * @buf: Trace debuging data buffer to write to tty target
+ * port. Null value will return with no write occurring.
+ * @count: Size of buf. Value of 0 or a negative number will
+ * return with no write occuring.
+ *
+ * Caveat: If this line discipline does not set the tty it sits
+ * on top of via an open() call, this API function will not
+ * call the tty's write() call because it will have no pointer
+ * to call the write().
+ */
+void n_tracesink_datadrain(u8 *buf, int count)
+{
+ mutex_lock(&writelock);
+
+ if ((buf != NULL) && (count > 0) && (this_tty != NULL))
+ this_tty->ops->write(this_tty, buf, count);
+
+ mutex_unlock(&writelock);
+}
+EXPORT_SYMBOL_GPL(n_tracesink_datadrain);
+
+/*
+ * Flush buffer is not impelemented as the ldisc has no internal buffering
+ * so the tty_driver_flush_buffer() is sufficient for this driver's needs.
+ */
+
+/*
+ * tty_ldisc function operations for this driver.
+ */
+static struct tty_ldisc_ops tty_n_tracesink = {
+ .owner = THIS_MODULE,
+ .magic = TTY_LDISC_MAGIC,
+ .name = DRIVERNAME,
+ .open = n_tracesink_open,
+ .close = n_tracesink_close,
+ .read = n_tracesink_read,
+ .write = n_tracesink_write
+};
+
+/**
+ * n_tracesink_init- module initialisation
+ *
+ * Registers this module as a line discipline driver.
+ *
+ * Return:
+ * 0 for success, any other value error.
+ */
+static int __init n_tracesink_init(void)
+{
+ /* Note N_TRACESINK is defined in linux/tty.h */
+ int retval = tty_register_ldisc(N_TRACESINK, &tty_n_tracesink);
+
+ if (retval < 0)
+ pr_err("%s: Registration failed: %d\n", __func__, retval);
+
+ return retval;
+}
+
+/**
+ * n_tracesink_exit - module unload
+ *
+ * Removes this module as a line discipline driver.
+ */
+static void __exit n_tracesink_exit(void)
+{
+ int retval = tty_unregister_ldisc(N_TRACESINK);
+
+ if (retval < 0)
+ pr_err("%s: Unregistration failed: %d\n", __func__, retval);
+}
+
+module_init(n_tracesink_init);
+module_exit(n_tracesink_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jay Freyensee");
+MODULE_ALIAS_LDISC(N_TRACESINK);
+MODULE_DESCRIPTION("Trace sink ldisc driver");
diff --git a/drivers/tty/n_tracesink.h b/drivers/tty/n_tracesink.h
new file mode 100644
index 00000000000..a68bb44f1ef
--- /dev/null
+++ b/drivers/tty/n_tracesink.h
@@ -0,0 +1,36 @@
+/*
+ * n_tracesink.h - Kernel driver API to route trace data in kernel space.
+ *
+ * Copyright (C) Intel 2011
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * The PTI (Parallel Trace Interface) driver directs trace data routed from
+ * various parts in the system out through the Intel Penwell PTI port and
+ * out of the mobile device for analysis with a debugging tool
+ * (Lauterbach, Fido). This is part of a solution for the MIPI P1149.7,
+ * compact JTAG, standard.
+ *
+ * This header file is used by n_tracerouter to be able to send the
+ * data of it's tty port to the tty port this module sits. This
+ * mechanism can also be used independent of the PTI module.
+ *
+ */
+
+#ifndef N_TRACESINK_H_
+#define N_TRACESINK_H_
+
+void n_tracesink_datadrain(u8 *buf, int count);
+
+#endif
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 0ad32888091..95d0a9c2dd1 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -81,38 +81,6 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
return put_user(x, ptr);
}
-/**
- * n_tty_set__room - receive space
- * @tty: terminal
- *
- * Called by the driver to find out how much data it is
- * permitted to feed to the line discipline without any being lost
- * and thus to manage flow control. Not serialized. Answers for the
- * "instant".
- */
-
-static void n_tty_set_room(struct tty_struct *tty)
-{
- /* tty->read_cnt is not read locked ? */
- int left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
- int old_left;
-
- /*
- * If we are doing input canonicalization, and there are no
- * pending newlines, let characters through without limit, so
- * that erase characters will be handled. Other excess
- * characters will be beeped.
- */
- if (left <= 0)
- left = tty->icanon && !tty->canon_data;
- old_left = tty->receive_room;
- tty->receive_room = left;
-
- /* Did this open up the receive buffer? We may need to flip */
- if (left && !old_left)
- schedule_work(&tty->buf.work);
-}
-
static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
{
if (tty->read_cnt < N_TTY_BUF_SIZE) {
@@ -184,7 +152,6 @@ static void reset_buffer_flags(struct tty_struct *tty)
tty->canon_head = tty->canon_data = tty->erasing = 0;
memset(&tty->read_flags, 0, sizeof tty->read_flags);
- n_tty_set_room(tty);
check_unthrottle(tty);
}
@@ -1360,17 +1327,19 @@ static void n_tty_write_wakeup(struct tty_struct *tty)
* calls one at a time and in order (or using flush_to_ldisc)
*/
-static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static unsigned int n_tty_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
const unsigned char *p;
char *f, flags = TTY_NORMAL;
int i;
char buf[64];
unsigned long cpuflags;
+ int left;
+ int ret = 0;
if (!tty->read_buf)
- return;
+ return 0;
if (tty->real_raw) {
spin_lock_irqsave(&tty->read_lock, cpuflags);
@@ -1380,6 +1349,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
memcpy(tty->read_buf + tty->read_head, cp, i);
tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
tty->read_cnt += i;
+ ret += i;
cp += i;
count -= i;
@@ -1389,8 +1359,10 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
memcpy(tty->read_buf + tty->read_head, cp, i);
tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
tty->read_cnt += i;
+ ret += i;
spin_unlock_irqrestore(&tty->read_lock, cpuflags);
} else {
+ ret = count;
for (i = count, p = cp, f = fp; i; i--, p++) {
if (f)
flags = *f++;
@@ -1418,8 +1390,6 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
tty->ops->flush_chars(tty);
}
- n_tty_set_room(tty);
-
if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
L_EXTPROC(tty)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
@@ -1432,8 +1402,12 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
* mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet!
*/
- if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
+ left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
+ if (left < TTY_THRESHOLD_THROTTLE)
tty_throttle(tty);
+
+ return ret;
}
int is_ignored(int sig)
@@ -1477,7 +1451,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
tty->raw = 1;
tty->real_raw = 1;
- n_tty_set_room(tty);
return;
}
if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
@@ -1530,7 +1503,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
else
tty->real_raw = 0;
}
- n_tty_set_room(tty);
/* The termios change make the tty ready for I/O */
wake_up_interruptible(&tty->write_wait);
wake_up_interruptible(&tty->read_wait);
@@ -1812,8 +1784,6 @@ do_it_again:
retval = -ERESTARTSYS;
break;
}
- /* FIXME: does n_tty_set_room need locking ? */
- n_tty_set_room(tty);
timeout = schedule_timeout(timeout);
continue;
}
@@ -1885,10 +1855,8 @@ do_it_again:
* longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
* we won't get any more characters.
*/
- if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
- n_tty_set_room(tty);
+ if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE)
check_unthrottle(tty);
- }
if (b - buf >= minimum)
break;
@@ -1910,7 +1878,6 @@ do_it_again:
} else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
goto do_it_again;
- n_tty_set_room(tty);
return retval;
}
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index fd0a98524d5..b1aecc7bb32 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -364,8 +364,6 @@ struct port {
u8 toggle_ul;
u16 token_dl;
- /* mutex to ensure one access patch to this port */
- struct mutex tty_sem;
wait_queue_head_t tty_wait;
struct async_icount tty_icount;
@@ -1431,8 +1429,8 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
}
for (i = PORT_MDM; i < MAX_PORT; i++) {
- if (kfifo_alloc(&dc->port[i].fifo_ul,
- FIFO_BUFFER_SIZE_UL, GFP_ATOMIC)) {
+ if (kfifo_alloc(&dc->port[i].fifo_ul, FIFO_BUFFER_SIZE_UL,
+ GFP_KERNEL)) {
dev_err(&pdev->dev,
"Could not allocate kfifo buffer\n");
ret = -ENOMEM;
@@ -1474,7 +1472,6 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
struct device *tty_dev;
struct port *port = &dc->port[i];
port->dc = dc;
- mutex_init(&port->tty_sem);
tty_port_init(&port->port);
port->port.ops = &noz_tty_port_ops;
tty_dev = tty_register_device(ntty_driver, dc->index_start + i,
@@ -1688,13 +1685,6 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
if (!dc || !port)
return -ENODEV;
- mutex_lock(&port->tty_sem);
-
- if (unlikely(!port->port.count)) {
- DBG1(" ");
- goto exit;
- }
-
rval = kfifo_in(&port->fifo_ul, (unsigned char *)buffer, count);
/* notify card */
@@ -1719,7 +1709,6 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
spin_unlock_irqrestore(&dc->spin_mutex, flags);
exit:
- mutex_unlock(&port->tty_sem);
return rval;
}
@@ -1738,12 +1727,9 @@ static int ntty_write_room(struct tty_struct *tty)
int room = 4096;
const struct nozomi *dc = get_dc_by_tty(tty);
- if (dc) {
- mutex_lock(&port->tty_sem);
- if (port->port.count)
- room = kfifo_avail(&port->fifo_ul);
- mutex_unlock(&port->tty_sem);
- }
+ if (dc)
+ room = kfifo_avail(&port->fifo_ul);
+
return room;
}
@@ -1889,11 +1875,6 @@ static s32 ntty_chars_in_buffer(struct tty_struct *tty)
goto exit_in_buffer;
}
- if (unlikely(!port->port.count)) {
- dev_err(&dc->pdev->dev, "No tty open?\n");
- goto exit_in_buffer;
- }
-
rval = kfifo_len(&port->fifo_ul);
exit_in_buffer:
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 210774726ad..98b6e3bdb00 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/pty.c
- *
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Added support for a Unix98-style ptmx device.
@@ -295,8 +293,8 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
return -ENOMEM;
if (!try_module_get(driver->other->owner)) {
/* This cannot in fact currently happen */
- free_tty_struct(o_tty);
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto err_free_tty;
}
initialize_tty_struct(o_tty, driver->other, idx);
@@ -304,13 +302,11 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
the easy way .. */
retval = tty_init_termios(tty);
if (retval)
- goto free_mem_out;
+ goto err_deinit_tty;
retval = tty_init_termios(o_tty);
- if (retval) {
- tty_free_termios(tty);
- goto free_mem_out;
- }
+ if (retval)
+ goto err_free_termios;
/*
* Everything allocated ... set up the o_tty structure.
@@ -327,10 +323,14 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
tty->count++;
driver->ttys[idx] = tty;
return 0;
-free_mem_out:
+err_free_termios:
+ tty_free_termios(tty);
+err_deinit_tty:
+ deinitialize_tty_struct(o_tty);
module_put(o_tty->driver->owner);
+err_free_tty:
free_tty_struct(o_tty);
- return -ENOMEM;
+ return retval;
}
static int pty_bsd_ioctl(struct tty_struct *tty,
@@ -559,20 +559,19 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
return -ENOMEM;
if (!try_module_get(driver->other->owner)) {
/* This cannot in fact currently happen */
- free_tty_struct(o_tty);
- return -ENOMEM;
+ goto err_free_tty;
}
initialize_tty_struct(o_tty, driver->other, idx);
tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
if (tty->termios == NULL)
- goto free_mem_out;
+ goto err_free_mem;
*tty->termios = driver->init_termios;
tty->termios_locked = tty->termios + 1;
o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
if (o_tty->termios == NULL)
- goto free_mem_out;
+ goto err_free_mem;
*o_tty->termios = driver->other->init_termios;
o_tty->termios_locked = o_tty->termios + 1;
@@ -591,11 +590,13 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
tty->count++;
pty_count++;
return 0;
-free_mem_out:
+err_free_mem:
+ deinitialize_tty_struct(o_tty);
kfree(o_tty->termios);
+ kfree(tty->termios);
module_put(o_tty->driver->owner);
+err_free_tty:
free_tty_struct(o_tty);
- kfree(tty->termios);
return -ENOMEM;
}
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 036feeb5e3f..13043e8d37f 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -1380,7 +1380,6 @@ static void rp_send_xchar(struct tty_struct *tty, char ch)
static void rp_throttle(struct tty_struct *tty)
{
struct r_port *info = tty->driver_data;
- CHANNEL_t *cp;
#ifdef ROCKET_DEBUG_THROTTLE
printk(KERN_INFO "throttle %s: %d....\n", tty->name,
@@ -1390,7 +1389,6 @@ static void rp_throttle(struct tty_struct *tty)
if (rocket_paranoia_check(info, "rp_throttle"))
return;
- cp = &info->channel;
if (I_IXOFF(tty))
rp_send_xchar(tty, STOP_CHAR(tty));
@@ -1400,7 +1398,6 @@ static void rp_throttle(struct tty_struct *tty)
static void rp_unthrottle(struct tty_struct *tty)
{
struct r_port *info = tty->driver_data;
- CHANNEL_t *cp;
#ifdef ROCKET_DEBUG_THROTTLE
printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
tty->ldisc.chars_in_buffer(tty));
@@ -1409,7 +1406,6 @@ static void rp_unthrottle(struct tty_struct *tty)
if (rocket_paranoia_check(info, "rp_throttle"))
return;
- cp = &info->channel;
if (I_IXOFF(tty))
rp_send_xchar(tty, START_CHAR(tty));
@@ -1722,13 +1718,10 @@ static int rp_write_room(struct tty_struct *tty)
static int rp_chars_in_buffer(struct tty_struct *tty)
{
struct r_port *info = tty->driver_data;
- CHANNEL_t *cp;
if (rocket_paranoia_check(info, "rp_chars_in_buffer"))
return 0;
- cp = &info->channel;
-
#ifdef ROCKET_DEBUG_WRITE
printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt);
#endif
@@ -1779,7 +1772,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
{
int num_aiops, aiop, max_num_aiops, num_chan, chan;
unsigned int aiopio[MAX_AIOPS_PER_BOARD];
- char *str, *board_type;
CONTROLLER_t *ctlp;
int fast_clock = 0;
@@ -1800,7 +1792,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
/* Depending on the model, set up some config variables */
switch (dev->device) {
case PCI_DEVICE_ID_RP4QUAD:
- str = "Quadcable";
max_num_aiops = 1;
ports_per_aiop = 4;
rocketModel[i].model = MODEL_RP4QUAD;
@@ -1808,42 +1799,36 @@ static __init int register_PCI(int i, struct pci_dev *dev)
rocketModel[i].numPorts = 4;
break;
case PCI_DEVICE_ID_RP8OCTA:
- str = "Octacable";
max_num_aiops = 1;
rocketModel[i].model = MODEL_RP8OCTA;
strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable");
rocketModel[i].numPorts = 8;
break;
case PCI_DEVICE_ID_URP8OCTA:
- str = "Octacable";
max_num_aiops = 1;
rocketModel[i].model = MODEL_UPCI_RP8OCTA;
strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable");
rocketModel[i].numPorts = 8;
break;
case PCI_DEVICE_ID_RP8INTF:
- str = "8";
max_num_aiops = 1;
rocketModel[i].model = MODEL_RP8INTF;
strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F");
rocketModel[i].numPorts = 8;
break;
case PCI_DEVICE_ID_URP8INTF:
- str = "8";
max_num_aiops = 1;
rocketModel[i].model = MODEL_UPCI_RP8INTF;
strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F");
rocketModel[i].numPorts = 8;
break;
case PCI_DEVICE_ID_RP8J:
- str = "8J";
max_num_aiops = 1;
rocketModel[i].model = MODEL_RP8J;
strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors");
rocketModel[i].numPorts = 8;
break;
case PCI_DEVICE_ID_RP4J:
- str = "4J";
max_num_aiops = 1;
ports_per_aiop = 4;
rocketModel[i].model = MODEL_RP4J;
@@ -1851,56 +1836,48 @@ static __init int register_PCI(int i, struct pci_dev *dev)
rocketModel[i].numPorts = 4;
break;
case PCI_DEVICE_ID_RP8SNI:
- str = "8 (DB78 Custom)";
max_num_aiops = 1;
rocketModel[i].model = MODEL_RP8SNI;
strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78");
rocketModel[i].numPorts = 8;
break;
case PCI_DEVICE_ID_RP16SNI:
- str = "16 (DB78 Custom)";
max_num_aiops = 2;
rocketModel[i].model = MODEL_RP16SNI;
strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78");
rocketModel[i].numPorts = 16;
break;
case PCI_DEVICE_ID_RP16INTF:
- str = "16";
max_num_aiops = 2;
rocketModel[i].model = MODEL_RP16INTF;
strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F");
rocketModel[i].numPorts = 16;
break;
case PCI_DEVICE_ID_URP16INTF:
- str = "16";
max_num_aiops = 2;
rocketModel[i].model = MODEL_UPCI_RP16INTF;
strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F");
rocketModel[i].numPorts = 16;
break;
case PCI_DEVICE_ID_CRP16INTF:
- str = "16";
max_num_aiops = 2;
rocketModel[i].model = MODEL_CPCI_RP16INTF;
strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F");
rocketModel[i].numPorts = 16;
break;
case PCI_DEVICE_ID_RP32INTF:
- str = "32";
max_num_aiops = 4;
rocketModel[i].model = MODEL_RP32INTF;
strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F");
rocketModel[i].numPorts = 32;
break;
case PCI_DEVICE_ID_URP32INTF:
- str = "32";
max_num_aiops = 4;
rocketModel[i].model = MODEL_UPCI_RP32INTF;
strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F");
rocketModel[i].numPorts = 32;
break;
case PCI_DEVICE_ID_RPP4:
- str = "Plus Quadcable";
max_num_aiops = 1;
ports_per_aiop = 4;
altChanRingIndicator++;
@@ -1910,7 +1887,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
rocketModel[i].numPorts = 4;
break;
case PCI_DEVICE_ID_RPP8:
- str = "Plus Octacable";
max_num_aiops = 2;
ports_per_aiop = 4;
altChanRingIndicator++;
@@ -1920,7 +1896,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
rocketModel[i].numPorts = 8;
break;
case PCI_DEVICE_ID_RP2_232:
- str = "Plus 2 (RS-232)";
max_num_aiops = 1;
ports_per_aiop = 2;
altChanRingIndicator++;
@@ -1930,7 +1905,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
rocketModel[i].numPorts = 2;
break;
case PCI_DEVICE_ID_RP2_422:
- str = "Plus 2 (RS-422)";
max_num_aiops = 1;
ports_per_aiop = 2;
altChanRingIndicator++;
@@ -1943,7 +1917,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
max_num_aiops = 1;
ports_per_aiop = 6;
- str = "6-port";
/* If revision is 1, the rocketmodem flash must be loaded.
* If it is 2 it is a "socketed" version. */
@@ -1961,7 +1934,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
case PCI_DEVICE_ID_RP4M:
max_num_aiops = 1;
ports_per_aiop = 4;
- str = "4-port";
if (dev->revision == 1) {
rcktpt_type[i] = ROCKET_TYPE_MODEMII;
rocketModel[i].loadrm2 = 1;
@@ -1974,7 +1946,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
rocketModel[i].numPorts = 4;
break;
default:
- str = "(unknown/unsupported)";
max_num_aiops = 0;
break;
}
@@ -2000,14 +1971,12 @@ static __init int register_PCI(int i, struct pci_dev *dev)
if (!
(sInW(ConfigIO + _PCI_9030_GPIO_CTRL) &
PCI_GPIO_CTRL_8PORT)) {
- str = "Quadcable";
ports_per_aiop = 4;
rocketModel[i].numPorts = 4;
}
}
break;
case PCI_DEVICE_ID_UPCI_RM3_8PORT:
- str = "8 ports";
max_num_aiops = 1;
rocketModel[i].model = MODEL_UPCI_RM3_8PORT;
strcpy(rocketModel[i].modelString, "RocketModem III 8 port");
@@ -2018,7 +1987,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
break;
case PCI_DEVICE_ID_UPCI_RM3_4PORT:
- str = "4 ports";
max_num_aiops = 1;
rocketModel[i].model = MODEL_UPCI_RM3_4PORT;
strcpy(rocketModel[i].modelString, "RocketModem III 4 port");
@@ -2032,21 +2000,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
break;
}
- switch (rcktpt_type[i]) {
- case ROCKET_TYPE_MODEM:
- board_type = "RocketModem";
- break;
- case ROCKET_TYPE_MODEMII:
- board_type = "RocketModem II";
- break;
- case ROCKET_TYPE_MODEMIII:
- board_type = "RocketModem III";
- break;
- default:
- board_type = "RocketPort";
- break;
- }
-
if (fast_clock) {
sClockPrescale = 0x12; /* mod 2 (divide by 3) */
rp_baud_base[i] = 921600;
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c
index d89aa38c5cf..1b37626e8f1 100644
--- a/drivers/tty/serial/21285.c
+++ b/drivers/tty/serial/21285.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/21285.c
- *
* Driver for the serial port on the 21285 StrongArm-110 core logic chip.
*
* Based on drivers/char/serial.c
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index 6611535f444..b40f7b90c81 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/8250.c
- *
* Driver for 8250/16550-type serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
@@ -273,7 +271,7 @@ static const struct serial8250_config uart_config[] = {
.fifo_size = 32,
.tx_loadsz = 32,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
- .flags = UART_CAP_FIFO | UART_CAP_UUE,
+ .flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE,
},
[PORT_RM9000] = {
.name = "RM9000",
@@ -303,6 +301,14 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
+ [PORT_TEGRA] = {
+ .name = "Tegra",
+ .fifo_size = 32,
+ .tx_loadsz = 8,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
+ UART_FCR_T_TRIG_01,
+ .flags = UART_CAP_FIFO | UART_CAP_RTOIE,
+ },
};
#if defined(CONFIG_MIPS_ALCHEMY)
@@ -1427,6 +1433,27 @@ static void serial8250_enable_ms(struct uart_port *port)
serial_out(up, UART_IER, up->ier);
}
+/*
+ * Clear the Tegra rx fifo after a break
+ *
+ * FIXME: This needs to become a port specific callback once we have a
+ * framework for this
+ */
+static void clear_rx_fifo(struct uart_8250_port *up)
+{
+ unsigned int status, tmout = 10000;
+ do {
+ status = serial_in(up, UART_LSR);
+ if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
+ status = serial_in(up, UART_RX);
+ else
+ break;
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while (1);
+}
+
static void
receive_chars(struct uart_8250_port *up, unsigned int *status)
{
@@ -1462,6 +1489,13 @@ receive_chars(struct uart_8250_port *up, unsigned int *status)
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
up->port.icount.brk++;
/*
+ * If tegra port then clear the rx fifo to
+ * accept another break/character.
+ */
+ if (up->port.type == PORT_TEGRA)
+ clear_rx_fifo(up);
+
+ /*
* We do the SysRQ and SAK checking
* here because otherwise the break
* may get masked by ignore_status_mask
@@ -2405,7 +2439,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
UART_ENABLE_MS(&up->port, termios->c_cflag))
up->ier |= UART_IER_MSI;
if (up->capabilities & UART_CAP_UUE)
- up->ier |= UART_IER_UUE | UART_IER_RTOIE;
+ up->ier |= UART_IER_UUE;
+ if (up->capabilities & UART_CAP_RTOIE)
+ up->ier |= UART_IER_RTOIE;
serial_out(up, UART_IER, up->ier);
diff --git a/drivers/tty/serial/8250.h b/drivers/tty/serial/8250.h
index 6e19ea3e48d..6edf4a6a22d 100644
--- a/drivers/tty/serial/8250.h
+++ b/drivers/tty/serial/8250.h
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/8250.h
- *
* Driver for 8250/16550-type serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
@@ -44,6 +42,7 @@ struct serial8250_config {
#define UART_CAP_SLEEP (1 << 10) /* UART has IER sleep */
#define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */
#define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */
+#define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */
#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
diff --git a/drivers/tty/serial/8250_accent.c b/drivers/tty/serial/8250_accent.c
index 9c10262f246..34b51c65119 100644
--- a/drivers/tty/serial/8250_accent.c
+++ b/drivers/tty/serial/8250_accent.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/8250_accent.c
- *
* Copyright (C) 2005 Russell King.
* Data taken from include/asm-i386/serial.h
*
diff --git a/drivers/tty/serial/8250_boca.c b/drivers/tty/serial/8250_boca.c
index 3bfe0f7b26f..d125dc10798 100644
--- a/drivers/tty/serial/8250_boca.c
+++ b/drivers/tty/serial/8250_boca.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/8250_boca.c
- *
* Copyright (C) 2005 Russell King.
* Data taken from include/asm-i386/serial.h
*
diff --git a/drivers/tty/serial/8250_exar_st16c554.c b/drivers/tty/serial/8250_exar_st16c554.c
index 567143ace15..bf53aabf9b5 100644
--- a/drivers/tty/serial/8250_exar_st16c554.c
+++ b/drivers/tty/serial/8250_exar_st16c554.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/8250_exar.c
- *
* Written by Paul B Schroeder < pschroeder "at" uplogix "dot" com >
* Based on 8250_boca.
*
diff --git a/drivers/tty/serial/8250_fourport.c b/drivers/tty/serial/8250_fourport.c
index 6375d68b791..be158260962 100644
--- a/drivers/tty/serial/8250_fourport.c
+++ b/drivers/tty/serial/8250_fourport.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/8250_fourport.c
- *
* Copyright (C) 2005 Russell King.
* Data taken from include/asm-i386/serial.h
*
diff --git a/drivers/tty/serial/8250_hub6.c b/drivers/tty/serial/8250_hub6.c
index 7609150e7d5..a5c778e83de 100644
--- a/drivers/tty/serial/8250_hub6.c
+++ b/drivers/tty/serial/8250_hub6.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/8250_hub6.c
- *
* Copyright (C) 2005 Russell King.
* Data taken from include/asm-i386/serial.h
*
diff --git a/drivers/tty/serial/8250_mca.c b/drivers/tty/serial/8250_mca.c
index d10be944ad4..d20abf04541 100644
--- a/drivers/tty/serial/8250_mca.c
+++ b/drivers/tty/serial/8250_mca.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/8250_mca.c
- *
* Copyright (C) 2005 Russell King.
* Data taken from include/asm-i386/serial.h
*
diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c
index 738cec9807d..4b4968a294b 100644
--- a/drivers/tty/serial/8250_pci.c
+++ b/drivers/tty/serial/8250_pci.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/8250_pci.c
- *
* Probe module for 8250/16550-type PCI serial ports.
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
@@ -973,6 +971,14 @@ ce4100_serial_setup(struct serial_private *priv,
return ret;
}
+static int
+pci_omegapci_setup(struct serial_private *priv,
+ struct pciserial_board *board,
+ struct uart_port *port, int idx)
+{
+ return setup_port(priv, port, 2, idx * 8, 0);
+}
+
static int skip_tx_en_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
@@ -1012,6 +1018,8 @@ static int skip_tx_en_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_TITAN_200EI 0xA016
#define PCI_DEVICE_ID_TITAN_200EISI 0xA017
#define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538
+#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6
+#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
@@ -1412,7 +1420,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.setup = pci_default_setup,
},
/*
- * For Oxford Semiconductor and Mainpine
+ * For Oxford Semiconductor Tornado based devices
*/
{
.vendor = PCI_VENDOR_ID_OXSEMI,
@@ -1430,6 +1438,24 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.init = pci_oxsemi_tornado_init,
.setup = pci_default_setup,
},
+ {
+ .vendor = PCI_VENDOR_ID_DIGI,
+ .device = PCIE_DEVICE_ID_NEO_2_OX_IBM,
+ .subvendor = PCI_SUBVENDOR_ID_IBM,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_default_setup,
+ },
+ /*
+ * Cronyx Omega PCI (PLX-chip based)
+ */
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_CRONYX_OMEGA,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_omegapci_setup,
+ },
/*
* Default "match everything" terminator entry
*/
@@ -1617,6 +1643,7 @@ enum pci_board_num_t {
pbn_ADDIDATA_PCIe_4_3906250,
pbn_ADDIDATA_PCIe_8_3906250,
pbn_ce4100_1_115200,
+ pbn_omegapci,
};
/*
@@ -2312,6 +2339,12 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.base_baud = 921600,
.reg_shift = 2,
},
+ [pbn_omegapci] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 0x200,
+ },
};
static const struct pci_device_id softmodem_blacklist[] = {
@@ -3075,6 +3108,14 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */
PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
pbn_oxsemi_8_4000000 },
+
+ /*
+ * Digi/IBM PCIe 2-port Async EIA-232 Adapter utilizing OxSemi Tornado
+ */
+ { PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM,
+ PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+
/*
* SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,
* from skokodyn@yahoo.com
@@ -3801,6 +3842,12 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_ce4100_1_115200 },
+ /*
+ * Cronyx Omega PCI
+ */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_CRONYX_OMEGA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_omegapci },
/*
* These entries match devices with class COMMUNICATION_SERIAL,
diff --git a/drivers/tty/serial/8250_pnp.c b/drivers/tty/serial/8250_pnp.c
index 4822cb50cd0..fc301f6722e 100644
--- a/drivers/tty/serial/8250_pnp.c
+++ b/drivers/tty/serial/8250_pnp.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/8250_pnp.c
- *
* Probe module for 8250/16550-type ISAPNP serial ports.
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index b1f0f83b870..636144cea93 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -537,7 +537,7 @@ config SERIAL_S3C6400
config SERIAL_S5PV210
tristate "Samsung S5PV210 Serial port support"
- depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_EXYNOS4210)
+ depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_EXYNOS4210)
select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_EXYNOS4210)
default y
help
@@ -1585,7 +1585,7 @@ config SERIAL_IFX6X60
Support for the IFX6x60 modem devices on Intel MID platforms.
config SERIAL_PCH_UART
- tristate "Intel EG20T PCH UART/OKI SEMICONDUCTOR ML7213 IOH"
+ tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) UART"
depends on PCI
select SERIAL_CORE
help
@@ -1593,10 +1593,12 @@ config SERIAL_PCH_UART
which is an IOH(Input/Output Hub) for x86 embedded processor.
Enabling PCH_DMA, this PCH UART works as DMA mode.
- This driver also can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/
- Output Hub) which is for IVI(In-Vehicle Infotainment) use.
- ML7213 is companion chip for Intel Atom E6xx series.
- ML7213 is completely compatible for Intel EG20T PCH.
+ This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+ Output Hub), ML7213 and ML7223.
+ ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
+ for MP(Media Phone) use.
+ ML7213/ML7223 is companion chip for Intel Atom E6xx series.
+ ML7213/ML7223 is completely compatible for Intel EG20T PCH.
config SERIAL_MSM_SMD
bool "Enable tty device interface for some SMD ports"
@@ -1620,4 +1622,17 @@ config SERIAL_MXS_AUART_CONSOLE
help
Enable a MXS AUART port to be the system console.
+config SERIAL_XILINX_PS_UART
+ tristate "Xilinx PS UART support"
+ select SERIAL_CORE
+ help
+ This driver supports the Xilinx PS UART port.
+
+config SERIAL_XILINX_PS_UART_CONSOLE
+ bool "Xilinx PS UART console support"
+ depends on SERIAL_XILINX_PS_UART=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Enable a Xilinx PS UART port to be the system console.
+
endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 35276043d9d..cb2628fee4c 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -95,3 +95,4 @@ obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
+obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 6d5b036ac78..50bc5a5ac65 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -540,11 +540,14 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
int i = pdev->id;
int ret;
- /* -1 emphasizes that the platform must have one port, no .N suffix */
- if (i == -1)
- i = 0;
+ /* if id is -1 scan for a free id and use that one */
+ if (i == -1) {
+ for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS; i++)
+ if (altera_uart_ports[i].port.mapbase == 0)
+ break;
+ }
- if (i >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
+ if (i < 0 || i >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
return -EINVAL;
port = &altera_uart_ports[i].port;
@@ -587,6 +590,8 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
port->ops = &altera_uart_ops;
port->flags = UPF_BOOT_AUTOCONF;
+ dev_set_drvdata(&pdev->dev, port);
+
uart_add_one_port(&altera_uart_driver, port);
return 0;
@@ -594,14 +599,13 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
static int __devexit altera_uart_remove(struct platform_device *pdev)
{
- struct uart_port *port;
- int i = pdev->id;
+ struct uart_port *port = dev_get_drvdata(&pdev->dev);
- if (i == -1)
- i = 0;
-
- port = &altera_uart_ports[i].port;
- uart_remove_one_port(&altera_uart_driver, port);
+ if (port) {
+ uart_remove_one_port(&altera_uart_driver, port);
+ dev_set_drvdata(&pdev->dev, NULL);
+ port->mapbase = 0;
+ }
return 0;
}
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index d742dd2c525..c0d10c4ddb7 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/amba.c
- *
* Driver for AMBA serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 6deee4e546b..8dc0541feec 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/amba.c
- *
* Driver for AMBA serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index f119d176110..652bdac8ce8 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/atmel_serial.c
- *
* Driver for Atmel AT91 / AT32 Serial ports
* Copyright (C) 2003 Rick Bronson
*
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index b6acd19b458..e6c3dbd781d 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/clps711x.c
- *
* Driver for CLPS711x serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h
index b754dcf0fda..cf34d26ff6c 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart.h
+++ b/drivers/tty/serial/cpm_uart/cpm_uart.h
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/cpm_uart.h
- *
* Driver for CPM (SCC/SMC) serial ports
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index a9a6a5fd169..9488da74d4f 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/cpm_uart.c
- *
* Driver for CPM (SCC/SMC) serial ports; core driver
*
* Based on arch/ppc/cpm2_io/uart.c by Dan Malek
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
index 3fc1d66e32c..18f79575894 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/cpm_uart.c
- *
* Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
*
* Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h
index 10eecd6af6d..60c7e94cde1 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/cpm_uart/cpm_uart_cpm1.h
- *
* Driver for CPM (SCC/SMC) serial ports
*
* definitions for cpm1
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
index 814ac006393..a4927e66e74 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/cpm_uart_cpm2.c
- *
* Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
*
* Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h
index 7194c63dcf5..51e651a6993 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/cpm_uart/cpm_uart_cpm2.h
- *
* Driver for CPM (SCC/SMC) serial ports
*
* definitions for cpm2
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 8ee5a41d340..5315525220f 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -41,7 +41,6 @@
#include <linux/tty.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
-#include <linux/tty.h>
#include <linux/kfifo.h>
#include <linux/tty_flip.h>
#include <linux/timer.h>
@@ -56,7 +55,6 @@
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/wait.h>
-#include <linux/tty.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/spi/ifx_modem.h>
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 62df72d9f0a..a54473123e0 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/imx.c
- *
* Driver for Motorola IMX serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index bfee9b4c666..e6ba8387650 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1,5 +1,5 @@
/*
- * drivers/serial/msm_serial.c - driver for msm7k serial device and console
+ * Driver for msm7k serial device and console
*
* Copyright (C) 2007 Google, Inc.
* Author: Robert Love <rlove@google.com>
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
index 9b8dc5d0d85..e4acef5de77 100644
--- a/drivers/tty/serial/msm_serial.h
+++ b/drivers/tty/serial/msm_serial.h
@@ -1,6 +1,4 @@
/*
- * drivers/serial/msm_serial.h
- *
* Copyright (C) 2007 Google, Inc.
* Author: Robert Love <rlove@google.com>
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c
index beeff1e8609..4f41dcdcb77 100644
--- a/drivers/tty/serial/msm_smd_tty.c
+++ b/drivers/tty/serial/msm_smd_tty.c
@@ -1,5 +1,4 @@
-/* drivers/tty/serial/msm_smd_tty.c
- *
+/*
* Copyright (C) 2007 Google, Inc.
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c
index 7735c9f35fa..d40da78e7c8 100644
--- a/drivers/tty/serial/netx-serial.c
+++ b/drivers/tty/serial/netx-serial.c
@@ -1,6 +1,4 @@
/*
- * drivers/serial/netx-serial.c
- *
* Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 26403b8e4b9..c63d0d152af 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -253,6 +253,8 @@ enum pch_uart_num_t {
pch_ml7213_uart0,
pch_ml7213_uart1,
pch_ml7213_uart2,
+ pch_ml7223_uart0,
+ pch_ml7223_uart1,
};
static struct pch_uart_driver_data drv_dat[] = {
@@ -263,6 +265,8 @@ static struct pch_uart_driver_data drv_dat[] = {
[pch_ml7213_uart0] = {PCH_UART_8LINE, 0},
[pch_ml7213_uart1] = {PCH_UART_2LINE, 1},
[pch_ml7213_uart2] = {PCH_UART_2LINE, 2},
+ [pch_ml7223_uart0] = {PCH_UART_8LINE, 0},
+ [pch_ml7223_uart1] = {PCH_UART_2LINE, 1},
};
static unsigned int default_baud = 9600;
@@ -1534,6 +1538,10 @@ static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
.driver_data = pch_ml7213_uart1},
{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8029),
.driver_data = pch_ml7213_uart2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x800C),
+ .driver_data = pch_ml7223_uart0},
+ {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x800D),
+ .driver_data = pch_ml7223_uart1},
{0,},
};
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index e1c8d4f1ce5..5acd24a27d0 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/pmac_zilog.c
- *
* Driver for PowerMac Z85c30 based ESCC cell found in the
* "macio" ASICs of various PowerMac models
*
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 1102a39b44f..4302e6e3768 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/serial/pxa.c
- *
* Based on drivers/serial/8250.c by Russell King.
*
* Author: Nicolas Pitre
diff --git a/drivers/tty/serial/s3c2400.c b/drivers/tty/serial/s3c2400.c
index fed1a9a1ffb..d13051b3df8 100644
--- a/drivers/tty/serial/s3c2400.c
+++ b/drivers/tty/serial/s3c2400.c
@@ -1,5 +1,4 @@
-/* linux/drivers/serial/s3c240.c
- *
+/*
* Driver for Samsung SoC onboard UARTs.
*
* Ben Dooks, Copyright (c) 2003-2005 Simtec Electronics
diff --git a/drivers/tty/serial/s3c2410.c b/drivers/tty/serial/s3c2410.c
index 73f089d3efd..bffe6ff9b15 100644
--- a/drivers/tty/serial/s3c2410.c
+++ b/drivers/tty/serial/s3c2410.c
@@ -1,5 +1,4 @@
-/* linux/drivers/serial/s3c2410.c
- *
+/*
* Driver for Samsung S3C2410 SoC onboard UARTs.
*
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
diff --git a/drivers/tty/serial/s3c2412.c b/drivers/tty/serial/s3c2412.c
index 1700b1a2fb7..7e2b9504a68 100644
--- a/drivers/tty/serial/s3c2412.c
+++ b/drivers/tty/serial/s3c2412.c
@@ -1,5 +1,4 @@
-/* linux/drivers/serial/s3c2412.c
- *
+/*
* Driver for Samsung S3C2412 and S3C2413 SoC onboard UARTs.
*
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
diff --git a/drivers/tty/serial/s3c2440.c b/drivers/tty/serial/s3c2440.c
index 094cc3904b1..9e10d415d5f 100644
--- a/drivers/tty/serial/s3c2440.c
+++ b/drivers/tty/serial/s3c2440.c
@@ -1,5 +1,4 @@
-/* linux/drivers/serial/s3c2440.c
- *
+/*
* Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs.
*
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
diff --git a/drivers/tty/serial/s3c24a0.c b/drivers/tty/serial/s3c24a0.c
index fad6083ca42..914eff22e49 100644
--- a/drivers/tty/serial/s3c24a0.c
+++ b/drivers/tty/serial/s3c24a0.c
@@ -1,5 +1,4 @@
-/* linux/drivers/serial/s3c24a0.c
- *
+/*
* Driver for Samsung S3C24A0 SoC onboard UARTs.
*
* Based on drivers/serial/s3c2410.c
diff --git a/drivers/tty/serial/s3c6400.c b/drivers/tty/serial/s3c6400.c
index 4be92ab5005..ded26c42ff3 100644
--- a/drivers/tty/serial/s3c6400.c
+++ b/drivers/tty/serial/s3c6400.c
@@ -1,5 +1,4 @@
-/* linux/drivers/serial/s3c6400.c
- *
+/*
* Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs.
*
* Copyright 2008 Openmoko, Inc.
diff --git a/drivers/tty/serial/s5pv210.c b/drivers/tty/serial/s5pv210.c
index 6ebccd70a70..fb2619f93d8 100644
--- a/drivers/tty/serial/s5pv210.c
+++ b/drivers/tty/serial/s5pv210.c
@@ -1,5 +1,4 @@
-/* linux/drivers/serial/s5pv210.c
- *
+/*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index 2199d819a98..ef7a21a6a01 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/sa1100.c
- *
* Driver for SA11x0 serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 9e2fa8d784e..f66f6482930 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1,5 +1,4 @@
-/* linux/drivers/serial/samsuing.c
- *
+/*
* Driver core for Samsung SoC onboard UARTs.
*
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index 0ac06a07d25..5b098cd7604 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -1,5 +1,4 @@
-/* linux/drivers/serial/samsung.h
- *
+/*
* Driver for Samsung SoC onboard UARTs.
*
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c
index 602d9845c52..ea2340b814e 100644
--- a/drivers/tty/serial/sb1250-duart.c
+++ b/drivers/tty/serial/sb1250-duart.c
@@ -1,6 +1,4 @@
/*
- * drivers/serial/sb1250-duart.c
- *
* Support for the asynchronous serial interface (DUART) included
* in the BCM1250 and derived System-On-a-Chip (SOC) devices.
*
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 733fe8e73f0..db7912cb7ae 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/core.c
- *
* Driver core for serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
@@ -172,12 +170,16 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, int in
retval = uport->ops->startup(uport);
if (retval == 0) {
- if (init_hw) {
- /*
- * Initialise the hardware port settings.
- */
- uart_change_speed(tty, state, NULL);
+ if (uart_console(uport) && uport->cons->cflag) {
+ tty->termios->c_cflag = uport->cons->cflag;
+ uport->cons->cflag = 0;
+ }
+ /*
+ * Initialise the hardware port settings.
+ */
+ uart_change_speed(tty, state, NULL);
+ if (init_hw) {
/*
* Setup the RTS and DTR signals once the
* port is open and ready to respond.
@@ -1240,17 +1242,6 @@ static void uart_set_termios(struct tty_struct *tty,
}
spin_unlock_irqrestore(&state->uart_port->lock, flags);
}
-#if 0
- /*
- * No need to wake up processes in open wait, since they
- * sample the CLOCAL flag once, and don't recheck it.
- * XXX It's not clear whether the current behavior is correct
- * or not. Hence, this may change.....
- */
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&state->uart_port.open_wait);
-#endif
}
/*
@@ -1423,7 +1414,6 @@ static void __uart_wait_until_sent(struct uart_port *port, int timeout)
if (time_after(jiffies, expire))
break;
}
- set_current_state(TASK_RUNNING); /* might not be needed */
}
static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
@@ -1466,45 +1456,6 @@ static void uart_hangup(struct tty_struct *tty)
mutex_unlock(&port->mutex);
}
-/**
- * uart_update_termios - update the terminal hw settings
- * @tty: tty associated with UART
- * @state: UART to update
- *
- * Copy across the serial console cflag setting into the termios settings
- * for the initial open of the port. This allows continuity between the
- * kernel settings, and the settings init adopts when it opens the port
- * for the first time.
- */
-static void uart_update_termios(struct tty_struct *tty,
- struct uart_state *state)
-{
- struct uart_port *port = state->uart_port;
-
- if (uart_console(port) && port->cons->cflag) {
- tty->termios->c_cflag = port->cons->cflag;
- port->cons->cflag = 0;
- }
-
- /*
- * If the device failed to grab its irq resources,
- * or some other error occurred, don't try to talk
- * to the port hardware.
- */
- if (!(tty->flags & (1 << TTY_IO_ERROR))) {
- /*
- * Make termios settings take effect.
- */
- uart_change_speed(tty, state, NULL);
-
- /*
- * And finally enable the RTS and DTR signals.
- */
- if (tty->termios->c_cflag & CBAUD)
- uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
- }
-}
-
static int uart_carrier_raised(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
@@ -1524,16 +1475,8 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- if (onoff) {
+ if (onoff)
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
-
- /*
- * If this is the first open to succeed,
- * adjust things to suit.
- */
- if (!test_and_set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags))
- uart_update_termios(port->tty, state);
- }
else
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
}
@@ -1586,15 +1529,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
pr_debug("uart_open(%d) called\n", line);
/*
- * tty->driver->num won't change, so we won't fail here with
- * tty->driver_data set to something non-NULL (and therefore
- * we won't get caught by uart_close()).
- */
- retval = -ENODEV;
- if (line >= tty->driver->num)
- goto fail;
-
- /*
* We take the semaphore inside uart_get to guarantee that we won't
* be re-entered while allocating the state structure, or while we
* request any IRQs that the driver may need. This also has the nice
@@ -1972,13 +1906,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
struct tty_port *port = &state->port;
struct device *tty_dev;
struct uart_match match = {uport, drv};
- struct tty_struct *tty;
mutex_lock(&port->mutex);
- /* Must be inside the mutex lock until we convert to tty_port */
- tty = port->tty;
-
tty_dev = device_find_child(uport->dev, &match, serial_match_port);
if (device_may_wakeup(tty_dev)) {
if (!enable_irq_wake(uport->irq))
diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
index b1962025b1a..2430319f2f5 100644
--- a/drivers/tty/serial/serial_ks8695.c
+++ b/drivers/tty/serial/serial_ks8695.c
@@ -1,6 +1,4 @@
/*
- * drivers/serial/serial_ks8695.c
- *
* Driver for KS8695 serial ports
*
* Based on drivers/serial/serial_amba.c, by Kam Lee.
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index c50e9fbbf74..8e3fc1944e6 100644
--- a/drivers/tty/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
@@ -1,6 +1,4 @@
/*
- * drivers/serial/serial_txx9.c
- *
* Derived from many drivers using generic_serial interface,
* especially serial_tx3912.c by Steven J. Hill and r39xx_serial.c
* (was in Linux/VR tree) by Jim Pick.
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 920a6f929c8..f35b8fb94b8 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1,6 +1,4 @@
/*
- * drivers/serial/sh-sci.c
- *
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
*
* Copyright (C) 2002 - 2011 Paul Mundt
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 322bf56c0d8..37fc4e3d487 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -1,6 +1,4 @@
/*
- * drivers/serial/vt8500_serial.c
- *
* Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
*
* Based on msm_serial.c, which is:
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
new file mode 100644
index 00000000000..19cc1e8149d
--- /dev/null
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -0,0 +1,1113 @@
+/*
+ * Xilinx PS UART driver
+ *
+ * 2011 (c) Xilinx Inc.
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#define XUARTPS_TTY_NAME "ttyPS"
+#define XUARTPS_NAME "xuartps"
+#define XUARTPS_MAJOR 0 /* use dynamic node allocation */
+#define XUARTPS_MINOR 0 /* works best with devtmpfs */
+#define XUARTPS_NR_PORTS 2
+#define XUARTPS_FIFO_SIZE 16 /* FIFO size */
+#define XUARTPS_REGISTER_SPACE 0xFFF
+
+#define xuartps_readl(offset) ioread32(port->membase + offset)
+#define xuartps_writel(val, offset) iowrite32(val, port->membase + offset)
+
+/********************************Register Map********************************/
+/** UART
+ *
+ * Register offsets for the UART.
+ *
+ */
+#define XUARTPS_CR_OFFSET 0x00 /* Control Register [8:0] */
+#define XUARTPS_MR_OFFSET 0x04 /* Mode Register [10:0] */
+#define XUARTPS_IER_OFFSET 0x08 /* Interrupt Enable [10:0] */
+#define XUARTPS_IDR_OFFSET 0x0C /* Interrupt Disable [10:0] */
+#define XUARTPS_IMR_OFFSET 0x10 /* Interrupt Mask [10:0] */
+#define XUARTPS_ISR_OFFSET 0x14 /* Interrupt Status [10:0]*/
+#define XUARTPS_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator [15:0] */
+#define XUARTPS_RXTOUT_OFFSET 0x1C /* RX Timeout [7:0] */
+#define XUARTPS_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level [5:0] */
+#define XUARTPS_MODEMCR_OFFSET 0x24 /* Modem Control [5:0] */
+#define XUARTPS_MODEMSR_OFFSET 0x28 /* Modem Status [8:0] */
+#define XUARTPS_SR_OFFSET 0x2C /* Channel Status [11:0] */
+#define XUARTPS_FIFO_OFFSET 0x30 /* FIFO [15:0] or [7:0] */
+#define XUARTPS_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider [7:0] */
+#define XUARTPS_FLOWDEL_OFFSET 0x38 /* Flow Delay [15:0] */
+#define XUARTPS_IRRX_PWIDTH_OFFSET 0x3C /* IR Minimum Received Pulse
+ Width [15:0] */
+#define XUARTPS_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse
+ Width [7:0] */
+#define XUARTPS_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level [5:0] */
+
+/** Control Register
+ *
+ * The Control register (CR) controls the major functions of the device.
+ *
+ * Control Register Bit Definitions
+ */
+#define XUARTPS_CR_STOPBRK 0x00000100 /* Stop TX break */
+#define XUARTPS_CR_STARTBRK 0x00000080 /* Set TX break */
+#define XUARTPS_CR_TX_DIS 0x00000020 /* TX disabled. */
+#define XUARTPS_CR_TX_EN 0x00000010 /* TX enabled */
+#define XUARTPS_CR_RX_DIS 0x00000008 /* RX disabled. */
+#define XUARTPS_CR_RX_EN 0x00000004 /* RX enabled */
+#define XUARTPS_CR_TXRST 0x00000002 /* TX logic reset */
+#define XUARTPS_CR_RXRST 0x00000001 /* RX logic reset */
+#define XUARTPS_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
+
+/** Mode Register
+ *
+ * The mode register (MR) defines the mode of transfer as well as the data
+ * format. If this register is modified during transmission or reception,
+ * data validity cannot be guaranteed.
+ *
+ * Mode Register Bit Definitions
+ *
+ */
+#define XUARTPS_MR_CLKSEL 0x00000001 /* Pre-scalar selection */
+#define XUARTPS_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */
+#define XUARTPS_MR_CHMODE_NORM 0x00000000 /* Normal mode */
+
+#define XUARTPS_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */
+#define XUARTPS_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */
+
+#define XUARTPS_MR_PARITY_NONE 0x00000020 /* No parity mode */
+#define XUARTPS_MR_PARITY_MARK 0x00000018 /* Mark parity mode */
+#define XUARTPS_MR_PARITY_SPACE 0x00000010 /* Space parity mode */
+#define XUARTPS_MR_PARITY_ODD 0x00000008 /* Odd parity mode */
+#define XUARTPS_MR_PARITY_EVEN 0x00000000 /* Even parity mode */
+
+#define XUARTPS_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */
+#define XUARTPS_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */
+#define XUARTPS_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */
+
+/** Interrupt Registers
+ *
+ * Interrupt control logic uses the interrupt enable register (IER) and the
+ * interrupt disable register (IDR) to set the value of the bits in the
+ * interrupt mask register (IMR). The IMR determines whether to pass an
+ * interrupt to the interrupt status register (ISR).
+ * Writing a 1 to IER Enables an interrupt, writing a 1 to IDR disables an
+ * interrupt. IMR and ISR are read only, and IER and IDR are write only.
+ * Reading either IER or IDR returns 0x00.
+ *
+ * All four registers have the same bit definitions.
+ */
+#define XUARTPS_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */
+#define XUARTPS_IXR_PARITY 0x00000080 /* Parity error interrupt */
+#define XUARTPS_IXR_FRAMING 0x00000040 /* Framing error interrupt */
+#define XUARTPS_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */
+#define XUARTPS_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */
+#define XUARTPS_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */
+#define XUARTPS_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */
+#define XUARTPS_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */
+#define XUARTPS_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */
+#define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
+#define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */
+
+/** Channel Status Register
+ *
+ * The channel status register (CSR) is provided to enable the control logic
+ * to monitor the status of bits in the channel interrupt status register,
+ * even if these are masked out by the interrupt mask register.
+ */
+#define XUARTPS_SR_RXEMPTY 0x00000002 /* RX FIFO empty */
+#define XUARTPS_SR_TXEMPTY 0x00000008 /* TX FIFO empty */
+#define XUARTPS_SR_TXFULL 0x00000010 /* TX FIFO full */
+#define XUARTPS_SR_RXTRIG 0x00000001 /* Rx Trigger */
+
+/**
+ * xuartps_isr - Interrupt handler
+ * @irq: Irq number
+ * @dev_id: Id of the port
+ *
+ * Returns IRQHANDLED
+ **/
+static irqreturn_t xuartps_isr(int irq, void *dev_id)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+ struct tty_struct *tty;
+ unsigned long flags;
+ unsigned int isrstatus, numbytes;
+ unsigned int data;
+ char status = TTY_NORMAL;
+
+ /* Get the tty which could be NULL so don't assume it's valid */
+ tty = tty_port_tty_get(&port->state->port);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Read the interrupt status register to determine which
+ * interrupt(s) is/are active.
+ */
+ isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET);
+
+ /* drop byte with parity error if IGNPAR specified */
+ if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY)
+ isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT);
+
+ isrstatus &= port->read_status_mask;
+ isrstatus &= ~port->ignore_status_mask;
+
+ if ((isrstatus & XUARTPS_IXR_TOUT) ||
+ (isrstatus & XUARTPS_IXR_RXTRIG)) {
+ /* Receive Timeout Interrupt */
+ while ((xuartps_readl(XUARTPS_SR_OFFSET) &
+ XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) {
+ data = xuartps_readl(XUARTPS_FIFO_OFFSET);
+ port->icount.rx++;
+
+ if (isrstatus & XUARTPS_IXR_PARITY) {
+ port->icount.parity++;
+ status = TTY_PARITY;
+ } else if (isrstatus & XUARTPS_IXR_FRAMING) {
+ port->icount.frame++;
+ status = TTY_FRAME;
+ } else if (isrstatus & XUARTPS_IXR_OVERRUN)
+ port->icount.overrun++;
+
+ if (tty)
+ uart_insert_char(port, isrstatus,
+ XUARTPS_IXR_OVERRUN, data,
+ status);
+ }
+ spin_unlock(&port->lock);
+ if (tty)
+ tty_flip_buffer_push(tty);
+ spin_lock(&port->lock);
+ }
+
+ /* Dispatch an appropriate handler */
+ if ((isrstatus & XUARTPS_IXR_TXEMPTY) == XUARTPS_IXR_TXEMPTY) {
+ if (uart_circ_empty(&port->state->xmit)) {
+ xuartps_writel(XUARTPS_IXR_TXEMPTY,
+ XUARTPS_IDR_OFFSET);
+ } else {
+ numbytes = port->fifosize;
+ /* Break if no more data available in the UART buffer */
+ while (numbytes--) {
+ if (uart_circ_empty(&port->state->xmit))
+ break;
+ /* Get the data from the UART circular buffer
+ * and write it to the xuartps's TX_FIFO
+ * register.
+ */
+ xuartps_writel(
+ port->state->xmit.buf[port->state->xmit.
+ tail], XUARTPS_FIFO_OFFSET);
+
+ port->icount.tx++;
+
+ /* Adjust the tail of the UART buffer and wrap
+ * the buffer if it reaches limit.
+ */
+ port->state->xmit.tail =
+ (port->state->xmit.tail + 1) & \
+ (UART_XMIT_SIZE - 1);
+ }
+
+ if (uart_circ_chars_pending(
+ &port->state->xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+ }
+ }
+
+ xuartps_writel(isrstatus, XUARTPS_ISR_OFFSET);
+
+ /* be sure to release the lock and tty before leaving */
+ spin_unlock_irqrestore(&port->lock, flags);
+ tty_kref_put(tty);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * xuartps_set_baud_rate - Calculate and set the baud rate
+ * @port: Handle to the uart port structure
+ * @baud: Baud rate to set
+ *
+ * Returns baud rate, requested baud when possible, or actual baud when there
+ * was too much error
+ **/
+static unsigned int xuartps_set_baud_rate(struct uart_port *port,
+ unsigned int baud)
+{
+ unsigned int sel_clk;
+ unsigned int calc_baud = 0;
+ unsigned int brgr_val, brdiv_val;
+ unsigned int bauderror;
+
+ /* Formula to obtain baud rate is
+ * baud_tx/rx rate = sel_clk/CD * (BDIV + 1)
+ * input_clk = (Uart User Defined Clock or Apb Clock)
+ * depends on UCLKEN in MR Reg
+ * sel_clk = input_clk or input_clk/8;
+ * depends on CLKS in MR reg
+ * CD and BDIV depends on values in
+ * baud rate generate register
+ * baud rate clock divisor register
+ */
+ sel_clk = port->uartclk;
+ if (xuartps_readl(XUARTPS_MR_OFFSET) & XUARTPS_MR_CLKSEL)
+ sel_clk = sel_clk / 8;
+
+ /* Find the best values for baud generation */
+ for (brdiv_val = 4; brdiv_val < 255; brdiv_val++) {
+
+ brgr_val = sel_clk / (baud * (brdiv_val + 1));
+ if (brgr_val < 2 || brgr_val > 65535)
+ continue;
+
+ calc_baud = sel_clk / (brgr_val * (brdiv_val + 1));
+
+ if (baud > calc_baud)
+ bauderror = baud - calc_baud;
+ else
+ bauderror = calc_baud - baud;
+
+ /* use the values when percent error is acceptable */
+ if (((bauderror * 100) / baud) < 3) {
+ calc_baud = baud;
+ break;
+ }
+ }
+
+ /* Set the values for the new baud rate */
+ xuartps_writel(brgr_val, XUARTPS_BAUDGEN_OFFSET);
+ xuartps_writel(brdiv_val, XUARTPS_BAUDDIV_OFFSET);
+
+ return calc_baud;
+}
+
+/*----------------------Uart Operations---------------------------*/
+
+/**
+ * xuartps_start_tx - Start transmitting bytes
+ * @port: Handle to the uart port structure
+ *
+ **/
+static void xuartps_start_tx(struct uart_port *port)
+{
+ unsigned int status, numbytes = port->fifosize;
+
+ if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port))
+ return;
+
+ status = xuartps_readl(XUARTPS_CR_OFFSET);
+ /* Set the TX enable bit and clear the TX disable bit to enable the
+ * transmitter.
+ */
+ xuartps_writel((status & ~XUARTPS_CR_TX_DIS) | XUARTPS_CR_TX_EN,
+ XUARTPS_CR_OFFSET);
+
+ while (numbytes-- && ((xuartps_readl(XUARTPS_SR_OFFSET)
+ & XUARTPS_SR_TXFULL)) != XUARTPS_SR_TXFULL) {
+
+ /* Break if no more data available in the UART buffer */
+ if (uart_circ_empty(&port->state->xmit))
+ break;
+
+ /* Get the data from the UART circular buffer and
+ * write it to the xuartps's TX_FIFO register.
+ */
+ xuartps_writel(
+ port->state->xmit.buf[port->state->xmit.tail],
+ XUARTPS_FIFO_OFFSET);
+ port->icount.tx++;
+
+ /* Adjust the tail of the UART buffer and wrap
+ * the buffer if it reaches limit.
+ */
+ port->state->xmit.tail = (port->state->xmit.tail + 1) &
+ (UART_XMIT_SIZE - 1);
+ }
+
+ /* Enable the TX Empty interrupt */
+ xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_IER_OFFSET);
+
+ if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+/**
+ * xuartps_stop_tx - Stop TX
+ * @port: Handle to the uart port structure
+ *
+ **/
+static void xuartps_stop_tx(struct uart_port *port)
+{
+ unsigned int regval;
+
+ regval = xuartps_readl(XUARTPS_CR_OFFSET);
+ regval |= XUARTPS_CR_TX_DIS;
+ /* Disable the transmitter */
+ xuartps_writel(regval, XUARTPS_CR_OFFSET);
+}
+
+/**
+ * xuartps_stop_rx - Stop RX
+ * @port: Handle to the uart port structure
+ *
+ **/
+static void xuartps_stop_rx(struct uart_port *port)
+{
+ unsigned int regval;
+
+ regval = xuartps_readl(XUARTPS_CR_OFFSET);
+ regval |= XUARTPS_CR_RX_DIS;
+ /* Disable the receiver */
+ xuartps_writel(regval, XUARTPS_CR_OFFSET);
+}
+
+/**
+ * xuartps_tx_empty - Check whether TX is empty
+ * @port: Handle to the uart port structure
+ *
+ * Returns TIOCSER_TEMT on success, 0 otherwise
+ **/
+static unsigned int xuartps_tx_empty(struct uart_port *port)
+{
+ unsigned int status;
+
+ status = xuartps_readl(XUARTPS_ISR_OFFSET) & XUARTPS_IXR_TXEMPTY;
+ return status ? TIOCSER_TEMT : 0;
+}
+
+/**
+ * xuartps_break_ctl - Based on the input ctl we have to start or stop
+ * transmitting char breaks
+ * @port: Handle to the uart port structure
+ * @ctl: Value based on which start or stop decision is taken
+ *
+ **/
+static void xuartps_break_ctl(struct uart_port *port, int ctl)
+{
+ unsigned int status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ status = xuartps_readl(XUARTPS_CR_OFFSET);
+
+ if (ctl == -1)
+ xuartps_writel(XUARTPS_CR_STARTBRK | status,
+ XUARTPS_CR_OFFSET);
+ else {
+ if ((status & XUARTPS_CR_STOPBRK) == 0)
+ xuartps_writel(XUARTPS_CR_STOPBRK | status,
+ XUARTPS_CR_OFFSET);
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/**
+ * xuartps_set_termios - termios operations, handling data length, parity,
+ * stop bits, flow control, baud rate
+ * @port: Handle to the uart port structure
+ * @termios: Handle to the input termios structure
+ * @old: Values of the previously saved termios structure
+ *
+ **/
+static void xuartps_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ unsigned int cval = 0;
+ unsigned int baud;
+ unsigned long flags;
+ unsigned int ctrl_reg, mode_reg;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Empty the receive FIFO 1st before making changes */
+ while ((xuartps_readl(XUARTPS_SR_OFFSET) &
+ XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) {
+ xuartps_readl(XUARTPS_FIFO_OFFSET);
+ }
+
+ /* Disable the TX and RX to set baud rate */
+ xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
+ (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS),
+ XUARTPS_CR_OFFSET);
+
+ /* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk */
+ baud = uart_get_baud_rate(port, termios, old, 0, 10000000);
+ baud = xuartps_set_baud_rate(port, baud);
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+
+ /*
+ * Update the per-port timeout.
+ */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ /* Set TX/RX Reset */
+ xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
+ (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST),
+ XUARTPS_CR_OFFSET);
+
+ ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET);
+
+ /* Clear the RX disable and TX disable bits and then set the TX enable
+ * bit and RX enable bit to enable the transmitter and receiver.
+ */
+ xuartps_writel(
+ (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS))
+ | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN),
+ XUARTPS_CR_OFFSET);
+
+ xuartps_writel(10, XUARTPS_RXTOUT_OFFSET);
+
+ port->read_status_mask = XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXTRIG |
+ XUARTPS_IXR_OVERRUN | XUARTPS_IXR_TOUT;
+ port->ignore_status_mask = 0;
+
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= XUARTPS_IXR_PARITY |
+ XUARTPS_IXR_FRAMING;
+
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= XUARTPS_IXR_PARITY |
+ XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN;
+
+ /* ignore all characters if CREAD is not set */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= XUARTPS_IXR_RXTRIG |
+ XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY |
+ XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN;
+
+ mode_reg = xuartps_readl(XUARTPS_MR_OFFSET);
+
+ /* Handling Data Size */
+ switch (termios->c_cflag & CSIZE) {
+ case CS6:
+ cval |= XUARTPS_MR_CHARLEN_6_BIT;
+ break;
+ case CS7:
+ cval |= XUARTPS_MR_CHARLEN_7_BIT;
+ break;
+ default:
+ case CS8:
+ cval |= XUARTPS_MR_CHARLEN_8_BIT;
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= CS8;
+ break;
+ }
+
+ /* Handling Parity and Stop Bits length */
+ if (termios->c_cflag & CSTOPB)
+ cval |= XUARTPS_MR_STOPMODE_2_BIT; /* 2 STOP bits */
+ else
+ cval |= XUARTPS_MR_STOPMODE_1_BIT; /* 1 STOP bit */
+
+ if (termios->c_cflag & PARENB) {
+ /* Mark or Space parity */
+ if (termios->c_cflag & CMSPAR) {
+ if (termios->c_cflag & PARODD)
+ cval |= XUARTPS_MR_PARITY_MARK;
+ else
+ cval |= XUARTPS_MR_PARITY_SPACE;
+ } else if (termios->c_cflag & PARODD)
+ cval |= XUARTPS_MR_PARITY_ODD;
+ else
+ cval |= XUARTPS_MR_PARITY_EVEN;
+ } else
+ cval |= XUARTPS_MR_PARITY_NONE;
+ xuartps_writel(cval , XUARTPS_MR_OFFSET);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/**
+ * xuartps_startup - Called when an application opens a xuartps port
+ * @port: Handle to the uart port structure
+ *
+ * Returns 0 on success, negative error otherwise
+ **/
+static int xuartps_startup(struct uart_port *port)
+{
+ unsigned int retval = 0, status = 0;
+
+ retval = request_irq(port->irq, xuartps_isr, 0, XUARTPS_NAME,
+ (void *)port);
+ if (retval)
+ return retval;
+
+ /* Disable the TX and RX */
+ xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS,
+ XUARTPS_CR_OFFSET);
+
+ /* Set the Control Register with TX/RX Enable, TX/RX Reset,
+ * no break chars.
+ */
+ xuartps_writel(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST,
+ XUARTPS_CR_OFFSET);
+
+ status = xuartps_readl(XUARTPS_CR_OFFSET);
+
+ /* Clear the RX disable and TX disable bits and then set the TX enable
+ * bit and RX enable bit to enable the transmitter and receiver.
+ */
+ xuartps_writel((status & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS))
+ | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN |
+ XUARTPS_CR_STOPBRK), XUARTPS_CR_OFFSET);
+
+ /* Set the Mode Register with normal mode,8 data bits,1 stop bit,
+ * no parity.
+ */
+ xuartps_writel(XUARTPS_MR_CHMODE_NORM | XUARTPS_MR_STOPMODE_1_BIT
+ | XUARTPS_MR_PARITY_NONE | XUARTPS_MR_CHARLEN_8_BIT,
+ XUARTPS_MR_OFFSET);
+
+ /* Set the RX FIFO Trigger level to 14 assuming FIFO size as 16 */
+ xuartps_writel(14, XUARTPS_RXWM_OFFSET);
+
+ /* Receive Timeout register is enabled with value of 10 */
+ xuartps_writel(10, XUARTPS_RXTOUT_OFFSET);
+
+
+ /* Set the Interrupt Registers with desired interrupts */
+ xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
+ XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
+ XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET);
+ xuartps_writel(~(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
+ XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
+ XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT), XUARTPS_IDR_OFFSET);
+
+ return retval;
+}
+
+/**
+ * xuartps_shutdown - Called when an application closes a xuartps port
+ * @port: Handle to the uart port structure
+ *
+ **/
+static void xuartps_shutdown(struct uart_port *port)
+{
+ int status;
+
+ /* Disable interrupts */
+ status = xuartps_readl(XUARTPS_IMR_OFFSET);
+ xuartps_writel(status, XUARTPS_IDR_OFFSET);
+
+ /* Disable the TX and RX */
+ xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS,
+ XUARTPS_CR_OFFSET);
+ free_irq(port->irq, port);
+}
+
+/**
+ * xuartps_type - Set UART type to xuartps port
+ * @port: Handle to the uart port structure
+ *
+ * Returns string on success, NULL otherwise
+ **/
+static const char *xuartps_type(struct uart_port *port)
+{
+ return port->type == PORT_XUARTPS ? XUARTPS_NAME : NULL;
+}
+
+/**
+ * xuartps_verify_port - Verify the port params
+ * @port: Handle to the uart port structure
+ * @ser: Handle to the structure whose members are compared
+ *
+ * Returns 0 if success otherwise -EINVAL
+ **/
+static int xuartps_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_XUARTPS)
+ return -EINVAL;
+ if (port->irq != ser->irq)
+ return -EINVAL;
+ if (ser->io_type != UPIO_MEM)
+ return -EINVAL;
+ if (port->iobase != ser->port)
+ return -EINVAL;
+ if (ser->hub6 != 0)
+ return -EINVAL;
+ return 0;
+}
+
+/**
+ * xuartps_request_port - Claim the memory region attached to xuartps port,
+ * called when the driver adds a xuartps port via
+ * uart_add_one_port()
+ * @port: Handle to the uart port structure
+ *
+ * Returns 0, -ENOMEM if request fails
+ **/
+static int xuartps_request_port(struct uart_port *port)
+{
+ if (!request_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE,
+ XUARTPS_NAME)) {
+ return -ENOMEM;
+ }
+
+ port->membase = ioremap(port->mapbase, XUARTPS_REGISTER_SPACE);
+ if (!port->membase) {
+ dev_err(port->dev, "Unable to map registers\n");
+ release_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/**
+ * xuartps_release_port - Release the memory region attached to a xuartps
+ * port, called when the driver removes a xuartps
+ * port via uart_remove_one_port().
+ * @port: Handle to the uart port structure
+ *
+ **/
+static void xuartps_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE);
+ iounmap(port->membase);
+ port->membase = NULL;
+}
+
+/**
+ * xuartps_config_port - Configure xuartps, called when the driver adds a
+ * xuartps port
+ * @port: Handle to the uart port structure
+ * @flags: If any
+ *
+ **/
+static void xuartps_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE && xuartps_request_port(port) == 0)
+ port->type = PORT_XUARTPS;
+}
+
+/**
+ * xuartps_get_mctrl - Get the modem control state
+ *
+ * @port: Handle to the uart port structure
+ *
+ * Returns the modem control state
+ *
+ **/
+static unsigned int xuartps_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void xuartps_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* N/A */
+}
+
+static void xuartps_enable_ms(struct uart_port *port)
+{
+ /* N/A */
+}
+
+/** The UART operations structure
+ */
+static struct uart_ops xuartps_ops = {
+ .set_mctrl = xuartps_set_mctrl,
+ .get_mctrl = xuartps_get_mctrl,
+ .enable_ms = xuartps_enable_ms,
+
+ .start_tx = xuartps_start_tx, /* Start transmitting */
+ .stop_tx = xuartps_stop_tx, /* Stop transmission */
+ .stop_rx = xuartps_stop_rx, /* Stop reception */
+ .tx_empty = xuartps_tx_empty, /* Transmitter busy? */
+ .break_ctl = xuartps_break_ctl, /* Start/stop
+ * transmitting break
+ */
+ .set_termios = xuartps_set_termios, /* Set termios */
+ .startup = xuartps_startup, /* App opens xuartps */
+ .shutdown = xuartps_shutdown, /* App closes xuartps */
+ .type = xuartps_type, /* Set UART type */
+ .verify_port = xuartps_verify_port, /* Verification of port
+ * params
+ */
+ .request_port = xuartps_request_port, /* Claim resources
+ * associated with a
+ * xuartps port
+ */
+ .release_port = xuartps_release_port, /* Release resources
+ * associated with a
+ * xuartps port
+ */
+ .config_port = xuartps_config_port, /* Configure when driver
+ * adds a xuartps port
+ */
+};
+
+static struct uart_port xuartps_port[2];
+
+/**
+ * xuartps_get_port - Configure the port from the platform device resource
+ * info
+ *
+ * Returns a pointer to a uart_port or NULL for failure
+ **/
+static struct uart_port *xuartps_get_port(void)
+{
+ struct uart_port *port;
+ int id;
+
+ /* Find the next unused port */
+ for (id = 0; id < XUARTPS_NR_PORTS; id++)
+ if (xuartps_port[id].mapbase == 0)
+ break;
+
+ if (id >= XUARTPS_NR_PORTS)
+ return NULL;
+
+ port = &xuartps_port[id];
+
+ /* At this point, we've got an empty uart_port struct, initialize it */
+ spin_lock_init(&port->lock);
+ port->membase = NULL;
+ port->iobase = 1; /* mark port in use */
+ port->irq = 0;
+ port->type = PORT_UNKNOWN;
+ port->iotype = UPIO_MEM32;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->ops = &xuartps_ops;
+ port->fifosize = XUARTPS_FIFO_SIZE;
+ port->line = id;
+ port->dev = NULL;
+ return port;
+}
+
+/*-----------------------Console driver operations--------------------------*/
+
+#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
+/**
+ * xuartps_console_wait_tx - Wait for the TX to be full
+ * @port: Handle to the uart port structure
+ *
+ **/
+static void xuartps_console_wait_tx(struct uart_port *port)
+{
+ while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY)
+ != XUARTPS_SR_TXEMPTY)
+ barrier();
+}
+
+/**
+ * xuartps_console_putchar - write the character to the FIFO buffer
+ * @port: Handle to the uart port structure
+ * @ch: Character to be written
+ *
+ **/
+static void xuartps_console_putchar(struct uart_port *port, int ch)
+{
+ xuartps_console_wait_tx(port);
+ xuartps_writel(ch, XUARTPS_FIFO_OFFSET);
+}
+
+/**
+ * xuartps_console_write - perform write operation
+ * @port: Handle to the uart port structure
+ * @s: Pointer to character array
+ * @count: No of characters
+ **/
+static void xuartps_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port = &xuartps_port[co->index];
+ unsigned long flags;
+ unsigned int imr;
+ int locked = 1;
+
+ if (oops_in_progress)
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ else
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* save and disable interrupt */
+ imr = xuartps_readl(XUARTPS_IMR_OFFSET);
+ xuartps_writel(imr, XUARTPS_IDR_OFFSET);
+
+ uart_console_write(port, s, count, xuartps_console_putchar);
+ xuartps_console_wait_tx(port);
+
+ /* restore interrupt state, it seems like there may be a h/w bug
+ * in that the interrupt enable register should not need to be
+ * written based on the data sheet
+ */
+ xuartps_writel(~imr, XUARTPS_IDR_OFFSET);
+ xuartps_writel(imr, XUARTPS_IER_OFFSET);
+
+ if (locked)
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/**
+ * xuartps_console_setup - Initialize the uart to default config
+ * @co: Console handle
+ * @options: Initial settings of uart
+ *
+ * Returns 0, -ENODEV if no device
+ **/
+static int __init xuartps_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port = &xuartps_port[co->index];
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index < 0 || co->index >= XUARTPS_NR_PORTS)
+ return -EINVAL;
+
+ if (!port->mapbase) {
+ pr_debug("console on ttyPS%i not present\n", co->index);
+ return -ENODEV;
+ }
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver xuartps_uart_driver;
+
+static struct console xuartps_console = {
+ .name = XUARTPS_TTY_NAME,
+ .write = xuartps_console_write,
+ .device = uart_console_device,
+ .setup = xuartps_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */
+ .data = &xuartps_uart_driver,
+};
+
+/**
+ * xuartps_console_init - Initialization call
+ *
+ * Returns 0 on success, negative error otherwise
+ **/
+static int __init xuartps_console_init(void)
+{
+ register_console(&xuartps_console);
+ return 0;
+}
+
+console_initcall(xuartps_console_init);
+
+#endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
+
+/** Structure Definitions
+ */
+static struct uart_driver xuartps_uart_driver = {
+ .owner = THIS_MODULE, /* Owner */
+ .driver_name = XUARTPS_NAME, /* Driver name */
+ .dev_name = XUARTPS_TTY_NAME, /* Node name */
+ .major = XUARTPS_MAJOR, /* Major number */
+ .minor = XUARTPS_MINOR, /* Minor number */
+ .nr = XUARTPS_NR_PORTS, /* Number of UART ports */
+#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
+ .cons = &xuartps_console, /* Console */
+#endif
+};
+
+/* ---------------------------------------------------------------------
+ * Platform bus binding
+ */
+/**
+ * xuartps_probe - Platform driver probe
+ * @pdev: Pointer to the platform device structure
+ *
+ * Returns 0 on success, negative error otherwise
+ **/
+static int __devinit xuartps_probe(struct platform_device *pdev)
+{
+ int rc;
+ struct uart_port *port;
+ struct resource *res, *res2;
+ int clk = 0;
+
+#ifdef CONFIG_OF
+ const unsigned int *prop;
+
+ prop = of_get_property(pdev->dev.of_node, "clock", NULL);
+ if (prop)
+ clk = be32_to_cpup(prop);
+#else
+ clk = *((unsigned int *)(pdev->dev.platform_data));
+#endif
+ if (!clk) {
+ dev_err(&pdev->dev, "no clock specified\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
+
+ /* Initialize the port structure */
+ port = xuartps_get_port();
+
+ if (!port) {
+ dev_err(&pdev->dev, "Cannot get uart_port structure\n");
+ return -ENODEV;
+ } else {
+ /* Register the port.
+ * This function also registers this device with the tty layer
+ * and triggers invocation of the config_port() entry point.
+ */
+ port->mapbase = res->start;
+ port->irq = res2->start;
+ port->dev = &pdev->dev;
+ port->uartclk = clk;
+ dev_set_drvdata(&pdev->dev, port);
+ rc = uart_add_one_port(&xuartps_uart_driver, port);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "uart_add_one_port() failed; err=%i\n", rc);
+ dev_set_drvdata(&pdev->dev, NULL);
+ return rc;
+ }
+ return 0;
+ }
+}
+
+/**
+ * xuartps_remove - called when the platform driver is unregistered
+ * @pdev: Pointer to the platform device structure
+ *
+ * Returns 0 on success, negative error otherwise
+ **/
+static int __devexit xuartps_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = dev_get_drvdata(&pdev->dev);
+ int rc = 0;
+
+ /* Remove the xuartps port from the serial core */
+ if (port) {
+ rc = uart_remove_one_port(&xuartps_uart_driver, port);
+ dev_set_drvdata(&pdev->dev, NULL);
+ port->mapbase = 0;
+ }
+ return rc;
+}
+
+/**
+ * xuartps_suspend - suspend event
+ * @pdev: Pointer to the platform device structure
+ * @state: State of the device
+ *
+ * Returns 0
+ **/
+static int xuartps_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ /* Call the API provided in serial_core.c file which handles
+ * the suspend.
+ */
+ uart_suspend_port(&xuartps_uart_driver, &xuartps_port[pdev->id]);
+ return 0;
+}
+
+/**
+ * xuartps_resume - Resume after a previous suspend
+ * @pdev: Pointer to the platform device structure
+ *
+ * Returns 0
+ **/
+static int xuartps_resume(struct platform_device *pdev)
+{
+ uart_resume_port(&xuartps_uart_driver, &xuartps_port[pdev->id]);
+ return 0;
+}
+
+/* Match table for of_platform binding */
+
+#ifdef CONFIG_OF
+static struct of_device_id xuartps_of_match[] __devinitdata = {
+ { .compatible = "xlnx,xuartps", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, xuartps_of_match);
+#else
+#define xuartps_of_match NULL
+#endif
+
+static struct platform_driver xuartps_platform_driver = {
+ .probe = xuartps_probe, /* Probe method */
+ .remove = __exit_p(xuartps_remove), /* Detach method */
+ .suspend = xuartps_suspend, /* Suspend */
+ .resume = xuartps_resume, /* Resume after a suspend */
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = XUARTPS_NAME, /* Driver name */
+ .of_match_table = xuartps_of_match,
+ },
+};
+
+/* ---------------------------------------------------------------------
+ * Module Init and Exit
+ */
+/**
+ * xuartps_init - Initial driver registration call
+ *
+ * Returns whether the registration was successful or not
+ **/
+static int __init xuartps_init(void)
+{
+ int retval = 0;
+
+ /* Register the xuartps driver with the serial core */
+ retval = uart_register_driver(&xuartps_uart_driver);
+ if (retval)
+ return retval;
+
+ /* Register the platform driver */
+ retval = platform_driver_register(&xuartps_platform_driver);
+ if (retval)
+ uart_unregister_driver(&xuartps_uart_driver);
+
+ return retval;
+}
+
+/**
+ * xuartps_exit - Driver unregistration call
+ **/
+static void __exit xuartps_exit(void)
+{
+ /* The order of unregistration is important. Unregister the
+ * UART driver before the platform driver crashes the system.
+ */
+
+ /* Unregister the platform driver */
+ platform_driver_unregister(&xuartps_platform_driver);
+
+ /* Unregister the xuartps driver */
+ uart_unregister_driver(&xuartps_uart_driver);
+}
+
+module_init(xuartps_init);
+module_exit(xuartps_exit);
+
+MODULE_DESCRIPTION("Driver for PS UART");
+MODULE_AUTHOR("Xilinx Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 27da23d98e3..272e417a9b0 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/synclink.c
- *
* $Id: synclink.c,v 4.38 2005/11/07 16:30:34 paulkf Exp $
*
* Device driver for Microgate SyncLink ISA and PCI
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index f1a7918d71a..46de2e075da 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -416,6 +416,7 @@ static void flush_to_ldisc(struct work_struct *work)
struct tty_buffer *head, *tail = tty->buf.tail;
int seen_tail = 0;
while ((head = tty->buf.head) != NULL) {
+ int copied;
int count;
char *char_buf;
unsigned char *flag_buf;
@@ -442,17 +443,19 @@ static void flush_to_ldisc(struct work_struct *work)
line discipline as we want to empty the queue */
if (test_bit(TTY_FLUSHPENDING, &tty->flags))
break;
- if (!tty->receive_room || seen_tail)
- break;
- if (count > tty->receive_room)
- count = tty->receive_room;
char_buf = head->char_buf_ptr + head->read;
flag_buf = head->flag_buf_ptr + head->read;
- head->read += count;
spin_unlock_irqrestore(&tty->buf.lock, flags);
- disc->ops->receive_buf(tty, char_buf,
+ copied = disc->ops->receive_buf(tty, char_buf,
flag_buf, count);
spin_lock_irqsave(&tty->buf.lock, flags);
+
+ head->read += copied;
+
+ if (copied == 0 || seen_tail) {
+ schedule_work(&tty->buf.work);
+ break;
+ }
}
clear_bit(TTY_FLUSHING, &tty->flags);
}
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index d7d50b48287..6556f7452ba 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/tty_io.c
- *
* Copyright (C) 1991, 1992 Linus Torvalds
*/
@@ -964,12 +962,14 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
}
void tty_write_unlock(struct tty_struct *tty)
+ __releases(&tty->atomic_write_lock)
{
mutex_unlock(&tty->atomic_write_lock);
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
}
int tty_write_lock(struct tty_struct *tty, int ndelay)
+ __acquires(&tty->atomic_write_lock)
{
if (!mutex_trylock(&tty->atomic_write_lock)) {
if (ndelay)
@@ -1391,16 +1391,15 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
return ERR_PTR(-ENODEV);
tty = alloc_tty_struct();
- if (!tty)
- goto fail_no_mem;
+ if (!tty) {
+ retval = -ENOMEM;
+ goto err_module_put;
+ }
initialize_tty_struct(tty, driver, idx);
retval = tty_driver_install_tty(driver, tty);
- if (retval < 0) {
- free_tty_struct(tty);
- module_put(driver->owner);
- return ERR_PTR(retval);
- }
+ if (retval < 0)
+ goto err_deinit_tty;
/*
* Structures all installed ... call the ldisc open routines.
@@ -1409,15 +1408,18 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
*/
retval = tty_ldisc_setup(tty, tty->link);
if (retval)
- goto release_mem_out;
+ goto err_release_tty;
return tty;
-fail_no_mem:
+err_deinit_tty:
+ deinitialize_tty_struct(tty);
+ free_tty_struct(tty);
+err_module_put:
module_put(driver->owner);
- return ERR_PTR(-ENOMEM);
+ return ERR_PTR(retval);
/* call the tty release_tty routine to clean out this slot */
-release_mem_out:
+err_release_tty:
if (printk_ratelimit())
printk(KERN_INFO "tty_init_dev: ldisc open failed, "
"clearing slot %d\n", idx);
@@ -1892,6 +1894,7 @@ got_driver:
retval = tty_add_file(tty, filp);
if (retval) {
tty_unlock();
+ tty_release(inode, filp);
return retval;
}
@@ -1902,12 +1905,10 @@ got_driver:
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "opening %s...", tty->name);
#endif
- if (!retval) {
- if (tty->ops->open)
- retval = tty->ops->open(tty, filp);
- else
- retval = -ENODEV;
- }
+ if (tty->ops->open)
+ retval = tty->ops->open(tty, filp);
+ else
+ retval = -ENODEV;
filp->f_flags = saved_flags;
if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
@@ -2888,6 +2889,20 @@ void initialize_tty_struct(struct tty_struct *tty,
}
/**
+ * deinitialize_tty_struct
+ * @tty: tty to deinitialize
+ *
+ * This subroutine deinitializes a tty structure that has been newly
+ * allocated but tty_release cannot be called on that yet.
+ *
+ * Locking: none - tty in question must not be exposed at this point
+ */
+void deinitialize_tty_struct(struct tty_struct *tty)
+{
+ tty_ldisc_deinit(tty);
+}
+
+/**
* tty_put_char - write one character to a tty
* @tty: tty
* @ch: character
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 620c971422b..53f2442c609 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/tty_ioctl.c
- *
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
*
* Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index e19e1364711..5d01d32e2cf 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -956,6 +956,19 @@ void tty_ldisc_init(struct tty_struct *tty)
tty_ldisc_assign(tty, ld);
}
+/**
+ * tty_ldisc_init - ldisc cleanup for new tty
+ * @tty: tty that was allocated recently
+ *
+ * The tty structure must not becompletely set up (tty_ldisc_setup) when
+ * this call is made.
+ */
+void tty_ldisc_deinit(struct tty_struct *tty)
+{
+ put_ldisc(tty->ldisc);
+ tty_ldisc_assign(tty, NULL);
+}
+
void tty_ldisc_begin(void)
{
/* Setup the default TTY line discipline. */
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 133697540c7..3b2bb771944 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -1,6 +1,3 @@
-/*
- * drivers/char/tty_lock.c
- */
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index d6b342b5b42..3761ccf0f34 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/keyboard.c
- *
* Written for linux by Johan Myreen as a translation from
* the assembly version by Linus (with diacriticals added)
*
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index adf0ad2a885..67b1d0d7c8a 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/selection.c
- *
* This module exports the functions:
*
* 'int set_selection(struct tiocl_selection __user *, struct tty_struct *)'
@@ -334,8 +332,7 @@ int paste_selection(struct tty_struct *tty)
continue;
}
count = sel_buffer_lth - pasted;
- count = min(count, tty->receive_room);
- tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
+ count = tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
NULL, count);
pasted += count;
}
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 1564261e80c..66825c9f516 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/vc_screen.c
- *
* Provide access to virtual console memory.
* /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
* /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 4bea1efaec9..b3915b7ad3e 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/vt.c
- *
* Copyright (C) 1991, 1992 Linus Torvalds
*/
@@ -858,7 +856,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
{
unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
unsigned long end;
- unsigned int old_cols, old_rows, old_row_size, old_screen_size;
+ unsigned int old_rows, old_row_size;
unsigned int new_cols, new_rows, new_row_size, new_screen_size;
unsigned int user;
unsigned short *newscreen;
@@ -887,9 +885,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
return -ENOMEM;
old_rows = vc->vc_rows;
- old_cols = vc->vc_cols;
old_row_size = vc->vc_size_row;
- old_screen_size = vc->vc_screenbuf_size;
err = resize_screen(vc, new_cols, new_rows, user);
if (err) {
@@ -1197,6 +1193,13 @@ static void csi_J(struct vc_data *vc, int vpar)
vc->vc_x + 1);
}
break;
+ case 3: /* erase scroll-back buffer (and whole display) */
+ scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
+ vc->vc_screenbuf_size >> 1);
+ set_origin(vc);
+ if (CON_IS_VISIBLE(vc))
+ update_screen(vc);
+ /* fall through */
case 2: /* erase whole display */
count = vc->vc_cols * vc->vc_rows;
start = (unsigned short *)vc->vc_origin;
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 937d1721998..5e096f43bce 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/char/vt_ioctl.c
- *
* Copyright (C) 1992 obz under the linux copyright
*
* Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
@@ -698,10 +696,23 @@ int vt_ioctl(struct tty_struct *tty,
break;
case KDGKBMODE:
- uival = ((kbd->kbdmode == VC_RAW) ? K_RAW :
- (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
- (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
- K_XLATE);
+ 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;
/* this could be folded into KDSKBMODE, but for compatibility
@@ -1499,7 +1510,6 @@ long vt_compat_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;
void __user *up = (void __user *)arg;
int perm;
@@ -1522,7 +1532,6 @@ long vt_compat_ioctl(struct tty_struct *tty,
if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
perm = 1;
- kbd = kbd_table + console;
switch (cmd) {
/*
* these need special handlers for incompatible data structures